Merge remote-tracking branch 'aosp/upstream-master' into mergeupstream

Change-Id: If9ce6bf5a59f5fd502241197f53421f9419bf30b
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..8d9ed33
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,4 @@
+docker
+*/*/target
+target
+.git
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6ead6aa
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+target/
+**/*.rs.bk
+**/*.sw[po]
+**/*.orig
+**/Cargo.lock
+!/Cargo.lock
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..f04998d
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "tpm2-sys/libtpm2"]
+	path = tpm2-sys/libtpm2
+	url = https://chromium.googlesource.com/chromiumos/third_party/tpm2
diff --git a/.rustfmt.toml b/.rustfmt.toml
new file mode 100644
index 0000000..a2db301
--- /dev/null
+++ b/.rustfmt.toml
@@ -0,0 +1,2 @@
+use_field_init_shorthand = true
+use_try_shorthand = true
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..8446532
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,604 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "aarch64"
+version = "0.1.0"
+dependencies = [
+ "arch 0.1.0",
+ "data_model 0.1.0",
+ "devices 0.1.0",
+ "io_jail 0.1.0",
+ "kernel_cmdline 0.1.0",
+ "kvm 0.1.0",
+ "kvm_sys 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "remain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "resources 0.1.0",
+ "sync 0.1.0",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "arch"
+version = "0.1.0"
+dependencies = [
+ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "devices 0.1.0",
+ "io_jail 0.1.0",
+ "kernel_cmdline 0.1.0",
+ "kvm 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "resources 0.1.0",
+ "sync 0.1.0",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "assertions"
+version = "0.1.0"
+
+[[package]]
+name = "audio_streams"
+version = "0.1.0"
+
+[[package]]
+name = "bit_field"
+version = "0.1.0"
+dependencies = [
+ "bit_field_derive 0.1.0",
+]
+
+[[package]]
+name = "bit_field_derive"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "byteorder"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cc"
+version = "1.0.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cras-sys"
+version = "0.1.0"
+dependencies = [
+ "data_model 0.1.0",
+]
+
+[[package]]
+name = "crosvm"
+version = "0.1.0"
+dependencies = [
+ "aarch64 0.1.0",
+ "arch 0.1.0",
+ "assertions 0.1.0",
+ "audio_streams 0.1.0",
+ "bit_field 0.1.0",
+ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crosvm_plugin 0.17.0",
+ "data_model 0.1.0",
+ "devices 0.1.0",
+ "enumn 0.1.0",
+ "gpu_buffer 0.1.0",
+ "io_jail 0.1.0",
+ "kernel_cmdline 0.1.0",
+ "kernel_loader 0.1.0",
+ "kvm 0.1.0",
+ "kvm_sys 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libcras 0.1.0",
+ "msg_socket 0.1.0",
+ "net_util 0.1.0",
+ "p9 0.1.0",
+ "protobuf 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "protos 0.1.0",
+ "qcow 0.1.0",
+ "rand_ish 0.1.0",
+ "remain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "render_node_forward 0.1.0",
+ "resources 0.1.0",
+ "sync 0.1.0",
+ "sys_util 0.1.0",
+ "vhost 0.1.0",
+ "vm_control 0.1.0",
+ "x86_64 0.1.0",
+]
+
+[[package]]
+name = "crosvm_plugin"
+version = "0.17.0"
+dependencies = [
+ "kvm 0.1.0",
+ "kvm_sys 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "protobuf 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "protos 0.1.0",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "data_model"
+version = "0.1.0"
+dependencies = [
+ "assertions 0.1.0",
+]
+
+[[package]]
+name = "devices"
+version = "0.1.0"
+dependencies = [
+ "audio_streams 0.1.0",
+ "bit_field 0.1.0",
+ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "data_model 0.1.0",
+ "enumn 0.1.0",
+ "gpu_buffer 0.1.0",
+ "gpu_display 0.1.0",
+ "gpu_renderer 0.1.0",
+ "io_jail 0.1.0",
+ "kvm 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "msg_on_socket_derive 0.1.0",
+ "msg_socket 0.1.0",
+ "net_sys 0.1.0",
+ "net_util 0.1.0",
+ "p9 0.1.0",
+ "protos 0.1.0",
+ "remain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "resources 0.1.0",
+ "sync 0.1.0",
+ "sys_util 0.1.0",
+ "tpm2 0.1.0",
+ "usb_util 0.1.0",
+ "vhost 0.1.0",
+ "virtio_sys 0.1.0",
+ "vm_control 0.1.0",
+]
+
+[[package]]
+name = "enumn"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "getopts"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "gpu_buffer"
+version = "0.1.0"
+dependencies = [
+ "data_model 0.1.0",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "gpu_display"
+version = "0.1.0"
+dependencies = [
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "data_model 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "gpu_renderer"
+version = "0.1.0"
+dependencies = [
+ "data_model 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "io_jail"
+version = "0.1.0"
+dependencies = [
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "kernel_cmdline"
+version = "0.1.0"
+dependencies = [
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "kernel_loader"
+version = "0.1.0"
+dependencies = [
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "kvm"
+version = "0.1.0"
+dependencies = [
+ "kvm_sys 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "msg_socket 0.1.0",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "kvm_sys"
+version = "0.1.0"
+dependencies = [
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libcras"
+version = "0.1.0"
+dependencies = [
+ "audio_streams 0.1.0",
+ "cras-sys 0.1.0",
+ "data_model 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "log"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "msg_on_socket_derive"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "msg_socket"
+version = "0.1.0"
+dependencies = [
+ "data_model 0.1.0",
+ "msg_on_socket_derive 0.1.0",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "net_sys"
+version = "0.1.0"
+dependencies = [
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "net_util"
+version = "0.1.0"
+dependencies = [
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net_sys 0.1.0",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "p9"
+version = "0.1.0"
+dependencies = [
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wire_format_derive 0.1.0",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "poll_token_derive"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "0.4.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "protobuf"
+version = "2.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "protobuf-codegen"
+version = "2.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "protobuf 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "protoc"
+version = "2.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "protoc-rust"
+version = "2.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "protobuf 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "protobuf-codegen 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "protoc 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.7",
+]
+
+[[package]]
+name = "protos"
+version = "0.1.0"
+dependencies = [
+ "kvm_sys 0.1.0",
+ "protobuf 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "protoc-rust 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "qcow"
+version = "0.1.0"
+dependencies = [
+ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "data_model 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "remain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "qcow_utils"
+version = "0.1.0"
+dependencies = [
+ "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "qcow 0.1.0",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "quote"
+version = "0.6.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_ish"
+version = "0.1.0"
+
+[[package]]
+name = "remain"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "render_node_forward"
+version = "0.1.0"
+dependencies = [
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "resources"
+version = "0.1.0"
+dependencies = [
+ "gpu_buffer 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "msg_socket 0.1.0",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "syn"
+version = "0.15.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "sync"
+version = "0.1.0"
+
+[[package]]
+name = "sys_util"
+version = "0.1.0"
+dependencies = [
+ "data_model 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "poll_token_derive 0.1.0",
+ "sync 0.1.0",
+ "syscall_defines 0.1.0",
+]
+
+[[package]]
+name = "syscall_defines"
+version = "0.1.0"
+
+[[package]]
+name = "tempfile"
+version = "3.0.7"
+dependencies = [
+ "rand_ish 0.1.0",
+]
+
+[[package]]
+name = "tpm2"
+version = "0.1.0"
+dependencies = [
+ "tpm2-sys 0.1.0",
+]
+
+[[package]]
+name = "tpm2-sys"
+version = "0.1.0"
+dependencies = [
+ "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-xid"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "usb_util"
+version = "0.1.0"
+dependencies = [
+ "assertions 0.1.0",
+ "data_model 0.1.0",
+ "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sync 0.1.0",
+]
+
+[[package]]
+name = "vhost"
+version = "0.1.0"
+dependencies = [
+ "assertions 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net_util 0.1.0",
+ "sys_util 0.1.0",
+ "virtio_sys 0.1.0",
+]
+
+[[package]]
+name = "virtio_sys"
+version = "0.1.0"
+dependencies = [
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "vm_control"
+version = "0.1.0"
+dependencies = [
+ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "data_model 0.1.0",
+ "kvm 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "msg_socket 0.1.0",
+ "resources 0.1.0",
+ "sys_util 0.1.0",
+]
+
+[[package]]
+name = "wire_format_derive"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "x86_64"
+version = "0.1.0"
+dependencies = [
+ "arch 0.1.0",
+ "assertions 0.1.0",
+ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "data_model 0.1.0",
+ "devices 0.1.0",
+ "io_jail 0.1.0",
+ "kernel_cmdline 0.1.0",
+ "kernel_loader 0.1.0",
+ "kvm 0.1.0",
+ "kvm_sys 0.1.0",
+ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "remain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "resources 0.1.0",
+ "sync 0.1.0",
+ "sys_util 0.1.0",
+]
+
+[metadata]
+"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d"
+"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
+"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
+"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797"
+"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311"
+"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f"
+"checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238"
+"checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f"
+"checksum proc-macro2 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)" = "ab2fc21ba78ac73e4ff6b3818ece00be4e175ffbef4d0a717d978b48b24150c4"
+"checksum protobuf 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "524d165d95627ddebba768db728216c4429bbb62882f7e6ab1a6c3c54a7ed830"
+"checksum protobuf-codegen 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e142c5972a0736674d647714ac7a454f20aef31b09902d330583b8d8a96401a1"
+"checksum protoc 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "82ac4c59bf852f415c62a1d30da3348f977322dc66bdb283c92b3df9bee2073a"
+"checksum protoc-rust 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9dc0547688715431c954528a3dabe7559b4d53b3161426981e19419ea7b1f0"
+"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
+"checksum remain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3bec2543b50be4539fdc27fde082e218cf4c3895358ca77f5c52fe930589e209"
+"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
+"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
+"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..048681f
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,83 @@
+[package]
+name = "crosvm"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[profile.release]
+panic = 'abort'
+overflow-checks = true
+
+[workspace]
+members = ["qcow_utils"]
+exclude = [
+    "assertions",
+    "data_model",
+    "rand_ish",
+    "sync",
+    "sys_util",
+    "syscall_defines",
+    "tempfile",
+]
+
+[features]
+default-no-sandbox = []
+gpu = ["devices/gpu"]
+gpu-forward = ["render_node_forward"]
+plugin = ["protos/plugin", "crosvm_plugin", "protobuf"]
+sandboxed-libusb = ["devices/sandboxed-libusb", "vm_control/sandboxed-libusb"]
+tpm = ["devices/tpm"]
+wl-dmabuf = ["devices/wl-dmabuf", "gpu_buffer", "resources/wl-dmabuf"]
+
+[dependencies]
+arch = { path = "arch" }
+assertions = { path = "assertions" }
+audio_streams = "*"
+bit_field = { path = "bit_field" }
+byteorder = "=1.1.0"
+crosvm_plugin = { path = "crosvm_plugin", optional = true }
+data_model = "*"
+devices = { path = "devices" }
+enumn = { path = "enumn" }
+gpu_buffer = { path = "gpu_buffer", optional = true }
+io_jail = { path = "io_jail" }
+kernel_cmdline = { path = "kernel_cmdline" }
+kernel_loader = { path = "kernel_loader" }
+kvm = { path = "kvm" }
+kvm_sys = { path = "kvm_sys" }
+libc = "=0.2.44"
+libcras = "*"
+msg_socket = { path = "msg_socket" }
+net_util = { path = "net_util" }
+p9 = { path = "p9" }
+protobuf = { version = "2.3", optional = true }
+protos = { path = "protos", optional = true }
+qcow = { path = "qcow" }
+rand_ish = { path = "rand_ish" }
+remain = "*"
+render_node_forward = { path = "render_node_forward", optional = true }
+resources = { path = "resources" }
+sync = { path = "sync" }
+sys_util = "*"
+vhost = { path = "vhost" }
+vm_control = { path = "vm_control" }
+
+[target.'cfg(target_arch = "x86_64")'.dependencies]
+x86_64 = { path = "x86_64" }
+
+[target.'cfg(any(target_arch = "aarch64", target_arch = "arm"))'.dependencies]
+aarch64 = { path = "aarch64" }
+
+[dev-dependencies]
+sys_util = "*"
+
+[patch.crates-io]
+assertions = { path = "assertions" }
+audio_streams = { path = "../../third_party/adhd/audio_streams" } # ignored by ebuild
+data_model = { path = "data_model" }
+libcras = { path = "../../third_party/adhd/cras/client/libcras" } # ignored by ebuild
+poll_token_derive = { path = "sys_util/poll_token_derive" }
+sync = { path = "sync" }
+sys_util = { path = "sys_util" }
+syscall_defines = { path = "syscall_defines" }
+tempfile = { path = "tempfile" }
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8bafca3
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..f4d5b78
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,5 @@
+chirantan@chromium.org
+dgreid@chromium.org
+dverkamp@chromium.org
+smbarber@chromium.org
+zachr@chromium.org
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d287af8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,189 @@
+# crosvm - The Chrome OS Virtual Machine Monitor
+
+This component, known as crosvm, runs untrusted operating systems along with
+virtualized devices. No actual hardware is emulated. This only runs VMs
+through the Linux's KVM interface. What makes crosvm unique is a focus on
+safety within the programming language and a sandbox around the virtual
+devices to protect the kernel from attack in case of an exploit in the
+devices.
+
+## Building with Docker
+
+See the [README](docker/README.md) from the `docker` subdirectory to learn how
+to build crosvm in enviroments outside of the Chrome OS chroot.
+
+## Usage
+
+To see the usage information for your version of crosvm, run `crosvm` or `crosvm
+run --help`.
+
+### Boot a Kernel
+
+To run a very basic VM with just a kernel and default devices:
+
+```bash
+$ crosvm run "${KERNEL_PATH}"
+```
+
+The uncompressed kernel image, also known as vmlinux, can be found in your kernel
+build directory in the case of x86 at `arch/x86/boot/compressed/vmlinux`.
+
+### Rootfs
+
+In most cases, you will want to give the VM a virtual block device to use as a
+root file system:
+
+```bash
+$ crosvm run -r "${ROOT_IMAGE}" "${KERNEL_PATH}"
+```
+
+The root image must be a path to a disk image formatted in a way that the kernel
+can read. Typically this is a squashfs image made with `mksquashfs` or an ext4
+image made with `mkfs.ext4`. By using the `-r` argument, the kernel is
+automatically told to use that image as the root, and therefore can only be
+given once. More disks can be given with `-d` or `--rwdisk` if a writable disk
+is desired.
+
+To run crosvm with a writable rootfs:
+
+>**WARNING:** Writable disks are at risk of corruption by a malicious or
+malfunctioning guest OS.
+```bash
+crosvm run --rwdisk "${ROOT_IMAGE}" -p "root=/dev/vda" vmlinux
+```
+>**NOTE:** If more disks arguments are added prior to the desired rootfs image,
+the `root=/dev/vda` must be adjusted to the appropriate letter.
+
+### Control Socket
+
+If the control socket was enabled with `-s`, the main process can be controlled
+while crosvm is running. To tell crosvm to stop and exit, for example:
+
+>**NOTE:** If the socket path given is for a directory, a socket name underneath
+that path will be generated based on crosvm's PID.
+```bash
+$ crosvm run -s /run/crosvm.sock ${USUAL_CROSVM_ARGS}
+    <in another shell>
+$ crosvm stop /run/crosvm.sock
+```
+>**WARNING:** The guest OS will not be notified or gracefully shutdown.
+
+This will cause the original crosvm process to exit in an orderly fashion,
+allowing it to clean up any OS resources that might have stuck around if crosvm
+were terminated early.
+
+### Multiprocess Mode
+
+By default crosvm runs in multiprocess mode. Each device that supports running
+inside of a sandbox will run in a jailed child process of crosvm. The
+appropriate minijail seccomp policy files must be present either in
+`/usr/share/policy/crosvm` or in the path specified by the
+`--seccomp-policy-dir` argument. The sandbox can be disabled for testing with
+the `--disable-sandbox` option.
+
+### Virtio Wayland
+
+Virtio Wayland support requires special support on the part of the guest and as
+such is unlikely to work out of the box unless you are using a Chrome OS kernel
+along with a `termina` rootfs.
+
+To use it, ensure that the `XDG_RUNTIME_DIR` enviroment variable is set and that
+the path `$XDG_RUNTIME_DIR/wayland-0` points to the socket of the Wayland
+compositor you would like the guest to use.
+
+## Defaults
+
+The following are crosvm's default arguments and how to override them.
+
+* 256MB of memory (set with `-m`)
+* 1 virtual CPU (set with `-c`)
+* no block devices (set with `-r`, `-d`, or `--rwdisk`)
+* no network (set with `--host_ip`, `--netmask`, and `--mac`)
+* virtio wayland support if `XDG_RUNTIME_DIR` enviroment variable is set (disable with `--no-wl`)
+* only the kernel arguments necessary to run with the supported devices (add more with `-p`)
+* run in multiprocess mode (run in single process mode with `--disable-sandbox`)
+* no control socket (set with `-s`)
+
+## System Requirements
+
+A Linux kernel with KVM support (check for `/dev/kvm`) is required to run
+crosvm. In order to run certain devices, there are additional system
+requirements:
+
+* `virtio-wayland` - The `memfd_create` syscall, introduced in Linux 3.17, and a Wayland compositor.
+* `vsock` - Host Linux kernel with vhost-vsock support, introduced in Linux 4.8.
+* `multiprocess` - Host Linux kernel with seccomp-bpf and Linux namespacing support.
+* `virtio-net` - Host Linux kernel with TUN/TAP support (check for `/dev/net/tun`) and running with `CAP_NET_ADMIN` privileges.
+
+## Emulated Devices
+
+| Device           | Description                                                                        |
+|------------------|------------------------------------------------------------------------------------|
+| `CMOS/RTC`       | Used to get the current calendar time.                                             |
+| `i8042`          | Used by the guest kernel to exit crosvm.                                           |
+| `serial`         | x86 I/O port driven serial devices that print to stdout and take input from stdin. |
+| `virtio-block`   | Basic read/write block device.                                                     |
+| `virtio-net`     | Device to interface the host and guest networks.                                   |
+| `virtio-rng`     | Entropy source used to seed guest OS's entropy pool.                               |
+| `virtio-vsock`   | Enabled VSOCKs for the guests.                                                     |
+| `virtio-wayland` | Allowed guest to use host Wayland socket.                                          |
+
+## Contributing
+
+### Code Health
+
+#### `build_test`
+
+There are no automated tests run before code is committed to crosvm. In order to
+maintain sanity, please execute `build_test` before submitting code for review.
+All tests should be passing or ignored and there should be no compiler warnings
+or errors. All supported architectures are built, but only tests for x86_64 are
+run. In order to build everything without failures, sysroots must be supplied
+for each architecture. See `build_test -h` for more information.
+
+#### `rustfmt`
+
+All code should be formatted with `rustfmt`. We have a script that applies
+rustfmt to all Rust code in the crosvm repo: please run `bin/fmt` before
+checking in a change. This is different from `cargo fmt --all` which formats
+multiple crates but a single workspace only; crosvm consists of multiple
+workspaces.
+
+#### Dependencies
+
+With a few exceptions, external dependencies inside of the `Cargo.toml` files
+are not allowed. The reason being that community made crates tend to explode the
+binary size by including dozens of transitive dependencies. All these
+dependencies also must be reviewed to ensure their suitability to the crosvm
+project. Currently allowed crates are:
+
+* `byteorder` - A very small library used for endian swaps.
+* `cc` - Build time dependency needed to build C source code used in crosvm.
+* `libc` - Required to use the standard library, this crate is a simple wrapper around `libc`'s symbols.
+
+### Code Overview
+
+The crosvm source code is written in Rust and C. To build, crosvm generally
+requires the most recent stable version of rustc.
+
+Source code is organized into crates, each with their own unit tests. These
+crates are:
+
+* `crosvm` - The top-level binary front-end for using crosvm.
+* `devices` - Virtual devices exposed to the guest OS.
+* `io_jail` - Creates jailed process using `libminijail`.
+* `kernel_loader` - Loads elf64 kernel files to a slice of memory.
+* `kvm_sys` - Low-level (mostly) auto-generated structures and constants for using KVM.
+* `kvm` - Unsafe, low-level wrapper code for using `kvm_sys`.
+* `net_sys` - Low-level (mostly) auto-generated structures and constants for creating TUN/TAP devices.
+* `net_util` - Wrapper for creating TUN/TAP devices.
+* `sys_util` - Mostly safe wrappers for small system facilities such as `eventfd` or `syslog`.
+* `syscall_defines` - Lists of syscall numbers in each architecture used to make syscalls not supported in `libc`.
+* `vhost` - Wrappers for creating vhost based devices.
+* `virtio_sys` - Low-level (mostly) auto-generated structures and constants for interfacing with kernel vhost support.
+* `vm_control` - IPC for the VM.
+* `x86_64` - Support code specific to 64 bit intel machines.
+
+The `seccomp` folder contains minijail seccomp policy files for each sandboxed
+device. Because some syscalls vary by architecture, the seccomp policies are
+split by architecture.
diff --git a/aarch64/Cargo.toml b/aarch64/Cargo.toml
new file mode 100644
index 0000000..8c754d1
--- /dev/null
+++ b/aarch64/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "aarch64"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+arch = { path = "../arch" }
+data_model = { path = "../data_model" }
+devices = { path = "../devices" }
+io_jail = { path = "../io_jail" }
+kernel_cmdline = { path = "../kernel_cmdline" }
+kvm = { path = "../kvm" }
+kvm_sys = { path = "../kvm_sys" }
+libc = "*"
+remain = "*"
+resources = { path = "../resources" }
+sync = { path = "../sync" }
+sys_util = { path = "../sys_util" }
diff --git a/aarch64/src/fdt.rs b/aarch64/src/fdt.rs
new file mode 100644
index 0000000..753ca0f
--- /dev/null
+++ b/aarch64/src/fdt.rs
@@ -0,0 +1,369 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::ffi::CStr;
+use std::fs::File;
+
+use arch::fdt::{
+    begin_node, end_node, finish_fdt, generate_prop32, generate_prop64, property, property_cstring,
+    property_null, property_string, property_u32, property_u64, start_fdt, Error, Result,
+};
+use devices::{PciInterruptPin, SERIAL_ADDR};
+use sys_util::{GuestAddress, GuestMemory};
+
+// This is the start of DRAM in the physical address space.
+use crate::AARCH64_PHYS_MEM_START;
+
+// These are GIC address-space location constants.
+use crate::AARCH64_GIC_CPUI_BASE;
+use crate::AARCH64_GIC_CPUI_SIZE;
+use crate::AARCH64_GIC_DIST_BASE;
+use crate::AARCH64_GIC_DIST_SIZE;
+
+// These are RTC related constants
+use crate::AARCH64_RTC_ADDR;
+use crate::AARCH64_RTC_IRQ;
+use crate::AARCH64_RTC_SIZE;
+use devices::pl030::PL030_AMBA_ID;
+
+// These are serial device related constants.
+use crate::AARCH64_SERIAL_1_3_IRQ;
+use crate::AARCH64_SERIAL_2_4_IRQ;
+use crate::AARCH64_SERIAL_SIZE;
+use crate::AARCH64_SERIAL_SPEED;
+
+// These are related to guest virtio devices.
+use crate::AARCH64_IRQ_BASE;
+use crate::AARCH64_MMIO_BASE;
+use crate::AARCH64_MMIO_SIZE;
+use crate::AARCH64_PCI_CFG_BASE;
+use crate::AARCH64_PCI_CFG_SIZE;
+
+// This is an arbitrary number to specify the node for the GIC.
+// If we had a more complex interrupt architecture, then we'd need an enum for
+// these.
+const PHANDLE_GIC: u32 = 1;
+
+// These are specified by the Linux GIC bindings
+const GIC_FDT_IRQ_NUM_CELLS: u32 = 3;
+const GIC_FDT_IRQ_TYPE_SPI: u32 = 0;
+const GIC_FDT_IRQ_TYPE_PPI: u32 = 1;
+const GIC_FDT_IRQ_PPI_CPU_SHIFT: u32 = 8;
+const GIC_FDT_IRQ_PPI_CPU_MASK: u32 = (0xff << GIC_FDT_IRQ_PPI_CPU_SHIFT);
+const IRQ_TYPE_EDGE_RISING: u32 = 0x00000001;
+const IRQ_TYPE_LEVEL_HIGH: u32 = 0x00000004;
+const IRQ_TYPE_LEVEL_LOW: u32 = 0x00000008;
+
+fn create_memory_node(fdt: &mut Vec<u8>, guest_mem: &GuestMemory) -> Result<()> {
+    let mem_size = guest_mem.memory_size();
+    let mem_reg_prop = generate_prop64(&[AARCH64_PHYS_MEM_START, mem_size]);
+
+    begin_node(fdt, "memory")?;
+    property_string(fdt, "device_type", "memory")?;
+    property(fdt, "reg", &mem_reg_prop)?;
+    end_node(fdt)?;
+    Ok(())
+}
+
+fn create_cpu_nodes(fdt: &mut Vec<u8>, num_cpus: u32) -> Result<()> {
+    begin_node(fdt, "cpus")?;
+    property_u32(fdt, "#address-cells", 0x1)?;
+    property_u32(fdt, "#size-cells", 0x0)?;
+
+    for cpu_id in 0..num_cpus {
+        let cpu_name = format!("cpu@{:x}", cpu_id);
+        begin_node(fdt, &cpu_name)?;
+        property_string(fdt, "device_type", "cpu")?;
+        property_string(fdt, "compatible", "arm,arm-v8")?;
+        if num_cpus > 1 {
+            property_string(fdt, "enable-method", "psci")?;
+        }
+        property_u32(fdt, "reg", cpu_id)?;
+        end_node(fdt)?;
+    }
+    end_node(fdt)?;
+    Ok(())
+}
+
+fn create_gic_node(fdt: &mut Vec<u8>) -> Result<()> {
+    let gic_reg_prop = generate_prop64(&[
+        AARCH64_GIC_DIST_BASE,
+        AARCH64_GIC_DIST_SIZE,
+        AARCH64_GIC_CPUI_BASE,
+        AARCH64_GIC_CPUI_SIZE,
+    ]);
+
+    begin_node(fdt, "intc")?;
+    property_string(fdt, "compatible", "arm,cortex-a15-gic")?;
+    property_u32(fdt, "#interrupt-cells", GIC_FDT_IRQ_NUM_CELLS)?;
+    property_null(fdt, "interrupt-controller")?;
+    property(fdt, "reg", &gic_reg_prop)?;
+    property_u32(fdt, "phandle", PHANDLE_GIC)?;
+    property_u32(fdt, "#address-cells", 2)?;
+    property_u32(fdt, "#size-cells", 2)?;
+    end_node(fdt)?;
+
+    Ok(())
+}
+
+fn create_timer_node(fdt: &mut Vec<u8>, num_cpus: u32) -> Result<()> {
+    // These are fixed interrupt numbers for the timer device.
+    let irqs = [13, 14, 11, 10];
+    let compatible = "arm,armv8-timer";
+    let cpu_mask: u32 =
+        (((1 << num_cpus) - 1) << GIC_FDT_IRQ_PPI_CPU_SHIFT) & GIC_FDT_IRQ_PPI_CPU_MASK;
+
+    let mut timer_reg_cells = Vec::new();
+    for &irq in &irqs {
+        timer_reg_cells.push(GIC_FDT_IRQ_TYPE_PPI);
+        timer_reg_cells.push(irq);
+        timer_reg_cells.push(cpu_mask | IRQ_TYPE_LEVEL_LOW);
+    }
+    let timer_reg_prop = generate_prop32(timer_reg_cells.as_slice());
+
+    begin_node(fdt, "timer")?;
+    property_string(fdt, "compatible", compatible)?;
+    property(fdt, "interrupts", &timer_reg_prop)?;
+    property_null(fdt, "always-on")?;
+    end_node(fdt)?;
+
+    Ok(())
+}
+
+fn create_serial_node(fdt: &mut Vec<u8>, addr: u64, irq: u32) -> Result<()> {
+    let serial_reg_prop = generate_prop64(&[addr, AARCH64_SERIAL_SIZE]);
+    let irq = generate_prop32(&[GIC_FDT_IRQ_TYPE_SPI, irq, IRQ_TYPE_EDGE_RISING]);
+
+    begin_node(fdt, &format!("U6_16550A@{:x}", addr))?;
+    property_string(fdt, "compatible", "ns16550a")?;
+    property(fdt, "reg", &serial_reg_prop)?;
+    property_u32(fdt, "clock-frequency", AARCH64_SERIAL_SPEED)?;
+    property(fdt, "interrupts", &irq)?;
+    end_node(fdt)?;
+
+    Ok(())
+}
+
+fn create_serial_nodes(fdt: &mut Vec<u8>) -> Result<()> {
+    // Note that SERIAL_ADDR contains the I/O port addresses conventionally used
+    // for serial ports on x86. This uses the same addresses (but on the MMIO bus)
+    // to simplify the shared serial code.
+    create_serial_node(fdt, SERIAL_ADDR[0], AARCH64_SERIAL_1_3_IRQ)?;
+    create_serial_node(fdt, SERIAL_ADDR[1], AARCH64_SERIAL_2_4_IRQ)?;
+    create_serial_node(fdt, SERIAL_ADDR[2], AARCH64_SERIAL_1_3_IRQ)?;
+    create_serial_node(fdt, SERIAL_ADDR[3], AARCH64_SERIAL_2_4_IRQ)?;
+
+    Ok(())
+}
+
+// TODO(sonnyrao) -- check to see if host kernel supports PSCI 0_2
+fn create_psci_node(fdt: &mut Vec<u8>) -> Result<()> {
+    let compatible = "arm,psci-0.2";
+    begin_node(fdt, "psci")?;
+    property_string(fdt, "compatible", compatible)?;
+    // Only support aarch64 guest
+    property_string(fdt, "method", "hvc")?;
+    // These constants are from PSCI
+    property_u32(fdt, "cpu_suspend", 0xc4000001)?;
+    property_u32(fdt, "cpu_off", 0x84000002)?;
+    property_u32(fdt, "cpu_on", 0xc4000003)?;
+    property_u32(fdt, "migrate", 0xc4000005)?;
+    end_node(fdt)?;
+
+    Ok(())
+}
+
+fn create_chosen_node(
+    fdt: &mut Vec<u8>,
+    cmdline: &CStr,
+    initrd: Option<(GuestAddress, usize)>,
+) -> Result<()> {
+    begin_node(fdt, "chosen")?;
+    property_u32(fdt, "linux,pci-probe-only", 1)?;
+    property_cstring(fdt, "bootargs", cmdline)?;
+    property_u64(fdt, "kaslr", 0)?;
+    if let Some((initrd_addr, initrd_size)) = initrd {
+        let initrd_start = initrd_addr.offset() as u32;
+        let initrd_end = initrd_start + initrd_size as u32;
+        property_u32(fdt, "linux,initrd-start", initrd_start)?;
+        property_u32(fdt, "linux,initrd-end", initrd_end)?;
+    }
+    end_node(fdt)?;
+
+    Ok(())
+}
+
+fn create_pci_nodes(
+    fdt: &mut Vec<u8>,
+    pci_irqs: Vec<(u32, PciInterruptPin)>,
+    pci_device_base: u64,
+    pci_device_size: u64,
+) -> Result<()> {
+    // Add devicetree nodes describing a PCI generic host controller.
+    // See Documentation/devicetree/bindings/pci/host-generic-pci.txt in the kernel
+    // and "PCI Bus Binding to IEEE Std 1275-1994".
+    let ranges = generate_prop32(&[
+        // mmio addresses
+        0x3000000,                        // (ss = 11: 64-bit memory space)
+        (AARCH64_MMIO_BASE >> 32) as u32, // PCI address
+        AARCH64_MMIO_BASE as u32,
+        (AARCH64_MMIO_BASE >> 32) as u32, // CPU address
+        AARCH64_MMIO_BASE as u32,
+        (AARCH64_MMIO_SIZE >> 32) as u32, // size
+        AARCH64_MMIO_SIZE as u32,
+        // device addresses
+        0x3000000,                      // (ss = 11: 64-bit memory space)
+        (pci_device_base >> 32) as u32, // PCI address
+        pci_device_base as u32,
+        (pci_device_base >> 32) as u32, // CPU address
+        pci_device_base as u32,
+        (pci_device_size >> 32) as u32, // size
+        pci_device_size as u32,
+    ]);
+    let bus_range = generate_prop32(&[0, 0]); // Only bus 0
+    let reg = generate_prop64(&[AARCH64_PCI_CFG_BASE, AARCH64_PCI_CFG_SIZE]);
+
+    let mut interrupts: Vec<u32> = Vec::new();
+    let mut masks: Vec<u32> = Vec::new();
+
+    for (i, pci_irq) in pci_irqs.iter().enumerate() {
+        // PCI_DEVICE(3)
+        interrupts.push((pci_irq.0 + 1) << 11);
+        interrupts.push(0);
+        interrupts.push(0);
+
+        // INT#(1)
+        interrupts.push(pci_irq.1.to_mask() + 1);
+
+        // CONTROLLER(PHANDLE)
+        interrupts.push(PHANDLE_GIC);
+        interrupts.push(0);
+        interrupts.push(0);
+
+        // CONTROLLER_DATA(3)
+        interrupts.push(GIC_FDT_IRQ_TYPE_SPI);
+        interrupts.push(AARCH64_IRQ_BASE + i as u32);
+        interrupts.push(IRQ_TYPE_LEVEL_HIGH);
+
+        // PCI_DEVICE(3)
+        masks.push(0xf800); // bits 11..15 (device)
+        masks.push(0);
+        masks.push(0);
+
+        // INT#(1)
+        masks.push(0x7); // allow INTA#-INTD# (1 | 2 | 3 | 4)
+    }
+
+    let interrupt_map = generate_prop32(&interrupts);
+    let interrupt_map_mask = generate_prop32(&masks);
+
+    begin_node(fdt, "pci")?;
+    property_string(fdt, "compatible", "pci-host-cam-generic")?;
+    property_string(fdt, "device_type", "pci")?;
+    property(fdt, "ranges", &ranges)?;
+    property(fdt, "bus-range", &bus_range)?;
+    property_u32(fdt, "#address-cells", 3)?;
+    property_u32(fdt, "#size-cells", 2)?;
+    property(fdt, "reg", &reg)?;
+    property_u32(fdt, "#interrupt-cells", 1)?;
+    property(fdt, "interrupt-map", &interrupt_map)?;
+    property(fdt, "interrupt-map-mask", &interrupt_map_mask)?;
+    property_null(fdt, "dma-coherent")?;
+    end_node(fdt)?;
+
+    Ok(())
+}
+
+fn create_rtc_node(fdt: &mut Vec<u8>) -> Result<()> {
+    // the kernel driver for pl030 really really wants a clock node
+    // associated with an AMBA device or it will fail to probe, so we
+    // need to make up a clock node to associate with the pl030 rtc
+    // node and an associated handle with a unique phandle value.
+    const CLK_PHANDLE: u32 = 24;
+    begin_node(fdt, "pclk@3M")?;
+    property_u32(fdt, "#clock-cells", 0)?;
+    property_string(fdt, "compatible", "fixed-clock")?;
+    property_u32(fdt, "clock-frequency", 3141592)?;
+    property_u32(fdt, "phandle", CLK_PHANDLE)?;
+    end_node(fdt)?;
+
+    let rtc_name = format!("rtc@{:x}", AARCH64_RTC_ADDR);
+    let reg = generate_prop64(&[AARCH64_RTC_ADDR, AARCH64_RTC_SIZE]);
+    let irq = generate_prop32(&[GIC_FDT_IRQ_TYPE_SPI, AARCH64_RTC_IRQ, IRQ_TYPE_LEVEL_HIGH]);
+
+    begin_node(fdt, &rtc_name)?;
+    property_string(fdt, "compatible", "arm,primecell")?;
+    property_u32(fdt, "arm,primecell-periphid", PL030_AMBA_ID)?;
+    property(fdt, "reg", &reg)?;
+    property(fdt, "interrupts", &irq)?;
+    property_u32(fdt, "clocks", CLK_PHANDLE)?;
+    property_string(fdt, "clock-names", "apb_pclk")?;
+    end_node(fdt)?;
+    Ok(())
+}
+
+/// Creates a flattened device tree containing all of the parameters for the
+/// kernel and loads it into the guest memory at the specified offset.
+///
+/// # Arguments
+///
+/// * `fdt_max_size` - The amount of space reserved for the device tree
+/// * `guest_mem` - The guest memory object
+/// * `pci_irqs` - List of PCI device number to PCI interrupt pin mappings
+/// * `num_cpus` - Number of virtual CPUs the guest will have
+/// * `fdt_load_offset` - The offset into physical memory for the device tree
+/// * `pci_device_base` - The offset into physical memory for PCI device memory
+/// * `pci_device_size` - The size of PCI device memory
+/// * `cmdline` - The kernel commandline
+/// * `initrd` - An optional tuple of initrd guest physical address and size
+/// * `android_fstab` - An optional file holding Android fstab entries
+pub fn create_fdt(
+    fdt_max_size: usize,
+    guest_mem: &GuestMemory,
+    pci_irqs: Vec<(u32, PciInterruptPin)>,
+    num_cpus: u32,
+    fdt_load_offset: u64,
+    pci_device_base: u64,
+    pci_device_size: u64,
+    cmdline: &CStr,
+    initrd: Option<(GuestAddress, usize)>,
+    android_fstab: Option<File>,
+) -> Result<()> {
+    let mut fdt = vec![0; fdt_max_size];
+    start_fdt(&mut fdt, fdt_max_size)?;
+
+    // The whole thing is put into one giant node with some top level properties
+    begin_node(&mut fdt, "")?;
+    property_u32(&mut fdt, "interrupt-parent", PHANDLE_GIC)?;
+    property_string(&mut fdt, "compatible", "linux,dummy-virt")?;
+    property_u32(&mut fdt, "#address-cells", 0x2)?;
+    property_u32(&mut fdt, "#size-cells", 0x2)?;
+    if let Some(android_fstab) = android_fstab {
+        arch::android::create_android_fdt(&mut fdt, android_fstab)?;
+    }
+    create_chosen_node(&mut fdt, cmdline, initrd)?;
+    create_memory_node(&mut fdt, guest_mem)?;
+    create_cpu_nodes(&mut fdt, num_cpus)?;
+    create_gic_node(&mut fdt)?;
+    create_timer_node(&mut fdt, num_cpus)?;
+    create_serial_nodes(&mut fdt)?;
+    create_psci_node(&mut fdt)?;
+    create_pci_nodes(&mut fdt, pci_irqs, pci_device_base, pci_device_size)?;
+    create_rtc_node(&mut fdt)?;
+    // End giant node
+    end_node(&mut fdt)?;
+
+    // Allocate another buffer so we can format and then write fdt to guest
+    let mut fdt_final = vec![0; fdt_max_size];
+    finish_fdt(&mut fdt, &mut fdt_final, fdt_max_size)?;
+
+    let fdt_address = GuestAddress(AARCH64_PHYS_MEM_START + fdt_load_offset);
+    let written = guest_mem
+        .write_at_addr(fdt_final.as_slice(), fdt_address)
+        .map_err(|_| Error::FdtGuestMemoryWriteError)?;
+    if written < fdt_max_size {
+        return Err(Error::FdtGuestMemoryWriteError);
+    }
+    Ok(())
+}
diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs
new file mode 100644
index 0000000..d21d70d
--- /dev/null
+++ b/aarch64/src/lib.rs
@@ -0,0 +1,548 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::collections::BTreeMap;
+use std::error::Error as StdError;
+use std::ffi::{CStr, CString};
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::io;
+use std::os::unix::io::FromRawFd;
+use std::sync::Arc;
+
+use arch::{RunnableLinuxVm, VmComponents, VmImage};
+use devices::{
+    get_serial_tty_string, Bus, BusError, PciConfigMmio, PciDevice, PciInterruptPin,
+    SerialParameters,
+};
+use io_jail::Minijail;
+use remain::sorted;
+use resources::SystemAllocator;
+use sync::Mutex;
+use sys_util::{EventFd, GuestAddress, GuestMemory, GuestMemoryError};
+
+use kvm::*;
+use kvm_sys::kvm_device_attr;
+
+mod fdt;
+
+// We place the kernel at offset 8MB
+const AARCH64_KERNEL_OFFSET: u64 = 0x80000;
+const AARCH64_FDT_MAX_SIZE: u64 = 0x200000;
+const AARCH64_INITRD_ALIGN: u64 = 0x1000000;
+
+// These constants indicate the address space used by the ARM vGIC.
+const AARCH64_GIC_DIST_SIZE: u64 = 0x10000;
+const AARCH64_GIC_CPUI_SIZE: u64 = 0x20000;
+
+// This indicates the start of DRAM inside the physical address space.
+const AARCH64_PHYS_MEM_START: u64 = 0x80000000;
+const AARCH64_AXI_BASE: u64 = 0x40000000;
+
+// These constants indicate the placement of the GIC registers in the physical
+// address space.
+const AARCH64_GIC_DIST_BASE: u64 = AARCH64_AXI_BASE - AARCH64_GIC_DIST_SIZE;
+const AARCH64_GIC_CPUI_BASE: u64 = AARCH64_GIC_DIST_BASE - AARCH64_GIC_CPUI_SIZE;
+
+// This is the minimum number of SPI interrupts aligned to 32 + 32 for the
+// PPI (16) and GSI (16).
+const AARCH64_GIC_NR_IRQS: u32 = 64;
+
+// PSR (Processor State Register) bits
+const PSR_MODE_EL1H: u64 = 0x00000005;
+const PSR_F_BIT: u64 = 0x00000040;
+const PSR_I_BIT: u64 = 0x00000080;
+const PSR_A_BIT: u64 = 0x00000100;
+const PSR_D_BIT: u64 = 0x00000200;
+
+macro_rules! offset__of {
+    ($str:ty, $($field:ident).+ $([$idx:expr])*) => {
+        unsafe { &(*(0 as *const $str))$(.$field)*  $([$idx])* as *const _ as usize }
+    }
+}
+
+const KVM_REG_ARM64: u64 = 0x6000000000000000;
+const KVM_REG_SIZE_U64: u64 = 0x0030000000000000;
+const KVM_REG_ARM_COPROC_SHIFT: u64 = 16;
+const KVM_REG_ARM_CORE: u64 = 0x0010 << KVM_REG_ARM_COPROC_SHIFT;
+
+macro_rules! arm64_core_reg {
+    ($reg: tt) => {
+        KVM_REG_ARM64
+            | KVM_REG_SIZE_U64
+            | KVM_REG_ARM_CORE
+            | ((offset__of!(kvm_sys::user_pt_regs, $reg) / 4) as u64)
+    };
+}
+
+fn get_kernel_addr() -> GuestAddress {
+    GuestAddress(AARCH64_PHYS_MEM_START + AARCH64_KERNEL_OFFSET)
+}
+
+// Serial device requires 8 bytes of registers;
+const AARCH64_SERIAL_SIZE: u64 = 0x8;
+// This was the speed kvmtool used, not sure if it matters.
+const AARCH64_SERIAL_SPEED: u32 = 1843200;
+// The serial device gets the first interrupt line
+// Which gets mapped to the first SPI interrupt (physical 32).
+const AARCH64_SERIAL_1_3_IRQ: u32 = 0;
+const AARCH64_SERIAL_2_4_IRQ: u32 = 2;
+
+// Place the RTC device at page 2
+const AARCH64_RTC_ADDR: u64 = 0x2000;
+// The RTC device gets one 4k page
+const AARCH64_RTC_SIZE: u64 = 0x1000;
+// The RTC device gets the second interrupt line
+const AARCH64_RTC_IRQ: u32 = 1;
+
+// PCI MMIO configuration region base address.
+const AARCH64_PCI_CFG_BASE: u64 = 0x10000;
+// PCI MMIO configuration region size.
+const AARCH64_PCI_CFG_SIZE: u64 = 0x1000000;
+// This is the base address of MMIO devices.
+const AARCH64_MMIO_BASE: u64 = 0x1010000;
+// Size of the whole MMIO region.
+const AARCH64_MMIO_SIZE: u64 = 0x100000;
+// Virtio devices start at SPI interrupt number 3
+const AARCH64_IRQ_BASE: u32 = 3;
+
+#[sorted]
+#[derive(Debug)]
+pub enum Error {
+    CloneEventFd(sys_util::Error),
+    Cmdline(kernel_cmdline::Error),
+    CreateDevices(Box<dyn StdError>),
+    CreateEventFd(sys_util::Error),
+    CreateFdt(arch::fdt::Error),
+    CreateGICFailure(sys_util::Error),
+    CreateKvm(sys_util::Error),
+    CreatePciRoot(arch::DeviceRegistrationError),
+    CreateSerialDevices(arch::DeviceRegistrationError),
+    CreateSocket(io::Error),
+    CreateVcpu(sys_util::Error),
+    CreateVm(sys_util::Error),
+    InitrdLoadFailure(arch::LoadImageError),
+    KernelLoadFailure(arch::LoadImageError),
+    KernelMissing,
+    ReadPreferredTarget(sys_util::Error),
+    RegisterIrqfd(sys_util::Error),
+    RegisterPci(BusError),
+    RegisterVsock(arch::DeviceRegistrationError),
+    SetDeviceAttr(sys_util::Error),
+    SetReg(sys_util::Error),
+    SetupGuestMemory(GuestMemoryError),
+    VcpuInit(sys_util::Error),
+}
+
+impl Display for Error {
+    #[remain::check]
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        #[sorted]
+        match self {
+            CloneEventFd(e) => write!(f, "unable to clone an EventFd: {}", e),
+            Cmdline(e) => write!(f, "the given kernel command line was invalid: {}", e),
+            CreateDevices(e) => write!(f, "error creating devices: {}", e),
+            CreateEventFd(e) => write!(f, "unable to make an EventFd: {}", e),
+            CreateFdt(e) => write!(f, "FDT could not be created: {}", e),
+            CreateGICFailure(e) => write!(f, "failed to create GIC: {}", e),
+            CreateKvm(e) => write!(f, "failed to open /dev/kvm: {}", e),
+            CreatePciRoot(e) => write!(f, "failed to create a PCI root hub: {}", e),
+            CreateSerialDevices(e) => write!(f, "unable to create serial devices: {}", e),
+            CreateSocket(e) => write!(f, "failed to create socket: {}", e),
+            CreateVcpu(e) => write!(f, "failed to create VCPU: {}", e),
+            CreateVm(e) => write!(f, "failed to create vm: {}", e),
+            InitrdLoadFailure(e) => write!(f, "initrd cound not be loaded: {}", e),
+            KernelLoadFailure(e) => write!(f, "kernel cound not be loaded: {}", e),
+            KernelMissing => write!(f, "aarch64 requires a kernel"),
+            ReadPreferredTarget(e) => write!(f, "failed to read preferred target: {}", e),
+            RegisterIrqfd(e) => write!(f, "failed to register irq fd: {}", e),
+            RegisterPci(e) => write!(f, "error registering PCI bus: {}", e),
+            RegisterVsock(e) => write!(f, "error registering virtual socket device: {}", e),
+            SetDeviceAttr(e) => write!(f, "failed to set device attr: {}", e),
+            SetReg(e) => write!(f, "failed to set register: {}", e),
+            SetupGuestMemory(e) => write!(f, "failed to set up guest memory: {}", e),
+            VcpuInit(e) => write!(f, "failed to initialize VCPU: {}", e),
+        }
+    }
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl std::error::Error for Error {}
+
+/// Returns a Vec of the valid memory addresses.
+/// These should be used to configure the GuestMemory structure for the platfrom.
+pub fn arch_memory_regions(size: u64) -> Vec<(GuestAddress, u64)> {
+    vec![(GuestAddress(AARCH64_PHYS_MEM_START), size)]
+}
+
+fn fdt_offset(mem_size: u64) -> u64 {
+    // Put fdt up near the top of memory
+    // TODO(sonnyrao): will have to handle this differently if there's
+    // > 4GB memory
+    mem_size - AARCH64_FDT_MAX_SIZE - 0x10000
+}
+
+pub struct AArch64;
+
+impl arch::LinuxArch for AArch64 {
+    type Error = Error;
+
+    fn build_vm<F, E>(
+        mut components: VmComponents,
+        _split_irqchip: bool,
+        serial_parameters: &BTreeMap<u8, SerialParameters>,
+        create_devices: F,
+    ) -> Result<RunnableLinuxVm>
+    where
+        F: FnOnce(
+            &GuestMemory,
+            &mut Vm,
+            &mut SystemAllocator,
+            &EventFd,
+        ) -> std::result::Result<Vec<(Box<dyn PciDevice>, Option<Minijail>)>, E>,
+        E: StdError + 'static,
+    {
+        let mut resources =
+            Self::get_resource_allocator(components.memory_size, components.wayland_dmabuf);
+        let mem = Self::setup_memory(components.memory_size)?;
+        let kvm = Kvm::new().map_err(Error::CreateKvm)?;
+        let mut vm = Vm::new(&kvm, mem.clone()).map_err(Error::CreateVm)?;
+
+        let vcpu_count = components.vcpu_count;
+        let mut vcpus = Vec::with_capacity(vcpu_count as usize);
+        for cpu_id in 0..vcpu_count {
+            let vcpu = Vcpu::new(cpu_id as libc::c_ulong, &kvm, &vm).map_err(Error::CreateVcpu)?;
+            Self::configure_vcpu(
+                vm.get_memory(),
+                &kvm,
+                &vm,
+                &vcpu,
+                cpu_id as u64,
+                vcpu_count as u64,
+            )?;
+            vcpus.push(vcpu);
+        }
+
+        let vcpu_affinity = components.vcpu_affinity;
+
+        let irq_chip = Self::create_irq_chip(&vm)?;
+
+        let mut mmio_bus = devices::Bus::new();
+
+        let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?;
+
+        let pci_devices = create_devices(&mem, &mut vm, &mut resources, &exit_evt)
+            .map_err(|e| Error::CreateDevices(Box::new(e)))?;
+        let (pci, pci_irqs, pid_debug_label_map) =
+            arch::generate_pci_root(pci_devices, &mut mmio_bus, &mut resources, &mut vm)
+                .map_err(Error::CreatePciRoot)?;
+        let pci_bus = Arc::new(Mutex::new(PciConfigMmio::new(pci)));
+
+        // ARM doesn't really use the io bus like x86, so just create an empty bus.
+        let io_bus = devices::Bus::new();
+
+        Self::add_arch_devs(&mut vm, &mut mmio_bus)?;
+
+        let com_evt_1_3 = EventFd::new().map_err(Error::CreateEventFd)?;
+        let com_evt_2_4 = EventFd::new().map_err(Error::CreateEventFd)?;
+        let (stdio_serial_num, stdio_serial) = arch::add_serial_devices(
+            &mut mmio_bus,
+            &com_evt_1_3,
+            &com_evt_2_4,
+            &serial_parameters,
+        )
+        .map_err(Error::CreateSerialDevices)?;
+
+        vm.register_irqfd(&com_evt_1_3, AARCH64_SERIAL_1_3_IRQ)
+            .map_err(Error::RegisterIrqfd)?;
+        vm.register_irqfd(&com_evt_2_4, AARCH64_SERIAL_2_4_IRQ)
+            .map_err(Error::RegisterIrqfd)?;
+
+        mmio_bus
+            .insert(
+                pci_bus.clone(),
+                AARCH64_PCI_CFG_BASE,
+                AARCH64_PCI_CFG_SIZE,
+                false,
+            )
+            .map_err(Error::RegisterPci)?;
+
+        let mut cmdline = Self::get_base_linux_cmdline(stdio_serial_num);
+        for param in components.extra_kernel_params {
+            cmdline.insert_str(&param).map_err(Error::Cmdline)?;
+        }
+
+        let kernel_image = if let VmImage::Kernel(ref mut img) = components.vm_image {
+            img
+        } else {
+            return Err(Error::KernelMissing);
+        };
+
+        // separate out kernel loading from other setup to get a specific error for
+        // kernel loading
+        let kernel_size = arch::load_image(&mem, kernel_image, get_kernel_addr(), u64::max_value())
+            .map_err(Error::KernelLoadFailure)?;
+        let kernel_end = get_kernel_addr().offset() + kernel_size as u64;
+        Self::setup_system_memory(
+            &mem,
+            components.memory_size,
+            vcpu_count,
+            &CString::new(cmdline).unwrap(),
+            components.initrd_image,
+            pci_irqs,
+            components.android_fstab,
+            kernel_end,
+        )?;
+
+        Ok(RunnableLinuxVm {
+            vm,
+            kvm,
+            resources,
+            stdio_serial,
+            exit_evt,
+            vcpus,
+            vcpu_affinity,
+            irq_chip,
+            io_bus,
+            mmio_bus,
+            pid_debug_label_map,
+        })
+    }
+}
+
+impl AArch64 {
+    fn setup_system_memory(
+        mem: &GuestMemory,
+        mem_size: u64,
+        vcpu_count: u32,
+        cmdline: &CStr,
+        initrd_file: Option<File>,
+        pci_irqs: Vec<(u32, PciInterruptPin)>,
+        android_fstab: Option<File>,
+        kernel_end: u64,
+    ) -> Result<()> {
+        let initrd = match initrd_file {
+            Some(initrd_file) => {
+                let mut initrd_file = initrd_file;
+                let initrd_addr =
+                    (kernel_end + (AARCH64_INITRD_ALIGN - 1)) & !(AARCH64_INITRD_ALIGN - 1);
+                let initrd_max_size = mem_size - (initrd_addr - AARCH64_PHYS_MEM_START);
+                let initrd_addr = GuestAddress(initrd_addr);
+                let initrd_size =
+                    arch::load_image(mem, &mut initrd_file, initrd_addr, initrd_max_size)
+                        .map_err(Error::InitrdLoadFailure)?;
+                Some((initrd_addr, initrd_size))
+            }
+            None => None,
+        };
+        let (pci_device_base, pci_device_size) = Self::get_device_addr_base_size(mem_size);
+        fdt::create_fdt(
+            AARCH64_FDT_MAX_SIZE as usize,
+            mem,
+            pci_irqs,
+            vcpu_count,
+            fdt_offset(mem_size),
+            pci_device_base,
+            pci_device_size,
+            cmdline,
+            initrd,
+            android_fstab,
+        )
+        .map_err(Error::CreateFdt)?;
+        Ok(())
+    }
+
+    fn setup_memory(mem_size: u64) -> Result<GuestMemory> {
+        let arch_mem_regions = arch_memory_regions(mem_size);
+        let mem = GuestMemory::new(&arch_mem_regions).map_err(Error::SetupGuestMemory)?;
+        Ok(mem)
+    }
+
+    fn get_device_addr_base_size(mem_size: u64) -> (u64, u64) {
+        let base = AARCH64_PHYS_MEM_START + mem_size;
+        let size = u64::max_value() - base;
+        (base, size)
+    }
+
+    /// This returns a base part of the kernel command for this architecture
+    fn get_base_linux_cmdline(stdio_serial_num: Option<u8>) -> kernel_cmdline::Cmdline {
+        let mut cmdline = kernel_cmdline::Cmdline::new(sys_util::pagesize());
+        if stdio_serial_num.is_some() {
+            let tty_string = get_serial_tty_string(stdio_serial_num.unwrap());
+            cmdline.insert("console", &tty_string).unwrap();
+        }
+        cmdline.insert_str("panic=-1").unwrap();
+        cmdline
+    }
+
+    /// Returns a system resource allocator.
+    fn get_resource_allocator(mem_size: u64, gpu_allocation: bool) -> SystemAllocator {
+        let (device_addr_base, device_addr_size) = Self::get_device_addr_base_size(mem_size);
+        SystemAllocator::builder()
+            .add_device_addresses(device_addr_base, device_addr_size)
+            .add_mmio_addresses(AARCH64_MMIO_BASE, AARCH64_MMIO_SIZE)
+            .create_allocator(AARCH64_IRQ_BASE, gpu_allocation)
+            .unwrap()
+    }
+
+    /// This adds any early platform devices for this architecture.
+    ///
+    /// # Arguments
+    ///
+    /// * `vm` - The vm to add irqs to.
+    /// * `bus` - The bus to add devices to.
+    fn add_arch_devs(vm: &mut Vm, bus: &mut Bus) -> Result<()> {
+        let rtc_evt = EventFd::new().map_err(Error::CreateEventFd)?;
+        vm.register_irqfd(&rtc_evt, AARCH64_RTC_IRQ)
+            .map_err(Error::RegisterIrqfd)?;
+
+        let rtc = Arc::new(Mutex::new(devices::pl030::Pl030::new(rtc_evt)));
+        bus.insert(rtc, AARCH64_RTC_ADDR, AARCH64_RTC_SIZE, false)
+            .expect("failed to add rtc device");
+
+        Ok(())
+    }
+
+    /// The creates the interrupt controller device and optionally returns the fd for it.
+    /// Some architectures may not have a separate descriptor for the interrupt
+    /// controller, so they would return None even on success.
+    ///
+    /// # Arguments
+    ///
+    /// * `vm` - the vm object
+    fn create_irq_chip(vm: &Vm) -> Result<Option<File>> {
+        let cpu_if_addr: u64 = AARCH64_GIC_CPUI_BASE;
+        let dist_if_addr: u64 = AARCH64_GIC_DIST_BASE;
+        let raw_cpu_if_addr = &cpu_if_addr as *const u64;
+        let raw_dist_if_addr = &dist_if_addr as *const u64;
+
+        let cpu_if_attr = kvm_device_attr {
+            group: kvm_sys::KVM_DEV_ARM_VGIC_GRP_ADDR,
+            attr: kvm_sys::KVM_VGIC_V2_ADDR_TYPE_CPU as u64,
+            addr: raw_cpu_if_addr as u64,
+            flags: 0,
+        };
+        let dist_attr = kvm_device_attr {
+            group: kvm_sys::KVM_DEV_ARM_VGIC_GRP_ADDR,
+            attr: kvm_sys::KVM_VGIC_V2_ADDR_TYPE_DIST as u64,
+            addr: raw_dist_if_addr as u64,
+            flags: 0,
+        };
+        let mut kcd = kvm_sys::kvm_create_device {
+            type_: kvm_sys::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2,
+            fd: 0,
+            flags: 0,
+        };
+        vm.create_device(&mut kcd)
+            .map_err(|e| Error::CreateGICFailure(e))?;
+
+        // Safe because the kernel is passing us an FD back inside
+        // the struct after we successfully did the create_device ioctl
+        let vgic_fd = unsafe { File::from_raw_fd(kcd.fd as i32) };
+
+        // Safe because we allocated the struct that's being passed in
+        let ret = unsafe {
+            sys_util::ioctl_with_ref(&vgic_fd, kvm_sys::KVM_SET_DEVICE_ATTR(), &cpu_if_attr)
+        };
+        if ret != 0 {
+            return Err(Error::CreateGICFailure(sys_util::Error::new(ret)));
+        }
+
+        // Safe because we allocated the struct that's being passed in
+        let ret = unsafe {
+            sys_util::ioctl_with_ref(&vgic_fd, kvm_sys::KVM_SET_DEVICE_ATTR(), &dist_attr)
+        };
+        if ret != 0 {
+            return Err(Error::CreateGICFailure(sys_util::Error::new(ret)));
+        }
+
+        // We need to tell the kernel how many irqs to support with this vgic
+        let nr_irqs: u32 = AARCH64_GIC_NR_IRQS;
+        let nr_irqs_ptr = &nr_irqs as *const u32;
+        let nr_irqs_attr = kvm_device_attr {
+            group: kvm_sys::KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
+            attr: 0,
+            addr: nr_irqs_ptr as u64,
+            flags: 0,
+        };
+        // Safe because we allocated the struct that's being passed in
+        let ret = unsafe {
+            sys_util::ioctl_with_ref(&vgic_fd, kvm_sys::KVM_SET_DEVICE_ATTR(), &nr_irqs_attr)
+        };
+        if ret != 0 {
+            return Err(Error::CreateGICFailure(sys_util::Error::new(ret)));
+        }
+
+        // Finalize the GIC
+        let init_gic_attr = kvm_device_attr {
+            group: kvm_sys::KVM_DEV_ARM_VGIC_GRP_CTRL,
+            attr: kvm_sys::KVM_DEV_ARM_VGIC_CTRL_INIT as u64,
+            addr: 0,
+            flags: 0,
+        };
+
+        // Safe because we allocated the struct that's being passed in
+        let ret = unsafe {
+            sys_util::ioctl_with_ref(&vgic_fd, kvm_sys::KVM_SET_DEVICE_ATTR(), &init_gic_attr)
+        };
+        if ret != 0 {
+            return Err(Error::SetDeviceAttr(sys_util::Error::new(ret)));
+        }
+        Ok(Some(vgic_fd))
+    }
+
+    fn configure_vcpu(
+        guest_mem: &GuestMemory,
+        _kvm: &Kvm,
+        vm: &Vm,
+        vcpu: &Vcpu,
+        cpu_id: u64,
+        _num_cpus: u64,
+    ) -> Result<()> {
+        let mut kvi = kvm_sys::kvm_vcpu_init {
+            target: kvm_sys::KVM_ARM_TARGET_GENERIC_V8,
+            features: [0; 7],
+        };
+
+        // This reads back the kernel's preferred target type.
+        vm.arm_preferred_target(&mut kvi)
+            .map_err(Error::ReadPreferredTarget)?;
+
+        // TODO(sonnyrao): need to verify this feature is supported by host kernel
+        kvi.features[0] |= 1 << kvm_sys::KVM_ARM_VCPU_PSCI_0_2;
+
+        // Non-boot cpus are powered off initially
+        if cpu_id > 0 {
+            kvi.features[0] |= 1 << kvm_sys::KVM_ARM_VCPU_POWER_OFF;
+        }
+        vcpu.arm_vcpu_init(&kvi).map_err(Error::VcpuInit)?;
+
+        // set up registers
+        let mut data: u64;
+        let mut reg_id: u64;
+
+        // All interrupts masked
+        data = PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT | PSR_MODE_EL1H;
+        reg_id = arm64_core_reg!(pstate);
+        vcpu.set_one_reg(reg_id, data).map_err(Error::SetReg)?;
+
+        // Other cpus are powered off initially
+        if cpu_id == 0 {
+            data = AARCH64_PHYS_MEM_START + AARCH64_KERNEL_OFFSET;
+            reg_id = arm64_core_reg!(pc);
+            vcpu.set_one_reg(reg_id, data).map_err(Error::SetReg)?;
+
+            /* X0 -- fdt address */
+            let mem_size = guest_mem.memory_size();
+            data = (AARCH64_PHYS_MEM_START + fdt_offset(mem_size)) as u64;
+            // hack -- can't get this to do offsetof(regs[0]) but luckily it's at offset 0
+            reg_id = arm64_core_reg!(regs);
+            vcpu.set_one_reg(reg_id, data).map_err(Error::SetReg)?;
+        }
+        Ok(())
+    }
+}
diff --git a/arch/Cargo.toml b/arch/Cargo.toml
new file mode 100644
index 0000000..f562fca
--- /dev/null
+++ b/arch/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "arch"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+byteorder = "*"
+devices = { path = "../devices" }
+io_jail = { path = "../io_jail" }
+kernel_cmdline = { path = "../kernel_cmdline" }
+kvm = { path = "../kvm" }
+libc = "*"
+resources = { path = "../resources" }
+sync = { path = "../sync" }
+sys_util = { path = "../sys_util" }
diff --git a/arch/src/android.rs b/arch/src/android.rs
new file mode 100644
index 0000000..3d459d4
--- /dev/null
+++ b/arch/src/android.rs
@@ -0,0 +1,50 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fs::File;
+use std::io::BufRead;
+use std::io::BufReader;
+
+use crate::fdt::{begin_node, end_node, property_string, Error, Result};
+
+fn parse_fstab_line(line: &str) -> Result<Vec<String>> {
+    let vec: Vec<&str> = line.split_whitespace().collect();
+    if vec.len() != 5 {
+        return Err(Error::FdtFileParseError);
+    }
+    Ok(vec.iter().map(|s| s.to_string()).collect())
+}
+
+/// Creates a flattened device tree containing all of the parameters used
+/// by Android.
+///
+/// # Arguments
+///
+/// * `fdt` - The DTB to modify. The top-most node should be open.
+/// * `android-fstab` - A text file of Android fstab entries to add to the DTB
+pub fn create_android_fdt(fdt: &mut Vec<u8>, fstab: File) -> Result<()> {
+    let vecs = BufReader::new(fstab)
+        .lines()
+        .map(|l| parse_fstab_line(&l.map_err(Error::FdtIoError)?))
+        .collect::<Result<Vec<Vec<String>>>>()?;
+    begin_node(fdt, "firmware")?;
+    begin_node(fdt, "android")?;
+    property_string(fdt, "compatible", "android,firmware")?;
+    begin_node(fdt, "fstab")?;
+    property_string(fdt, "compatible", "android,fstab")?;
+    for vec in vecs {
+        let partition = &vec[1][1..];
+        begin_node(fdt, partition)?;
+        property_string(fdt, "compatible", &("android,".to_owned() + partition))?;
+        property_string(fdt, "dev", &vec[0])?;
+        property_string(fdt, "type", &vec[2])?;
+        property_string(fdt, "mnt_flags", &vec[3])?;
+        property_string(fdt, "fsmgr_flags", &vec[4])?;
+        end_node(fdt)?;
+    }
+    end_node(fdt)?; // fstab
+    end_node(fdt)?; // android
+    end_node(fdt)?; // firmware
+    Ok(())
+}
diff --git a/arch/src/fdt.rs b/arch/src/fdt.rs
new file mode 100644
index 0000000..71c791d
--- /dev/null
+++ b/arch/src/fdt.rs
@@ -0,0 +1,228 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use byteorder::{BigEndian, ByteOrder};
+use libc::{c_char, c_int, c_void};
+use std::ffi::{CStr, CString};
+use std::fmt::{self, Display};
+use std::io;
+use std::ptr::null;
+
+// This links to libfdt which handles the creation of the binary blob
+// flattened device tree (fdt) that is passed to the kernel and indicates
+// the hardware configuration of the machine.
+#[link(name = "fdt")]
+extern "C" {
+    fn fdt_create(buf: *mut c_void, bufsize: c_int) -> c_int;
+    fn fdt_finish_reservemap(fdt: *mut c_void) -> c_int;
+    fn fdt_begin_node(fdt: *mut c_void, name: *const c_char) -> c_int;
+    fn fdt_property(fdt: *mut c_void, name: *const c_char, val: *const c_void, len: c_int)
+        -> c_int;
+    fn fdt_end_node(fdt: *mut c_void) -> c_int;
+    fn fdt_open_into(fdt: *const c_void, buf: *mut c_void, bufsize: c_int) -> c_int;
+    fn fdt_finish(fdt: *const c_void) -> c_int;
+    fn fdt_pack(fdt: *mut c_void) -> c_int;
+}
+
+#[derive(Debug)]
+pub enum Error {
+    FdtCreateError(c_int),
+    FdtFinishReservemapError(c_int),
+    FdtBeginNodeError(c_int),
+    FdtPropertyError(c_int),
+    FdtEndNodeError(c_int),
+    FdtOpenIntoError(c_int),
+    FdtFinishError(c_int),
+    FdtPackError(c_int),
+    FdtGuestMemoryWriteError,
+    FdtFileParseError,
+    FdtIoError(io::Error),
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        write!(f, "libfdt: ")?;
+
+        match self {
+            FdtCreateError(ret) => write!(f, "error creating FDT, code={}", ret),
+            FdtFinishReservemapError(ret) => write!(f, "error finishing reserve map, code={}", ret),
+            FdtBeginNodeError(ret) => write!(f, "error beginning FDT node, code={}", ret),
+            FdtPropertyError(ret) => write!(f, "error adding FDT property, code={}", ret),
+            FdtEndNodeError(ret) => write!(f, "error ending FDT node, code={}", ret),
+            FdtOpenIntoError(ret) => write!(f, "error copying FDT to Guest, code={}", ret),
+            FdtFinishError(ret) => write!(f, "error performing FDT finish, code={}", ret),
+            FdtPackError(ret) => write!(f, "error packing FDT, code={}", ret),
+            FdtGuestMemoryWriteError => write!(f, "error writing FDT to guest memory"),
+            FdtFileParseError => write!(f, "parse error reading FDT parameters"),
+            FdtIoError(ret) => write!(f, "I/O error reading FDT parameters code={}", ret),
+        }
+    }
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl std::error::Error for Error {}
+
+pub fn begin_node(fdt: &mut Vec<u8>, name: &str) -> Result<()> {
+    let cstr_name = CString::new(name).unwrap();
+
+    // Safe because we allocated fdt and converted name to a CString
+    let fdt_ret = unsafe { fdt_begin_node(fdt.as_mut_ptr() as *mut c_void, cstr_name.as_ptr()) };
+    if fdt_ret != 0 {
+        return Err(Error::FdtBeginNodeError(fdt_ret));
+    }
+    Ok(())
+}
+
+pub fn end_node(fdt: &mut Vec<u8>) -> Result<()> {
+    // Safe because we allocated fdt
+    let fdt_ret = unsafe { fdt_end_node(fdt.as_mut_ptr() as *mut c_void) };
+    if fdt_ret != 0 {
+        return Err(Error::FdtEndNodeError(fdt_ret));
+    }
+    Ok(())
+}
+
+pub fn property(fdt: &mut Vec<u8>, name: &str, val: &[u8]) -> Result<()> {
+    let cstr_name = CString::new(name).unwrap();
+    let val_ptr = val.as_ptr() as *const c_void;
+
+    // Safe because we allocated fdt and converted name to a CString
+    let fdt_ret = unsafe {
+        fdt_property(
+            fdt.as_mut_ptr() as *mut c_void,
+            cstr_name.as_ptr(),
+            val_ptr,
+            val.len() as i32,
+        )
+    };
+    if fdt_ret != 0 {
+        return Err(Error::FdtPropertyError(fdt_ret));
+    }
+    Ok(())
+}
+
+fn cpu_to_fdt32(input: u32) -> [u8; 4] {
+    let mut buf = [0; 4];
+    BigEndian::write_u32(&mut buf, input);
+    buf
+}
+
+fn cpu_to_fdt64(input: u64) -> [u8; 8] {
+    let mut buf = [0; 8];
+    BigEndian::write_u64(&mut buf, input);
+    buf
+}
+
+pub fn property_u32(fdt: &mut Vec<u8>, name: &str, val: u32) -> Result<()> {
+    property(fdt, name, &cpu_to_fdt32(val))
+}
+
+pub fn property_u64(fdt: &mut Vec<u8>, name: &str, val: u64) -> Result<()> {
+    property(fdt, name, &cpu_to_fdt64(val))
+}
+
+// Helper to generate a properly formatted byte vector using 32-bit cells
+pub fn generate_prop32(cells: &[u32]) -> Vec<u8> {
+    let mut ret: Vec<u8> = Vec::new();
+    for &e in cells {
+        ret.extend(&cpu_to_fdt32(e));
+    }
+    ret
+}
+
+// Helper to generate a properly formatted byte vector using 64-bit cells
+pub fn generate_prop64(cells: &[u64]) -> Vec<u8> {
+    let mut ret: Vec<u8> = Vec::new();
+    for &e in cells {
+        ret.extend(&cpu_to_fdt64(e));
+    }
+    ret
+}
+
+pub fn property_null(fdt: &mut Vec<u8>, name: &str) -> Result<()> {
+    let cstr_name = CString::new(name).unwrap();
+
+    // Safe because we allocated fdt, converted name to a CString
+    let fdt_ret = unsafe {
+        fdt_property(
+            fdt.as_mut_ptr() as *mut c_void,
+            cstr_name.as_ptr(),
+            null(),
+            0,
+        )
+    };
+    if fdt_ret != 0 {
+        return Err(Error::FdtPropertyError(fdt_ret));
+    }
+    Ok(())
+}
+
+pub fn property_cstring(fdt: &mut Vec<u8>, name: &str, cstr_value: &CStr) -> Result<()> {
+    let value_bytes = cstr_value.to_bytes_with_nul();
+    let cstr_name = CString::new(name).unwrap();
+
+    // Safe because we allocated fdt, converted name and value to CStrings
+    let fdt_ret = unsafe {
+        fdt_property(
+            fdt.as_mut_ptr() as *mut c_void,
+            cstr_name.as_ptr(),
+            value_bytes.as_ptr() as *mut c_void,
+            value_bytes.len() as i32,
+        )
+    };
+    if fdt_ret != 0 {
+        return Err(Error::FdtPropertyError(fdt_ret));
+    }
+    Ok(())
+}
+
+pub fn property_string(fdt: &mut Vec<u8>, name: &str, value: &str) -> Result<()> {
+    let cstr_value = CString::new(value).unwrap();
+    property_cstring(fdt, name, &cstr_value)
+}
+
+pub fn start_fdt(fdt: &mut Vec<u8>, fdt_max_size: usize) -> Result<()> {
+    // Safe since we allocated this array with fdt_max_size
+    let mut fdt_ret = unsafe { fdt_create(fdt.as_mut_ptr() as *mut c_void, fdt_max_size as c_int) };
+
+    if fdt_ret != 0 {
+        return Err(Error::FdtCreateError(fdt_ret));
+    }
+    // Safe since we allocated this array
+    fdt_ret = unsafe { fdt_finish_reservemap(fdt.as_mut_ptr() as *mut c_void) };
+    if fdt_ret != 0 {
+        return Err(Error::FdtFinishReservemapError(fdt_ret));
+    }
+    Ok(())
+}
+
+pub fn finish_fdt(fdt: &mut Vec<u8>, fdt_final: &mut Vec<u8>, fdt_max_size: usize) -> Result<()> {
+    // Safe since we allocated fdt_final and previously passed in it's size
+    let mut fdt_ret = unsafe { fdt_finish(fdt.as_mut_ptr() as *mut c_void) };
+    if fdt_ret != 0 {
+        return Err(Error::FdtFinishError(fdt_ret));
+    }
+
+    // Safe because we allocated both arrays with the correct size
+    fdt_ret = unsafe {
+        fdt_open_into(
+            fdt.as_mut_ptr() as *mut c_void,
+            fdt_final.as_mut_ptr() as *mut c_void,
+            fdt_max_size as i32,
+        )
+    };
+    if fdt_ret != 0 {
+        return Err(Error::FdtOpenIntoError(fdt_ret));
+    }
+
+    // Safe since we allocated fdt_final
+    fdt_ret = unsafe { fdt_pack(fdt_final.as_mut_ptr() as *mut c_void) };
+    if fdt_ret != 0 {
+        return Err(Error::FdtPackError(fdt_ret));
+    }
+    Ok(())
+}
diff --git a/arch/src/lib.rs b/arch/src/lib.rs
new file mode 100644
index 0000000..71e4327
--- /dev/null
+++ b/arch/src/lib.rs
@@ -0,0 +1,391 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+pub mod android;
+pub mod fdt;
+
+use std::collections::BTreeMap;
+use std::error::Error as StdError;
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::io::{self, Read, Seek, SeekFrom};
+use std::os::unix::io::AsRawFd;
+use std::sync::Arc;
+
+use devices::virtio::VirtioDevice;
+use devices::{
+    Bus, BusDevice, BusError, PciDevice, PciDeviceError, PciInterruptPin, PciRoot, ProxyDevice,
+    Serial, SerialParameters, DEFAULT_SERIAL_PARAMS, SERIAL_ADDR,
+};
+use io_jail::Minijail;
+use kvm::{IoeventAddress, Kvm, Vcpu, Vm};
+use resources::SystemAllocator;
+use sync::Mutex;
+use sys_util::{syslog, EventFd, GuestAddress, GuestMemory, GuestMemoryError};
+
+pub enum VmImage {
+    Kernel(File),
+    Bios(File),
+}
+
+/// Holds the pieces needed to build a VM. Passed to `build_vm` in the `LinuxArch` trait below to
+/// create a `RunnableLinuxVm`.
+pub struct VmComponents {
+    pub memory_size: u64,
+    pub vcpu_count: u32,
+    pub vcpu_affinity: Vec<usize>,
+    pub vm_image: VmImage,
+    pub android_fstab: Option<File>,
+    pub initrd_image: Option<File>,
+    pub extra_kernel_params: Vec<String>,
+    pub wayland_dmabuf: bool,
+}
+
+/// Holds the elements needed to run a Linux VM. Created by `build_vm`.
+pub struct RunnableLinuxVm {
+    pub vm: Vm,
+    pub kvm: Kvm,
+    pub resources: SystemAllocator,
+    pub stdio_serial: Option<Arc<Mutex<Serial>>>,
+    pub exit_evt: EventFd,
+    pub vcpus: Vec<Vcpu>,
+    pub vcpu_affinity: Vec<usize>,
+    pub irq_chip: Option<File>,
+    pub io_bus: Bus,
+    pub mmio_bus: Bus,
+    pub pid_debug_label_map: BTreeMap<u32, String>,
+}
+
+/// The device and optional jail.
+pub struct VirtioDeviceStub {
+    pub dev: Box<dyn VirtioDevice>,
+    pub jail: Option<Minijail>,
+}
+
+/// Trait which is implemented for each Linux Architecture in order to
+/// set up the memory, cpus, and system devices and to boot the kernel.
+pub trait LinuxArch {
+    type Error: StdError;
+
+    /// Takes `VmComponents` and generates a `RunnableLinuxVm`.
+    ///
+    /// # Arguments
+    ///
+    /// * `components` - Parts to use to build the VM.
+    /// * `split_irqchip` - whether to use a split IRQ chip (i.e. userspace PIT/PIC/IOAPIC)
+    /// * `serial_parameters` - definitions for how the serial devices should be configured.
+    /// * `create_devices` - Function to generate a list of devices.
+    fn build_vm<F, E>(
+        components: VmComponents,
+        split_irqchip: bool,
+        serial_parameters: &BTreeMap<u8, SerialParameters>,
+        create_devices: F,
+    ) -> Result<RunnableLinuxVm, Self::Error>
+    where
+        F: FnOnce(
+            &GuestMemory,
+            &mut Vm,
+            &mut SystemAllocator,
+            &EventFd,
+        ) -> Result<Vec<(Box<dyn PciDevice>, Option<Minijail>)>, E>,
+        E: StdError + 'static;
+}
+
+/// Errors for device manager.
+#[derive(Debug)]
+pub enum DeviceRegistrationError {
+    /// Could not allocate IO space for the device.
+    AllocateIoAddrs(PciDeviceError),
+    /// Could not allocate device address space for the device.
+    AllocateDeviceAddrs(PciDeviceError),
+    /// Could not allocate an IRQ number.
+    AllocateIrq,
+    /// Could not create the mmio device to wrap a VirtioDevice.
+    CreateMmioDevice(sys_util::Error),
+    //  Unable to create serial device from serial parameters
+    CreateSerialDevice(devices::SerialError),
+    /// Could not create an event fd.
+    EventFdCreate(sys_util::Error),
+    /// Could not add a device to the mmio bus.
+    MmioInsert(BusError),
+    /// Failed to register ioevent with VM.
+    RegisterIoevent(sys_util::Error),
+    /// Failed to register irq eventfd with VM.
+    RegisterIrqfd(sys_util::Error),
+    /// Failed to initialize proxy device for jailed device.
+    ProxyDeviceCreation(devices::ProxyError),
+    /// Appending to kernel command line failed.
+    Cmdline(kernel_cmdline::Error),
+    /// No more IRQs are available.
+    IrqsExhausted,
+    /// No more MMIO space available.
+    AddrsExhausted,
+    /// Could not register PCI device capabilities.
+    RegisterDeviceCapabilities(PciDeviceError),
+}
+
+impl Display for DeviceRegistrationError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::DeviceRegistrationError::*;
+
+        match self {
+            AllocateIoAddrs(e) => write!(f, "Allocating IO addresses: {}", e),
+            AllocateDeviceAddrs(e) => write!(f, "Allocating device addresses: {}", e),
+            AllocateIrq => write!(f, "Allocating IRQ number"),
+            CreateMmioDevice(e) => write!(f, "failed to create mmio device: {}", e),
+            CreateSerialDevice(e) => write!(f, "failed to create serial device: {}", e),
+            Cmdline(e) => write!(f, "unable to add device to kernel command line: {}", e),
+            EventFdCreate(e) => write!(f, "failed to create eventfd: {}", e),
+            MmioInsert(e) => write!(f, "failed to add to mmio bus: {}", e),
+            RegisterIoevent(e) => write!(f, "failed to register ioevent to VM: {}", e),
+            RegisterIrqfd(e) => write!(f, "failed to register irq eventfd to VM: {}", e),
+            ProxyDeviceCreation(e) => write!(f, "failed to create proxy device: {}", e),
+            IrqsExhausted => write!(f, "no more IRQs are available"),
+            AddrsExhausted => write!(f, "no more addresses are available"),
+            RegisterDeviceCapabilities(e) => {
+                write!(f, "could not register PCI device capabilities: {}", e)
+            }
+        }
+    }
+}
+
+/// Creates a root PCI device for use by this Vm.
+pub fn generate_pci_root(
+    devices: Vec<(Box<dyn PciDevice>, Option<Minijail>)>,
+    mmio_bus: &mut Bus,
+    resources: &mut SystemAllocator,
+    vm: &mut Vm,
+) -> Result<(PciRoot, Vec<(u32, PciInterruptPin)>, BTreeMap<u32, String>), DeviceRegistrationError>
+{
+    let mut root = PciRoot::new();
+    let mut pci_irqs = Vec::new();
+    let mut pid_labels = BTreeMap::new();
+    for (dev_idx, (mut device, jail)) in devices.into_iter().enumerate() {
+        // Only support one bus.
+        device.assign_bus_dev(0, dev_idx as u8);
+
+        let mut keep_fds = device.keep_fds();
+        syslog::push_fds(&mut keep_fds);
+
+        let irqfd = EventFd::new().map_err(DeviceRegistrationError::EventFdCreate)?;
+        let irq_resample_fd = EventFd::new().map_err(DeviceRegistrationError::EventFdCreate)?;
+        let irq_num = resources
+            .allocate_irq()
+            .ok_or(DeviceRegistrationError::AllocateIrq)? as u32;
+        let pci_irq_pin = match dev_idx % 4 {
+            0 => PciInterruptPin::IntA,
+            1 => PciInterruptPin::IntB,
+            2 => PciInterruptPin::IntC,
+            3 => PciInterruptPin::IntD,
+            _ => panic!(""), // Obviously not possible, but the compiler is not smart enough.
+        };
+        vm.register_irqfd_resample(&irqfd, &irq_resample_fd, irq_num)
+            .map_err(DeviceRegistrationError::RegisterIrqfd)?;
+        keep_fds.push(irqfd.as_raw_fd());
+        keep_fds.push(irq_resample_fd.as_raw_fd());
+        device.assign_irq(irqfd, irq_resample_fd, irq_num, pci_irq_pin);
+        pci_irqs.push((dev_idx as u32, pci_irq_pin));
+
+        let ranges = device
+            .allocate_io_bars(resources)
+            .map_err(DeviceRegistrationError::AllocateIoAddrs)?;
+        let device_ranges = device
+            .allocate_device_bars(resources)
+            .map_err(DeviceRegistrationError::AllocateDeviceAddrs)?;
+        device
+            .register_device_capabilities()
+            .map_err(DeviceRegistrationError::RegisterDeviceCapabilities)?;
+        for (event, addr, datamatch) in device.ioeventfds() {
+            let io_addr = IoeventAddress::Mmio(addr);
+            vm.register_ioevent(&event, io_addr, datamatch)
+                .map_err(DeviceRegistrationError::RegisterIoevent)?;
+            keep_fds.push(event.as_raw_fd());
+        }
+        let arced_dev: Arc<Mutex<dyn BusDevice>> = if let Some(jail) = jail {
+            let proxy = ProxyDevice::new(device, &jail, keep_fds)
+                .map_err(DeviceRegistrationError::ProxyDeviceCreation)?;
+            pid_labels.insert(proxy.pid() as u32, proxy.debug_label());
+            Arc::new(Mutex::new(proxy))
+        } else {
+            device.on_sandboxed();
+            Arc::new(Mutex::new(device))
+        };
+        root.add_device(arced_dev.clone());
+        for range in &ranges {
+            mmio_bus
+                .insert(arced_dev.clone(), range.0, range.1, true)
+                .map_err(DeviceRegistrationError::MmioInsert)?;
+        }
+
+        for range in &device_ranges {
+            mmio_bus
+                .insert(arced_dev.clone(), range.0, range.1, true)
+                .map_err(DeviceRegistrationError::MmioInsert)?;
+        }
+    }
+    Ok((root, pci_irqs, pid_labels))
+}
+
+/// Adds serial devices to the provided bus based on the serial parameters given. Returns the serial
+///  port number and serial device to be used for stdout if defined.
+///
+/// # Arguments
+///
+/// * `io_bus` - Bus to add the devices to
+/// * `com_evt_1_3` - eventfd for com1 and com3
+/// * `com_evt_1_4` - eventfd for com2 and com4
+/// * `io_bus` - Bus to add the devices to
+/// * `serial_parameters` - definitions of serial parameter configuationis. If a setting is not
+///     provided for a port, then it will use the default configuation.
+pub fn add_serial_devices(
+    io_bus: &mut Bus,
+    com_evt_1_3: &EventFd,
+    com_evt_2_4: &EventFd,
+    serial_parameters: &BTreeMap<u8, SerialParameters>,
+) -> Result<(Option<u8>, Option<Arc<Mutex<Serial>>>), DeviceRegistrationError> {
+    let mut stdio_serial_num = None;
+    let mut stdio_serial = None;
+
+    for x in 0..=3 {
+        let com_evt = match x {
+            0 => com_evt_1_3,
+            1 => com_evt_2_4,
+            2 => com_evt_1_3,
+            3 => com_evt_2_4,
+            _ => com_evt_1_3,
+        };
+
+        let param = serial_parameters
+            .get(&(x + 1))
+            .unwrap_or(&DEFAULT_SERIAL_PARAMS[x as usize]);
+
+        let com = Arc::new(Mutex::new(
+            param
+                .create_serial_device(&com_evt)
+                .map_err(DeviceRegistrationError::CreateSerialDevice)?,
+        ));
+        io_bus
+            .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8, false)
+            .unwrap();
+
+        if param.console {
+            stdio_serial_num = Some(x + 1);
+            stdio_serial = Some(com.clone());
+        }
+    }
+
+    Ok((stdio_serial_num, stdio_serial))
+}
+
+/// Errors for image loading.
+#[derive(Debug)]
+pub enum LoadImageError {
+    BadAlignment(u64),
+    Seek(io::Error),
+    ImageSizeTooLarge(u64),
+    ReadToMemory(GuestMemoryError),
+}
+
+impl Display for LoadImageError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::LoadImageError::*;
+
+        match self {
+            BadAlignment(a) => write!(f, "Alignment not a power of two: {}", a),
+            Seek(e) => write!(f, "Seek failed: {}", e),
+            ImageSizeTooLarge(size) => write!(f, "Image size too large: {}", size),
+            ReadToMemory(e) => write!(f, "Reading image into memory failed: {}", e),
+        }
+    }
+}
+
+/// Load an image from a file into guest memory.
+///
+/// # Arguments
+///
+/// * `guest_mem` - The memory to be used by the guest.
+/// * `guest_addr` - The starting address to load the image in the guest memory.
+/// * `max_size` - The amount of space in bytes available in the guest memory for the image.
+/// * `image` - The file containing the image to be loaded.
+///
+/// The size in bytes of the loaded image is returned.
+pub fn load_image<F>(
+    guest_mem: &GuestMemory,
+    image: &mut F,
+    guest_addr: GuestAddress,
+    max_size: u64,
+) -> Result<usize, LoadImageError>
+where
+    F: Read + Seek + AsRawFd,
+{
+    let size = image.seek(SeekFrom::End(0)).map_err(LoadImageError::Seek)?;
+
+    if size > usize::max_value() as u64 || size > max_size {
+        return Err(LoadImageError::ImageSizeTooLarge(size));
+    }
+
+    // This is safe due to the bounds check above.
+    let size = size as usize;
+
+    image
+        .seek(SeekFrom::Start(0))
+        .map_err(LoadImageError::Seek)?;
+
+    guest_mem
+        .read_to_memory(guest_addr, image, size)
+        .map_err(LoadImageError::ReadToMemory)?;
+
+    Ok(size)
+}
+
+/// Load an image from a file into guest memory at the highest possible address.
+///
+/// # Arguments
+///
+/// * `guest_mem` - The memory to be used by the guest.
+/// * `image` - The file containing the image to be loaded.
+/// * `min_guest_addr` - The minimum address of the start of the image.
+/// * `max_guest_addr` - The address to load the last byte of the image.
+/// * `align` - The minimum alignment of the start address of the image in bytes
+///   (must be a power of two).
+///
+/// The guest address and size in bytes of the loaded image are returned.
+pub fn load_image_high<F>(
+    guest_mem: &GuestMemory,
+    image: &mut F,
+    min_guest_addr: GuestAddress,
+    max_guest_addr: GuestAddress,
+    align: u64,
+) -> Result<(GuestAddress, usize), LoadImageError>
+where
+    F: Read + Seek + AsRawFd,
+{
+    if !align.is_power_of_two() {
+        return Err(LoadImageError::BadAlignment(align));
+    }
+
+    let max_size = max_guest_addr.offset_from(min_guest_addr) & !(align - 1);
+    let size = image.seek(SeekFrom::End(0)).map_err(LoadImageError::Seek)?;
+
+    if size > usize::max_value() as u64 || size > max_size {
+        return Err(LoadImageError::ImageSizeTooLarge(size));
+    }
+
+    image
+        .seek(SeekFrom::Start(0))
+        .map_err(LoadImageError::Seek)?;
+
+    // Load image at the maximum aligned address allowed.
+    // The subtraction cannot underflow because of the size checks above.
+    let guest_addr = GuestAddress((max_guest_addr.offset() - size) & !(align - 1));
+
+    // This is safe due to the bounds check above.
+    let size = size as usize;
+
+    guest_mem
+        .read_to_memory(guest_addr, image, size)
+        .map_err(LoadImageError::ReadToMemory)?;
+
+    Ok((guest_addr, size))
+}
diff --git a/assertions/Cargo.toml b/assertions/Cargo.toml
new file mode 100644
index 0000000..60b1c5e
--- /dev/null
+++ b/assertions/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "assertions"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+include = ["src/**/*", "Cargo.toml"]
+
+[workspace]
diff --git a/assertions/src/lib.rs b/assertions/src/lib.rs
new file mode 100644
index 0000000..2e9d188
--- /dev/null
+++ b/assertions/src/lib.rs
@@ -0,0 +1,45 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Macros that assert properties of code at compile time.
+//!
+//! A static assertion is particularly appropriate when unsafe code relies on
+//! two types to have the same size, or on some type to have a particular size.
+
+#[doc(hidden)]
+pub mod mechanism;
+
+// Re-export so that these types appear with a more concise name in error
+// messages.
+#[doc(hidden)]
+pub use crate::mechanism::*;
+
+/// Macro that fails to compile if a given const expression is not true.
+///
+/// # Example
+///
+/// ```rust
+/// use assertions::const_assert;
+///
+/// fn main() {
+///     const_assert!(std::mem::size_of::<String>() == 24);
+/// }
+/// ```
+///
+/// # Example that fails to compile
+///
+/// ```rust,compile_fail
+/// use assertions::const_assert;
+///
+/// fn main() {
+///     // fails to compile:
+///     const_assert!(std::mem::size_of::<String>() == 8);
+/// }
+/// ```
+#[macro_export]
+macro_rules! const_assert {
+    ($e:expr) => {
+        let _: $crate::Assert<[(); $e as bool as usize]>;
+    };
+}
diff --git a/assertions/src/mechanism.rs b/assertions/src/mechanism.rs
new file mode 100644
index 0000000..e14b91a
--- /dev/null
+++ b/assertions/src/mechanism.rs
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::marker::PhantomData;
+
+pub struct True;
+pub struct False;
+
+pub trait Expr {
+    type Value;
+}
+
+impl Expr for [(); 0] {
+    type Value = False;
+}
+
+impl Expr for [(); 1] {
+    type Value = True;
+}
+
+// If the macro instantiates this with `T = [(); 1]` then it compiles successfully.
+//
+// On the other hand if `T = [(); 0]` the user receives an error like the following:
+//
+//    error[E0271]: type mismatch resolving `<[(); 0] as assertions::Expr>::Value == assertions::True`
+//     --> src/main.rs:5:5
+//      |
+//    5 |     const_assert!(std::mem::size_of::<String>() == 8);
+//      |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `assertions::True`, found struct `assertions::False`
+//
+pub struct Assert<T: Expr<Value = True>> {
+    marker: PhantomData<T>,
+}
diff --git a/bin/clippy b/bin/clippy
new file mode 100755
index 0000000..9f31816
--- /dev/null
+++ b/bin/clippy
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Run `cargo clippy` on all Rust code in crosvm with a mindful set of lints
+# suppressed.
+
+set -euo pipefail
+
+# Change into directory of script, which is crosvm/bin.
+cd "$(dirname "${BASH_SOURCE[0]}")"
+
+# Jump up to root directory of crosvm repo.
+cd ..
+
+SUPPRESS=(
+    # To be resolved.
+    let_unit_value
+    question_mark
+    range_plus_one
+    unit_arg
+
+    # We don't care about these lints. Okay to remain suppressed globally.
+    blacklisted_name
+    cast_lossless
+    cognitive_complexity
+    enum_variant_names
+    identity_op
+    len_without_is_empty
+    len_zero
+    match_bool
+    match_wild_err_arm
+    module_inception
+    needless_bool
+    new_without_default
+    or_fun_call
+    should_implement_trait
+    single_char_pattern
+    too_many_arguments
+    transmute_ptr_to_ptr
+    trivially_copy_pass_by_ref
+    type_complexity
+    unreadable_literal
+    useless_let_if_seq
+    useless_transmute
+)
+
+# Needed or else clippy won't re-run on code that has already compiled.
+cargo clean
+
+cargo clippy --all-features -- ${SUPPRESS[@]/#/-Aclippy::} "$@"
diff --git a/bin/fmt b/bin/fmt
new file mode 100755
index 0000000..39eac2c
--- /dev/null
+++ b/bin/fmt
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Run `cargo fmt` on all Rust code contained in crosvm. This is different from
+# `cargo fmt --all` which formats multiple crates but a single workspace only.
+# Crosvm consists of multiple workspaces.
+#
+# Usage:
+#
+#    $ bin/fmt
+#
+# To print a diff and exit 1 if code is not formatted, but without changing any
+# files, use:
+#
+#    $ bin/fmt --check
+#
+
+set -euo pipefail
+
+# Change into directory of script, which is crosvm/bin.
+cd "$(dirname "${BASH_SOURCE[0]}")"
+
+# Jump up to root directory of crosvm repo.
+cd ..
+
+# Keep track of whether any cargo fmt invocation exited with error.
+EXIT=0
+
+FIND_CARGO_TOMLS="$(find "$PWD" -name Cargo.toml)"
+
+while read path_to_cargo_toml; do
+    cd "$(dirname "$path_to_cargo_toml")"
+
+    if grep --quiet '\[workspace\]' Cargo.toml; then
+        if ! cargo fmt --all -- "$@"; then
+            EXIT=1
+        fi
+    fi
+done <<< "$FIND_CARGO_TOMLS"
+
+exit $EXIT
diff --git a/bin/smoke_test b/bin/smoke_test
new file mode 100755
index 0000000..e488e0e
--- /dev/null
+++ b/bin/smoke_test
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -ex
+
+cd "$(dirname "${BASH_SOURCE[0]}")"
+cd ../
+
+rustup default "$(cat rust-toolchain)"
+rustup component add rustfmt-preview
+cargo --version && rustc --version && rustfmt --version
+echo "Running cargo test"
+cargo test --no-fail-fast --features plugin,default-no-sandbox,wl-dmabuf,gpu,tpm,gpu-forward \
+    --all --exclude aarch64 $TEST_FLAGS -- \
+    --test-threads=1 $TEST_RUNNER_FLAGS
+echo "Running cargo fmt"
+bin/fmt --check
diff --git a/bit_field/Cargo.toml b/bit_field/Cargo.toml
new file mode 100644
index 0000000..ac8846c
--- /dev/null
+++ b/bit_field/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "bit_field"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+bit_field_derive = { path = "bit_field_derive" }
diff --git a/bit_field/bit_field_derive/Cargo.toml b/bit_field/bit_field_derive/Cargo.toml
new file mode 100644
index 0000000..df84a2a
--- /dev/null
+++ b/bit_field/bit_field_derive/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "bit_field_derive"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+proc-macro2 = "=0.4"
+quote = "=0.6"
+syn = "=0.15"
+
+[lib]
+proc-macro = true
+path = "bit_field_derive.rs"
diff --git a/bit_field/bit_field_derive/bit_field_derive.rs b/bit_field/bit_field_derive/bit_field_derive.rs
new file mode 100644
index 0000000..7084e22
--- /dev/null
+++ b/bit_field/bit_field_derive/bit_field_derive.rs
@@ -0,0 +1,799 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![recursion_limit = "256"]
+
+extern crate proc_macro;
+
+use proc_macro2::{Span, TokenStream};
+use quote::{quote, quote_spanned};
+use syn::parse::{Error, Result};
+use syn::{
+    parse_macro_input, Attribute, Data, DataEnum, DeriveInput, Fields, FieldsNamed, FieldsUnnamed,
+    Ident, Lit, LitInt, Meta, Type, Visibility,
+};
+
+/// The function that derives the actual implementation.
+#[proc_macro_attribute]
+pub fn bitfield(
+    _args: proc_macro::TokenStream,
+    input: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+    let derive_input = parse_macro_input!(input as DeriveInput);
+
+    let expanded = bitfield_impl(&derive_input).unwrap_or_else(|err| {
+        let compile_error = err.to_compile_error();
+        quote! {
+            #compile_error
+
+            // Include the original input to avoid "use of undeclared type"
+            // errors elsewhere.
+            #derive_input
+        }
+    });
+
+    expanded.into()
+}
+
+fn bitfield_impl(ast: &DeriveInput) -> Result<TokenStream> {
+    if !ast.generics.params.is_empty() {
+        return Err(Error::new(
+            Span::call_site(),
+            "#[bitfield] does not support generic parameters",
+        ));
+    }
+
+    match &ast.data {
+        Data::Struct(data_struct) => match &data_struct.fields {
+            Fields::Named(fields_named) => bitfield_struct_impl(ast, fields_named),
+            Fields::Unnamed(fields_unnamed) => bitfield_tuple_struct_impl(ast, fields_unnamed),
+            Fields::Unit => Err(Error::new(
+                Span::call_site(),
+                "#[bitfield] does not work with unit struct",
+            )),
+        },
+        Data::Enum(data_enum) => bitfield_enum_impl(ast, data_enum),
+        Data::Union(_) => Err(Error::new(
+            Span::call_site(),
+            "#[bitfield] does not support unions",
+        )),
+    }
+}
+
+fn bitfield_tuple_struct_impl(ast: &DeriveInput, fields: &FieldsUnnamed) -> Result<TokenStream> {
+    let mut ast = ast.clone();
+    let width = match parse_remove_bits_attr(&mut ast)? {
+        Some(w) => w,
+        None => {
+            return Err(Error::new(
+                Span::call_site(),
+                "tuple struct field must have bits attribute",
+            ));
+        }
+    };
+
+    let ident = &ast.ident;
+
+    if width.value() > 64 {
+        return Err(Error::new(
+            Span::call_site(),
+            "max width of bitfield field is 64",
+        ));
+    }
+
+    let bits = width.value() as u8;
+
+    if fields.unnamed.len() != 1 {
+        return Err(Error::new(
+            Span::call_site(),
+            "tuple struct field must have exactly 1 field",
+        ));
+    }
+
+    let field_type = match &fields.unnamed.first().unwrap().value().ty {
+        Type::Path(t) => t,
+        _ => {
+            return Err(Error::new(
+                Span::call_site(),
+                "tuple struct field must have primitive field",
+            ));
+        }
+    };
+    let span = field_type
+        .path
+        .segments
+        .first()
+        .unwrap()
+        .value()
+        .ident
+        .span();
+
+    let from_u64 = quote_spanned! {
+        span => val as #field_type
+    };
+
+    let into_u64 = quote_spanned! {
+        span => val.0 as u64
+    };
+
+    let expanded = quote! {
+        #ast
+
+        impl bit_field::BitFieldSpecifier for #ident {
+            const FIELD_WIDTH: u8 = #bits;
+            type SetterType = Self;
+            type GetterType = Self;
+
+            #[inline]
+            fn from_u64(val: u64) -> Self::GetterType {
+                Self(#from_u64)
+            }
+
+            #[inline]
+            fn into_u64(val: Self::SetterType) -> u64 {
+                #into_u64
+            }
+        }
+    };
+
+    Ok(expanded)
+}
+
+fn bitfield_enum_impl(ast: &DeriveInput, data: &DataEnum) -> Result<TokenStream> {
+    let mut ast = ast.clone();
+    let width = parse_remove_bits_attr(&mut ast)?;
+    match width {
+        None => bitfield_enum_without_width_impl(&ast, data),
+        Some(width) => bitfield_enum_with_width_impl(&ast, data, &width),
+    }
+}
+
+fn bitfield_enum_with_width_impl(
+    ast: &DeriveInput,
+    data: &DataEnum,
+    width: &LitInt,
+) -> Result<TokenStream> {
+    if width.value() > 64 {
+        return Err(Error::new(
+            Span::call_site(),
+            "max width of bitfield enum is 64",
+        ));
+    }
+    let bits = width.value() as u8;
+    let declare_discriminants = get_declare_discriminants_for_enum(bits, ast, data);
+
+    let ident = &ast.ident;
+    let type_name = ident.to_string();
+    let variants = &data.variants;
+    let match_discriminants = variants.iter().map(|variant| {
+        let variant = &variant.ident;
+        quote! {
+            discriminant::#variant => Ok(#ident::#variant),
+        }
+    });
+
+    let expanded = quote! {
+        #ast
+
+        impl bit_field::BitFieldSpecifier for #ident {
+            const FIELD_WIDTH: u8 = #bits;
+            type SetterType = Self;
+            type GetterType = std::result::Result<Self, bit_field::Error>;
+
+            #[inline]
+            fn from_u64(val: u64) -> Self::GetterType {
+                struct discriminant;
+                impl discriminant {
+                    #(#declare_discriminants)*
+                }
+                match val {
+                    #(#match_discriminants)*
+                    v => Err(bit_field::Error::new(#type_name, v)),
+                }
+            }
+
+            #[inline]
+            fn into_u64(val: Self::SetterType) -> u64 {
+                val as u64
+            }
+        }
+    };
+
+    Ok(expanded)
+}
+// Expand to an impl of BitFieldSpecifier for an enum like:
+//
+//     #[bitfield]
+//     #[derive(Debug, PartialEq)]
+//     enum TwoBits {
+//         Zero = 0b00,
+//         One = 0b01,
+//         Two = 0b10,
+//         Three = 0b11,
+//     }
+//
+// Such enums may be used as a field of a bitfield struct.
+//
+//     #[bitfield]
+//     struct Struct {
+//         prefix: BitField1,
+//         two_bits: TwoBits,
+//         suffix: BitField5,
+//     }
+//
+fn bitfield_enum_without_width_impl(ast: &DeriveInput, data: &DataEnum) -> Result<TokenStream> {
+    let ident = &ast.ident;
+    let variants = &data.variants;
+    let len = variants.len();
+    if len.count_ones() != 1 {
+        return Err(Error::new(
+            Span::call_site(),
+            "#[bitfield] expected a number of variants which is a power of 2 when bits is not \
+             specified for the enum",
+        ));
+    }
+
+    let bits = len.trailing_zeros() as u8;
+    let declare_discriminants = get_declare_discriminants_for_enum(bits, ast, data);
+
+    let match_discriminants = variants.iter().map(|variant| {
+        let variant = &variant.ident;
+        quote! {
+            discriminant::#variant => #ident::#variant,
+        }
+    });
+
+    let expanded = quote! {
+        #ast
+
+        impl bit_field::BitFieldSpecifier for #ident {
+            const FIELD_WIDTH: u8 = #bits;
+            type SetterType = Self;
+            type GetterType = Self;
+
+            #[inline]
+            fn from_u64(val: u64) -> Self::GetterType {
+                struct discriminant;
+                impl discriminant {
+                    #(#declare_discriminants)*
+                }
+                match val {
+                    #(#match_discriminants)*
+                    _ => unreachable!(),
+                }
+            }
+
+            #[inline]
+            fn into_u64(val: Self::SetterType) -> u64 {
+                val as u64
+            }
+        }
+    };
+
+    Ok(expanded)
+}
+
+fn get_declare_discriminants_for_enum(
+    bits: u8,
+    ast: &DeriveInput,
+    data: &DataEnum,
+) -> Vec<TokenStream> {
+    let variants = &data.variants;
+    let upper_bound = 2u64.pow(bits as u32);
+    let ident = &ast.ident;
+
+    variants
+        .iter()
+        .map(|variant| {
+            let variant = &variant.ident;
+            let span = variant.span();
+
+            let assertion = quote_spanned! {span=>
+                // If IS_IN_BOUNDS is true, this evaluates to 0.
+                //
+                // If IS_IN_BOUNDS is false, this evaluates to `0 - 1` which
+                // triggers a compile error on underflow when referenced below. The
+                // error is not beautiful but does carry the span of the problematic
+                // enum variant so at least it points to the right line.
+                //
+                //     error: any use of this value will cause an error
+                //       --> bit_field/test.rs:10:5
+                //        |
+                //     10 |     OutOfBounds = 0b111111,
+                //        |     ^^^^^^^^^^^ attempt to subtract with overflow
+                //        |
+                //
+                //     error[E0080]: erroneous constant used
+                //      --> bit_field/test.rs:5:1
+                //       |
+                //     5 | #[bitfield]
+                //       | ^^^^^^^^^^^ referenced constant has errors
+                //
+                const ASSERT: u64 = 0 - !IS_IN_BOUNDS as u64;
+            };
+
+            quote! {
+                #[allow(non_upper_case_globals)]
+                const #variant: u64 = {
+                    const IS_IN_BOUNDS: bool = (#ident::#variant as u64) < #upper_bound;
+
+                    #assertion
+
+                    #ident::#variant as u64 + ASSERT
+                };
+            }
+        })
+        .collect()
+}
+
+fn bitfield_struct_impl(ast: &DeriveInput, fields: &FieldsNamed) -> Result<TokenStream> {
+    let name = &ast.ident;
+    let vis = &ast.vis;
+    let attrs = &ast.attrs;
+    let fields = get_struct_fields(fields)?;
+    let struct_def = get_struct_def(vis, &name, &fields);
+    let bits_impl = get_bits_impl(&name);
+    let fields_impl = get_fields_impl(&fields);
+    let debug_fmt_impl = get_debug_fmt_impl(&name, &fields);
+
+    let expanded = quote! {
+        #(#attrs)*
+        #struct_def
+        #bits_impl
+        impl #name {
+            #(#fields_impl)*
+        }
+        #debug_fmt_impl
+    };
+
+    Ok(expanded)
+}
+
+struct FieldSpec<'a> {
+    ident: &'a Ident,
+    ty: &'a Type,
+    expected_bits: Option<LitInt>,
+}
+
+// Unwrap ast to get the named fields. We only care about field names and types:
+// "myfield : BitField3" -> ("myfield", Token(BitField3))
+fn get_struct_fields(fields: &FieldsNamed) -> Result<Vec<FieldSpec>> {
+    let mut vec = Vec::new();
+
+    for field in &fields.named {
+        let ident = field
+            .ident
+            .as_ref()
+            .expect("Fields::Named has named fields");
+        let ty = &field.ty;
+        let expected_bits = parse_bits_attr(&field.attrs)?;
+        vec.push(FieldSpec {
+            ident,
+            ty,
+            expected_bits,
+        });
+    }
+
+    Ok(vec)
+}
+
+// For example: #[bits = 1]
+fn parse_bits_attr(attrs: &[Attribute]) -> Result<Option<LitInt>> {
+    let mut expected_bits = None;
+
+    for attr in attrs {
+        if attr.path.is_ident("doc") {
+            continue;
+        }
+        if let Some(v) = try_parse_bits_attr(attr)? {
+            expected_bits = Some(v);
+            continue;
+        }
+
+        return Err(Error::new_spanned(attr, "unrecognized attribute"));
+    }
+
+    Ok(expected_bits)
+}
+
+// This function will return None if the attribute is not #[bits = *].
+fn try_parse_bits_attr(attr: &Attribute) -> Result<Option<LitInt>> {
+    if attr.path.is_ident("bits") {
+        if let Meta::NameValue(name_value) = attr.parse_meta()? {
+            if let Lit::Int(int) = name_value.lit {
+                return Ok(Some(int));
+            }
+        }
+    }
+    Ok(None)
+}
+
+fn parse_remove_bits_attr(ast: &mut DeriveInput) -> Result<Option<LitInt>> {
+    let mut width = None;
+    let mut bits_idx = 0;
+
+    for (i, attr) in ast.attrs.iter().enumerate() {
+        if let Some(w) = try_parse_bits_attr(attr)? {
+            bits_idx = i;
+            width = Some(w);
+        }
+    }
+
+    if width.is_some() {
+        ast.attrs.remove(bits_idx);
+    }
+
+    Ok(width)
+}
+
+fn get_struct_def(vis: &Visibility, name: &Ident, fields: &[FieldSpec]) -> TokenStream {
+    let mut field_types = Vec::new();
+    for spec in fields {
+        field_types.push(spec.ty);
+    }
+
+    // `(BitField1::FIELD_WIDTH + BitField3::FIELD_WIDTH + ...)`
+    let data_size_in_bits = quote! {
+        (
+            #(
+                <#field_types as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+            )+*
+        )
+    };
+
+    quote! {
+        #[repr(C)]
+        #vis struct #name {
+            data: [u8; #data_size_in_bits / 8],
+        }
+
+        impl #name {
+            pub fn new() -> #name {
+                let _: ::bit_field::Check<[u8; #data_size_in_bits % 8]>;
+
+                #name {
+                    data: [0; #data_size_in_bits / 8],
+                }
+            }
+        }
+    }
+}
+
+// Implement setter and getter for all fields.
+fn get_fields_impl(fields: &[FieldSpec]) -> Vec<TokenStream> {
+    let mut impls = Vec::new();
+    // This vec keeps track of types before this field, used to generate the offset.
+    let current_types = &mut vec![quote!(::bit_field::BitField0)];
+
+    for spec in fields {
+        let ty = spec.ty;
+        let getter_ident = Ident::new(format!("get_{}", spec.ident).as_str(), Span::call_site());
+        let setter_ident = Ident::new(format!("set_{}", spec.ident).as_str(), Span::call_site());
+
+        // Optional #[bits = N] attribute to provide compile-time checked
+        // documentation of how many bits some field covers.
+        let check_expected_bits = spec.expected_bits.as_ref().map(|expected_bits| {
+            // If expected_bits does not match the actual number of bits in the
+            // bit field specifier, this will fail to compile with an error
+            // pointing into the #[bits = N] attribute.
+            let span = expected_bits.span();
+            quote_spanned! {span=>
+                #[allow(dead_code)]
+                const EXPECTED_BITS: [(); #expected_bits as usize] =
+                    [(); <#ty as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize];
+            }
+        });
+
+        impls.push(quote! {
+            pub fn #getter_ident(&self) -> <#ty as ::bit_field::BitFieldSpecifier>::GetterType {
+                #check_expected_bits
+                let offset = #(<#current_types as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)+*;
+                let val = self.get(offset, <#ty as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH);
+                <#ty as ::bit_field::BitFieldSpecifier>::from_u64(val)
+            }
+
+            pub fn #setter_ident(&mut self, val: <#ty as ::bit_field::BitFieldSpecifier>::SetterType) {
+                let val = <#ty as ::bit_field::BitFieldSpecifier>::into_u64(val);
+                debug_assert!(val <= ::bit_field::max::<#ty>());
+                let offset = #(<#current_types as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)+*;
+                self.set(offset, <#ty as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH, val)
+            }
+        });
+
+        current_types.push(quote!(#ty));
+    }
+
+    impls
+}
+
+// Implement setter and getter for all fields.
+fn get_debug_fmt_impl(name: &Ident, fields: &[FieldSpec]) -> TokenStream {
+    // print fields:
+    let mut impls = Vec::new();
+    for spec in fields {
+        let field_name = spec.ident.to_string();
+        let getter_ident = Ident::new(&format!("get_{}", spec.ident), Span::call_site());
+        impls.push(quote! {
+            .field(#field_name, &self.#getter_ident())
+        });
+    }
+
+    let name_str = format!("{}", name);
+    quote! {
+        impl std::fmt::Debug for #name {
+            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+                f.debug_struct(#name_str)
+                #(#impls)*
+                    .finish()
+            }
+        }
+    }
+}
+
+fn get_bits_impl(name: &Ident) -> TokenStream {
+    quote! {
+        impl #name {
+            #[inline]
+            fn check_access(&self, offset: usize, width: u8) {
+                debug_assert!(width <= 64);
+                debug_assert!(offset / 8 < self.data.len());
+                debug_assert!((offset + (width as usize)) <= (self.data.len() * 8));
+            }
+
+            #[inline]
+            pub fn get_bit(&self, offset: usize) -> bool {
+                self.check_access(offset, 1);
+
+                let byte_index = offset / 8;
+                let bit_offset = offset % 8;
+
+                let byte = self.data[byte_index];
+                let mask = 1 << bit_offset;
+
+                byte & mask == mask
+            }
+
+            #[inline]
+            pub fn set_bit(&mut self, offset: usize, val: bool) {
+                self.check_access(offset, 1);
+
+                let byte_index = offset / 8;
+                let bit_offset = offset % 8;
+
+                let byte = &mut self.data[byte_index];
+                let mask = 1 << bit_offset;
+
+                if val {
+                    *byte |= mask;
+                } else {
+                    *byte &= !mask;
+                }
+            }
+
+            #[inline]
+            pub fn get(&self, offset: usize, width: u8) -> u64 {
+                self.check_access(offset, width);
+                let mut val = 0;
+
+                for i in 0..(width as usize) {
+                    if self.get_bit(i + offset) {
+                        val |= 1 << i;
+                    }
+                }
+
+                val
+            }
+
+            #[inline]
+            pub fn set(&mut self, offset: usize, width: u8, val: u64) {
+                self.check_access(offset, width);
+
+                for i in 0..(width as usize) {
+                    let mask = 1 << i;
+                    let val_bit_is_set = val & mask == mask;
+                    self.set_bit(i + offset, val_bit_is_set);
+                }
+            }
+        }
+    }
+}
+
+// Only intended to be used from the bit_field crate. This macro emits the
+// marker types bit_field::BitField0 through bit_field::BitField64.
+#[proc_macro]
+#[doc(hidden)]
+pub fn define_bit_field_specifiers(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let mut code = TokenStream::new();
+
+    for width in 0u8..=64 {
+        let span = Span::call_site();
+        let long_name = Ident::new(&format!("BitField{}", width), span);
+        let short_name = Ident::new(&format!("B{}", width), span);
+
+        let default_field_type = if width <= 8 {
+            quote!(u8)
+        } else if width <= 16 {
+            quote!(u16)
+        } else if width <= 32 {
+            quote!(u32)
+        } else {
+            quote!(u64)
+        };
+
+        code.extend(quote! {
+            pub struct #long_name;
+            pub use self::#long_name as #short_name;
+
+            impl BitFieldSpecifier for #long_name {
+                const FIELD_WIDTH: u8 = #width;
+                type SetterType = #default_field_type;
+                type GetterType = #default_field_type;
+
+                #[inline]
+                fn from_u64(val: u64) -> Self::GetterType {
+                    val as Self::GetterType
+                }
+
+                #[inline]
+                fn into_u64(val: Self::SetterType) -> u64 {
+                    val as u64
+                }
+            }
+        });
+    }
+
+    code.into()
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use syn::parse_quote;
+
+    #[test]
+    fn end_to_end() {
+        let input: DeriveInput = parse_quote! {
+            #[derive(Clone)]
+            struct MyBitField {
+                a: BitField1,
+                b: BitField2,
+                c: BitField5,
+            }
+        };
+
+        let expected = quote! {
+            #[derive(Clone)]
+            #[repr(C)]
+            struct MyBitField {
+                data: [u8; (<BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+                            + <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+                            + <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)
+                    / 8],
+            }
+            impl MyBitField {
+                pub fn new() -> MyBitField {
+                    let _: ::bit_field::Check<[
+                        u8;
+                        (<BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+                                + <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+                                + <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)
+                            % 8
+                    ]>;
+
+                    MyBitField {
+                        data: [0; (<BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+                                   + <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+                                   + <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)
+                            / 8],
+                    }
+                }
+            }
+            impl MyBitField {
+                #[inline]
+                fn check_access(&self, offset: usize, width: u8) {
+                    debug_assert!(width <= 64);
+                    debug_assert!(offset / 8 < self.data.len());
+                    debug_assert!((offset + (width as usize)) <= (self.data.len() * 8));
+                }
+                #[inline]
+                pub fn get_bit(&self, offset: usize) -> bool {
+                    self.check_access(offset, 1);
+                    let byte_index = offset / 8;
+                    let bit_offset = offset % 8;
+                    let byte = self.data[byte_index];
+                    let mask = 1 << bit_offset;
+                    byte & mask == mask
+                }
+                #[inline]
+                pub fn set_bit(&mut self, offset: usize, val: bool) {
+                    self.check_access(offset, 1);
+                    let byte_index = offset / 8;
+                    let bit_offset = offset % 8;
+                    let byte = &mut self.data[byte_index];
+                    let mask = 1 << bit_offset;
+                    if val {
+                        *byte |= mask;
+                    } else {
+                        *byte &= !mask;
+                    }
+                }
+                #[inline]
+                pub fn get(&self, offset: usize, width: u8) -> u64 {
+                    self.check_access(offset, width);
+                    let mut val = 0;
+                    for i in 0..(width as usize) {
+                        if self.get_bit(i + offset) {
+                            val |= 1 << i;
+                        }
+                    }
+                    val
+                }
+                #[inline]
+                pub fn set(&mut self, offset: usize, width: u8, val: u64) {
+                    self.check_access(offset, width);
+                    for i in 0..(width as usize) {
+                        let mask = 1 << i;
+                        let val_bit_is_set = val & mask == mask;
+                        self.set_bit(i + offset, val_bit_is_set);
+                    }
+                }
+            }
+            impl MyBitField {
+                pub fn get_a(&self) -> <BitField1 as ::bit_field::BitFieldSpecifier>::GetterType {
+                    let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
+                    let val = self.get(offset, <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH);
+                    <BitField1 as ::bit_field::BitFieldSpecifier>::from_u64(val)
+                }
+                pub fn set_a(&mut self, val: <BitField1 as ::bit_field::BitFieldSpecifier>::SetterType) {
+                    let val = <BitField1 as ::bit_field::BitFieldSpecifier>::into_u64(val);
+                    debug_assert!(val <= ::bit_field::max::<BitField1>());
+                    let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
+                    self.set(offset, <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH, val)
+                }
+                pub fn get_b(&self) -> <BitField2 as ::bit_field::BitFieldSpecifier>::GetterType {
+                    let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+                        + <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
+                    let val = self.get(offset, <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH);
+                    <BitField2 as ::bit_field::BitFieldSpecifier>::from_u64(val)
+                }
+                pub fn set_b(&mut self, val: <BitField2 as ::bit_field::BitFieldSpecifier>::SetterType) {
+                    let val = <BitField2 as ::bit_field::BitFieldSpecifier>::into_u64(val);
+                    debug_assert!(val <= ::bit_field::max::<BitField2>());
+                    let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+                        + <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
+                    self.set(offset, <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH, val)
+                }
+                pub fn get_c(&self) -> <BitField5 as ::bit_field::BitFieldSpecifier>::GetterType {
+                    let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+                        + <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+                        + <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
+                    let val = self.get(offset, <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH);
+                    <BitField5 as ::bit_field::BitFieldSpecifier>::from_u64(val)
+                }
+                pub fn set_c(&mut self, val: <BitField5 as ::bit_field::BitFieldSpecifier>::SetterType) {
+                    let val = <BitField5 as ::bit_field::BitFieldSpecifier>::into_u64(val);
+                    debug_assert!(val <= ::bit_field::max::<BitField5>());
+                    let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+                        + <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
+                        + <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
+                    self.set(offset, <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH, val)
+                }
+            }
+            impl std::fmt::Debug for MyBitField {
+                fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+                    f.debug_struct("MyBitField")
+                        .field("a", &self.get_a())
+                        .field("b", &self.get_b())
+                        .field("c", &self.get_c())
+                        .finish()
+                }
+            }
+        };
+
+        assert_eq!(
+            bitfield_impl(&input).unwrap().to_string(),
+            expected.to_string()
+        );
+    }
+}
diff --git a/bit_field/src/lib.rs b/bit_field/src/lib.rs
new file mode 100644
index 0000000..1455430
--- /dev/null
+++ b/bit_field/src/lib.rs
@@ -0,0 +1,361 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! This crate provides a `#[bitfield]` attribute macro for defining structs in
+//! a packed binary representation that supports access to ranges of bits.
+//!
+//! We conceptualize one of these structs as a sequence of bits 0..N. The bits
+//! are grouped into fields in the order specified by a struct written by the
+//! caller. The `#[bitfield]` attribute rewrites the caller's struct into a
+//! private byte array representation with public getter and setter methods for
+//! each field.
+//!
+//! Byte order: note that we consider the bit `i` to be the `i % 8`'th least
+//! significant bit in the `i / 8`'th byte of the struct.
+//!
+//! The total number of bits N is required to be a multiple of 8 (this is
+//! checked at compile time).
+//!
+//! # Examples
+//!
+//! The following invocation builds a struct with a total size of 32 bits or 4
+//! bytes. It places field `a` in the least significant bit of the first byte,
+//! field `b` in the next three least significant bits, field `c` in the
+//! remaining four most significant bits of the first byte, and field `d`
+//! spanning the next three bytes. The least significant byte of `d` will be
+//! held in the second byte of our struct, adjacent to the byte holding the
+//! first three fields.
+//!
+//! ```
+//! use bit_field::*;
+//!
+//! #[bitfield]
+//! pub struct MyFourBytes {
+//!     a: B1,
+//!     b: B3,
+//!     c: B4,
+//!     d: B24,
+//! }
+//! ```
+//!
+//! ```text
+//!                                             less significant
+//!                                            /             more significant
+//!                                           /             /
+//!      (first byte)      (second byte)     /   (third)   /   (fourth byte)
+//!     0 1 2 3 4 5 6 7   0 1 2 3 4 5 6 7   0 1 2 3 4 5 6 7   0 1 2 3 4 5 6 7
+//!     |  \ /   \_ _/     \_______________________ _______________________/
+//!     a   b      c        less significant       d       more significant
+//! ```
+//!
+//! The code emitted by the `#[bitfield]` macro for this struct is as follows.
+//! Note that the field getters and setters use whichever of `u8`, `u16`, `u32`,
+//! `u64` is the smallest while being at least as large as the number of bits in
+//! the field.
+//!
+//! ```ignore
+//! impl MyFourBytes {
+//!     // Initializes all fields to 0.
+//!     pub fn new() -> Self;
+//!
+//!     // Field getters and setters:
+//!     pub fn get_a(&self) -> u8;
+//!     pub fn set_a(&mut self, val: u8);
+//!     pub fn get_b(&self) -> u8;
+//!     pub fn set_b(&mut self, val: u8);
+//!     pub fn get_c(&self) -> u8;
+//!     pub fn set_c(&mut self, val: u8);
+//!     pub fn get_d(&self) -> u32;
+//!     pub fn set_d(&mut self, val: u32);
+//!
+//!     // Bit-level accessors:
+//!     pub fn get_bit(&self, offset: usize) -> bool;
+//!     pub fn set_bit(&mut self, offset: usize, val: bool);
+//!     pub fn get(&self, offset: usize, width: u8) -> u64;
+//!     pub fn set(&mut self, offset: usize, width: u8, val: u64);
+//! }
+//! ```
+//!
+//! # Bit field specifier types
+//!
+//! Field types may be specified as B1 through B64, or alternatively as
+//! BitField1 through BitField64 in code that benefits from the clarification.
+//!
+//! Fields may also be specified as `bool`, which is laid out equivalently to
+//! `B1` but with accessors that use `bool` rather than `u8`.
+//!
+//! ```
+//! use bit_field::*;
+//!
+//! #[bitfield]
+//! pub struct MyFourBytes {
+//!     a: bool,
+//!     b: B3,
+//!     c: B4,
+//!     d: B24,
+//! }
+//! ```
+//!
+//! Fields may be user-defined single element tuple struct with primitive types. Use must specify
+//! the width with `#[bits = N]`. This should be used to improve type safety.
+//!
+//! ```
+//! use bit_field::*;
+//!
+//! #[bitfield]
+//! #[bits = 60]
+//! struct AddressField(u64);
+//!
+//! impl AddressField {
+//!     pub fn new(addr: u64) -> AddressField {
+//!         AddressField(addr >> 4)
+//!     }
+//!
+//!     pub fn get_addr(&self) -> u64 {
+//!         self.0 << 4
+//!     }
+//! }
+//!
+//! ```
+//!
+//! Finally, fields may be of user-defined enum types. The enum must satisfy one of the following
+//! requirements.
+//!
+//! The enum has `#[bits = N]` attributes with it. `N` will be the width of the field. The getter
+//! function of this enum field will return `Result<EnumType, u64>`. Raw value that does not match
+//! any variant will result in an `Err(u64)`.
+//!
+//! ```
+//! use bit_field::*;
+//!
+//! #[bitfield]
+//! #[bits = 2]
+//! #[derive(Debug, PartialEq)]
+//! enum TwoBits {
+//!     Zero = 0b00,
+//!     One = 0b01,
+//!     Three = 0b11,
+//! }
+//!
+//! #[bitfield]
+//! struct Struct {
+//!     prefix: BitField1,
+//!     two_bits: TwoBits,
+//!     suffix: BitField5,
+//! }
+//! ```
+//!
+//! The enum has a number of variants which is a power of 2 and the discriminant values
+//! (explicit or implicit) are 0 through (2^n)-1. In this case the generated
+//! getter and setter are defined in terms of the given enum type.
+//!
+//! ```
+//! use bit_field::*;
+//!
+//! #[bitfield]
+//! #[derive(Debug, PartialEq)]
+//! enum TwoBits {
+//!     Zero = 0b00,
+//!     One = 0b01,
+//!     Two = 0b10,
+//!     Three = 0b11,
+//! }
+//!
+//! #[bitfield]
+//! struct Struct {
+//!     prefix: BitField1,
+//!     two_bits: TwoBits,
+//!     suffix: BitField5,
+//! }
+//! ```
+//!
+//! An optional `#[bits = N]` attribute may be used to document the number of
+//! bits in any field. This is intended for fields of enum type whose name does
+//! not clearly indicate the number of bits. The attribute is optional but helps
+//! make it possible to read off the field sizes directly from the definition of
+//! a bitfield struct.
+//!
+//! ```
+//! use bit_field::*;
+//!
+//! #[bitfield]
+//! #[derive(Debug, PartialEq)]
+//! enum WhoKnows {
+//!     Zero = 0b00,
+//!     One = 0b01,
+//!     Two = 0b10,
+//!     Three = 0b11,
+//! }
+//!
+//! #[bitfield]
+//! struct Struct {
+//!     prefix: BitField1,
+//!     #[bits = 2]
+//!     two_bits: WhoKnows,
+//!     suffix: BitField5,
+//! }
+//! ```
+//!
+//! # Derives
+//!
+//! Derives may be specified and are applied to the data structure post
+//! rewriting by the macro.
+//!
+//! ```
+//! use bit_field::*;
+//!
+//! #[bitfield]
+//! #[derive(Copy, Clone)]
+//! pub struct ExampleWithDerives {
+//!     car: B4,
+//!     cdr: B4,
+//! }
+//! ```
+//!
+//! # Compile time checks
+//!
+//! If the total size is not a multiple of 8 bits, you will receive an error
+//! message at compile time mentioning:
+//!
+//! > the trait `bit_field::checks::TotalSizeIsMultipleOfEightBits` is not implemented
+//!
+//! ```compile_fail
+//! use bit_field::*;
+//!
+//! #[bitfield]
+//! pub struct Broken {
+//!     field_a: B1,
+//!     field_b: B3,
+//!     field_c: B6,
+//! }
+//! ```
+//!
+//! If a bitfield enum has discriminants that are outside the range 0 through
+//! (2^n)-1, it will be caught at compile time.
+//!
+//! ```compile_fail
+//! use bit_field::*;
+//!
+//! #[bitfield]
+//! enum Broken {
+//!     Zero = 0b00,
+//!     One = 0b01,
+//!     Two = 0b10,
+//!     Nine = 0b1001, // error
+//! }
+//! ```
+//!
+//! If the value provided in a #[bits = N] attribute does not match the real
+//! number of bits in that field, it will be caught.
+//!
+//! ```compile_fail
+//! use bit_field::*;
+//!
+//! #[bitfield]
+//! #[derive(Debug, PartialEq)]
+//! enum OneBit {
+//!     No = 0,
+//!     Yes = 1,
+//! }
+//!
+//! #[bitfield]
+//! struct Struct {
+//!     #[bits = 4] // error
+//!     two_bits: OneBit,
+//!     padding: BitField7,
+//! }
+//! ```
+
+use std::fmt::{self, Display};
+
+pub use bit_field_derive::bitfield;
+
+/// Error type for bit field get.
+#[derive(Debug)]
+pub struct Error {
+    type_name: &'static str,
+    val: u64,
+}
+
+impl Error {
+    pub fn new(type_name: &'static str, val: u64) -> Error {
+        Error { type_name, val }
+    }
+
+    pub fn raw_val(&self) -> u64 {
+        self.val
+    }
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            f,
+            "enum field type {} has a bad value {}",
+            self.type_name, self.val
+        )
+    }
+}
+
+impl std::error::Error for Error {}
+
+#[doc(hidden)]
+pub trait BitFieldSpecifier {
+    // Width of this field in bits.
+    const FIELD_WIDTH: u8;
+    // Date type for setter of this field.
+    // For any field, we use the closest u* type. e.g. FIELD_WIDTH <= 8 will
+    // have defulat type of u8.
+    // It's possible to write a custom specifier and use i8.
+    type SetterType;
+    // Data type for getter of this field. For enums, it will be Result<EnumType, SetterType>.
+    // For others, it will be the same as SetterType.
+    type GetterType;
+
+    fn from_u64(val: u64) -> Self::GetterType;
+    fn into_u64(val: Self::SetterType) -> u64;
+}
+
+// Largest u64 representable by this bit field specifier. Used by generated code
+// in bit_field_derive.
+#[doc(hidden)]
+#[inline]
+pub fn max<T: BitFieldSpecifier>() -> u64 {
+    if T::FIELD_WIDTH < 64 {
+        (1 << T::FIELD_WIDTH) - 1
+    } else {
+        u64::max_value()
+    }
+}
+
+// Defines bit_field::BitField0 through bit_field::BitField64.
+bit_field_derive::define_bit_field_specifiers!();
+
+impl BitFieldSpecifier for bool {
+    const FIELD_WIDTH: u8 = 1;
+    type SetterType = bool;
+    type GetterType = bool;
+
+    #[inline]
+    fn from_u64(val: u64) -> Self::GetterType {
+        val > 0
+    }
+
+    #[inline]
+    fn into_u64(val: Self::SetterType) -> u64 {
+        val as u64
+    }
+}
+
+// Instantiated by the generated code to prove that the total size of fields is
+// a multiple of 8 bits.
+#[doc(hidden)]
+pub struct Check<T: checks::TotalSizeIsMultipleOfEightBits> {
+    marker: std::marker::PhantomData<T>,
+}
+
+mod checks {
+    pub trait TotalSizeIsMultipleOfEightBits {}
+    impl TotalSizeIsMultipleOfEightBits for [u8; 0] {}
+}
diff --git a/bit_field/tests/test_enum.rs b/bit_field/tests/test_enum.rs
new file mode 100644
index 0000000..3839f21
--- /dev/null
+++ b/bit_field/tests/test_enum.rs
@@ -0,0 +1,52 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use bit_field::*;
+
+#[bitfield]
+#[derive(Debug, PartialEq)]
+enum TwoBits {
+    Zero = 0b00,
+    One = 0b01,
+    Two = 0b10,
+    Three = 0b11,
+}
+
+#[bitfield]
+#[bits = 3]
+#[derive(Debug, PartialEq)]
+enum ThreeBits {
+    Zero = 0b00,
+    One = 0b01,
+    Two = 0b10,
+    Three = 0b111,
+}
+
+#[bitfield]
+struct Struct {
+    prefix: BitField1,
+    two_bits: TwoBits,
+    three_bits: ThreeBits,
+    suffix: BitField2,
+}
+
+#[test]
+fn test_enum() {
+    let mut s = Struct::new();
+    assert_eq!(s.get(0, 8), 0b_0000_0000);
+    assert_eq!(s.get_two_bits(), TwoBits::Zero);
+
+    s.set_two_bits(TwoBits::Three);
+    assert_eq!(s.get(0, 8), 0b_0000_0110);
+    assert_eq!(s.get_two_bits(), TwoBits::Three);
+
+    s.set(0, 8, 0b_1010_1010);
+    //                   ^^ TwoBits
+    //               ^^_^ Three Bits.
+    assert_eq!(s.get_two_bits(), TwoBits::One);
+    assert_eq!(s.get_three_bits().unwrap_err().raw_val(), 0b101);
+
+    s.set_three_bits(ThreeBits::Two);
+    assert_eq!(s.get(0, 8), 0b_1001_0010);
+}
diff --git a/bit_field/tests/test_tuple_struct.rs b/bit_field/tests/test_tuple_struct.rs
new file mode 100644
index 0000000..13566a0
--- /dev/null
+++ b/bit_field/tests/test_tuple_struct.rs
@@ -0,0 +1,27 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use bit_field::*;
+
+#[bitfield]
+#[bits = 5]
+#[derive(Debug, PartialEq)]
+pub struct FiveBits(u8);
+
+#[bitfield]
+struct Struct {
+    prefix: BitField1,
+    five_bits: FiveBits,
+    suffix: BitField2,
+}
+
+#[test]
+fn test_enum() {
+    let mut s = Struct::new();
+    assert_eq!(s.get(0, 8), 0b_0000_0000);
+
+    s.set_five_bits(FiveBits(0b10101));
+    assert_eq!(s.get(0, 8), 0b_0010_1010);
+    assert_eq!(s.get_five_bits(), FiveBits(0b10101));
+}
diff --git a/build_test b/build_test
new file mode 120000
index 0000000..a864fcf
--- /dev/null
+++ b/build_test
@@ -0,0 +1 @@
+build_test.py
\ No newline at end of file
diff --git a/build_test.py b/build_test.py
new file mode 100755
index 0000000..21d87df
--- /dev/null
+++ b/build_test.py
@@ -0,0 +1,237 @@
+#!/usr/bin/env python3
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Builds crosvm in debug/release mode on all supported target architectures.
+
+A sysroot for each target architectures is required. The defaults are all
+generic boards' sysroots, but they can be changed with the command line
+arguments.
+
+To test changes more quickly, set the --noclean option. This prevents the
+target directories from being removed before building and testing.
+"""
+
+from __future__ import print_function
+import argparse
+import multiprocessing.pool
+import os
+import shutil
+import subprocess
+import sys
+
+ARM_TRIPLE = os.getenv('ARM_TRIPLE', 'armv7a-cros-linux-gnueabihf')
+AARCH64_TRIPLE = os.getenv('AARCH64_TRIPLE', 'aarch64-cros-linux-gnu')
+X86_64_TRIPLE = os.getenv('X86_64_TRIPLE', 'x86_64-cros-linux-gnu')
+
+TEST_MODULES_PARALLEL = [
+    'crosvm',
+    'data_model',
+    'kernel_loader',
+    'kvm',
+    'kvm_sys',
+    'net_sys',
+    'net_util',
+    'syscall_defines',
+    'vhost',
+    'virtio_sys',
+    'x86_64',
+]
+
+TEST_MODULES_SERIAL = [
+    'io_jail',
+    'sys_util',
+]
+
+# Bright green.
+PASS_COLOR = '\033[1;32m'
+# Bright red.
+FAIL_COLOR = '\033[1;31m'
+# Default color.
+END_COLOR = '\033[0m'
+
+
+def get_target_path(triple, kind, test_it):
+  """Constructs a target path based on the configuration parameters.
+
+  Args:
+    triple: Target triple. Example: 'x86_64-unknown-linux-gnu'.
+    kind: 'debug' or 'release'.
+    test_it: If this target is tested.
+  """
+  target_path = '/tmp/%s_%s' % (triple, kind)
+  if test_it:
+    target_path += '_test'
+  return target_path
+
+
+def build_target(triple, is_release, env):
+  """Does a cargo build for the triple in release or debug mode.
+
+  Args:
+    triple: Target triple. Example: 'x86_64-unknown-linux-gnu'.
+    is_release: True to build a release version.
+    env: Enviroment variables to run cargo with.
+  """
+  args = ['cargo', 'build', '--target=%s' % triple]
+
+  if is_release:
+    args.append('--release')
+
+  return subprocess.Popen(args, env=env).wait() == 0
+
+
+def test_target_modules(triple, is_release, env, modules, parallel):
+  """Does a cargo test on given modules for the triple and configuration.
+
+  Args:
+    triple: Target triple. Example: 'x86_64-unknown-linux-gnu'.
+    is_release: True to build a release version.
+    env: Enviroment variables to run cargo with.
+    modules: List of module strings to test.
+    parallel: True to run the tests in parallel threads.
+  """
+  args = ['cargo', 'test', '--target=%s' % triple]
+
+  if is_release:
+    args.append('--release')
+
+  for mod in modules:
+    args.append('-p')
+    args.append(mod)
+
+  if not parallel:
+    args.append('--')
+    args.append('--test-threads=1')
+
+  return subprocess.Popen(args, env=env).wait() == 0
+
+
+def test_target(triple, is_release, env):
+  """Does a cargo test for the given triple and configuration.
+
+  Args:
+    triple: Target triple. Example: 'x86_64-unknown-linux-gnu'.
+    is_release: True to build a release version.
+    env: Enviroment variables to run cargo with.
+  """
+
+  parallel_result = test_target_modules(
+      triple, is_release, env, TEST_MODULES_PARALLEL, True)
+
+  serial_result = test_target_modules(
+      triple, is_release, env, TEST_MODULES_SERIAL, False)
+
+  return parallel_result and serial_result
+
+
+def check_build(sysroot, triple, kind, test_it, clean):
+  """Runs relavent builds/tests for the given triple and configuration
+
+  Args:
+    sysroot: path to the target's sysroot directory.
+    triple: Target triple. Example: 'x86_64-unknown-linux-gnu'.
+    kind: 'debug' or 'release'.
+    test_it: True to test this triple and kind.
+    clean: True to skip cleaning the target path.
+  """
+  if not os.path.isdir(sysroot):
+    return 'sysroot missing'
+
+  target_path = get_target_path(triple, kind, test_it)
+
+  if clean:
+    shutil.rmtree(target_path, True)
+
+  is_release = kind == 'release'
+
+  env = os.environ.copy()
+  env['TARGET_CC'] = '%s-clang'%triple
+  env['SYSROOT'] = sysroot
+  env['CARGO_TARGET_DIR'] = target_path
+
+  if test_it:
+    if not test_target(triple, is_release, env):
+      return 'test error'
+  else:
+    if not build_target(triple, is_release, env):
+      return 'build error'
+
+  return 'pass'
+
+
+def get_stripped_size(triple):
+  """Returns the formatted size of the given triple's release binary.
+
+  Args:
+    triple: Target triple. Example: 'x86_64-unknown-linux-gnu'.
+  """
+  target_path = get_target_path(triple, 'release', False)
+  bin_path = os.path.join(target_path, triple, 'release', 'crosvm')
+  proc = subprocess.Popen(['%s-strip' % triple, bin_path])
+
+  if proc.wait() != 0:
+    return 'failed'
+
+  return '%dKiB' % (os.path.getsize(bin_path) / 1024)
+
+
+def get_parser():
+  """Gets the argument parser"""
+  parser = argparse.ArgumentParser(description=__doc__)
+  parser.add_argument('--arm-sysroot',
+                      default='/build/arm-generic',
+                      help='ARM sysroot directory (default=%(default)s)')
+  parser.add_argument('--aarch64-sysroot',
+                      default='/build/arm64-generic',
+                      help='AARCH64 sysroot directory (default=%(default)s)')
+  parser.add_argument('--x86_64-sysroot',
+                      default='/build/amd64-generic',
+                      help='x86_64 sysroot directory (default=%(default)s)')
+  parser.add_argument('--noclean', dest='clean', default=True,
+                      action='store_false',
+                      help='Keep the tempororary build directories.')
+  return parser
+
+
+def main(argv):
+  opts = get_parser().parse_args(argv)
+  build_test_cases = (
+      #(sysroot path, target triple, debug/release, should test?)
+      (opts.arm_sysroot, ARM_TRIPLE, "debug", False, opts.clean),
+      (opts.arm_sysroot, ARM_TRIPLE, "release", False, opts.clean),
+      (opts.aarch64_sysroot, AARCH64_TRIPLE, "debug", False, opts.clean),
+      (opts.aarch64_sysroot, AARCH64_TRIPLE, "release", False, opts.clean),
+      (opts.x86_64_sysroot, X86_64_TRIPLE, "debug", False, opts.clean),
+      (opts.x86_64_sysroot, X86_64_TRIPLE, "release", False, opts.clean),
+      (opts.x86_64_sysroot, X86_64_TRIPLE, "debug", True, opts.clean),
+      (opts.x86_64_sysroot, X86_64_TRIPLE, "release", True, opts.clean),
+  )
+
+  os.chdir(os.path.dirname(sys.argv[0]))
+  pool = multiprocessing.pool.Pool(len(build_test_cases))
+  results = pool.starmap(check_build, build_test_cases, 1)
+
+  print('---')
+  print('build test summary:')
+  for test_case, result in zip(build_test_cases, results):
+    _, triple, kind, test_it, _ = test_case
+    title = '%s_%s' % (triple.split('-')[0], kind)
+    if test_it:
+      title += "_test"
+
+    result_color = FAIL_COLOR
+    if result == 'pass':
+      result_color = PASS_COLOR
+
+    display_size = ''
+    if result == 'pass' and kind == 'release' and not test_it:
+      display_size = get_stripped_size(triple) + ' stripped binary'
+
+    print('%20s: %s%15s%s %s' %
+          (title, result_color, result, END_COLOR, display_size))
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/crosvm_plugin/Cargo.toml b/crosvm_plugin/Cargo.toml
new file mode 100644
index 0000000..6805898
--- /dev/null
+++ b/crosvm_plugin/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "crosvm_plugin"
+version = "0.17.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+kvm = { path = "../kvm" }
+kvm_sys = { path = "../kvm_sys" }
+libc = "*"
+protobuf = "2.3"
+protos = { path = "../protos", features = ["plugin"] }
+sys_util = { path = "../sys_util" }
diff --git a/crosvm_plugin/crosvm.h b/crosvm_plugin/crosvm.h
new file mode 100644
index 0000000..d7a036c
--- /dev/null
+++ b/crosvm_plugin/crosvm.h
@@ -0,0 +1,559 @@
+/*
+ * Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __CROSVM_H__
+#define __CROSVM_H__
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <linux/kvm.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This module is used to implement a plugin for crosvm.
+ *
+ * A plugin for crosvm interfaces with the virtual machine using the `struct
+ * crosvm` object and its child objects. A typical plugin is expected to call
+ * `crosvm_connect`, perform some amount of setup with the functions defined
+ * here, get a handle to every vcpu using `struct crosvm_vcpu` and then call
+ * `crosvm_start`. Each vcpu will then be waited on with `crosvm_vcpu_wait`,
+ * each event will be responded to by the plugin, and then the vcpu is resumed
+ * with `crosvm_vcpu_resume`. The vcpu state can only be examined and modified
+ * between the `crosvm_vcpu_wait` and `crosvm_vcpu_resume` calls. The crosvm
+ * connection can be used to modify global virtual machine state at any time,
+ * with some structural restrictions after `crosvm_start` is called.
+ *
+ * In general, functions that return an `int` return 0 on success or a non-
+ * negative file descriptor if one is expected. A negative return value is an
+ * errno and indicates error. Functions that take a pointer-to-pointer to an
+ * opaque structure either return a structure or delete and nullify that
+ * structure pointer.
+ */
+
+/*
+ * We use Semantic Versioning (http://semver.org/) here, which means that as
+ * long as MAJOR is 0, breaking changes can occur, but once MAJOR is non-zero, a
+ * breaking change requires a MAJOR version bump. The MINOR number increases as
+ * backward compatible functionality is added. The PATCH number increases bug
+ * fixes are done. The version numbers indicate here are for the plugin API and
+ * do not indicate anything about what version of crosvm is running.
+ */
+#define CROSVM_API_MAJOR 0
+#define CROSVM_API_MINOR 17
+#define CROSVM_API_PATCH 0
+
+enum crosvm_address_space {
+  /* I/O port */
+  CROSVM_ADDRESS_SPACE_IOPORT = 0,
+  /* physical memory space */
+  CROSVM_ADDRESS_SPACE_MMIO,
+};
+
+/* Handle to the parent crosvm process. */
+struct crosvm;
+
+/* Handle to a register ioeventfd. */
+struct crosvm_io;
+
+/* Handle to a registered range of shared memory. */
+struct crosvm_memory;
+
+/* Handle to a registered irqfd. */
+struct crosvm_irq;
+
+/* Handle to one of the VM's VCPUs. */
+struct crosvm_vcpu;
+
+/*
+ * Connects to the parent crosvm process and returns a new `struct crosvm`
+ * interface object.
+ *
+ * This is the entry point for interfacing with crosvm as a plugin. This should
+ * be called before any other function. The returned object is not-thread safe.
+ */
+int crosvm_connect(struct crosvm**);
+
+/*
+ * Creates another connection for interfacing with crosvm concurrently.
+ *
+ * The new connection behaves exactly like the original `struct crosvm` but can
+ * be used concurrently on a different thread than the original. Actual
+ * execution order of the requests to crosvm is unspecified but every request is
+ * completed when the `crosvm_*` call returns.
+ *
+ * It is invalid to call this after `crosvm_start` is called on any `struct
+ * crosvm`.
+ */
+int crosvm_new_connection(struct crosvm*, struct crosvm**);
+
+/*
+ * Destroys this connection and tells the parent crosvm process to stop
+ * listening for messages from it.
+ */
+int crosvm_destroy_connection(struct crosvm**);
+
+/*
+ * Gets an eventfd that is triggered when this plugin should exit.
+ *
+ * The returned eventfd is owned by the caller but the underlying event is
+ * shared and will therefore only trigger once.
+ */
+int crosvm_get_shutdown_eventfd(struct crosvm*);
+
+/*
+ * Gets a bool indicating if a KVM_CAP_* enum is supported on this VM
+ */
+int crosvm_check_extension(struct crosvm*, uint32_t __extension,
+                           bool *has_extension);
+
+/*
+ * Queries x86 cpuid features which are supported by the hardware and
+ * kvm.
+ */
+int crosvm_get_supported_cpuid(struct crosvm*, uint32_t __entry_count,
+                               struct kvm_cpuid_entry2 *__cpuid_entries,
+                               uint32_t *__out_count);
+
+/*
+ * Queries x86 cpuid features which are emulated by kvm.
+ */
+int crosvm_get_emulated_cpuid(struct crosvm*, uint32_t __entry_count,
+                              struct kvm_cpuid_entry2 *__cpuid_entries,
+                              uint32_t *__out_count);
+
+/*
+ * Queries kvm for list of supported MSRs.
+ */
+int crosvm_get_msr_index_list(struct crosvm*, uint32_t __entry_count,
+                              uint32_t *__msr_indices,
+                              uint32_t *__out_count);
+
+/*
+ * The network configuration for a crosvm instance.
+ */
+struct crosvm_net_config {
+  /*
+   * The tap device fd. This fd is owned by the caller, and should be closed
+   * by the caller when it is no longer in use.
+   */
+  int tap_fd;
+  /* The IPv4 address of the tap interface, in network (big-endian) format. */
+  uint32_t host_ip;
+  /* The netmask of the tap interface subnet, in network (big-endian) format. */
+  uint32_t netmask;
+  /* The mac address of the host side of the tap interface. */
+  uint8_t host_mac_address[6];
+  uint8_t _padding[2];
+};
+
+#ifdef static_assert
+static_assert(sizeof(struct crosvm_net_config) == 20,
+              "extra padding in struct crosvm_net_config");
+#endif
+
+/*
+ * Gets the network configuration.
+ */
+int crosvm_net_get_config(struct crosvm*, struct crosvm_net_config*);
+
+/*
+ * Registers a range in the given address space that, when accessed, will block
+ * and wait for a crosvm_vcpu_resume call.
+ *
+ * To unreserve a range previously reserved by this function, pass the |__space|
+ * and |__start| of the old reservation with a 0 |__length|.
+ */
+int crosvm_reserve_range(struct crosvm*, uint32_t __space, uint64_t __start,
+                         uint64_t __length);
+
+/*
+ * Sets the state of the given irq pin.
+ */
+int crosvm_set_irq(struct crosvm*, uint32_t __irq_id, bool __active);
+
+enum crosvm_irq_route_kind {
+  /* IRQ pin to GSI route */
+  CROSVM_IRQ_ROUTE_IRQCHIP = 0,
+  /* MSI address and data to GSI route */
+  CROSVM_IRQ_ROUTE_MSI,
+};
+
+/* One entry in the array of irq routing table */
+struct crosvm_irq_route {
+  /* The IRQ number to trigger. */
+  uint32_t irq_id;
+  /* A `crosvm_irq_route_kind` indicating which union member to use */
+  uint32_t kind;
+  union {
+    struct {
+      /*
+       * One of KVM_IRQCHIP_PIC_MASTER, KVM_IRQCHIP_PIC_SLAVE, or
+       * KVM_IRQCHIP_IOAPIC indicating which irqchip the indicated pin is on.
+       */
+      uint32_t irqchip;
+      /* The pin on the irqchip used to trigger the IRQ. */
+      uint32_t pin;
+    } irqchip;
+
+    struct {
+      /* Address that triggers the irq. */
+      uint64_t address;
+      /* Data written to `address` that triggers the irq */
+      uint32_t data;
+
+      uint8_t _reserved[4];
+    } msi;
+
+    uint8_t _reserved[16];
+  };
+};
+
+#ifdef static_assert
+static_assert(sizeof(struct crosvm_irq_route) == 24,
+              "extra padding in struct crosvm_irq_route");
+#endif
+
+/*
+ * Sets all the gsi routing entries to those indicated by `routes`.
+ *
+ * To remove all routing entries, pass NULL for `routes` and 0 to route_count.
+ */
+int crosvm_set_irq_routing(struct crosvm*, uint32_t __route_count,
+                           const struct crosvm_irq_route* __routes);
+
+/* Gets the state of interrupt controller in a VM. */
+int crosvm_get_pic_state(struct crosvm *, bool __primary,
+                         struct kvm_pic_state *__pic_state);
+
+/* Sets the state of interrupt controller in a VM. */
+int crosvm_set_pic_state(struct crosvm *, bool __primary,
+                         const struct kvm_pic_state *__pic_state);
+
+/* Gets the state of IOAPIC in a VM. */
+int crosvm_get_ioapic_state(struct crosvm *,
+                            struct kvm_ioapic_state *__ioapic_state);
+
+/* Sets the state of IOAPIC in a VM. */
+int crosvm_set_ioapic_state(struct crosvm *,
+                            const struct kvm_ioapic_state *__ioapic_state);
+
+/* Gets the state of interrupt controller in a VM. */
+int crosvm_get_pit_state(struct crosvm *, struct kvm_pit_state2 *__pit_state);
+
+/* Sets the state of interrupt controller in a VM. */
+int crosvm_set_pit_state(struct crosvm *,
+                         const struct kvm_pit_state2 *__pit_state);
+
+/* Gets the current timestamp of kvmclock as seen by the VM. */
+int crosvm_get_clock(struct crosvm *, struct kvm_clock_data *__clock_data);
+
+/* Sets the current timestamp of kvmclock for the VM. */
+int crosvm_set_clock(struct crosvm *,
+                     const struct kvm_clock_data *__clock_data);
+
+/* Sets the identity map address as in the KVM_SET_IDENTITY_MAP_ADDR ioctl. */
+int crosvm_set_identity_map_addr(struct crosvm*, uint32_t __addr);
+
+/*
+ * Triggers a CROSVM_VCPU_EVENT_KIND_PAUSED event on each vcpu identified
+ * |__cpu_mask|.
+ *
+ * The `user` pointer will be given as the `user` pointer in the `struct
+ * crosvm_vcpu_event` returned by crosvm_vcpu_wait.
+ */
+int crosvm_pause_vcpus(struct crosvm*, uint64_t __cpu_mask, void* __user);
+
+/*
+ * Call once initialization is done. This indicates that crosvm should proceed
+ * with running the VM.
+ *
+ * After this call, this function is no longer valid to call.
+ */
+int crosvm_start(struct crosvm*);
+
+/*
+ * Allocates an eventfd that is triggered asynchronously on write in |__space|
+ * at the given |__addr|.
+ *
+ * If |__datamatch| is non-NULL, it must be contain |__length| bytes that will
+ * be compared to the bytes being written by the vcpu which will only trigger
+ * the eventfd if equal. If datamatch is NULL all writes to the address will
+ * trigger the eventfd.
+ *
+ * On successful allocation, returns a crosvm_io.  Obtain the actual fd
+ * by passing this result to crosvm_io_event_fd().
+ */
+int crosvm_create_io_event(struct crosvm*, uint32_t __space, uint64_t __addr,
+                           uint32_t __len, const uint8_t* __datamatch,
+                           struct crosvm_io**);
+
+/*
+ * Destroys the given io event and unregisters it from the VM.
+ */
+int crosvm_destroy_io_event(struct crosvm*, struct crosvm_io**);
+
+/*
+ * Gets the eventfd triggered by the given io event.
+ *
+ * The returned fd is owned by the given `struct crosvm_io` and has a lifetime
+ * equal to that handle.
+ */
+int crosvm_io_event_fd(struct crosvm_io*);
+
+/*
+ * Creates a shared memory segment backed by a memfd.
+ *
+ * Inserts non-overlapping memory pages in the guest physical address range
+ * specified by |__start| address and |__length| bytes. The memory pages are
+ * backed by the memfd |__fd| and are taken starting at |__offset| bytes from
+ * the beginning of the memfd.
+ *
+ * The `memfd_create` syscall |__fd| must be used to create |__fd| and a shrink
+ * seal must have been added to |__fd|. The memfd must be at least
+ * `__length+__offset` bytes long.
+ *
+ * If |read_only| is true, attempts by the guest to write to this memory region
+ * will trigger an IO access exit.
+ *
+ * To use the `crosvm_memory_get_dirty_log` method with the returned object,
+ * |__dirty_log| must be true.
+ */
+int crosvm_create_memory(struct crosvm*, int __fd, uint64_t __offset,
+                         uint64_t __length, uint64_t __start,
+                         bool __read_only, bool __dirty_log,
+                         struct crosvm_memory**);
+
+/*
+ * Destroys the given shared memory and unregisters it from guest physical
+ * address space.
+ */
+int crosvm_destroy_memory(struct crosvm*, struct crosvm_memory**);
+
+/*
+ * For a given memory region returns a bitmap containing any pages
+ * dirtied since the last call to this function.
+ *
+ * The `log` array must have as many bits as the memory segment has pages.
+ */
+int crosvm_memory_get_dirty_log(struct crosvm*, struct crosvm_memory*,
+                                uint8_t* __log);
+
+/*
+ * Creates an irq eventfd that can be used to trigger an irq asynchronously.
+ *
+ * The irq that will be triggered is identified as pin |__irq_id|.
+ */
+int crosvm_create_irq_event(struct crosvm*, uint32_t __irq_id,
+                            struct crosvm_irq**);
+
+/*
+ * Unregisters and destroys an irq eventfd.
+ */
+int crosvm_destroy_irq_event(struct crosvm*, struct crosvm_irq**);
+
+/*
+ * Gets the eventfd used to trigger the irq
+ *
+ * The returned fd is owned by the given `struct crosvm_irq` and has a lifetime
+ * equal to that handle.
+ */
+int crosvm_irq_event_get_fd(const struct crosvm_irq*);
+
+/*
+ * Gets the resample eventfd associated with the crosvm_irq object.
+ */
+int crosvm_irq_event_get_resample_fd(const struct crosvm_irq*);
+
+enum crosvm_vcpu_event_kind {
+  /*
+   * The first event returned by crosvm_vcpu_wait, indicating the VCPU has been
+   * created but not yet started for the first time.
+   */
+  CROSVM_VCPU_EVENT_KIND_INIT = 0,
+
+  /*
+   * Access to an address in a space previously reserved by
+   * crosvm_reserve_range.
+   */
+  CROSVM_VCPU_EVENT_KIND_IO_ACCESS,
+
+  /*
+   * A pause on this vcpu (and possibly others) was requested by this plugin in
+   * a `crosvm_pause_vcpus` call.
+   */
+  CROSVM_VCPU_EVENT_KIND_PAUSED,
+};
+
+struct crosvm_vcpu_event {
+  /* Indicates the kind of event and which union member is valid. */
+  uint32_t kind;
+
+  uint8_t _padding[4];
+
+  union {
+    /* CROSVM_VCPU_EVENT_KIND_IO_ACCESS */
+    struct {
+      /*
+       * One of `enum crosvm_address_space` indicating which address space the
+       * access occurred in.
+       */
+      uint32_t address_space;
+
+      uint8_t _padding[4];
+
+      /* The address that the access occurred at. */
+      uint64_t address;
+
+      /*
+       * In the case that `is_write` is true, the first `length` bytes are the
+       * data being written by the vcpu.
+       */
+      uint8_t *data;
+
+      /*
+       * Number of bytes in the access. In the case that the access is larger
+       * than 8 bytes, such as by AVX-512 instructions, multiple vcpu access
+       * events are generated serially to cover each 8 byte fragment of the
+       * access.
+       *
+       * Larger I/O accesses are possible.  "rep in" can generate I/Os larger
+       * than 8 bytes, though such accesses can also be split into multiple
+       * events.  Currently kvm doesn't seem to batch "rep out" I/Os.
+       */
+      uint32_t length;
+
+      /*
+       * True if the vcpu was attempting to write, false in case of an attempt
+       * to read.
+       */
+      uint8_t is_write;
+
+      uint8_t _reserved[3];
+    } io_access;
+
+    /* CROSVM_VCPU_EVENT_KIND_PAUSED */
+    void *user;
+
+    uint8_t _reserved[64];
+  };
+};
+
+#ifdef static_assert
+static_assert(sizeof(struct crosvm_vcpu_event) == 72,
+              "extra padding in struct crosvm_vcpu_event");
+#endif
+
+/*
+ * Gets the vcpu object for the given |__cpu_id|.
+ *
+ *
+ * The `struct crosvm_vcpu` is owned by `struct crosvm`. Each call with the same
+ * `crosvm` and |__cpu_id| will yield the same pointer. The `crosvm_vcpu` does
+ * not need to be destroyed or created explicitly.
+ *
+ * The range of valid |__cpu_id|s is 0 to the number of vcpus - 1. To get every
+ * `crosvm_vcpu`, simply call this function iteratively with increasing
+ * |__cpu_id| until `-ENOENT` is returned.
+ *
+ */
+int crosvm_get_vcpu(struct crosvm*, uint32_t __cpu_id, struct crosvm_vcpu**);
+
+/*
+ * Blocks until a vcpu event happens that requires a response.
+ *
+ * When crosvm_vcpu_wait returns successfully, the event structure is filled
+ * with the description of the event that occurred. The vcpu will suspend
+ * execution until a matching call to `crosvm_vcpu_resume` is made. Until such a
+ * call is made, the vcpu's run structure can be read and written using any
+ * `crosvm_vcpu_get` or `crosvm_vcpu_set` function.
+ */
+int crosvm_vcpu_wait(struct crosvm_vcpu*, struct crosvm_vcpu_event*);
+
+/*
+ * Resumes execution of a vcpu after a call to `crosvm_vcpu_wait` returns.
+ *
+ * In the case that the event was a read operation, `data` indicates what the
+ * result of that read operation should be. If the read operation was larger
+ * than 8 bytes, such as by AVX-512 instructions, this will not actually resume
+ * the vcpu, but instead generate another vcpu access event of the next fragment
+ * of the read, which can be handled by the next `crosvm_vcpu_wait` call.
+ *
+ * Once the vcpu event has been responded to sufficiently enough to resume
+ * execution, `crosvm_vcpu_resume` should be called. After `crosvm_vcpu_resume`
+ * is called, none of the vcpu state operations are valid until the next time
+ * `crosvm_vcpu_wait` returns.
+ */
+int crosvm_vcpu_resume(struct crosvm_vcpu*);
+
+/* Gets the state of the vcpu's registers. */
+int crosvm_vcpu_get_regs(struct crosvm_vcpu*, struct kvm_regs*);
+/* Sets the state of the vcpu's registers. */
+int crosvm_vcpu_set_regs(struct crosvm_vcpu*, const struct kvm_regs*);
+
+/* Gets the state of the vcpu's special registers. */
+int crosvm_vcpu_get_sregs(struct crosvm_vcpu*, struct kvm_sregs*);
+/* Sets the state of the vcpu's special registers. */
+int crosvm_vcpu_set_sregs(struct crosvm_vcpu*, const struct kvm_sregs*);
+
+/* Gets the state of the vcpu's floating point unint. */
+int crosvm_vcpu_get_fpu(struct crosvm_vcpu*, struct kvm_fpu*);
+/* Sets the state of the vcpu's floating point unint. */
+int crosvm_vcpu_set_fpu(struct crosvm_vcpu*, const struct kvm_fpu*);
+
+/* Gets the state of the vcpu's debug registers. */
+int crosvm_vcpu_get_debugregs(struct crosvm_vcpu*, struct kvm_debugregs*);
+/* Sets the state of the vcpu's debug registers */
+int crosvm_vcpu_set_debugregs(struct crosvm_vcpu*, const struct kvm_debugregs*);
+
+/* Gets the state of the vcpu's xcr registers. */
+int crosvm_vcpu_get_xcrs(struct crosvm_vcpu*, struct kvm_xcrs*);
+/* Sets the state of the vcpu's xcr registers. */
+int crosvm_vcpu_set_xcrs(struct crosvm_vcpu*, const struct kvm_xcrs*);
+
+/* Gets the MSRs of the vcpu indicated by the index field of each entry. */
+int crosvm_vcpu_get_msrs(struct crosvm_vcpu*, uint32_t __msr_count,
+                         struct kvm_msr_entry *__msr_entries,
+                         uint32_t *__out_count);
+/* Sets the MSRs of the vcpu indicated by the index field of each entry. */
+int crosvm_vcpu_set_msrs(struct crosvm_vcpu*, uint32_t __msr_count,
+                         const struct kvm_msr_entry *__msr_entries);
+
+/* Sets the responses to the cpuid instructions executed on this vcpu, */
+int crosvm_vcpu_set_cpuid(struct crosvm_vcpu*, uint32_t __cpuid_count,
+                          const struct kvm_cpuid_entry2 *__cpuid_entries);
+
+/* Gets state of LAPIC of the VCPU. */
+int crosvm_vcpu_get_lapic_state(struct crosvm_vcpu *,
+                                struct kvm_lapic_state *__lapic_state);
+/* Sets state of LAPIC of the VCPU. */
+int crosvm_vcpu_set_lapic_state(struct crosvm_vcpu *,
+                                const struct kvm_lapic_state *__lapic_state);
+
+/* Gets the "multiprocessor state" of given VCPU. */
+int crosvm_vcpu_get_mp_state(struct crosvm_vcpu *,
+                             struct kvm_mp_state *__mp_state);
+/* Sets the "multiprocessor state" of given VCPU. */
+int crosvm_vcpu_set_mp_state(struct crosvm_vcpu *,
+                             const struct kvm_mp_state *__mp_state);
+
+/* Gets currently pending exceptions, interrupts, NMIs, etc for VCPU. */
+int crosvm_vcpu_get_vcpu_events(struct crosvm_vcpu *,
+                                struct kvm_vcpu_events *);
+
+/* Sets currently pending exceptions, interrupts, NMIs, etc for VCPU. */
+int crosvm_vcpu_set_vcpu_events(struct crosvm_vcpu *,
+                                const struct kvm_vcpu_events *);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/crosvm_plugin/src/lib.rs b/crosvm_plugin/src/lib.rs
new file mode 100644
index 0000000..a6fd4df
--- /dev/null
+++ b/crosvm_plugin/src/lib.rs
@@ -0,0 +1,1686 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![allow(non_camel_case_types)]
+
+//! This module implements the dynamically loaded client library API used by a crosvm plugin,
+//! defined in `crosvm.h`. It implements the client half of the plugin protocol, which is defined in
+//! the `protos::plugin` module.
+//!
+//! To implement the `crosvm.h` C API, each function and struct definition is repeated here, with
+//! concrete definitions for each struct. Most functions are thin shims to the underlying object
+//! oriented Rust implementation method. Most methods require a request over the crosvm connection,
+//! which is done by creating a `MainRequest` or `VcpuRequest` protobuf and sending it over the
+//! connection's socket. Then, that socket is read for a `MainResponse` or `VcpuResponse`, which is
+//! translated to the appropriate return type for the C API.
+
+use std::env;
+use std::fs::File;
+use std::io::{Read, Write};
+use std::mem::{size_of, swap};
+use std::os::raw::{c_int, c_void};
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use std::os::unix::net::UnixDatagram;
+use std::ptr::{self, null_mut};
+use std::result;
+use std::slice;
+use std::slice::{from_raw_parts, from_raw_parts_mut};
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+use std::time::Instant;
+
+use libc::{E2BIG, EINVAL, ENOENT, ENOTCONN, EPROTO};
+
+use protobuf::{parse_from_bytes, Message, ProtobufEnum, RepeatedField};
+
+use sys_util::ScmSocket;
+
+use kvm::dirty_log_bitmap_size;
+
+use kvm_sys::{
+    kvm_clock_data, kvm_cpuid_entry2, kvm_debugregs, kvm_fpu, kvm_ioapic_state, kvm_lapic_state,
+    kvm_mp_state, kvm_msr_entry, kvm_pic_state, kvm_pit_state2, kvm_regs, kvm_sregs,
+    kvm_vcpu_events, kvm_xcrs,
+};
+
+use protos::plugin::*;
+
+// Needs to be large enough to receive all the VCPU sockets.
+const MAX_DATAGRAM_FD: usize = 32;
+// Needs to be large enough for a sizable dirty log.
+const MAX_DATAGRAM_SIZE: usize = 0x40000;
+
+const CROSVM_IRQ_ROUTE_IRQCHIP: u32 = 0;
+const CROSVM_IRQ_ROUTE_MSI: u32 = 1;
+
+const CROSVM_VCPU_EVENT_KIND_INIT: u32 = 0;
+const CROSVM_VCPU_EVENT_KIND_IO_ACCESS: u32 = 1;
+const CROSVM_VCPU_EVENT_KIND_PAUSED: u32 = 2;
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct crosvm_net_config {
+    tap_fd: c_int,
+    host_ipv4_address: u32,
+    netmask: u32,
+    host_mac_address: [u8; 6],
+    _reserved: [u8; 2],
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct anon_irqchip {
+    irqchip: u32,
+    pin: u32,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct anon_msi {
+    address: u64,
+    data: u32,
+}
+
+#[repr(C)]
+pub union anon_route {
+    irqchip: anon_irqchip,
+    msi: anon_msi,
+    reserved: [u8; 16],
+}
+
+#[repr(C)]
+pub struct crosvm_irq_route {
+    irq_id: u32,
+    kind: u32,
+    route: anon_route,
+}
+
+fn proto_error_to_int(e: protobuf::ProtobufError) -> c_int {
+    match e {
+        protobuf::ProtobufError::IoError(e) => e.raw_os_error().unwrap_or(EINVAL),
+        _ => EINVAL,
+    }
+}
+
+fn fd_cast<F: FromRawFd>(f: File) -> F {
+    // Safe because we are transferring unique ownership.
+    unsafe { F::from_raw_fd(f.into_raw_fd()) }
+}
+
+#[derive(Default)]
+struct IdAllocator(AtomicUsize);
+
+impl IdAllocator {
+    fn alloc(&self) -> u32 {
+        self.0.fetch_add(1, Ordering::Relaxed) as u32
+    }
+
+    fn free(&self, id: u32) {
+        self.0
+            .compare_and_swap(id as usize + 1, id as usize, Ordering::Relaxed);
+    }
+}
+
+#[repr(u8)]
+#[derive(Debug, Clone, Copy)]
+enum Stat {
+    IoEventFd,
+    MemoryGetDirtyLog,
+    IrqEventGetFd,
+    IrqEventGetResampleFd,
+    Connect,
+    DestroyConnection,
+    GetShutdownEventFd,
+    CheckExtentsion,
+    GetSupportedCpuid,
+    GetEmulatedCpuid,
+    GetMsrIndexList,
+    NetGetConfig,
+    ReserveRange,
+    SetIrq,
+    SetIrqRouting,
+    GetPicState,
+    SetPicState,
+    GetIoapicState,
+    SetIoapicState,
+    GetPitState,
+    SetPitState,
+    GetClock,
+    SetClock,
+    SetIdentityMapAddr,
+    PauseVcpus,
+    Start,
+    GetVcpu,
+    VcpuWait,
+    VcpuResume,
+    VcpuGetRegs,
+    VcpuSetRegs,
+    VcpuGetSregs,
+    VcpuSetSregs,
+    GetFpu,
+    SetFpu,
+    GetDebugRegs,
+    SetDebugRegs,
+    GetXCRegs,
+    SetXCRegs,
+    VcpuGetMsrs,
+    VcpuSetMsrs,
+    VcpuSetCpuid,
+    VcpuGetLapicState,
+    VcpuSetLapicState,
+    VcpuGetMpState,
+    VcpuSetMpState,
+    VcpuGetVcpuEvents,
+    VcpuSetVcpuEvents,
+    NewConnection,
+
+    Count,
+}
+
+#[derive(Clone, Copy)]
+struct StatEntry {
+    count: u64,
+    total: u64,
+    max: u64,
+}
+
+struct StatUpdater {
+    idx: usize,
+    start: Instant,
+}
+
+struct GlobalStats {
+    entries: [StatEntry; Stat::Count as usize],
+}
+
+static mut STATS: GlobalStats = GlobalStats {
+    entries: [StatEntry {
+        count: 0,
+        total: 0,
+        max: 0,
+    }; Stat::Count as usize],
+};
+
+impl GlobalStats {
+    // Record latency from this call until the end of block/function
+    // Example:
+    // pub fn foo() {
+    //     let _u = STATS.record(Stat::Foo);
+    //     // ... some operation ...
+    // }
+    // The added STATS.record will record latency of "some operation" and will
+    // update max and average latencies for it under Stats::Foo. Subsequent
+    // call to STATS.print() will print out max and average latencies for all
+    // operations that were performed.
+    fn record(&mut self, idx: Stat) -> StatUpdater {
+        StatUpdater {
+            idx: idx as usize,
+            start: Instant::now(),
+        }
+    }
+
+    fn print(&self) {
+        for idx in 0..Stat::Count as usize {
+            let e = &self.entries[idx as usize];
+            let stat = unsafe { std::mem::transmute::<u8, Stat>(idx as u8) };
+            if e.count > 0 {
+                println!(
+                    "Stat::{:?}: avg {}ns max {}ns",
+                    stat,
+                    e.total / e.count,
+                    e.max
+                );
+            }
+        }
+    }
+
+    fn update(&mut self, idx: usize, elapsed_nanos: u64) {
+        let e = &mut self.entries[idx as usize];
+        e.total += elapsed_nanos;
+        if e.max < elapsed_nanos {
+            e.max = elapsed_nanos;
+        }
+        e.count += 1;
+    }
+}
+
+impl Drop for StatUpdater {
+    fn drop(&mut self) {
+        let elapsed = self.start.elapsed();
+        let elapsed_nanos = elapsed.as_secs() * 1000000000 + elapsed.subsec_nanos() as u64;
+        // Unsafe due to racy access - OK for stats
+        unsafe {
+            STATS.update(self.idx, elapsed_nanos);
+        }
+    }
+}
+
+pub struct crosvm {
+    id_allocator: Arc<IdAllocator>,
+    socket: UnixDatagram,
+    request_buffer: Vec<u8>,
+    response_buffer: Vec<u8>,
+    vcpus: Arc<Vec<crosvm_vcpu>>,
+}
+
+impl crosvm {
+    fn from_connection(socket: UnixDatagram) -> result::Result<crosvm, c_int> {
+        let mut crosvm = crosvm {
+            id_allocator: Default::default(),
+            socket,
+            request_buffer: Vec::new(),
+            response_buffer: vec![0; MAX_DATAGRAM_SIZE],
+            vcpus: Default::default(),
+        };
+        crosvm.load_all_vcpus()?;
+        Ok(crosvm)
+    }
+
+    fn new(
+        id_allocator: Arc<IdAllocator>,
+        socket: UnixDatagram,
+        vcpus: Arc<Vec<crosvm_vcpu>>,
+    ) -> crosvm {
+        crosvm {
+            id_allocator,
+            socket,
+            request_buffer: Vec::new(),
+            response_buffer: vec![0; MAX_DATAGRAM_SIZE],
+            vcpus,
+        }
+    }
+
+    fn get_id_allocator(&self) -> &IdAllocator {
+        &*self.id_allocator
+    }
+
+    fn main_transaction(
+        &mut self,
+        request: &MainRequest,
+        fds: &[RawFd],
+    ) -> result::Result<(MainResponse, Vec<File>), c_int> {
+        self.request_buffer.clear();
+        request
+            .write_to_vec(&mut self.request_buffer)
+            .map_err(proto_error_to_int)?;
+        self.socket
+            .send_with_fds(self.request_buffer.as_slice(), fds)
+            .map_err(|e| -e.errno())?;
+
+        let mut datagram_fds = [0; MAX_DATAGRAM_FD];
+        let (msg_size, fd_count) = self
+            .socket
+            .recv_with_fds(&mut self.response_buffer, &mut datagram_fds)
+            .map_err(|e| -e.errno())?;
+        // Safe because the first fd_count fds from recv_with_fds are owned by us and valid.
+        let datagram_files = datagram_fds[..fd_count]
+            .iter()
+            .map(|&fd| unsafe { File::from_raw_fd(fd) })
+            .collect();
+
+        let response: MainResponse =
+            parse_from_bytes(&self.response_buffer[..msg_size]).map_err(proto_error_to_int)?;
+        if response.errno != 0 {
+            return Err(response.errno);
+        }
+        Ok((response, datagram_files))
+    }
+
+    fn try_clone(&mut self) -> result::Result<crosvm, c_int> {
+        let mut r = MainRequest::new();
+        r.mut_new_connection();
+        let mut files = self.main_transaction(&r, &[])?.1;
+        match files.pop() {
+            Some(new_socket) => Ok(crosvm::new(
+                self.id_allocator.clone(),
+                fd_cast(new_socket),
+                self.vcpus.clone(),
+            )),
+            None => Err(EPROTO),
+        }
+    }
+
+    fn destroy(&mut self, id: u32) -> result::Result<(), c_int> {
+        let mut r = MainRequest::new();
+        r.mut_destroy().id = id;
+        self.main_transaction(&r, &[])?;
+        self.get_id_allocator().free(id);
+        // Unsafe due to racy access - OK for stats
+        if std::env::var("CROSVM_STATS").is_ok() {
+            unsafe {
+                STATS.print();
+            }
+        }
+        Ok(())
+    }
+
+    // Only call this at `from_connection` function.
+    fn load_all_vcpus(&mut self) -> result::Result<(), c_int> {
+        let mut r = MainRequest::new();
+        r.mut_get_vcpus();
+        let (_, mut files) = self.main_transaction(&r, &[])?;
+        if files.is_empty() || files.len() % 2 != 0 {
+            return Err(EPROTO);
+        }
+
+        let mut vcpus = Vec::with_capacity(files.len() / 2);
+        while files.len() > 1 {
+            let write_pipe = files.remove(0);
+            let read_pipe = files.remove(0);
+            vcpus.push(crosvm_vcpu::new(fd_cast(read_pipe), fd_cast(write_pipe)));
+        }
+        // Only called once by the `from_connection` constructor, which makes a new unique
+        // `self.vcpus`.
+        let self_vcpus = Arc::get_mut(&mut self.vcpus).unwrap();
+        *self_vcpus = vcpus;
+        Ok(())
+    }
+
+    fn get_shutdown_eventfd(&mut self) -> result::Result<File, c_int> {
+        let mut r = MainRequest::new();
+        r.mut_get_shutdown_eventfd();
+        let (_, mut files) = self.main_transaction(&r, &[])?;
+        match files.pop() {
+            Some(f) => Ok(f),
+            None => Err(EPROTO),
+        }
+    }
+
+    fn check_extension(&mut self, extension: u32) -> result::Result<bool, c_int> {
+        let mut r = MainRequest::new();
+        r.mut_check_extension().extension = extension;
+        let (response, _) = self.main_transaction(&r, &[])?;
+        if !response.has_check_extension() {
+            return Err(EPROTO);
+        }
+        Ok(response.get_check_extension().has_extension)
+    }
+
+    fn get_supported_cpuid(
+        &mut self,
+        cpuid_entries: &mut [kvm_cpuid_entry2],
+        cpuid_count: &mut usize,
+    ) -> result::Result<(), c_int> {
+        *cpuid_count = 0;
+
+        let mut r = MainRequest::new();
+        r.mut_get_supported_cpuid();
+
+        let (response, _) = self.main_transaction(&r, &[])?;
+        if !response.has_get_supported_cpuid() {
+            return Err(EPROTO);
+        }
+
+        let supported_cpuids: &MainResponse_CpuidResponse = response.get_get_supported_cpuid();
+
+        *cpuid_count = supported_cpuids.get_entries().len();
+        if *cpuid_count > cpuid_entries.len() {
+            return Err(E2BIG);
+        }
+
+        for (proto_entry, kvm_entry) in supported_cpuids
+            .get_entries()
+            .iter()
+            .zip(cpuid_entries.iter_mut())
+        {
+            *kvm_entry = cpuid_proto_to_kvm(proto_entry);
+        }
+
+        Ok(())
+    }
+
+    fn get_emulated_cpuid(
+        &mut self,
+        cpuid_entries: &mut [kvm_cpuid_entry2],
+        cpuid_count: &mut usize,
+    ) -> result::Result<(), c_int> {
+        *cpuid_count = 0;
+
+        let mut r = MainRequest::new();
+        r.mut_get_emulated_cpuid();
+
+        let (response, _) = self.main_transaction(&r, &[])?;
+        if !response.has_get_emulated_cpuid() {
+            return Err(EPROTO);
+        }
+
+        let emulated_cpuids: &MainResponse_CpuidResponse = response.get_get_emulated_cpuid();
+
+        *cpuid_count = emulated_cpuids.get_entries().len();
+        if *cpuid_count > cpuid_entries.len() {
+            return Err(E2BIG);
+        }
+
+        for (proto_entry, kvm_entry) in emulated_cpuids
+            .get_entries()
+            .iter()
+            .zip(cpuid_entries.iter_mut())
+        {
+            *kvm_entry = cpuid_proto_to_kvm(proto_entry);
+        }
+
+        Ok(())
+    }
+
+    fn get_msr_index_list(
+        &mut self,
+        msr_indices: &mut [u32],
+        msr_count: &mut usize,
+    ) -> result::Result<(), c_int> {
+        *msr_count = 0;
+
+        let mut r = MainRequest::new();
+        r.mut_get_msr_index_list();
+
+        let (response, _) = self.main_transaction(&r, &[])?;
+        if !response.has_get_msr_index_list() {
+            return Err(EPROTO);
+        }
+
+        let msr_list: &MainResponse_MsrListResponse = response.get_get_msr_index_list();
+
+        *msr_count = msr_list.get_indices().len();
+        if *msr_count > msr_indices.len() {
+            return Err(E2BIG);
+        }
+
+        for (proto_entry, kvm_entry) in msr_list.get_indices().iter().zip(msr_indices.iter_mut()) {
+            *kvm_entry = *proto_entry;
+        }
+
+        Ok(())
+    }
+
+    fn reserve_range(&mut self, space: u32, start: u64, length: u64) -> result::Result<(), c_int> {
+        let mut r = MainRequest::new();
+        let reserve: &mut MainRequest_ReserveRange = r.mut_reserve_range();
+        reserve.space = AddressSpace::from_i32(space as i32).ok_or(EINVAL)?;
+        reserve.start = start;
+        reserve.length = length;
+
+        self.main_transaction(&r, &[])?;
+        Ok(())
+    }
+
+    fn set_irq(&mut self, irq_id: u32, active: bool) -> result::Result<(), c_int> {
+        let mut r = MainRequest::new();
+        let set_irq: &mut MainRequest_SetIrq = r.mut_set_irq();
+        set_irq.irq_id = irq_id;
+        set_irq.active = active;
+
+        self.main_transaction(&r, &[])?;
+        Ok(())
+    }
+
+    fn set_irq_routing(&mut self, routing: &[crosvm_irq_route]) -> result::Result<(), c_int> {
+        let mut r = MainRequest::new();
+        let set_irq_routing: &mut RepeatedField<MainRequest_SetIrqRouting_Route> =
+            r.mut_set_irq_routing().mut_routes();
+        for route in routing {
+            let mut entry = MainRequest_SetIrqRouting_Route::new();
+            entry.irq_id = route.irq_id;
+            match route.kind {
+                CROSVM_IRQ_ROUTE_IRQCHIP => {
+                    let irqchip: &mut MainRequest_SetIrqRouting_Route_Irqchip;
+                    irqchip = entry.mut_irqchip();
+                    // Safe because route.kind indicates which union field is valid.
+                    irqchip.irqchip = unsafe { route.route.irqchip }.irqchip;
+                    irqchip.pin = unsafe { route.route.irqchip }.pin;
+                }
+                CROSVM_IRQ_ROUTE_MSI => {
+                    let msi: &mut MainRequest_SetIrqRouting_Route_Msi = entry.mut_msi();
+                    // Safe because route.kind indicates which union field is valid.
+                    msi.address = unsafe { route.route.msi }.address;
+                    msi.data = unsafe { route.route.msi }.data;
+                }
+                _ => return Err(EINVAL),
+            }
+            set_irq_routing.push(entry);
+        }
+
+        self.main_transaction(&r, &[])?;
+        Ok(())
+    }
+
+    fn get_state(
+        &mut self,
+        state_set: MainRequest_StateSet,
+        out: &mut [u8],
+    ) -> result::Result<(), c_int> {
+        let mut r = MainRequest::new();
+        r.mut_get_state().set = state_set;
+        let (response, _) = self.main_transaction(&r, &[])?;
+        if !response.has_get_state() {
+            return Err(EPROTO);
+        }
+        let get_state: &MainResponse_GetState = response.get_get_state();
+        if get_state.state.len() != out.len() {
+            return Err(EPROTO);
+        }
+        out.copy_from_slice(&get_state.state);
+        Ok(())
+    }
+
+    fn set_state(
+        &mut self,
+        state_set: MainRequest_StateSet,
+        new_state: &[u8],
+    ) -> result::Result<(), c_int> {
+        let mut r = MainRequest::new();
+        let set_state: &mut MainRequest_SetState = r.mut_set_state();
+        set_state.set = state_set;
+        set_state.state = new_state.to_vec();
+
+        self.main_transaction(&r, &[])?;
+        Ok(())
+    }
+
+    fn set_identity_map_addr(&mut self, addr: u32) -> result::Result<(), c_int> {
+        let mut r = MainRequest::new();
+        r.mut_set_identity_map_addr().address = addr;
+
+        self.main_transaction(&r, &[])?;
+        Ok(())
+    }
+
+    fn pause_vcpus(&mut self, cpu_mask: u64, user: *mut c_void) -> result::Result<(), c_int> {
+        let mut r = MainRequest::new();
+        let pause_vcpus: &mut MainRequest_PauseVcpus = r.mut_pause_vcpus();
+        pause_vcpus.cpu_mask = cpu_mask;
+        pause_vcpus.user = user as u64;
+        self.main_transaction(&r, &[])?;
+        Ok(())
+    }
+
+    fn start(&mut self) -> result::Result<(), c_int> {
+        let mut r = MainRequest::new();
+        r.mut_start();
+        self.main_transaction(&r, &[])?;
+        Ok(())
+    }
+
+    fn get_vcpu(&mut self, cpu_id: u32) -> Result<*mut crosvm_vcpu, c_int> {
+        if let Some(vcpu) = self.vcpus.get(cpu_id as usize) {
+            Ok(vcpu as *const crosvm_vcpu as *mut crosvm_vcpu)
+        } else {
+            Err(ENOENT)
+        }
+    }
+
+    fn get_net_config(&mut self) -> result::Result<crosvm_net_config, c_int> {
+        let mut r = MainRequest::new();
+        r.mut_get_net_config();
+
+        let (response, mut files) = self.main_transaction(&r, &[])?;
+        if !response.has_get_net_config() {
+            return Err(EPROTO);
+        }
+        let config = response.get_get_net_config();
+
+        match files.pop() {
+            Some(f) => {
+                let mut net_config = crosvm_net_config {
+                    tap_fd: f.into_raw_fd(),
+                    host_ipv4_address: config.host_ipv4_address,
+                    netmask: config.netmask,
+                    host_mac_address: [0; 6],
+                    _reserved: [0; 2],
+                };
+
+                let mac_addr = config.get_host_mac_address();
+                if mac_addr.len() != net_config.host_mac_address.len() {
+                    return Err(EPROTO);
+                }
+                net_config.host_mac_address.copy_from_slice(mac_addr);
+
+                Ok(net_config)
+            }
+            None => Err(EPROTO),
+        }
+    }
+}
+
+/// This helper macro implements the C API's constructor/destructor for a given type. Because they
+/// all follow the same pattern and include lots of boilerplate unsafe code, it makes sense to write
+/// it once with this helper macro.
+macro_rules! impl_ctor_dtor {
+    (
+        $t:ident,
+        $ctor:ident ( $( $x:ident: $y:ty ),* ),
+        $dtor:ident,
+    ) => {
+        #[allow(unused_unsafe)]
+        #[no_mangle]
+        pub unsafe extern fn $ctor(self_: *mut crosvm, $($x: $y,)* obj_ptr: *mut *mut $t) -> c_int {
+            let self_ = &mut (*self_);
+            match $t::create(self_, $($x,)*) {
+                Ok(obj) => {
+                    *obj_ptr = Box::into_raw(Box::new(obj));
+                    0
+                }
+                Err(e) => -e,
+            }
+        }
+        #[no_mangle]
+        pub unsafe extern fn $dtor(self_: *mut crosvm, obj_ptr: *mut *mut $t) -> c_int {
+            let self_ = &mut (*self_);
+            let obj = Box::from_raw(*obj_ptr);
+            match self_.destroy(obj.id) {
+                Ok(_) => {
+                    *obj_ptr = null_mut();
+                    0
+                }
+                Err(e) =>  {
+                    Box::into_raw(obj);
+                    -e
+                }
+            }
+        }
+    }
+}
+
+pub struct crosvm_io_event {
+    id: u32,
+    evt: File,
+}
+
+impl crosvm_io_event {
+    // Clippy: we use ptr::read_unaligned to read from pointers that may be
+    // underaligned. Dereferencing such a pointer is always undefined behavior
+    // in Rust.
+    //
+    // Lint can be unsuppressed once Clippy recognizes this pattern as correct.
+    // https://github.com/rust-lang/rust-clippy/issues/2881
+    #[allow(clippy::cast_ptr_alignment)]
+    unsafe fn create(
+        crosvm: &mut crosvm,
+        space: u32,
+        addr: u64,
+        length: u32,
+        datamatch: *const u8,
+    ) -> result::Result<crosvm_io_event, c_int> {
+        let datamatch = match length {
+            0 => 0,
+            1 => ptr::read_unaligned(datamatch as *const u8) as u64,
+            2 => ptr::read_unaligned(datamatch as *const u16) as u64,
+            4 => ptr::read_unaligned(datamatch as *const u32) as u64,
+            8 => ptr::read_unaligned(datamatch as *const u64),
+            _ => return Err(EINVAL),
+        };
+        Self::safe_create(crosvm, space, addr, length, datamatch)
+    }
+
+    fn safe_create(
+        crosvm: &mut crosvm,
+        space: u32,
+        addr: u64,
+        length: u32,
+        datamatch: u64,
+    ) -> result::Result<crosvm_io_event, c_int> {
+        let id = crosvm.get_id_allocator().alloc();
+
+        let mut r = MainRequest::new();
+        let create: &mut MainRequest_Create = r.mut_create();
+        create.id = id;
+        let io_event: &mut MainRequest_Create_IoEvent = create.mut_io_event();
+        io_event.space = AddressSpace::from_i32(space as i32).ok_or(EINVAL)?;
+        io_event.address = addr;
+        io_event.length = length;
+        io_event.datamatch = datamatch;
+
+        let ret = match crosvm.main_transaction(&r, &[]) {
+            Ok((_, mut files)) => match files.pop() {
+                Some(evt) => return Ok(crosvm_io_event { id, evt }),
+                None => EPROTO,
+            },
+            Err(e) => e,
+        };
+        crosvm.get_id_allocator().free(id);
+        Err(ret)
+    }
+}
+
+impl_ctor_dtor!(
+    crosvm_io_event,
+    crosvm_create_io_event(space: u32, addr: u64, len: u32, datamatch: *const u8),
+    crosvm_destroy_io_event,
+);
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_io_event_fd(this: *mut crosvm_io_event) -> c_int {
+    let _u = STATS.record(Stat::IoEventFd);
+    (*this).evt.as_raw_fd()
+}
+
+pub struct crosvm_memory {
+    id: u32,
+    length: u64,
+}
+
+impl crosvm_memory {
+    fn create(
+        crosvm: &mut crosvm,
+        fd: c_int,
+        offset: u64,
+        length: u64,
+        start: u64,
+        read_only: bool,
+        dirty_log: bool,
+    ) -> result::Result<crosvm_memory, c_int> {
+        const PAGE_MASK: u64 = 0x0fff;
+        if offset & PAGE_MASK != 0 || length & PAGE_MASK != 0 {
+            return Err(EINVAL);
+        }
+        let id = crosvm.get_id_allocator().alloc();
+
+        let mut r = MainRequest::new();
+        let create: &mut MainRequest_Create = r.mut_create();
+        create.id = id;
+        let memory: &mut MainRequest_Create_Memory = create.mut_memory();
+        memory.offset = offset;
+        memory.start = start;
+        memory.length = length;
+        memory.read_only = read_only;
+        memory.dirty_log = dirty_log;
+
+        let ret = match crosvm.main_transaction(&r, &[fd]) {
+            Ok(_) => return Ok(crosvm_memory { id, length }),
+            Err(e) => e,
+        };
+        crosvm.get_id_allocator().free(id);
+        Err(ret)
+    }
+
+    fn get_dirty_log(&mut self, crosvm: &mut crosvm) -> result::Result<Vec<u8>, c_int> {
+        let mut r = MainRequest::new();
+        r.mut_dirty_log().id = self.id;
+        let (mut response, _) = crosvm.main_transaction(&r, &[])?;
+        if !response.has_dirty_log() {
+            return Err(EPROTO);
+        }
+        Ok(response.take_dirty_log().bitmap)
+    }
+}
+
+impl_ctor_dtor!(
+    crosvm_memory,
+    crosvm_create_memory(
+        fd: c_int,
+        offset: u64,
+        length: u64,
+        start: u64,
+        read_only: bool,
+        dirty_log: bool
+    ),
+    crosvm_destroy_memory,
+);
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_memory_get_dirty_log(
+    crosvm: *mut crosvm,
+    this: *mut crosvm_memory,
+    log: *mut u8,
+) -> c_int {
+    let _u = STATS.record(Stat::MemoryGetDirtyLog);
+    let crosvm = &mut *crosvm;
+    let this = &mut *this;
+    let log_slice = slice::from_raw_parts_mut(log, dirty_log_bitmap_size(this.length as usize));
+    match this.get_dirty_log(crosvm) {
+        Ok(bitmap) => {
+            if bitmap.len() == log_slice.len() {
+                log_slice.copy_from_slice(&bitmap);
+                0
+            } else {
+                -EPROTO
+            }
+        }
+        Err(e) => -e,
+    }
+}
+
+pub struct crosvm_irq_event {
+    id: u32,
+    trigger_evt: File,
+    resample_evt: File,
+}
+
+impl crosvm_irq_event {
+    fn create(crosvm: &mut crosvm, irq_id: u32) -> result::Result<crosvm_irq_event, c_int> {
+        let id = crosvm.get_id_allocator().alloc();
+
+        let mut r = MainRequest::new();
+        let create: &mut MainRequest_Create = r.mut_create();
+        create.id = id;
+        let irq_event: &mut MainRequest_Create_IrqEvent = create.mut_irq_event();
+        irq_event.irq_id = irq_id;
+        irq_event.resample = true;
+
+        let ret = match crosvm.main_transaction(&r, &[]) {
+            Ok((_, mut files)) => {
+                if files.len() >= 2 {
+                    let resample_evt = files.pop().unwrap();
+                    let trigger_evt = files.pop().unwrap();
+                    return Ok(crosvm_irq_event {
+                        id,
+                        trigger_evt,
+                        resample_evt,
+                    });
+                }
+                EPROTO
+            }
+            Err(e) => e,
+        };
+        crosvm.get_id_allocator().free(id);
+        Err(ret)
+    }
+}
+
+impl_ctor_dtor!(
+    crosvm_irq_event,
+    crosvm_create_irq_event(irq_id: u32),
+    crosvm_destroy_irq_event,
+);
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_irq_event_get_fd(this: *mut crosvm_irq_event) -> c_int {
+    let _u = STATS.record(Stat::IrqEventGetFd);
+    (*this).trigger_evt.as_raw_fd()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_irq_event_get_resample_fd(this: *mut crosvm_irq_event) -> c_int {
+    let _u = STATS.record(Stat::IrqEventGetResampleFd);
+    (*this).resample_evt.as_raw_fd()
+}
+
+#[allow(dead_code)]
+#[derive(Copy, Clone)]
+#[repr(C)]
+struct anon_io_access {
+    address_space: u32,
+    __reserved0: [u8; 4],
+    address: u64,
+    data: *mut u8,
+    length: u32,
+    is_write: u8,
+    __reserved1: u8,
+}
+
+#[repr(C)]
+union anon_vcpu_event {
+    io_access: anon_io_access,
+    user: *mut c_void,
+    #[allow(dead_code)]
+    __reserved: [u8; 64],
+}
+
+#[repr(C)]
+pub struct crosvm_vcpu_event {
+    kind: u32,
+    __reserved: [u8; 4],
+    event: anon_vcpu_event,
+}
+
+pub struct crosvm_vcpu {
+    read_pipe: File,
+    write_pipe: File,
+    send_init: bool,
+    request_buffer: Vec<u8>,
+    response_buffer: Vec<u8>,
+    resume_data: Vec<u8>,
+}
+
+impl crosvm_vcpu {
+    fn new(read_pipe: File, write_pipe: File) -> crosvm_vcpu {
+        crosvm_vcpu {
+            read_pipe,
+            write_pipe,
+            send_init: true,
+            request_buffer: Vec::new(),
+            response_buffer: vec![0; MAX_DATAGRAM_SIZE],
+            resume_data: Vec::new(),
+        }
+    }
+    fn vcpu_send(&mut self, request: &VcpuRequest) -> result::Result<(), c_int> {
+        self.request_buffer.clear();
+        request
+            .write_to_vec(&mut self.request_buffer)
+            .map_err(proto_error_to_int)?;
+        self.write_pipe
+            .write(self.request_buffer.as_slice())
+            .map_err(|e| -e.raw_os_error().unwrap_or(EINVAL))?;
+        Ok(())
+    }
+
+    fn vcpu_recv(&mut self) -> result::Result<VcpuResponse, c_int> {
+        let msg_size = self
+            .read_pipe
+            .read(&mut self.response_buffer)
+            .map_err(|e| -e.raw_os_error().unwrap_or(EINVAL))?;
+
+        let response: VcpuResponse =
+            parse_from_bytes(&self.response_buffer[..msg_size]).map_err(proto_error_to_int)?;
+        if response.errno != 0 {
+            return Err(response.errno);
+        }
+        Ok(response)
+    }
+
+    fn vcpu_transaction(&mut self, request: &VcpuRequest) -> result::Result<VcpuResponse, c_int> {
+        self.vcpu_send(request)?;
+        let response: VcpuResponse = self.vcpu_recv()?;
+        Ok(response)
+    }
+
+    fn wait(&mut self, event: &mut crosvm_vcpu_event) -> result::Result<(), c_int> {
+        if self.send_init {
+            self.send_init = false;
+            let mut r = VcpuRequest::new();
+            r.mut_wait();
+            self.vcpu_send(&r)?;
+        }
+        let mut response: VcpuResponse = self.vcpu_recv()?;
+        if !response.has_wait() {
+            return Err(EPROTO);
+        }
+        let wait: &mut VcpuResponse_Wait = response.mut_wait();
+        if wait.has_init() {
+            event.kind = CROSVM_VCPU_EVENT_KIND_INIT;
+            Ok(())
+        } else if wait.has_io() {
+            let mut io: VcpuResponse_Wait_Io = wait.take_io();
+            event.kind = CROSVM_VCPU_EVENT_KIND_IO_ACCESS;
+            event.event.io_access = anon_io_access {
+                address_space: io.space.value() as u32,
+                __reserved0: Default::default(),
+                address: io.address,
+                data: io.data.as_mut_ptr(),
+                length: io.data.len() as u32,
+                is_write: io.is_write as u8,
+                __reserved1: Default::default(),
+            };
+            self.resume_data = io.data;
+            Ok(())
+        } else if wait.has_user() {
+            let user: &VcpuResponse_Wait_User = wait.get_user();
+            event.kind = CROSVM_VCPU_EVENT_KIND_PAUSED;
+            event.event.user = user.user as *mut c_void;
+            Ok(())
+        } else {
+            Err(EPROTO)
+        }
+    }
+
+    fn resume(&mut self) -> result::Result<(), c_int> {
+        let mut r = VcpuRequest::new();
+        let resume: &mut VcpuRequest_Resume = r.mut_resume();
+        swap(&mut resume.data, &mut self.resume_data);
+
+        self.vcpu_send(&r)?;
+        Ok(())
+    }
+
+    fn get_state(
+        &mut self,
+        state_set: VcpuRequest_StateSet,
+        out: &mut [u8],
+    ) -> result::Result<(), c_int> {
+        let mut r = VcpuRequest::new();
+        r.mut_get_state().set = state_set;
+        let response = self.vcpu_transaction(&r)?;
+        if !response.has_get_state() {
+            return Err(EPROTO);
+        }
+        let get_state: &VcpuResponse_GetState = response.get_get_state();
+        if get_state.state.len() != out.len() {
+            return Err(EPROTO);
+        }
+        out.copy_from_slice(&get_state.state);
+        Ok(())
+    }
+
+    fn set_state(
+        &mut self,
+        state_set: VcpuRequest_StateSet,
+        new_state: &[u8],
+    ) -> result::Result<(), c_int> {
+        let mut r = VcpuRequest::new();
+        let set_state: &mut VcpuRequest_SetState = r.mut_set_state();
+        set_state.set = state_set;
+        set_state.state = new_state.to_vec();
+
+        self.vcpu_transaction(&r)?;
+        Ok(())
+    }
+
+    fn get_msrs(
+        &mut self,
+        msr_entries: &mut [kvm_msr_entry],
+        msr_count: &mut usize,
+    ) -> result::Result<(), c_int> {
+        *msr_count = 0;
+
+        let mut r = VcpuRequest::new();
+        let entry_indices: &mut Vec<u32> = r.mut_get_msrs().mut_entry_indices();
+        for entry in msr_entries.iter() {
+            entry_indices.push(entry.index);
+        }
+
+        let response = self.vcpu_transaction(&r)?;
+        if !response.has_get_msrs() {
+            return Err(EPROTO);
+        }
+        let get_msrs: &VcpuResponse_GetMsrs = response.get_get_msrs();
+        *msr_count = get_msrs.get_entry_data().len();
+        if *msr_count > msr_entries.len() {
+            return Err(E2BIG);
+        }
+        for (&msr_data, msr_entry) in get_msrs.get_entry_data().iter().zip(msr_entries) {
+            msr_entry.data = msr_data;
+        }
+        Ok(())
+    }
+
+    fn set_msrs(&mut self, msr_entries: &[kvm_msr_entry]) -> result::Result<(), c_int> {
+        let mut r = VcpuRequest::new();
+        let set_msrs_entries: &mut RepeatedField<VcpuRequest_MsrEntry> =
+            r.mut_set_msrs().mut_entries();
+        for msr_entry in msr_entries {
+            let mut entry = VcpuRequest_MsrEntry::new();
+            entry.index = msr_entry.index;
+            entry.data = msr_entry.data;
+            set_msrs_entries.push(entry);
+        }
+
+        self.vcpu_transaction(&r)?;
+        Ok(())
+    }
+
+    fn set_cpuid(&mut self, cpuid_entries: &[kvm_cpuid_entry2]) -> result::Result<(), c_int> {
+        let mut r = VcpuRequest::new();
+        let set_cpuid_entries: &mut RepeatedField<CpuidEntry> = r.mut_set_cpuid().mut_entries();
+        for cpuid_entry in cpuid_entries {
+            set_cpuid_entries.push(cpuid_kvm_to_proto(cpuid_entry));
+        }
+
+        self.vcpu_transaction(&r)?;
+        Ok(())
+    }
+}
+
+// crosvm API signals success as 0 and errors as negative values
+// derived from `errno`.
+fn to_crosvm_rc<T>(r: result::Result<T, c_int>) -> c_int {
+    match r {
+        Ok(_) => 0,
+        Err(e) => -e,
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_connect(out: *mut *mut crosvm) -> c_int {
+    let _u = STATS.record(Stat::Connect);
+    let socket_name = match env::var("CROSVM_SOCKET") {
+        Ok(v) => v,
+        _ => return -ENOTCONN,
+    };
+
+    let socket = match socket_name.parse() {
+        Ok(v) if v < 0 => return -EINVAL,
+        Ok(v) => v,
+        _ => return -EINVAL,
+    };
+
+    let socket = UnixDatagram::from_raw_fd(socket);
+    let crosvm = match crosvm::from_connection(socket) {
+        Ok(c) => c,
+        Err(e) => return -e,
+    };
+    *out = Box::into_raw(Box::new(crosvm));
+    0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_new_connection(self_: *mut crosvm, out: *mut *mut crosvm) -> c_int {
+    let _u = STATS.record(Stat::NewConnection);
+    let self_ = &mut (*self_);
+    match self_.try_clone() {
+        Ok(cloned) => {
+            *out = Box::into_raw(Box::new(cloned));
+            0
+        }
+        Err(e) => -e,
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_destroy_connection(self_: *mut *mut crosvm) -> c_int {
+    let _u = STATS.record(Stat::DestroyConnection);
+    Box::from_raw(*self_);
+    *self_ = null_mut();
+    0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_get_shutdown_eventfd(self_: *mut crosvm) -> c_int {
+    let _u = STATS.record(Stat::GetShutdownEventFd);
+    let self_ = &mut (*self_);
+    match self_.get_shutdown_eventfd() {
+        Ok(f) => f.into_raw_fd(),
+        Err(e) => -e,
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_check_extension(
+    self_: *mut crosvm,
+    extension: u32,
+    has_extension: *mut bool,
+) -> c_int {
+    let _u = STATS.record(Stat::CheckExtentsion);
+    let self_ = &mut (*self_);
+    let ret = self_.check_extension(extension);
+
+    if let Ok(supported) = ret {
+        *has_extension = supported;
+    }
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_get_supported_cpuid(
+    this: *mut crosvm,
+    entry_count: u32,
+    cpuid_entries: *mut kvm_cpuid_entry2,
+    out_count: *mut u32,
+) -> c_int {
+    let _u = STATS.record(Stat::GetSupportedCpuid);
+    let this = &mut *this;
+    let cpuid_entries = from_raw_parts_mut(cpuid_entries, entry_count as usize);
+    let mut cpuid_count: usize = 0;
+    let ret = this.get_supported_cpuid(cpuid_entries, &mut cpuid_count);
+    *out_count = cpuid_count as u32;
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_get_emulated_cpuid(
+    this: *mut crosvm,
+    entry_count: u32,
+    cpuid_entries: *mut kvm_cpuid_entry2,
+    out_count: *mut u32,
+) -> c_int {
+    let _u = STATS.record(Stat::GetEmulatedCpuid);
+    let this = &mut *this;
+    let cpuid_entries = from_raw_parts_mut(cpuid_entries, entry_count as usize);
+    let mut cpuid_count: usize = 0;
+    let ret = this.get_emulated_cpuid(cpuid_entries, &mut cpuid_count);
+    *out_count = cpuid_count as u32;
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_get_msr_index_list(
+    this: *mut crosvm,
+    entry_count: u32,
+    msr_indices: *mut u32,
+    out_count: *mut u32,
+) -> c_int {
+    let _u = STATS.record(Stat::GetMsrIndexList);
+    let this = &mut *this;
+    let msr_indices = from_raw_parts_mut(msr_indices, entry_count as usize);
+    let mut msr_count: usize = 0;
+    let ret = this.get_msr_index_list(msr_indices, &mut msr_count);
+    *out_count = msr_count as u32;
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_net_get_config(
+    self_: *mut crosvm,
+    config: *mut crosvm_net_config,
+) -> c_int {
+    let _u = STATS.record(Stat::NetGetConfig);
+    let self_ = &mut (*self_);
+    let ret = self_.get_net_config();
+
+    if let Ok(c) = ret {
+        *config = c;
+    }
+
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_reserve_range(
+    self_: *mut crosvm,
+    space: u32,
+    start: u64,
+    length: u64,
+) -> c_int {
+    let _u = STATS.record(Stat::ReserveRange);
+    let self_ = &mut (*self_);
+    let ret = self_.reserve_range(space, start, length);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_set_irq(self_: *mut crosvm, irq_id: u32, active: bool) -> c_int {
+    let _u = STATS.record(Stat::SetIrq);
+    let self_ = &mut (*self_);
+    let ret = self_.set_irq(irq_id, active);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_set_irq_routing(
+    self_: *mut crosvm,
+    route_count: u32,
+    routes: *const crosvm_irq_route,
+) -> c_int {
+    let _u = STATS.record(Stat::SetIrqRouting);
+    let self_ = &mut (*self_);
+    let ret = self_.set_irq_routing(slice::from_raw_parts(routes, route_count as usize));
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_get_pic_state(
+    this: *mut crosvm,
+    primary: bool,
+    state: *mut kvm_pic_state,
+) -> c_int {
+    let _u = STATS.record(Stat::GetPicState);
+    let this = &mut *this;
+    let state_set = if primary {
+        MainRequest_StateSet::PIC0
+    } else {
+        MainRequest_StateSet::PIC1
+    };
+    let state = from_raw_parts_mut(state as *mut u8, size_of::<kvm_pic_state>());
+    let ret = this.get_state(state_set, state);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_set_pic_state(
+    this: *mut crosvm,
+    primary: bool,
+    state: *mut kvm_pic_state,
+) -> c_int {
+    let _u = STATS.record(Stat::SetPicState);
+    let this = &mut *this;
+    let state_set = if primary {
+        MainRequest_StateSet::PIC0
+    } else {
+        MainRequest_StateSet::PIC1
+    };
+    let state = from_raw_parts(state as *mut u8, size_of::<kvm_pic_state>());
+    let ret = this.set_state(state_set, state);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_get_ioapic_state(
+    this: *mut crosvm,
+    state: *mut kvm_ioapic_state,
+) -> c_int {
+    let _u = STATS.record(Stat::GetIoapicState);
+    let this = &mut *this;
+    let state = from_raw_parts_mut(state as *mut u8, size_of::<kvm_ioapic_state>());
+    let ret = this.get_state(MainRequest_StateSet::IOAPIC, state);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_set_ioapic_state(
+    this: *mut crosvm,
+    state: *const kvm_ioapic_state,
+) -> c_int {
+    let _u = STATS.record(Stat::SetIoapicState);
+    let this = &mut *this;
+    let state = from_raw_parts(state as *mut u8, size_of::<kvm_ioapic_state>());
+    let ret = this.set_state(MainRequest_StateSet::IOAPIC, state);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_get_pit_state(
+    this: *mut crosvm,
+    state: *mut kvm_pit_state2,
+) -> c_int {
+    let _u = STATS.record(Stat::GetPitState);
+    let this = &mut *this;
+    let state = from_raw_parts_mut(state as *mut u8, size_of::<kvm_pit_state2>());
+    let ret = this.get_state(MainRequest_StateSet::PIT, state);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_set_pit_state(
+    this: *mut crosvm,
+    state: *const kvm_pit_state2,
+) -> c_int {
+    let _u = STATS.record(Stat::SetPitState);
+    let this = &mut *this;
+    let state = from_raw_parts(state as *mut u8, size_of::<kvm_pit_state2>());
+    let ret = this.set_state(MainRequest_StateSet::PIT, state);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_get_clock(
+    this: *mut crosvm,
+    clock_data: *mut kvm_clock_data,
+) -> c_int {
+    let _u = STATS.record(Stat::GetClock);
+    let this = &mut *this;
+    let state = from_raw_parts_mut(clock_data as *mut u8, size_of::<kvm_clock_data>());
+    let ret = this.get_state(MainRequest_StateSet::CLOCK, state);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_set_clock(
+    this: *mut crosvm,
+    clock_data: *const kvm_clock_data,
+) -> c_int {
+    let _u = STATS.record(Stat::SetClock);
+    let this = &mut *this;
+    let state = from_raw_parts(clock_data as *mut u8, size_of::<kvm_clock_data>());
+    let ret = this.set_state(MainRequest_StateSet::CLOCK, state);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_set_identity_map_addr(self_: *mut crosvm, addr: u32) -> c_int {
+    let _u = STATS.record(Stat::SetIdentityMapAddr);
+    let self_ = &mut (*self_);
+    let ret = self_.set_identity_map_addr(addr);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_pause_vcpus(
+    self_: *mut crosvm,
+    cpu_mask: u64,
+    user: *mut c_void,
+) -> c_int {
+    let _u = STATS.record(Stat::PauseVcpus);
+    let self_ = &mut (*self_);
+    let ret = self_.pause_vcpus(cpu_mask, user);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_start(self_: *mut crosvm) -> c_int {
+    let _u = STATS.record(Stat::Start);
+    let self_ = &mut (*self_);
+    let ret = self_.start();
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_get_vcpu(
+    self_: *mut crosvm,
+    cpu_id: u32,
+    out: *mut *mut crosvm_vcpu,
+) -> c_int {
+    let _u = STATS.record(Stat::GetVcpu);
+    let self_ = &mut (*self_);
+    let ret = self_.get_vcpu(cpu_id);
+
+    if let Ok(vcpu) = ret {
+        *out = vcpu;
+    }
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_wait(
+    this: *mut crosvm_vcpu,
+    event: *mut crosvm_vcpu_event,
+) -> c_int {
+    let _u = STATS.record(Stat::VcpuWait);
+    let this = &mut *this;
+    let event = &mut *event;
+    let ret = this.wait(event);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_resume(this: *mut crosvm_vcpu) -> c_int {
+    let _u = STATS.record(Stat::VcpuResume);
+    let this = &mut *this;
+    let ret = this.resume();
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_get_regs(
+    this: *mut crosvm_vcpu,
+    regs: *mut kvm_regs,
+) -> c_int {
+    let _u = STATS.record(Stat::VcpuGetRegs);
+    let this = &mut *this;
+    let regs = from_raw_parts_mut(regs as *mut u8, size_of::<kvm_regs>());
+    let ret = this.get_state(VcpuRequest_StateSet::REGS, regs);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_set_regs(
+    this: *mut crosvm_vcpu,
+    regs: *const kvm_regs,
+) -> c_int {
+    let _u = STATS.record(Stat::VcpuSetRegs);
+    let this = &mut *this;
+    let regs = from_raw_parts(regs as *mut u8, size_of::<kvm_regs>());
+    let ret = this.set_state(VcpuRequest_StateSet::REGS, regs);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_get_sregs(
+    this: *mut crosvm_vcpu,
+    sregs: *mut kvm_sregs,
+) -> c_int {
+    let _u = STATS.record(Stat::VcpuGetSregs);
+    let this = &mut *this;
+    let sregs = from_raw_parts_mut(sregs as *mut u8, size_of::<kvm_sregs>());
+    let ret = this.get_state(VcpuRequest_StateSet::SREGS, sregs);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_set_sregs(
+    this: *mut crosvm_vcpu,
+    sregs: *const kvm_sregs,
+) -> c_int {
+    let _u = STATS.record(Stat::VcpuSetSregs);
+    let this = &mut *this;
+    let sregs = from_raw_parts(sregs as *mut u8, size_of::<kvm_sregs>());
+    let ret = this.set_state(VcpuRequest_StateSet::SREGS, sregs);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_get_fpu(this: *mut crosvm_vcpu, fpu: *mut kvm_fpu) -> c_int {
+    let _u = STATS.record(Stat::GetFpu);
+    let this = &mut *this;
+    let fpu = from_raw_parts_mut(fpu as *mut u8, size_of::<kvm_fpu>());
+    let ret = this.get_state(VcpuRequest_StateSet::FPU, fpu);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_set_fpu(this: *mut crosvm_vcpu, fpu: *const kvm_fpu) -> c_int {
+    let _u = STATS.record(Stat::SetFpu);
+    let this = &mut *this;
+    let fpu = from_raw_parts(fpu as *mut u8, size_of::<kvm_fpu>());
+    let ret = this.set_state(VcpuRequest_StateSet::FPU, fpu);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_get_debugregs(
+    this: *mut crosvm_vcpu,
+    dregs: *mut kvm_debugregs,
+) -> c_int {
+    let _u = STATS.record(Stat::GetDebugRegs);
+    let this = &mut *this;
+    let dregs = from_raw_parts_mut(dregs as *mut u8, size_of::<kvm_debugregs>());
+    let ret = this.get_state(VcpuRequest_StateSet::DEBUGREGS, dregs);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_set_debugregs(
+    this: *mut crosvm_vcpu,
+    dregs: *const kvm_debugregs,
+) -> c_int {
+    let _u = STATS.record(Stat::SetDebugRegs);
+    let this = &mut *this;
+    let dregs = from_raw_parts(dregs as *mut u8, size_of::<kvm_debugregs>());
+    let ret = this.set_state(VcpuRequest_StateSet::DEBUGREGS, dregs);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_get_xcrs(
+    this: *mut crosvm_vcpu,
+    xcrs: *mut kvm_xcrs,
+) -> c_int {
+    let _u = STATS.record(Stat::GetXCRegs);
+    let this = &mut *this;
+    let xcrs = from_raw_parts_mut(xcrs as *mut u8, size_of::<kvm_xcrs>());
+    let ret = this.get_state(VcpuRequest_StateSet::XCREGS, xcrs);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_set_xcrs(
+    this: *mut crosvm_vcpu,
+    xcrs: *const kvm_xcrs,
+) -> c_int {
+    let _u = STATS.record(Stat::SetXCRegs);
+    let this = &mut *this;
+    let xcrs = from_raw_parts(xcrs as *mut u8, size_of::<kvm_xcrs>());
+    let ret = this.set_state(VcpuRequest_StateSet::XCREGS, xcrs);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_get_msrs(
+    this: *mut crosvm_vcpu,
+    msr_count: u32,
+    msr_entries: *mut kvm_msr_entry,
+    out_count: *mut u32,
+) -> c_int {
+    let _u = STATS.record(Stat::VcpuGetMsrs);
+    let this = &mut *this;
+    let msr_entries = from_raw_parts_mut(msr_entries, msr_count as usize);
+    let mut count: usize = 0;
+    let ret = this.get_msrs(msr_entries, &mut count);
+    *out_count = count as u32;
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_set_msrs(
+    this: *mut crosvm_vcpu,
+    msr_count: u32,
+    msr_entries: *const kvm_msr_entry,
+) -> c_int {
+    let _u = STATS.record(Stat::VcpuSetMsrs);
+    let this = &mut *this;
+    let msr_entries = from_raw_parts(msr_entries, msr_count as usize);
+    let ret = this.set_msrs(msr_entries);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_set_cpuid(
+    this: *mut crosvm_vcpu,
+    cpuid_count: u32,
+    cpuid_entries: *const kvm_cpuid_entry2,
+) -> c_int {
+    let _u = STATS.record(Stat::VcpuSetCpuid);
+    let this = &mut *this;
+    let cpuid_entries = from_raw_parts(cpuid_entries, cpuid_count as usize);
+    let ret = this.set_cpuid(cpuid_entries);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_get_lapic_state(
+    this: *mut crosvm_vcpu,
+    state: *mut kvm_lapic_state,
+) -> c_int {
+    let _u = STATS.record(Stat::VcpuGetLapicState);
+    let this = &mut *this;
+    let state = from_raw_parts_mut(state as *mut u8, size_of::<kvm_lapic_state>());
+    let ret = this.get_state(VcpuRequest_StateSet::LAPIC, state);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_set_lapic_state(
+    this: *mut crosvm_vcpu,
+    state: *const kvm_lapic_state,
+) -> c_int {
+    let _u = STATS.record(Stat::VcpuSetLapicState);
+    let this = &mut *this;
+    let state = from_raw_parts(state as *mut u8, size_of::<kvm_lapic_state>());
+    let ret = this.set_state(VcpuRequest_StateSet::LAPIC, state);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_get_mp_state(
+    this: *mut crosvm_vcpu,
+    state: *mut kvm_mp_state,
+) -> c_int {
+    let _u = STATS.record(Stat::VcpuGetMpState);
+    let this = &mut *this;
+    let state = from_raw_parts_mut(state as *mut u8, size_of::<kvm_mp_state>());
+    let ret = this.get_state(VcpuRequest_StateSet::MP, state);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_set_mp_state(
+    this: *mut crosvm_vcpu,
+    state: *const kvm_mp_state,
+) -> c_int {
+    let _u = STATS.record(Stat::VcpuSetMpState);
+    let this = &mut *this;
+    let state = from_raw_parts(state as *mut u8, size_of::<kvm_mp_state>());
+    let ret = this.set_state(VcpuRequest_StateSet::MP, state);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_get_vcpu_events(
+    this: *mut crosvm_vcpu,
+    events: *mut kvm_vcpu_events,
+) -> c_int {
+    let _u = STATS.record(Stat::VcpuGetVcpuEvents);
+    let this = &mut *this;
+    let events = from_raw_parts_mut(events as *mut u8, size_of::<kvm_vcpu_events>());
+    let ret = this.get_state(VcpuRequest_StateSet::EVENTS, events);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_set_vcpu_events(
+    this: *mut crosvm_vcpu,
+    events: *const kvm_vcpu_events,
+) -> c_int {
+    let _u = STATS.record(Stat::VcpuSetVcpuEvents);
+    let this = &mut *this;
+    let events = from_raw_parts(events as *mut u8, size_of::<kvm_vcpu_events>());
+    let ret = this.set_state(VcpuRequest_StateSet::EVENTS, events);
+    to_crosvm_rc(ret)
+}
diff --git a/data_model/Cargo.toml b/data_model/Cargo.toml
new file mode 100644
index 0000000..b1447a6
--- /dev/null
+++ b/data_model/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "data_model"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+include = ["src/**/*", "Cargo.toml"]
+
+[dependencies]
+assertions = { path = "../assertions" } # provided by ebuild
+
+[workspace]
diff --git a/data_model/src/endian.rs b/data_model/src/endian.rs
new file mode 100644
index 0000000..014bb7b
--- /dev/null
+++ b/data_model/src/endian.rs
@@ -0,0 +1,143 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Explicit endian types useful for embedding in structs or reinterpreting data.
+//!
+//! Each endian type is guarnteed to have the same size and alignment as a regular unsigned primiive
+//! of the equal size.
+//!
+//! # Examples
+//!
+//! ```
+//! # use  data_model::*;
+//!   let b: Be32 = From::from(3);
+//!   let l: Le32 = From::from(3);
+//!
+//!   assert_eq!(b.to_native(), 3);
+//!   assert_eq!(l.to_native(), 3);
+//!   assert!(b == 3);
+//!   assert!(l == 3);
+//!
+//!   let b_trans: u32 = unsafe { std::mem::transmute(b) };
+//!   let l_trans: u32 = unsafe { std::mem::transmute(l) };
+//!
+//!   #[cfg(target_endian = "little")]
+//!   assert_eq!(l_trans, 3);
+//!   #[cfg(target_endian = "big")]
+//!   assert_eq!(b_trans, 3);
+//!
+//!   assert_ne!(b_trans, l_trans);
+//! ```
+
+use assertions::const_assert;
+use std::mem::{align_of, size_of};
+
+use crate::DataInit;
+
+macro_rules! endian_type {
+    ($old_type:ident, $new_type:ident, $to_new:ident, $from_new:ident) => {
+        /// An unsigned integer type of with an explicit endianness.
+        ///
+        /// See module level documentation for examples.
+        #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
+        pub struct $new_type($old_type);
+
+        impl $new_type {
+            fn _assert() {
+                const_assert!(align_of::<$new_type>() == align_of::<$old_type>());
+                const_assert!(size_of::<$new_type>() == size_of::<$old_type>());
+            }
+
+            /// Converts `self` to the native endianness.
+            pub fn to_native(self) -> $old_type {
+                $old_type::$from_new(self.0)
+            }
+        }
+
+        unsafe impl DataInit for $new_type {}
+
+        impl PartialEq<$old_type> for $new_type {
+            fn eq(&self, other: &$old_type) -> bool {
+                self.0 == $old_type::$to_new(*other)
+            }
+        }
+
+        impl PartialEq<$new_type> for $old_type {
+            fn eq(&self, other: &$new_type) -> bool {
+                $old_type::$to_new(other.0) == *self
+            }
+        }
+
+        impl Into<$old_type> for $new_type {
+            fn into(self) -> $old_type {
+                $old_type::$from_new(self.0)
+            }
+        }
+
+        impl From<$old_type> for $new_type {
+            fn from(v: $old_type) -> $new_type {
+                $new_type($old_type::$to_new(v))
+            }
+        }
+    };
+}
+
+endian_type!(u16, Le16, to_le, from_le);
+endian_type!(u32, Le32, to_le, from_le);
+endian_type!(u64, Le64, to_le, from_le);
+endian_type!(usize, LeSize, to_le, from_le);
+endian_type!(u16, Be16, to_be, from_be);
+endian_type!(u32, Be32, to_be, from_be);
+endian_type!(u64, Be64, to_be, from_be);
+endian_type!(usize, BeSize, to_be, from_be);
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use std::convert::From;
+    use std::mem::transmute;
+
+    #[cfg(target_endian = "little")]
+    const NATIVE_LITTLE: bool = true;
+    #[cfg(target_endian = "big")]
+    const NATIVE_LITTLE: bool = false;
+    const NATIVE_BIG: bool = !NATIVE_LITTLE;
+
+    macro_rules! endian_test {
+        ($old_type:ty, $new_type:ty, $test_name:ident, $native:expr) => {
+            mod $test_name {
+                use super::*;
+
+                #[allow(overflowing_literals)]
+                #[test]
+                fn equality() {
+                    let v = 0x0123456789ABCDEF as $old_type;
+                    let endian_v: $new_type = From::from(v);
+                    let endian_into: $old_type = endian_v.into();
+                    let endian_transmute: $old_type = unsafe { transmute(endian_v) };
+
+                    if $native {
+                        assert_eq!(endian_v, endian_transmute);
+                    } else {
+                        assert_eq!(endian_v, endian_transmute.swap_bytes());
+                    }
+
+                    assert_eq!(v, endian_into);
+                    assert!(v == endian_v);
+                    assert!(endian_v == v);
+                }
+            }
+        };
+    }
+
+    endian_test!(u16, Le16, test_le16, NATIVE_LITTLE);
+    endian_test!(u32, Le32, test_le32, NATIVE_LITTLE);
+    endian_test!(u64, Le64, test_le64, NATIVE_LITTLE);
+    endian_test!(usize, LeSize, test_le_size, NATIVE_LITTLE);
+    endian_test!(u16, Be16, test_be16, NATIVE_BIG);
+    endian_test!(u32, Be32, test_be32, NATIVE_BIG);
+    endian_test!(u64, Be64, test_be64, NATIVE_BIG);
+    endian_test!(usize, BeSize, test_be_size, NATIVE_BIG);
+}
diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs
new file mode 100644
index 0000000..8288c84
--- /dev/null
+++ b/data_model/src/lib.rs
@@ -0,0 +1,162 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::mem::size_of;
+use std::slice::{from_raw_parts, from_raw_parts_mut};
+
+/// Types for which it is safe to initialize from raw data.
+///
+/// A type `T` is `DataInit` if and only if it can be initialized by reading its contents from a
+/// byte array.  This is generally true for all plain-old-data structs.  It is notably not true for
+/// any type that includes a reference.
+///
+/// Implementing this trait guarantees that it is safe to instantiate the struct with random data.
+pub unsafe trait DataInit: Copy + Send + Sync {
+    /// Converts a slice of raw data into a reference of `Self`.
+    ///
+    /// The value of `data` is not copied. Instead a reference is made from the given slice. The
+    /// value of `Self` will depend on the representation of the type in memory, and may change in
+    /// an unstable fashion.
+    ///
+    /// This will return `None` if the length of data does not match the size of `Self`, or if the
+    /// data is not aligned for the type of `Self`.
+    fn from_slice(data: &[u8]) -> Option<&Self> {
+        // Early out to avoid an unneeded `align_to` call.
+        if data.len() != size_of::<Self>() {
+            return None;
+        }
+
+        // Safe because the DataInit trait asserts any data is valid for this type, and we ensured
+        // the size of the pointer's buffer is the correct size. The `align_to` method ensures that
+        // we don't have any unaligned references. This aliases a pointer, but because the pointer
+        // is from a const slice reference, there are no mutable aliases. Finally, the reference
+        // returned can not outlive data because they have equal implicit lifetime constraints.
+        match unsafe { data.align_to::<Self>() } {
+            ([], [mid], []) => Some(mid),
+            _ => None,
+        }
+    }
+
+    /// Converts a mutable slice of raw data into a mutable reference of `Self`.
+    ///
+    /// Because `Self` is made from a reference to the mutable slice`, mutations to the returned
+    /// reference are immediately reflected in `data`. The value of the returned `Self` will depend
+    /// on the representation of the type in memory, and may change in an unstable fashion.
+    ///
+    /// This will return `None` if the length of data does not match the size of `Self`, or if the
+    /// data is not aligned for the type of `Self`.
+    fn from_mut_slice(data: &mut [u8]) -> Option<&mut Self> {
+        // Early out to avoid an unneeded `align_to_mut` call.
+        if data.len() != size_of::<Self>() {
+            return None;
+        }
+
+        // Safe because the DataInit trait asserts any data is valid for this type, and we ensured
+        // the size of the pointer's buffer is the correct size. The `align_to` method ensures that
+        // we don't have any unaligned references. This aliases a pointer, but because the pointer
+        // is from a mut slice reference, we borrow the passed in mutable reference. Finally, the
+        // reference returned can not outlive data because they have equal implicit lifetime
+        // constraints.
+        match unsafe { data.align_to_mut::<Self>() } {
+            ([], [mid], []) => Some(mid),
+            _ => None,
+        }
+    }
+
+    /// Converts a reference to `self` into a slice of bytes.
+    ///
+    /// The value of `self` is not copied. Instead, the slice is made from a reference to `self`.
+    /// The value of bytes in the returned slice will depend on the representation of the type in
+    /// memory, and may change in an unstable fashion.
+    fn as_slice(&self) -> &[u8] {
+        // Safe because the entire size of self is accessible as bytes because the trait guarantees
+        // it. The lifetime of the returned slice is the same as the passed reference, so that no
+        // dangling pointers will result from this pointer alias.
+        unsafe { from_raw_parts(self as *const Self as *const u8, size_of::<Self>()) }
+    }
+
+    /// Converts a mutable reference to `self` into a mutable slice of bytes.
+    ///
+    /// Because the slice is made from a reference to `self`, mutations to the returned slice are
+    /// immediately reflected in `self`. The value of bytes in the returned slice will depend on
+    /// the representation of the type in memory, and may change in an unstable fashion.
+    fn as_mut_slice(&mut self) -> &mut [u8] {
+        // Safe because the entire size of self is accessible as bytes because the trait guarantees
+        // it. The trait also guarantees that any combination of bytes is valid for this type, so
+        // modifying them in the form of a byte slice is valid. The lifetime of the returned slice
+        // is the same as the passed reference, so that no dangling pointers will result from this
+        // pointer alias. Although this does alias a mutable pointer, we do so by exclusively
+        // borrowing the given mutable reference.
+        unsafe { from_raw_parts_mut(self as *mut Self as *mut u8, size_of::<Self>()) }
+    }
+}
+
+// All intrinsic types and arays of intrinsic types are DataInit.  They are just numbers.
+macro_rules! array_data_init {
+    ($T:ty, $($N:expr)+) => {
+        $(
+            unsafe impl DataInit for [$T; $N] {}
+        )+
+    }
+}
+macro_rules! data_init_type {
+    ($($T:ident),*) => {
+        $(
+            unsafe impl DataInit for $T {}
+            array_data_init! {
+                $T,
+                0  1  2  3  4  5  6  7  8  9
+                10 11 12 13 14 15 16 17 18 19
+                20 21 22 23 24 25 26 27 28 29
+                30 31 32
+            }
+        )*
+        #[cfg(test)]
+        mod data_init_tests {
+            use std::mem::{size_of, align_of};
+            use crate::DataInit;
+
+            #[test]
+            fn from_slice_alignment() {
+                let mut v = [0u8; 32];
+                $(
+                    let (pre, _, _) = unsafe { v.align_to::<$T>() };
+                    let pre_len = pre.len();
+
+                    let aligned_v = &mut v[pre_len..pre_len + size_of::<$T>()];
+
+                    let from_aligned = $T::from_slice(aligned_v);
+                    assert_eq!(from_aligned, Some(&0));
+
+                    let from_aligned_mut = $T::from_mut_slice(aligned_v);
+                    assert_eq!(from_aligned_mut, Some(&mut 0));
+
+                    for i in 1..size_of::<$T>() {
+                        let begin = pre_len + i;
+                        let end = begin + size_of::<$T>();
+                        let unaligned_v = &mut v[begin..end];
+
+                        let from_unaligned = $T::from_slice(unaligned_v);
+                        if align_of::<$T>() != 1 {
+                            assert_eq!(from_unaligned, None);
+                        }
+
+                        let from_unaligned_mut = $T::from_mut_slice(unaligned_v);
+                        if align_of::<$T>() != 1 {
+                            assert_eq!(from_unaligned_mut, None);
+                        }
+                    }
+                )*
+
+            }
+        }
+    };
+}
+data_init_type!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
+
+pub mod endian;
+pub use crate::endian::*;
+
+pub mod volatile_memory;
+pub use crate::volatile_memory::*;
diff --git a/data_model/src/volatile_memory.rs b/data_model/src/volatile_memory.rs
new file mode 100644
index 0000000..6ce230b
--- /dev/null
+++ b/data_model/src/volatile_memory.rs
@@ -0,0 +1,555 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Types for volatile access to memory.
+//!
+//! Two of the core rules for safe rust is no data races and no aliased mutable references.
+//! `VolatileRef` and `VolatileSlice`, along with types that produce those which implement
+//! `VolatileMemory`, allow us to sidestep that rule by wrapping pointers that absolutely have to be
+//! accessed volatile. Some systems really do need to operate on shared memory and can't have the
+//! compiler reordering or eliding access because it has no visibility into what other systems are
+//! doing with that hunk of memory.
+//!
+//! For the purposes of maintaining safety, volatile memory has some rules of its own:
+//! 1. No references or slices to volatile memory (`&` or `&mut`).
+//! 2. Access should always been done with a volatile read or write.
+//! The First rule is because having references of any kind to memory considered volatile would
+//! violate pointer aliasing. The second is because unvolatile accesses are inherently undefined if
+//! done concurrently without synchronization. With volatile access we know that the compiler has
+//! not reordered or elided the access.
+
+use std::cmp::min;
+use std::fmt::{self, Display};
+use std::marker::PhantomData;
+use std::mem::size_of;
+use std::ptr::{copy, null_mut, read_volatile, write_bytes, write_volatile};
+use std::result;
+use std::{isize, usize};
+
+use crate::DataInit;
+
+#[derive(Eq, PartialEq, Debug)]
+pub enum VolatileMemoryError {
+    /// `addr` is out of bounds of the volatile memory slice.
+    OutOfBounds { addr: u64 },
+    /// Taking a slice at `base` with `offset` would overflow `u64`.
+    Overflow { base: u64, offset: u64 },
+}
+
+impl Display for VolatileMemoryError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::VolatileMemoryError::*;
+
+        match self {
+            OutOfBounds { addr } => write!(f, "address 0x{:x} is out of bounds", addr),
+            Overflow { base, offset } => write!(
+                f,
+                "address 0x{:x} offset by 0x{:x} would overflow",
+                base, offset
+            ),
+        }
+    }
+}
+
+pub type VolatileMemoryResult<T> = result::Result<T, VolatileMemoryError>;
+
+use crate::VolatileMemoryError as Error;
+type Result<T> = VolatileMemoryResult<T>;
+
+/// Convenience function for computing `base + offset` which returns
+/// `Err(VolatileMemoryError::Overflow)` instead of panicking in the case `base + offset` exceeds
+/// `u64::MAX`.
+///
+/// # Examples
+///
+/// ```
+/// # use data_model::*;
+/// # fn get_slice(offset: u64, count: u64) -> VolatileMemoryResult<()> {
+///   let mem_end = calc_offset(offset, count)?;
+///   if mem_end > 100 {
+///       return Err(VolatileMemoryError::OutOfBounds{addr: mem_end});
+///   }
+/// # Ok(())
+/// # }
+/// ```
+pub fn calc_offset(base: u64, offset: u64) -> Result<u64> {
+    match base.checked_add(offset) {
+        None => Err(Error::Overflow { base, offset }),
+        Some(m) => Ok(m),
+    }
+}
+
+/// Trait for types that support raw volatile access to their data.
+pub trait VolatileMemory {
+    /// Gets a slice of memory at `offset` that is `count` bytes in length and supports volatile
+    /// access.
+    fn get_slice(&self, offset: u64, count: u64) -> Result<VolatileSlice>;
+
+    /// Gets a `VolatileRef` at `offset`.
+    fn get_ref<T: DataInit>(&self, offset: u64) -> Result<VolatileRef<T>> {
+        let slice = self.get_slice(offset, size_of::<T>() as u64)?;
+        Ok(VolatileRef {
+            addr: slice.addr as *mut T,
+            phantom: PhantomData,
+        })
+    }
+}
+
+impl<'a> VolatileMemory for &'a mut [u8] {
+    fn get_slice(&self, offset: u64, count: u64) -> Result<VolatileSlice> {
+        let mem_end = calc_offset(offset, count)?;
+        if mem_end > self.len() as u64 {
+            return Err(Error::OutOfBounds { addr: mem_end });
+        }
+        Ok(unsafe { VolatileSlice::new((self.as_ptr() as u64 + offset) as *mut _, count) })
+    }
+}
+
+/// A slice of raw memory that supports volatile access.
+#[derive(Copy, Clone, Debug)]
+pub struct VolatileSlice<'a> {
+    addr: *mut u8,
+    size: u64,
+    phantom: PhantomData<&'a u8>,
+}
+
+impl<'a> Default for VolatileSlice<'a> {
+    fn default() -> VolatileSlice<'a> {
+        VolatileSlice {
+            addr: null_mut(),
+            size: 0,
+            phantom: PhantomData,
+        }
+    }
+}
+
+impl<'a> VolatileSlice<'a> {
+    /// Creates a slice of raw memory that must support volatile access.
+    ///
+    /// To use this safely, the caller must guarantee that the memory at `addr` is `size` bytes long
+    /// and is available for the duration of the lifetime of the new `VolatileSlice`. The caller
+    /// must also guarantee that all other users of the given chunk of memory are using volatile
+    /// accesses.
+    pub unsafe fn new(addr: *mut u8, size: u64) -> VolatileSlice<'a> {
+        VolatileSlice {
+            addr,
+            size,
+            phantom: PhantomData,
+        }
+    }
+
+    /// Gets the address of this slice's memory.
+    pub fn as_ptr(&self) -> *mut u8 {
+        self.addr
+    }
+
+    /// Gets the size of this slice.
+    pub fn size(&self) -> u64 {
+        self.size
+    }
+
+    /// Creates a copy of this slice with the address increased by `count` bytes, and the size
+    /// reduced by `count` bytes.
+    pub fn offset(self, count: u64) -> Result<VolatileSlice<'a>> {
+        let new_addr =
+            (self.addr as u64)
+                .checked_add(count)
+                .ok_or(VolatileMemoryError::Overflow {
+                    base: self.addr as u64,
+                    offset: count,
+                })?;
+        if new_addr > usize::MAX as u64 {
+            return Err(VolatileMemoryError::Overflow {
+                base: self.addr as u64,
+                offset: count,
+            })?;
+        }
+        let new_size = self
+            .size
+            .checked_sub(count)
+            .ok_or(VolatileMemoryError::OutOfBounds { addr: new_addr })?;
+        // Safe because the memory has the same lifetime and points to a subset of the memory of the
+        // original slice.
+        unsafe { Ok(VolatileSlice::new(new_addr as *mut u8, new_size)) }
+    }
+
+    /// Sets each byte of this slice with the given byte, similar to `memset`.
+    ///
+    /// The bytes of this slice are accessed in an arbitray order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use data_model::VolatileMemory;
+    /// # fn test_write_45() -> Result<(), ()> {
+    /// let mut mem = [0u8; 32];
+    /// let mem_ref = &mut mem[..];
+    /// let vslice = mem_ref.get_slice(0, 32).map_err(|_| ())?;
+    /// vslice.write_bytes(45);
+    /// for &mut v in mem_ref {
+    ///     assert_eq!(v, 45);
+    /// }
+    /// # Ok(())
+    /// # }
+    pub fn write_bytes(&self, value: u8) {
+        // Safe because the memory is valid and needs only byte alignment.
+        unsafe {
+            write_bytes(self.as_ptr(), value, self.size as usize);
+        }
+    }
+
+    /// Copies `self.size()` or `buf.len()` times the size of `T` bytes, whichever is smaller, to
+    /// `buf`.
+    ///
+    /// The copy happens from smallest to largest address in `T` sized chunks using volatile reads.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use std::fs::File;
+    /// # use std::path::Path;
+    /// # use data_model::VolatileMemory;
+    /// # fn test_write_null() -> Result<(), ()> {
+    /// let mut mem = [0u8; 32];
+    /// let mem_ref = &mut mem[..];
+    /// let vslice = mem_ref.get_slice(0, 32).map_err(|_| ())?;
+    /// let mut buf = [5u8; 16];
+    /// vslice.copy_to(&mut buf[..]);
+    /// for v in &buf[..] {
+    ///     assert_eq!(buf[0], 0);
+    /// }
+    /// # Ok(())
+    /// # }
+    /// ```
+    pub fn copy_to<T>(&self, buf: &mut [T])
+    where
+        T: DataInit,
+    {
+        let mut addr = self.addr;
+        for v in buf.iter_mut().take(self.size as usize / size_of::<T>()) {
+            unsafe {
+                *v = read_volatile(addr as *const T);
+                addr = addr.add(size_of::<T>());
+            }
+        }
+    }
+
+    /// Copies `self.size()` or `slice.size()` bytes, whichever is smaller, to `slice`.
+    ///
+    /// The copies happen in an undefined order.
+    /// # Examples
+    ///
+    /// ```
+    /// # use data_model::VolatileMemory;
+    /// # fn test_write_null() -> Result<(), ()> {
+    /// let mut mem = [0u8; 32];
+    /// let mem_ref = &mut mem[..];
+    /// let vslice = mem_ref.get_slice(0, 32).map_err(|_| ())?;
+    /// vslice.copy_to_volatile_slice(vslice.get_slice(16, 16).map_err(|_| ())?);
+    /// # Ok(())
+    /// # }
+    /// ```
+    pub fn copy_to_volatile_slice(&self, slice: VolatileSlice) {
+        unsafe {
+            copy(self.addr, slice.addr, min(self.size, slice.size) as usize);
+        }
+    }
+
+    /// Copies `self.size()` or `buf.len()` times the size of `T` bytes, whichever is smaller, to
+    /// this slice's memory.
+    ///
+    /// The copy happens from smallest to largest address in `T` sized chunks using volatile writes.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use std::fs::File;
+    /// # use std::path::Path;
+    /// # use data_model::VolatileMemory;
+    /// # fn test_write_null() -> Result<(), ()> {
+    /// let mut mem = [0u8; 32];
+    /// let mem_ref = &mut mem[..];
+    /// let vslice = mem_ref.get_slice(0, 32).map_err(|_| ())?;
+    /// let buf = [5u8; 64];
+    /// vslice.copy_from(&buf[..]);
+    /// for i in 0..4 {
+    ///     assert_eq!(vslice.get_ref::<u32>(i * 4).map_err(|_| ())?.load(), 0x05050505);
+    /// }
+    /// # Ok(())
+    /// # }
+    /// ```
+    pub fn copy_from<T>(&self, buf: &[T])
+    where
+        T: DataInit,
+    {
+        let mut addr = self.addr;
+        for &v in buf.iter().take(self.size as usize / size_of::<T>()) {
+            unsafe {
+                write_volatile(addr as *mut T, v);
+                addr = addr.add(size_of::<T>());
+            }
+        }
+    }
+}
+
+impl<'a> VolatileMemory for VolatileSlice<'a> {
+    fn get_slice(&self, offset: u64, count: u64) -> Result<VolatileSlice> {
+        let mem_end = calc_offset(offset, count)?;
+        if mem_end > self.size {
+            return Err(Error::OutOfBounds { addr: mem_end });
+        }
+        Ok(VolatileSlice {
+            addr: (self.addr as u64 + offset) as *mut _,
+            size: count,
+            phantom: PhantomData,
+        })
+    }
+}
+
+/// A memory location that supports volatile access of a `T`.
+///
+/// # Examples
+///
+/// ```
+/// # use data_model::VolatileRef;
+///   let mut v = 5u32;
+///   assert_eq!(v, 5);
+///   let v_ref = unsafe { VolatileRef::new(&mut v as *mut u32) };
+///   assert_eq!(v_ref.load(), 5);
+///   v_ref.store(500);
+///   assert_eq!(v, 500);
+#[derive(Debug)]
+pub struct VolatileRef<'a, T: DataInit>
+where
+    T: 'a,
+{
+    addr: *mut T,
+    phantom: PhantomData<&'a T>,
+}
+
+impl<'a, T: DataInit> VolatileRef<'a, T> {
+    /// Creates a reference to raw memory that must support volatile access of `T` sized chunks.
+    ///
+    /// To use this safely, the caller must guarantee that the memory at `addr` is big enough for a
+    /// `T` and is available for the duration of the lifetime of the new `VolatileRef`. The caller
+    /// must also guarantee that all other users of the given chunk of memory are using volatile
+    /// accesses.
+    pub unsafe fn new(addr: *mut T) -> VolatileRef<'a, T> {
+        VolatileRef {
+            addr,
+            phantom: PhantomData,
+        }
+    }
+
+    /// Gets the address of this slice's memory.
+    pub fn as_ptr(&self) -> *mut T {
+        self.addr
+    }
+
+    /// Gets the size of this slice.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use std::mem::size_of;
+    /// # use data_model::VolatileRef;
+    ///   let v_ref = unsafe { VolatileRef::new(0 as *mut u32) };
+    ///   assert_eq!(v_ref.size(), size_of::<u32>() as u64);
+    /// ```
+    pub fn size(&self) -> u64 {
+        size_of::<T>() as u64
+    }
+
+    /// Does a volatile write of the value `v` to the address of this ref.
+    #[inline(always)]
+    pub fn store(&self, v: T) {
+        unsafe { write_volatile(self.addr, v) };
+    }
+
+    /// Does a volatile read of the value at the address of this ref.
+    #[inline(always)]
+    pub fn load(&self) -> T {
+        // For the purposes of demonstrating why read_volatile is necessary, try replacing the code
+        // in this function with the commented code below and running `cargo test --release`.
+        // unsafe { *(self.addr as *const T) }
+        unsafe { read_volatile(self.addr) }
+    }
+
+    /// Converts this `T` reference to a raw slice with the same size and address.
+    pub fn to_slice(&self) -> VolatileSlice<'a> {
+        unsafe { VolatileSlice::new(self.addr as *mut u8, size_of::<T>() as u64) }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use std::sync::Arc;
+    use std::thread::{sleep, spawn};
+    use std::time::Duration;
+
+    #[derive(Clone)]
+    struct VecMem {
+        mem: Arc<Vec<u8>>,
+    }
+
+    impl VecMem {
+        fn new(size: usize) -> VecMem {
+            let mut mem = Vec::new();
+            mem.resize(size, 0);
+            VecMem { mem: Arc::new(mem) }
+        }
+    }
+
+    impl VolatileMemory for VecMem {
+        fn get_slice(&self, offset: u64, count: u64) -> Result<VolatileSlice> {
+            let mem_end = calc_offset(offset, count)?;
+            if mem_end > self.mem.len() as u64 {
+                return Err(Error::OutOfBounds { addr: mem_end });
+            }
+            Ok(unsafe { VolatileSlice::new((self.mem.as_ptr() as u64 + offset) as *mut _, count) })
+        }
+    }
+
+    #[test]
+    fn ref_store() {
+        let mut a = [0u8; 1];
+        let a_ref = &mut a[..];
+        let v_ref = a_ref.get_ref(0).unwrap();
+        v_ref.store(2u8);
+        assert_eq!(a[0], 2);
+    }
+
+    #[test]
+    fn ref_load() {
+        let mut a = [5u8; 1];
+        {
+            let a_ref = &mut a[..];
+            let c = {
+                let v_ref = a_ref.get_ref::<u8>(0).unwrap();
+                assert_eq!(v_ref.load(), 5u8);
+                v_ref
+            };
+            // To make sure we can take a v_ref out of the scope we made it in:
+            c.load();
+            // but not too far:
+            // c
+        } //.load()
+        ;
+    }
+
+    #[test]
+    fn ref_to_slice() {
+        let mut a = [1u8; 5];
+        let a_ref = &mut a[..];
+        let v_ref = a_ref.get_ref(1).unwrap();
+        v_ref.store(0x12345678u32);
+        let ref_slice = v_ref.to_slice();
+        assert_eq!(v_ref.as_ptr() as u64, ref_slice.as_ptr() as u64);
+        assert_eq!(v_ref.size(), ref_slice.size());
+    }
+
+    #[test]
+    fn observe_mutate() {
+        let a = VecMem::new(1);
+        let a_clone = a.clone();
+        let v_ref = a.get_ref::<u8>(0).unwrap();
+        v_ref.store(99);
+        spawn(move || {
+            sleep(Duration::from_millis(10));
+            let clone_v_ref = a_clone.get_ref::<u8>(0).unwrap();
+            clone_v_ref.store(0);
+        });
+
+        // Technically this is a race condition but we have to observe the v_ref's value changing
+        // somehow and this helps to ensure the sleep actually happens before the store rather then
+        // being reordered by the compiler.
+        assert_eq!(v_ref.load(), 99);
+
+        // Granted we could have a machine that manages to perform this many volatile loads in the
+        // amount of time the spawned thread sleeps, but the most likely reason the retry limit will
+        // get reached is because v_ref.load() is not actually performing the required volatile read
+        // or v_ref.store() is not doing a volatile write. A timer based solution was avoided
+        // because that might use a syscall which could hint the optimizer to reload v_ref's pointer
+        // regardless of volatile status. Note that we use a longer retry duration for optimized
+        // builds.
+        #[cfg(debug_assertions)]
+        const RETRY_MAX: u64 = 500_000_000;
+        #[cfg(not(debug_assertions))]
+        const RETRY_MAX: u64 = 10_000_000_000;
+
+        let mut retry = 0;
+        while v_ref.load() == 99 && retry < RETRY_MAX {
+            retry += 1;
+        }
+
+        assert_ne!(retry, RETRY_MAX, "maximum retry exceeded");
+        assert_eq!(v_ref.load(), 0);
+    }
+
+    #[test]
+    fn slice_size() {
+        let a = VecMem::new(100);
+        let s = a.get_slice(0, 27).unwrap();
+        assert_eq!(s.size(), 27);
+
+        let s = a.get_slice(34, 27).unwrap();
+        assert_eq!(s.size(), 27);
+
+        let s = s.get_slice(20, 5).unwrap();
+        assert_eq!(s.size(), 5);
+    }
+
+    #[test]
+    fn slice_overflow_error() {
+        use std::u64::MAX;
+        let a = VecMem::new(1);
+        let res = a.get_slice(MAX, 1).unwrap_err();
+        assert_eq!(
+            res,
+            Error::Overflow {
+                base: MAX,
+                offset: 1,
+            }
+        );
+    }
+
+    #[test]
+    fn slice_oob_error() {
+        let a = VecMem::new(100);
+        a.get_slice(50, 50).unwrap();
+        let res = a.get_slice(55, 50).unwrap_err();
+        assert_eq!(res, Error::OutOfBounds { addr: 105 });
+    }
+
+    #[test]
+    fn ref_overflow_error() {
+        use std::u64::MAX;
+        let a = VecMem::new(1);
+        let res = a.get_ref::<u8>(MAX).unwrap_err();
+        assert_eq!(
+            res,
+            Error::Overflow {
+                base: MAX,
+                offset: 1,
+            }
+        );
+    }
+
+    #[test]
+    fn ref_oob_error() {
+        let a = VecMem::new(100);
+        a.get_ref::<u8>(99).unwrap();
+        let res = a.get_ref::<u16>(99).unwrap_err();
+        assert_eq!(res, Error::OutOfBounds { addr: 101 });
+    }
+
+    #[test]
+    fn ref_oob_too_large() {
+        let a = VecMem::new(3);
+        let res = a.get_ref::<u32>(0).unwrap_err();
+        assert_eq!(res, Error::OutOfBounds { addr: 4 });
+    }
+}
diff --git a/devices/Cargo.toml b/devices/Cargo.toml
new file mode 100644
index 0000000..62b570e
--- /dev/null
+++ b/devices/Cargo.toml
@@ -0,0 +1,39 @@
+[package]
+name = "devices"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[features]
+gpu = ["gpu_buffer", "gpu_display", "gpu_renderer"]
+sandboxed-libusb = ["usb_util/sandboxed-libusb"]
+tpm = ["protos/trunks", "tpm2"]
+wl-dmabuf = []
+
+[dependencies]
+audio_streams = "*"
+bit_field = { path = "../bit_field" }
+byteorder = "*"
+data_model = { path = "../data_model" }
+enumn = { path = "../enumn" }
+gpu_buffer = { path = "../gpu_buffer", optional = true }
+gpu_display = { path = "../gpu_display", optional = true }
+gpu_renderer = { path = "../gpu_renderer", optional = true }
+io_jail = { path = "../io_jail" }
+kvm = { path = "../kvm" }
+libc = "*"
+msg_on_socket_derive = { path = "../msg_socket/msg_on_socket_derive" }
+msg_socket = { path = "../msg_socket" }
+net_sys = { path = "../net_sys" }
+net_util = { path = "../net_util" }
+p9 = { path = "../p9" }
+protos = { path = "../protos", optional = true }
+remain = "*"
+resources = { path = "../resources" }
+sync = { path = "../sync" }
+sys_util = { path = "../sys_util" }
+tpm2 = { path = "../tpm2", optional = true }
+usb_util = { path = "../usb_util" }
+vhost = { path = "../vhost" }
+virtio_sys = { path = "../virtio_sys" }
+vm_control = { path = "../vm_control" }
diff --git a/devices/src/bus.rs b/devices/src/bus.rs
new file mode 100644
index 0000000..d4b46eb
--- /dev/null
+++ b/devices/src/bus.rs
@@ -0,0 +1,354 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Handles routing to devices in an address space.
+
+use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
+use std::collections::btree_map::BTreeMap;
+use std::fmt::{self, Display};
+use std::result;
+use std::sync::Arc;
+
+use sync::Mutex;
+
+/// Trait for devices that respond to reads or writes in an arbitrary address space.
+///
+/// The device does not care where it exists in address space as each method is only given an offset
+/// into its allocated portion of address space.
+#[allow(unused_variables)]
+pub trait BusDevice: Send {
+    /// Returns a label suitable for debug output.
+    fn debug_label(&self) -> String;
+    /// Reads at `offset` from this device
+    fn read(&mut self, offset: u64, data: &mut [u8]) {}
+    /// Writes at `offset` into this device
+    fn write(&mut self, offset: u64, data: &[u8]) {}
+    /// Sets a register in the configuration space. Only used by PCI.
+    /// * `reg_idx` - The index of the config register to modify.
+    /// * `offset` - Offset in to the register.
+    fn config_register_write(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {}
+    /// Gets a register from the configuration space. Only used by PCI.
+    /// * `reg_idx` - The index of the config register to read.
+    fn config_register_read(&self, reg_idx: usize) -> u32 {
+        0
+    }
+    /// Invoked when the device is sandboxed.
+    fn on_sandboxed(&mut self) {}
+}
+
+#[derive(Debug)]
+pub enum Error {
+    /// The insertion failed because the new device overlapped with an old device.
+    Overlap,
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            Overlap => write!(f, "new device overlaps with an old device"),
+        }
+    }
+}
+
+pub type Result<T> = result::Result<T, Error>;
+
+/// Holds a base and length representing the address space occupied by a `BusDevice`.
+///
+/// * base - The address at which the range start.
+/// * len - The length of the range in bytes.
+/// * full_addr - If true, return the full address from `get_device`, otherwise return the offset
+///               from `base`
+#[derive(Debug, Copy, Clone)]
+pub struct BusRange {
+    pub base: u64,
+    pub len: u64,
+    pub full_addr: bool,
+}
+
+impl BusRange {
+    /// Returns true if `addr` is within the range.
+    pub fn contains(&self, addr: u64) -> bool {
+        self.base <= addr && addr < self.base + self.len
+    }
+
+    /// Returns true if there is overlap with the given range.
+    pub fn overlaps(&self, base: u64, len: u64) -> bool {
+        self.base < (base + len) && base < self.base + self.len
+    }
+}
+
+impl Eq for BusRange {}
+
+impl PartialEq for BusRange {
+    fn eq(&self, other: &BusRange) -> bool {
+        self.base == other.base
+    }
+}
+
+impl Ord for BusRange {
+    fn cmp(&self, other: &BusRange) -> Ordering {
+        self.base.cmp(&other.base)
+    }
+}
+
+impl PartialOrd for BusRange {
+    fn partial_cmp(&self, other: &BusRange) -> Option<Ordering> {
+        self.base.partial_cmp(&other.base)
+    }
+}
+
+/// A device container for routing reads and writes over some address space.
+///
+/// This doesn't have any restrictions on what kind of device or address space this applies to. The
+/// only restriction is that no two devices can overlap in this address space.
+#[derive(Clone)]
+pub struct Bus {
+    devices: BTreeMap<BusRange, Arc<Mutex<dyn BusDevice>>>,
+}
+
+impl Bus {
+    /// Constructs an a bus with an empty address space.
+    pub fn new() -> Bus {
+        Bus {
+            devices: BTreeMap::new(),
+        }
+    }
+
+    fn first_before(&self, addr: u64) -> Option<(BusRange, &Mutex<dyn BusDevice>)> {
+        let (range, dev) = self
+            .devices
+            .range(
+                ..=BusRange {
+                    base: addr,
+                    len: 1,
+                    full_addr: false,
+                },
+            )
+            .rev()
+            .next()?;
+        Some((*range, dev))
+    }
+
+    fn get_device(&self, addr: u64) -> Option<(u64, &Mutex<dyn BusDevice>)> {
+        if let Some((range, dev)) = self.first_before(addr) {
+            let offset = addr - range.base;
+            if offset < range.len {
+                if range.full_addr {
+                    return Some((addr, dev));
+                } else {
+                    return Some((offset, dev));
+                }
+            }
+        }
+        None
+    }
+
+    /// Puts the given device at the given address space.
+    pub fn insert(
+        &mut self,
+        device: Arc<Mutex<dyn BusDevice>>,
+        base: u64,
+        len: u64,
+        full_addr: bool,
+    ) -> Result<()> {
+        if len == 0 {
+            return Err(Error::Overlap);
+        }
+
+        // Reject all cases where the new device's range overlaps with an existing device.
+        if self
+            .devices
+            .iter()
+            .any(|(range, _dev)| range.overlaps(base, len))
+        {
+            return Err(Error::Overlap);
+        }
+
+        if self
+            .devices
+            .insert(
+                BusRange {
+                    base,
+                    len,
+                    full_addr,
+                },
+                device,
+            )
+            .is_some()
+        {
+            return Err(Error::Overlap);
+        }
+
+        Ok(())
+    }
+
+    /// Reads data from the device that owns the range containing `addr` and puts it into `data`.
+    ///
+    /// Returns true on success, otherwise `data` is untouched.
+    pub fn read(&self, addr: u64, data: &mut [u8]) -> bool {
+        if let Some((offset, dev)) = self.get_device(addr) {
+            dev.lock().read(offset, data);
+            true
+        } else {
+            false
+        }
+    }
+
+    /// Writes `data` to the device that owns the range containing `addr`.
+    ///
+    /// Returns true on success, otherwise `data` is untouched.
+    pub fn write(&self, addr: u64, data: &[u8]) -> bool {
+        if let Some((offset, dev)) = self.get_device(addr) {
+            dev.lock().write(offset, data);
+            true
+        } else {
+            false
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    struct DummyDevice;
+    impl BusDevice for DummyDevice {
+        fn debug_label(&self) -> String {
+            "dummy device".to_owned()
+        }
+    }
+
+    struct ConstantDevice;
+    impl BusDevice for ConstantDevice {
+        fn debug_label(&self) -> String {
+            "constant device".to_owned()
+        }
+
+        fn read(&mut self, offset: u64, data: &mut [u8]) {
+            for (i, v) in data.iter_mut().enumerate() {
+                *v = (offset as u8) + (i as u8);
+            }
+        }
+
+        fn write(&mut self, offset: u64, data: &[u8]) {
+            for (i, v) in data.iter().enumerate() {
+                assert_eq!(*v, (offset as u8) + (i as u8))
+            }
+        }
+    }
+
+    #[test]
+    fn bus_insert() {
+        let mut bus = Bus::new();
+        let dummy = Arc::new(Mutex::new(DummyDevice));
+        assert!(bus.insert(dummy.clone(), 0x10, 0, false).is_err());
+        assert!(bus.insert(dummy.clone(), 0x10, 0x10, false).is_ok());
+        assert!(bus.insert(dummy.clone(), 0x0f, 0x10, false).is_err());
+        assert!(bus.insert(dummy.clone(), 0x10, 0x10, false).is_err());
+        assert!(bus.insert(dummy.clone(), 0x10, 0x15, false).is_err());
+        assert!(bus.insert(dummy.clone(), 0x12, 0x15, false).is_err());
+        assert!(bus.insert(dummy.clone(), 0x12, 0x01, false).is_err());
+        assert!(bus.insert(dummy.clone(), 0x0, 0x20, false).is_err());
+        assert!(bus.insert(dummy.clone(), 0x20, 0x05, false).is_ok());
+        assert!(bus.insert(dummy.clone(), 0x25, 0x05, false).is_ok());
+        assert!(bus.insert(dummy.clone(), 0x0, 0x10, false).is_ok());
+    }
+
+    #[test]
+    fn bus_insert_full_addr() {
+        let mut bus = Bus::new();
+        let dummy = Arc::new(Mutex::new(DummyDevice));
+        assert!(bus.insert(dummy.clone(), 0x10, 0, true).is_err());
+        assert!(bus.insert(dummy.clone(), 0x10, 0x10, true).is_ok());
+        assert!(bus.insert(dummy.clone(), 0x0f, 0x10, true).is_err());
+        assert!(bus.insert(dummy.clone(), 0x10, 0x10, true).is_err());
+        assert!(bus.insert(dummy.clone(), 0x10, 0x15, true).is_err());
+        assert!(bus.insert(dummy.clone(), 0x12, 0x15, true).is_err());
+        assert!(bus.insert(dummy.clone(), 0x12, 0x01, true).is_err());
+        assert!(bus.insert(dummy.clone(), 0x0, 0x20, true).is_err());
+        assert!(bus.insert(dummy.clone(), 0x20, 0x05, true).is_ok());
+        assert!(bus.insert(dummy.clone(), 0x25, 0x05, true).is_ok());
+        assert!(bus.insert(dummy.clone(), 0x0, 0x10, true).is_ok());
+    }
+
+    #[test]
+    fn bus_read_write() {
+        let mut bus = Bus::new();
+        let dummy = Arc::new(Mutex::new(DummyDevice));
+        assert!(bus.insert(dummy.clone(), 0x10, 0x10, false).is_ok());
+        assert!(bus.read(0x10, &mut [0, 0, 0, 0]));
+        assert!(bus.write(0x10, &[0, 0, 0, 0]));
+        assert!(bus.read(0x11, &mut [0, 0, 0, 0]));
+        assert!(bus.write(0x11, &[0, 0, 0, 0]));
+        assert!(bus.read(0x16, &mut [0, 0, 0, 0]));
+        assert!(bus.write(0x16, &[0, 0, 0, 0]));
+        assert!(!bus.read(0x20, &mut [0, 0, 0, 0]));
+        assert!(!bus.write(0x20, &mut [0, 0, 0, 0]));
+        assert!(!bus.read(0x06, &mut [0, 0, 0, 0]));
+        assert!(!bus.write(0x06, &mut [0, 0, 0, 0]));
+    }
+
+    #[test]
+    fn bus_read_write_values() {
+        let mut bus = Bus::new();
+        let dummy = Arc::new(Mutex::new(ConstantDevice));
+        assert!(bus.insert(dummy.clone(), 0x10, 0x10, false).is_ok());
+
+        let mut values = [0, 1, 2, 3];
+        assert!(bus.read(0x10, &mut values));
+        assert_eq!(values, [0, 1, 2, 3]);
+        assert!(bus.write(0x10, &values));
+        assert!(bus.read(0x15, &mut values));
+        assert_eq!(values, [5, 6, 7, 8]);
+        assert!(bus.write(0x15, &values));
+    }
+
+    #[test]
+    fn bus_read_write_full_addr_values() {
+        let mut bus = Bus::new();
+        let dummy = Arc::new(Mutex::new(ConstantDevice));
+        assert!(bus.insert(dummy.clone(), 0x10, 0x10, true).is_ok());
+
+        let mut values = [0u8; 4];
+        assert!(bus.read(0x10, &mut values));
+        assert_eq!(values, [0x10, 0x11, 0x12, 0x13]);
+        assert!(bus.write(0x10, &values));
+        assert!(bus.read(0x15, &mut values));
+        assert_eq!(values, [0x15, 0x16, 0x17, 0x18]);
+        assert!(bus.write(0x15, &values));
+    }
+
+    #[test]
+    fn bus_range_contains() {
+        let a = BusRange {
+            base: 0x1000,
+            len: 0x400,
+            full_addr: false,
+        };
+        assert!(a.contains(0x1000));
+        assert!(a.contains(0x13ff));
+        assert!(!a.contains(0xfff));
+        assert!(!a.contains(0x1400));
+        assert!(a.contains(0x1200));
+    }
+
+    #[test]
+    fn bus_range_overlap() {
+        let a = BusRange {
+            base: 0x1000,
+            len: 0x400,
+            full_addr: false,
+        };
+        assert!(a.overlaps(0x1000, 0x400));
+        assert!(a.overlaps(0xf00, 0x400));
+        assert!(a.overlaps(0x1000, 0x01));
+        assert!(a.overlaps(0xfff, 0x02));
+        assert!(a.overlaps(0x1100, 0x100));
+        assert!(a.overlaps(0x13ff, 0x100));
+        assert!(!a.overlaps(0x1400, 0x100));
+        assert!(!a.overlaps(0xf00, 0x100));
+    }
+}
diff --git a/devices/src/cmos.rs b/devices/src/cmos.rs
new file mode 100644
index 0000000..daf391c
--- /dev/null
+++ b/devices/src/cmos.rs
@@ -0,0 +1,119 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use libc::{gmtime_r, time, time_t, tm};
+use std::cmp::min;
+use std::mem;
+
+use crate::BusDevice;
+
+const INDEX_MASK: u8 = 0x7f;
+const INDEX_OFFSET: u64 = 0x0;
+const DATA_OFFSET: u64 = 0x1;
+const DATA_LEN: usize = 128;
+
+/// A CMOS/RTC device commonly seen on x86 I/O port 0x70/0x71.
+pub struct Cmos {
+    index: u8,
+    data: [u8; DATA_LEN],
+}
+
+impl Cmos {
+    /// Constructs a CMOS/RTC device with initial data.
+    /// `mem_below_4g` is the size of memory in bytes below the 32-bit gap.
+    /// `mem_above_4g` is the size of memory in bytes above the 32-bit gap.
+    pub fn new(mem_below_4g: u64, mem_above_4g: u64) -> Cmos {
+        let mut data = [0u8; DATA_LEN];
+
+        // Extended memory from 16 MB to 4 GB in units of 64 KB
+        let ext_mem = min(
+            0xFFFF,
+            mem_below_4g.saturating_sub(16 * 1024 * 1024) / (64 * 1024),
+        );
+        data[0x34] = ext_mem as u8;
+        data[0x35] = (ext_mem >> 8) as u8;
+
+        // High memory (> 4GB) in units of 64 KB
+        let high_mem = min(0xFFFFFF, mem_above_4g / (64 * 1024));
+        data[0x5b] = high_mem as u8;
+        data[0x5c] = (high_mem >> 8) as u8;
+        data[0x5d] = (high_mem >> 16) as u8;
+
+        Cmos { index: 0, data }
+    }
+}
+
+impl BusDevice for Cmos {
+    fn debug_label(&self) -> String {
+        "cmos".to_owned()
+    }
+
+    fn write(&mut self, offset: u64, data: &[u8]) {
+        if data.len() != 1 {
+            return;
+        }
+
+        match offset {
+            INDEX_OFFSET => self.index = data[0] & INDEX_MASK,
+            DATA_OFFSET => self.data[self.index as usize] = data[0],
+            o => panic!("bad write offset on CMOS device: {}", o),
+        }
+    }
+
+    fn read(&mut self, offset: u64, data: &mut [u8]) {
+        fn to_bcd(v: u8) -> u8 {
+            assert!(v < 100);
+            ((v / 10) << 4) | (v % 10)
+        }
+
+        if data.len() != 1 {
+            return;
+        }
+
+        data[0] = match offset {
+            INDEX_OFFSET => self.index,
+            DATA_OFFSET => {
+                let seconds;
+                let minutes;
+                let hours;
+                let week_day;
+                let day;
+                let month;
+                let year;
+                // The time and gmtime_r calls are safe as long as the structs they are given are
+                // large enough, and neither of them fail. It is safe to zero initialize the tm
+                // struct because it contains only plain data.
+                unsafe {
+                    let mut tm: tm = mem::zeroed();
+                    let mut now: time_t = 0;
+                    time(&mut now as *mut _);
+                    gmtime_r(&now, &mut tm as *mut _);
+                    // The following lines of code are safe but depend on tm being in scope.
+                    seconds = tm.tm_sec;
+                    minutes = tm.tm_min;
+                    hours = tm.tm_hour;
+                    week_day = tm.tm_wday + 1;
+                    day = tm.tm_mday;
+                    month = tm.tm_mon + 1;
+                    year = tm.tm_year;
+                };
+                match self.index {
+                    0x00 => to_bcd(seconds as u8),
+                    0x02 => to_bcd(minutes as u8),
+                    0x04 => to_bcd(hours as u8),
+                    0x06 => to_bcd(week_day as u8),
+                    0x07 => to_bcd(day as u8),
+                    0x08 => to_bcd(month as u8),
+                    0x09 => to_bcd((year % 100) as u8),
+                    0x32 => to_bcd(((year + 1900) / 100) as u8),
+                    _ => {
+                        // self.index is always guaranteed to be in range via INDEX_MASK.
+                        self.data[(self.index & INDEX_MASK) as usize]
+                    }
+                }
+            }
+            o => panic!("bad read offset on CMOS device: {}", o),
+        }
+    }
+}
diff --git a/devices/src/i8042.rs b/devices/src/i8042.rs
new file mode 100644
index 0000000..1f8a837
--- /dev/null
+++ b/devices/src/i8042.rs
@@ -0,0 +1,46 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use sys_util::{error, EventFd};
+
+use crate::BusDevice;
+
+/// A i8042 PS/2 controller that emulates just enough to shutdown the machine.
+pub struct I8042Device {
+    reset_evt: EventFd,
+}
+
+impl I8042Device {
+    /// Constructs a i8042 device that will signal the given event when the guest requests it.
+    pub fn new(reset_evt: EventFd) -> I8042Device {
+        I8042Device { reset_evt }
+    }
+}
+
+// i8042 device is mapped I/O address 0x61. We partially implement two 8-bit
+// registers: port 0x61 (I8042_PORT_B_REG, offset 0 from base of 0x61), and
+// port 0x64 (I8042_COMMAND_REG, offset 3 from base of 0x61).
+impl BusDevice for I8042Device {
+    fn debug_label(&self) -> String {
+        "i8042".to_owned()
+    }
+
+    fn read(&mut self, offset: u64, data: &mut [u8]) {
+        if data.len() == 1 && offset == 3 {
+            data[0] = 0x0;
+        } else if data.len() == 1 && offset == 0 {
+            // Like kvmtool, we return bit 5 set in I8042_PORT_B_REG to
+            // avoid hang in pit_calibrate_tsc() in Linux kernel.
+            data[0] = 0x20;
+        }
+    }
+
+    fn write(&mut self, offset: u64, data: &[u8]) {
+        if data.len() == 1 && data[0] == 0xfe && offset == 3 {
+            if let Err(e) = self.reset_evt.write(1) {
+                error!("failed to trigger i8042 reset event: {}", e);
+            }
+        }
+    }
+}
diff --git a/devices/src/ioapic.rs b/devices/src/ioapic.rs
new file mode 100644
index 0000000..ce9f2b2
--- /dev/null
+++ b/devices/src/ioapic.rs
@@ -0,0 +1,737 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Implementation of an intel 82093AA Input/Output Advanced Programmable Interrupt Controller
+// See https://pdos.csail.mit.edu/6.828/2016/readings/ia32/ioapic.pdf for a specification.
+
+use crate::split_irqchip_common::*;
+use crate::BusDevice;
+use bit_field::*;
+use sys_util::warn;
+
+#[bitfield]
+#[derive(Clone, Copy, PartialEq)]
+pub struct RedirectionTableEntry {
+    vector: BitField8,
+    #[bits = 3]
+    delivery_mode: DeliveryMode,
+    #[bits = 1]
+    dest_mode: DestinationMode,
+    #[bits = 1]
+    delivery_status: DeliveryStatus,
+    polarity: BitField1,
+    remote_irr: bool,
+    #[bits = 1]
+    trigger_mode: TriggerMode,
+    interrupt_mask: bool, // true iff interrupts are masked.
+    reserved: BitField39,
+    dest_id: BitField8,
+}
+
+#[bitfield]
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum DeliveryStatus {
+    Idle = 0,
+    Pending = 1,
+}
+
+const IOAPIC_VERSION_ID: u32 = 0x00170011;
+#[allow(dead_code)]
+const IOAPIC_BASE_ADDRESS: u32 = 0xfec00000;
+// The Intel manual does not specify this size, but KVM uses it.
+#[allow(dead_code)]
+const IOAPIC_MEM_LENGTH_BYTES: usize = 0x100;
+
+// Constants for IOAPIC direct register offset.
+const IOAPIC_REG_ID: u8 = 0x00;
+const IOAPIC_REG_VERSION: u8 = 0x01;
+const IOAPIC_REG_ARBITRATION_ID: u8 = 0x02;
+
+// Register offsets
+pub const IOREGSEL_OFF: u8 = 0x0;
+pub const IOREGSEL_DUMMY_UPPER_32_BITS_OFF: u8 = 0x4;
+pub const IOWIN_OFF: u8 = 0x10;
+pub const IOWIN_SCALE: u8 = 0x2;
+
+/// Given an IRQ and whether or not the selector should refer to the high bits, return a selector
+/// suitable to use as an offset to read to/write from.
+#[allow(dead_code)]
+fn encode_selector_from_irq(irq: usize, is_high_bits: bool) -> u8 {
+    (irq as u8) * IOWIN_SCALE + IOWIN_OFF + (is_high_bits as u8)
+}
+
+/// Given an offset that was read from/written to, return a tuple of the relevant IRQ and whether
+/// the offset refers to the high bits of that register.
+fn decode_irq_from_selector(selector: u8) -> (usize, bool) {
+    (
+        ((selector - IOWIN_OFF) / IOWIN_SCALE) as usize,
+        selector & 1 != 0,
+    )
+}
+
+// The RTC needs special treatment to work properly for Windows (or other OSs that use tick
+// stuffing). In order to avoid time drift, we need to guarantee that the correct number of RTC
+// interrupts are injected into the guest. This hack essentialy treats RTC interrupts as level
+// triggered, which allows the IOAPIC to be responsible for interrupt coalescing and allows the
+// IOAPIC to pass back whether or not the interrupt was coalesced to the CMOS (which allows the
+// CMOS to perform tick stuffing). This deviates from the IOAPIC spec in ways very similar to (but
+// not exactly the same as) KVM's IOAPIC.
+const RTC_IRQ: usize = 0x8;
+
+pub struct Ioapic {
+    id: u32,
+    // Remote IRR for Edge Triggered Real Time Clock interrupts, which allows the CMOS to know when
+    // one of its interrupts is being coalesced.
+    rtc_remote_irr: bool,
+    current_interrupt_level_bitmap: u32,
+    redirect_table: [RedirectionTableEntry; kvm::NUM_IOAPIC_PINS],
+    // IOREGSEL is technically 32 bits, but only bottom 8 are writable: all others are fixed to 0.
+    ioregsel: u8,
+}
+
+impl BusDevice for Ioapic {
+    fn debug_label(&self) -> String {
+        "userspace IOAPIC".to_string()
+    }
+
+    fn read(&mut self, offset: u64, data: &mut [u8]) {
+        if data.len() > 8 || data.len() == 0 {
+            warn!("IOAPIC: Bad read size: {}", data.len());
+            return;
+        }
+        if offset >= 1 << 8 {
+            warn!("IOAPIC: Bad read from offset {}", offset);
+        }
+        let out = match offset as u8 {
+            IOREGSEL_OFF => self.ioregsel.into(),
+            IOREGSEL_DUMMY_UPPER_32_BITS_OFF => 0,
+            IOWIN_OFF => self.ioapic_read(),
+            _ => {
+                warn!("IOAPIC: Bad read from offset {}", offset);
+                return;
+            }
+        };
+        let out_arr = out.to_ne_bytes();
+        for i in 0..4 {
+            if i < data.len() {
+                data[i] = out_arr[i];
+            }
+        }
+    }
+
+    fn write(&mut self, offset: u64, data: &[u8]) {
+        if data.len() > 8 || data.len() == 0 {
+            warn!("IOAPIC: Bad write size: {}", data.len());
+            return;
+        }
+        if offset >= 1 << 8 {
+            warn!("IOAPIC: Bad write to offset {}", offset);
+        }
+        match offset as u8 {
+            IOREGSEL_OFF => self.ioregsel = data[0],
+            IOREGSEL_DUMMY_UPPER_32_BITS_OFF => {} // Ignored.
+            IOWIN_OFF => {
+                if data.len() != 4 {
+                    warn!("IOAPIC: Bad write size for iowin: {}", data.len());
+                    return;
+                }
+                let data_arr = [data[0], data[1], data[2], data[3]];
+                let val = u32::from_ne_bytes(data_arr);
+                self.ioapic_write(val);
+            }
+            _ => {
+                warn!("IOAPIC: Bad write to offset {}", offset);
+                return;
+            }
+        }
+    }
+}
+
+impl Ioapic {
+    pub fn new() -> Ioapic {
+        let mut entry = RedirectionTableEntry::new();
+        entry.set_interrupt_mask(true);
+        let entries = [entry; kvm::NUM_IOAPIC_PINS];
+        Ioapic {
+            id: 0,
+            rtc_remote_irr: false,
+            current_interrupt_level_bitmap: 0,
+            redirect_table: entries,
+            ioregsel: 0,
+        }
+    }
+
+    // The ioapic must be informed about EOIs in order to avoid sending multiple interrupts of the
+    // same type at the same time.
+    pub fn end_of_interrupt(&mut self, vector: u8) {
+        if self.redirect_table[RTC_IRQ].get_vector() == vector && self.rtc_remote_irr {
+            // Specifically clear RTC IRQ field
+            self.rtc_remote_irr = false;
+        }
+
+        for i in 0..kvm::NUM_IOAPIC_PINS {
+            if self.redirect_table[i].get_vector() == vector
+                && self.redirect_table[i].get_trigger_mode() == TriggerMode::Level
+            {
+                self.redirect_table[i].set_remote_irr(false);
+            }
+            // There is an inherent race condition in hardware if the OS is finished processing an
+            // interrupt and a new interrupt is delivered between issuing an EOI and the EOI being
+            // completed.  When that happens the ioapic is supposed to re-inject the interrupt.
+            if self.current_interrupt_level_bitmap & (1 << i) != 0 {
+                self.service_irq(i, true);
+            }
+        }
+    }
+
+    pub fn service_irq(&mut self, irq: usize, level: bool) -> bool {
+        let entry = &mut self.redirect_table[irq];
+        let line_status = if entry.get_polarity() == 1 {
+            !level
+        } else {
+            level
+        };
+
+        // De-assert the interrupt.
+        if !line_status {
+            self.current_interrupt_level_bitmap &= !(1 << irq);
+            return true;
+        }
+
+        // If it's an edge-triggered interrupt that's already high we ignore it.
+        if entry.get_trigger_mode() == TriggerMode::Edge
+            && self.current_interrupt_level_bitmap & (1 << irq) != 0
+        {
+            return false;
+        }
+
+        self.current_interrupt_level_bitmap |= 1 << irq;
+
+        // Interrupts are masked, so don't inject.
+        if entry.get_interrupt_mask() {
+            return false;
+        }
+
+        // Level-triggered and remote irr is already active, so we don't inject a new interrupt.
+        // (Coalesce with the prior one(s)).
+        if entry.get_trigger_mode() == TriggerMode::Level && entry.get_remote_irr() {
+            return false;
+        }
+
+        // Coalesce RTC interrupt to make tick stuffing work.
+        if irq == RTC_IRQ && self.rtc_remote_irr {
+            return false;
+        }
+
+        // TODO(mutexlox): Pulse (assert and deassert) interrupt
+        let injected = true;
+
+        if entry.get_trigger_mode() == TriggerMode::Level && line_status && injected {
+            entry.set_remote_irr(true);
+        } else if irq == RTC_IRQ && injected {
+            self.rtc_remote_irr = true;
+        }
+
+        injected
+    }
+
+    fn ioapic_write(&mut self, val: u32) {
+        match self.ioregsel {
+            IOAPIC_REG_VERSION => { /* read-only register */ }
+            IOAPIC_REG_ID => self.id = (val >> 24) & 0xf,
+            IOAPIC_REG_ARBITRATION_ID => { /* read-only register */ }
+            _ => {
+                if self.ioregsel < IOWIN_OFF {
+                    // Invalid write; ignore.
+                    return;
+                }
+                let (index, is_high_bits) = decode_irq_from_selector(self.ioregsel);
+                if index >= kvm::NUM_IOAPIC_PINS {
+                    // Invalid write; ignore.
+                    return;
+                }
+
+                let entry = &mut self.redirect_table[index];
+                if is_high_bits {
+                    entry.set(32, 32, val.into());
+                } else {
+                    let before = *entry;
+                    entry.set(0, 32, val.into());
+
+                    // respect R/O bits.
+                    entry.set_delivery_status(before.get_delivery_status());
+                    entry.set_remote_irr(before.get_remote_irr());
+
+                    // Clear remote_irr when switching to edge_triggered.
+                    if entry.get_trigger_mode() == TriggerMode::Edge {
+                        entry.set_remote_irr(false);
+                    }
+
+                    // NOTE: on pre-4.0 kernels, there's a race we would need to work around.
+                    // "KVM: x86: ioapic: Fix level-triggered EOI and IOAPIC reconfigure race"
+                    // is the fix for this.
+                }
+
+                // TODO(mutexlox): route MSI.
+                if self.redirect_table[index].get_trigger_mode() == TriggerMode::Level
+                    && self.current_interrupt_level_bitmap & (1 << index) != 0
+                    && !self.redirect_table[index].get_interrupt_mask()
+                {
+                    self.service_irq(index, true);
+                }
+            }
+        }
+    }
+
+    fn ioapic_read(&mut self) -> u32 {
+        match self.ioregsel {
+            IOAPIC_REG_VERSION => IOAPIC_VERSION_ID,
+            IOAPIC_REG_ID | IOAPIC_REG_ARBITRATION_ID => (self.id & 0xf) << 24,
+            _ => {
+                if self.ioregsel < IOWIN_OFF {
+                    // Invalid read; ignore and return 0.
+                    0
+                } else {
+                    let (index, is_high_bits) = decode_irq_from_selector(self.ioregsel);
+                    if index < kvm::NUM_IOAPIC_PINS {
+                        let offset = if is_high_bits { 32 } else { 0 };
+                        self.redirect_table[index].get(offset, 32) as u32
+                    } else {
+                        !0 // Invaild index - return all 1s
+                    }
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    const DEFAULT_VECTOR: u8 = 0x3a;
+    const DEFAULT_DESTINATION_ID: u8 = 0x5f;
+
+    fn set_up(trigger: TriggerMode) -> (Ioapic, usize) {
+        let irq = kvm::NUM_IOAPIC_PINS - 1;
+        let ioapic = set_up_with_irq(irq, trigger);
+        (ioapic, irq)
+    }
+
+    fn set_up_with_irq(irq: usize, trigger: TriggerMode) -> Ioapic {
+        let mut ioapic = Ioapic::new();
+        set_up_redirection_table_entry(&mut ioapic, irq, trigger);
+        ioapic
+    }
+
+    fn read_reg(ioapic: &mut Ioapic, selector: u8) -> u32 {
+        let mut data = [0; 4];
+        ioapic.write(IOREGSEL_OFF.into(), &[selector]);
+        ioapic.read(IOWIN_OFF.into(), &mut data);
+        u32::from_ne_bytes(data)
+    }
+
+    fn write_reg(ioapic: &mut Ioapic, selector: u8, value: u32) {
+        ioapic.write(IOREGSEL_OFF.into(), &[selector]);
+        ioapic.write(IOWIN_OFF.into(), &value.to_ne_bytes());
+    }
+
+    fn read_entry(ioapic: &mut Ioapic, irq: usize) -> RedirectionTableEntry {
+        let mut entry = RedirectionTableEntry::new();
+        entry.set(
+            0,
+            32,
+            read_reg(ioapic, encode_selector_from_irq(irq, false)).into(),
+        );
+        entry.set(
+            32,
+            32,
+            read_reg(ioapic, encode_selector_from_irq(irq, true)).into(),
+        );
+        entry
+    }
+
+    fn write_entry(ioapic: &mut Ioapic, irq: usize, entry: RedirectionTableEntry) {
+        write_reg(
+            ioapic,
+            encode_selector_from_irq(irq, false),
+            entry.get(0, 32) as u32,
+        );
+        write_reg(
+            ioapic,
+            encode_selector_from_irq(irq, true),
+            entry.get(32, 32) as u32,
+        );
+    }
+
+    fn set_up_redirection_table_entry(ioapic: &mut Ioapic, irq: usize, trigger_mode: TriggerMode) {
+        let mut entry = RedirectionTableEntry::new();
+        entry.set_vector(DEFAULT_DESTINATION_ID);
+        entry.set_delivery_mode(DeliveryMode::Startup);
+        entry.set_delivery_status(DeliveryStatus::Pending);
+        entry.set_dest_id(DEFAULT_VECTOR);
+        entry.set_trigger_mode(trigger_mode);
+        write_entry(ioapic, irq, entry);
+    }
+
+    fn set_mask(ioapic: &mut Ioapic, irq: usize, mask: bool) {
+        let mut entry = read_entry(ioapic, irq);
+        entry.set_interrupt_mask(mask);
+        write_entry(ioapic, irq, entry);
+    }
+
+    #[test]
+    fn write_read_ioregsel() {
+        let mut ioapic = Ioapic::new();
+        let data_write = [0x0f, 0xf0, 0x01, 0xff];
+        let mut data_read = [0; 4];
+
+        for i in 0..data_write.len() {
+            ioapic.write(IOREGSEL_OFF.into(), &data_write[i..i + 1]);
+            ioapic.read(IOREGSEL_OFF.into(), &mut data_read[i..i + 1]);
+            assert_eq!(data_write[i], data_read[i]);
+        }
+    }
+
+    // Verify that version register is actually read-only.
+    #[test]
+    fn write_read_ioaic_reg_version() {
+        let mut ioapic = Ioapic::new();
+        let before = read_reg(&mut ioapic, IOAPIC_REG_VERSION);
+        let data_write = !before;
+
+        write_reg(&mut ioapic, IOAPIC_REG_VERSION, data_write);
+        assert_eq!(read_reg(&mut ioapic, IOAPIC_REG_VERSION), before);
+    }
+
+    // Verify that only bits 27:24 of the IOAPICID are readable/writable.
+    #[test]
+    fn write_read_ioapic_reg_id() {
+        let mut ioapic = Ioapic::new();
+
+        write_reg(&mut ioapic, IOAPIC_REG_ID, 0x1f3e5d7c);
+        assert_eq!(read_reg(&mut ioapic, IOAPIC_REG_ID), 0x0f000000);
+    }
+
+    // Write to read-only register IOAPICARB.
+    #[test]
+    fn write_read_ioapic_arbitration_id() {
+        let mut ioapic = Ioapic::new();
+
+        let data_write_id = 0x1f3e5d7c;
+        let expected_result = 0x0f000000;
+
+        // Write to IOAPICID.  This should also change IOAPICARB.
+        write_reg(&mut ioapic, IOAPIC_REG_ID, data_write_id);
+
+        // Read IOAPICARB
+        assert_eq!(
+            read_reg(&mut ioapic, IOAPIC_REG_ARBITRATION_ID),
+            expected_result
+        );
+
+        // Try to write to IOAPICARB and verify unchanged result.
+        write_reg(&mut ioapic, IOAPIC_REG_ARBITRATION_ID, !data_write_id);
+        assert_eq!(
+            read_reg(&mut ioapic, IOAPIC_REG_ARBITRATION_ID),
+            expected_result
+        );
+    }
+
+    #[test]
+    #[should_panic(expected = "index out of bounds: the len is 24 but the index is 24")]
+    fn service_invalid_irq() {
+        let mut ioapic = Ioapic::new();
+        ioapic.service_irq(kvm::NUM_IOAPIC_PINS, false);
+    }
+
+    // Test a level triggered IRQ interrupt.
+    #[test]
+    fn service_level_irq() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Level);
+
+        // TODO(mutexlox): Check that interrupt is fired once.
+        ioapic.service_irq(irq, true);
+        ioapic.service_irq(irq, false);
+    }
+
+    #[test]
+    fn service_multiple_level_irqs() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Level);
+        // TODO(mutexlox): Check that interrupt is fired twice.
+        ioapic.service_irq(irq, true);
+        ioapic.service_irq(irq, false);
+        ioapic.end_of_interrupt(DEFAULT_DESTINATION_ID);
+        ioapic.service_irq(irq, true);
+    }
+
+    // Test multiple level interrupts without an EOI and verify that only one interrupt is
+    // delivered.
+    #[test]
+    fn coalesce_multiple_level_irqs() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Level);
+
+        // TODO(mutexlox): Test that only one interrupt is delivered.
+        ioapic.service_irq(irq, true);
+        ioapic.service_irq(irq, false);
+        ioapic.service_irq(irq, true);
+    }
+
+    // Test multiple RTC interrupts without an EOI and verify that only one interrupt is delivered.
+    #[test]
+    fn coalesce_multiple_rtc_irqs() {
+        let irq = RTC_IRQ;
+        let mut ioapic = set_up_with_irq(irq, TriggerMode::Edge);
+
+        // TODO(mutexlox): Verify that only one IRQ is delivered.
+        ioapic.service_irq(irq, true);
+        ioapic.service_irq(irq, false);
+        ioapic.service_irq(irq, true);
+    }
+
+    // Test that a level interrupt that has been coalesced is re-raised if a guest issues an
+    // EndOfInterrupt after the interrupt was coalesced while the line  is still asserted.
+    #[test]
+    fn reinject_level_interrupt() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Level);
+
+        // TODO(mutexlox): Verify that only one IRQ is delivered.
+        ioapic.service_irq(irq, true);
+        ioapic.service_irq(irq, false);
+        ioapic.service_irq(irq, true);
+
+        // TODO(mutexlox): Verify that this last interrupt occurs as a result of the EOI, rather
+        // than in response to the last service_irq.
+        ioapic.end_of_interrupt(DEFAULT_DESTINATION_ID);
+    }
+
+    #[test]
+    fn service_edge_triggered_irq() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Edge);
+
+        // TODO(mutexlox): Verify that one interrupt is delivered.
+        ioapic.service_irq(irq, true);
+        ioapic.service_irq(irq, true); // Repeated asserts before a deassert should be ignored.
+        ioapic.service_irq(irq, false);
+    }
+
+    // Verify that the state of an edge-triggered interrupt is properly tracked even when the
+    // interrupt is disabled.
+    #[test]
+    fn edge_trigger_unmask_test() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Edge);
+
+        // TODO(mutexlox): Expect an IRQ.
+
+        ioapic.service_irq(irq, true);
+
+        set_mask(&mut ioapic, irq, true);
+        ioapic.service_irq(irq, false);
+
+        // No interrupt triggered while masked.
+        ioapic.service_irq(irq, true);
+        ioapic.service_irq(irq, false);
+
+        set_mask(&mut ioapic, irq, false);
+
+        // TODO(mutexlox): Expect another interrupt.
+        // Interrupt triggered while unmasked, even though when it was masked the level was high.
+        ioapic.service_irq(irq, true);
+        ioapic.service_irq(irq, false);
+    }
+
+    // Verify that a level-triggered interrupt that is triggered while masked will fire once the
+    // interrupt is unmasked.
+    #[test]
+    fn level_trigger_unmask_test() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Level);
+
+        set_mask(&mut ioapic, irq, true);
+        ioapic.service_irq(irq, true);
+
+        // TODO(mutexlox): expect an interrupt after this.
+        set_mask(&mut ioapic, irq, false);
+    }
+
+    // Verify that multiple asserts before a deassert are ignored even if there's an EOI between
+    // them.
+    #[test]
+    fn end_of_interrupt_edge_triggered_irq() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Edge);
+
+        // TODO(mutexlox): Expect 1 interrupt.
+        ioapic.service_irq(irq, true);
+        ioapic.end_of_interrupt(DEFAULT_DESTINATION_ID);
+        // Repeated asserts before a de-assert should be ignored.
+        ioapic.service_irq(irq, true);
+        ioapic.service_irq(irq, false);
+    }
+
+    // Send multiple edge-triggered interrupts in a row.
+    #[test]
+    fn service_multiple_edge_irqs() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Edge);
+
+        ioapic.service_irq(irq, true);
+        // TODO(mutexlox): Verify that an interrupt occurs here.
+        ioapic.service_irq(irq, false);
+
+        ioapic.service_irq(irq, true);
+        // TODO(mutexlox): Verify that an interrupt occurs here.
+        ioapic.service_irq(irq, false);
+    }
+
+    // Test an interrupt line with negative polarity.
+    #[test]
+    fn service_negative_polarity_irq() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Level);
+
+        let mut entry = read_entry(&mut ioapic, irq);
+        entry.set_polarity(1);
+        write_entry(&mut ioapic, irq, entry);
+
+        // TODO(mutexlox): Expect an interrupt to fire.
+        ioapic.service_irq(irq, false);
+    }
+
+    // Ensure that remote IRR can't be edited via mmio.
+    #[test]
+    fn remote_irr_read_only() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Level);
+
+        ioapic.redirect_table[irq].set_remote_irr(true);
+
+        let mut entry = read_entry(&mut ioapic, irq);
+        entry.set_remote_irr(false);
+        write_entry(&mut ioapic, irq, entry);
+
+        assert_eq!(read_entry(&mut ioapic, irq).get_remote_irr(), true);
+    }
+
+    #[test]
+    fn delivery_status_read_only() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Level);
+
+        ioapic.redirect_table[irq].set_delivery_status(DeliveryStatus::Pending);
+
+        let mut entry = read_entry(&mut ioapic, irq);
+        entry.set_delivery_status(DeliveryStatus::Idle);
+        write_entry(&mut ioapic, irq, entry);
+
+        assert_eq!(
+            read_entry(&mut ioapic, irq).get_delivery_status(),
+            DeliveryStatus::Pending
+        );
+    }
+
+    #[test]
+    fn level_to_edge_transition_clears_remote_irr() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Level);
+
+        ioapic.redirect_table[irq].set_remote_irr(true);
+
+        let mut entry = read_entry(&mut ioapic, irq);
+        entry.set_trigger_mode(TriggerMode::Edge);
+        write_entry(&mut ioapic, irq, entry);
+
+        assert_eq!(read_entry(&mut ioapic, irq).get_remote_irr(), false);
+    }
+
+    #[test]
+    fn masking_preserves_remote_irr() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Level);
+
+        ioapic.redirect_table[irq].set_remote_irr(true);
+
+        set_mask(&mut ioapic, irq, true);
+        set_mask(&mut ioapic, irq, false);
+
+        assert_eq!(read_entry(&mut ioapic, irq).get_remote_irr(), true);
+    }
+
+    // Test reconfiguration racing with EOIs.
+    #[test]
+    fn reconfiguration_race() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Level);
+
+        // Fire one level-triggered interrupt.
+        // TODO(mutexlox): Check that it fires.
+        ioapic.service_irq(irq, true);
+
+        // Read the redirection table entry before the EOI...
+        let mut entry = read_entry(&mut ioapic, irq);
+        entry.set_trigger_mode(TriggerMode::Edge);
+
+        ioapic.service_irq(irq, false);
+        ioapic.end_of_interrupt(DEFAULT_DESTINATION_ID);
+
+        // ... and write back that (modified) value.
+        write_entry(&mut ioapic, irq, entry);
+
+        // Fire one *edge* triggered interrupt
+        // TODO(mutexlox): Assert that the interrupt fires once.
+        ioapic.service_irq(irq, true);
+        ioapic.service_irq(irq, false);
+    }
+
+    // Ensure that swapping to edge triggered and back clears the remote irr bit.
+    #[test]
+    fn implicit_eoi() {
+        let (mut ioapic, irq) = set_up(TriggerMode::Level);
+
+        // Fire one level-triggered interrupt.
+        ioapic.service_irq(irq, true);
+        // TODO(mutexlox): Verify that one interrupt was fired.
+        ioapic.service_irq(irq, false);
+
+        // Do an implicit EOI by cycling between edge and level triggered.
+        let mut entry = read_entry(&mut ioapic, irq);
+        entry.set_trigger_mode(TriggerMode::Edge);
+        write_entry(&mut ioapic, irq, entry);
+        entry.set_trigger_mode(TriggerMode::Level);
+        write_entry(&mut ioapic, irq, entry);
+
+        // Fire one level-triggered interrupt.
+        ioapic.service_irq(irq, true);
+        // TODO(mutexlox): Verify that one interrupt fires.
+        ioapic.service_irq(irq, false);
+    }
+
+    #[test]
+    fn set_redirection_entry_by_bits() {
+        let mut entry = RedirectionTableEntry::new();
+        //                                                          destination_mode
+        //                                                         polarity |
+        //                                                  trigger_mode |  |
+        //                                                             | |  |
+        // 0011 1010 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1001 0110 0101 1111
+        // |_______| |______________________________________________||  | |  |_| |_______|
+        //  dest_id                      reserved                    |  | |   |    vector
+        //                                               interrupt_mask | |   |
+        //                                                     remote_irr |   |
+        //                                                    delivery_status |
+        //                                                              delivery_mode
+        entry.set(0, 64, 0x3a0000000000965f);
+        assert_eq!(entry.get_vector(), 0x5f);
+        assert_eq!(entry.get_delivery_mode(), DeliveryMode::Startup);
+        assert_eq!(entry.get_dest_mode(), DestinationMode::Physical);
+        assert_eq!(entry.get_delivery_status(), DeliveryStatus::Pending);
+        assert_eq!(entry.get_polarity(), 0);
+        assert_eq!(entry.get_remote_irr(), false);
+        assert_eq!(entry.get_trigger_mode(), TriggerMode::Level);
+        assert_eq!(entry.get_interrupt_mask(), false);
+        assert_eq!(entry.get_reserved(), 0);
+        assert_eq!(entry.get_dest_id(), 0x3a);
+
+        let (mut ioapic, irq) = set_up(TriggerMode::Edge);
+        write_entry(&mut ioapic, irq, entry);
+        assert_eq!(
+            read_entry(&mut ioapic, irq).get_trigger_mode(),
+            TriggerMode::Level
+        );
+
+        // TODO(mutexlox): Verify that this actually fires an interrupt.
+        ioapic.service_irq(irq, true);
+    }
+}
diff --git a/devices/src/lib.rs b/devices/src/lib.rs
new file mode 100644
index 0000000..bc9c8c1
--- /dev/null
+++ b/devices/src/lib.rs
@@ -0,0 +1,43 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Emulates virtual and hardware devices.
+
+mod bus;
+mod cmos;
+mod i8042;
+mod ioapic;
+mod pci;
+mod pic;
+mod pit;
+pub mod pl030;
+mod proxy;
+#[macro_use]
+mod register_space;
+mod serial;
+pub mod split_irqchip_common;
+pub mod usb;
+mod utils;
+pub mod virtio;
+
+pub use self::bus::Error as BusError;
+pub use self::bus::{Bus, BusDevice, BusRange};
+pub use self::cmos::Cmos;
+pub use self::i8042::I8042Device;
+pub use self::ioapic::Ioapic;
+pub use self::pci::{
+    Ac97Dev, PciConfigIo, PciConfigMmio, PciDevice, PciDeviceError, PciInterruptPin, PciRoot,
+};
+pub use self::pic::Pic;
+pub use self::pit::{Pit, PitError};
+pub use self::pl030::Pl030;
+pub use self::proxy::Error as ProxyError;
+pub use self::proxy::ProxyDevice;
+pub use self::serial::Error as SerialError;
+pub use self::serial::{
+    get_serial_tty_string, Serial, SerialParameters, SerialType, DEFAULT_SERIAL_PARAMS, SERIAL_ADDR,
+};
+pub use self::usb::host_backend::host_backend_device_provider::HostBackendDeviceProvider;
+pub use self::usb::xhci::xhci_controller::XhciController;
+pub use self::virtio::VirtioPciDevice;
diff --git a/devices/src/pci/ac97.rs b/devices/src/pci/ac97.rs
new file mode 100644
index 0000000..aeab1f1
--- /dev/null
+++ b/devices/src/pci/ac97.rs
@@ -0,0 +1,253 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::os::unix::io::RawFd;
+
+use audio_streams::StreamSource;
+use resources::{Alloc, SystemAllocator};
+use sys_util::{error, EventFd, GuestMemory};
+
+use crate::pci::ac97_bus_master::Ac97BusMaster;
+use crate::pci::ac97_mixer::Ac97Mixer;
+use crate::pci::ac97_regs::*;
+use crate::pci::pci_configuration::{
+    PciBarConfiguration, PciClassCode, PciConfiguration, PciHeaderType, PciMultimediaSubclass,
+};
+use crate::pci::pci_device::{self, PciDevice, Result};
+use crate::pci::PciInterruptPin;
+
+// Use 82801AA because it's what qemu does.
+const PCI_DEVICE_ID_INTEL_82801AA_5: u16 = 0x2415;
+
+/// AC97 audio device emulation.
+/// Provides the PCI interface for the internal Ac97 emulation.
+/// Internally the `Ac97BusMaster` and `Ac97Mixer` structs are used to emulated the bus master and
+/// mixer registers respectively. `Ac97BusMaster` handles moving smaples between guest memory and
+/// the audio backend.
+pub struct Ac97Dev {
+    config_regs: PciConfiguration,
+    pci_bus_dev: Option<(u8, u8)>,
+    // The irq events are temporarily saved here. They need to be passed to the device after the
+    // jail forks. This happens when the bus is first written.
+    irq_evt: Option<EventFd>,
+    irq_resample_evt: Option<EventFd>,
+    bus_master: Ac97BusMaster,
+    mixer: Ac97Mixer,
+}
+
+impl Ac97Dev {
+    /// Creates an 'Ac97Dev' that uses the given `GuestMemory` and starts with all registers at
+    /// default values.
+    pub fn new(mem: GuestMemory, audio_server: Box<dyn StreamSource>) -> Self {
+        let config_regs = PciConfiguration::new(
+            0x8086,
+            PCI_DEVICE_ID_INTEL_82801AA_5,
+            PciClassCode::MultimediaController,
+            &PciMultimediaSubclass::AudioDevice,
+            None, // No Programming interface.
+            PciHeaderType::Device,
+            0x8086, // Subsystem Vendor ID
+            0x1,    // Subsystem ID.
+        );
+
+        Ac97Dev {
+            config_regs,
+            pci_bus_dev: None,
+            irq_evt: None,
+            irq_resample_evt: None,
+            bus_master: Ac97BusMaster::new(mem, audio_server),
+            mixer: Ac97Mixer::new(),
+        }
+    }
+
+    fn read_mixer(&mut self, offset: u64, data: &mut [u8]) {
+        match data.len() {
+            // The mixer is only accessed with 16-bit words.
+            2 => {
+                let val: u16 = self.mixer.readw(offset);
+                data[0] = val as u8;
+                data[1] = (val >> 8) as u8;
+            }
+            l => error!("mixer read length of {}", l),
+        }
+    }
+
+    fn write_mixer(&mut self, offset: u64, data: &[u8]) {
+        match data.len() {
+            // The mixer is only accessed with 16-bit words.
+            2 => self
+                .mixer
+                .writew(offset, u16::from(data[0]) | u16::from(data[1]) << 8),
+            l => error!("mixer write length of {}", l),
+        }
+        // Apply the new mixer settings to the bus master.
+        self.bus_master.update_mixer_settings(&self.mixer);
+    }
+
+    fn read_bus_master(&mut self, offset: u64, data: &mut [u8]) {
+        match data.len() {
+            1 => data[0] = self.bus_master.readb(offset),
+            2 => {
+                let val: u16 = self.bus_master.readw(offset);
+                data[0] = val as u8;
+                data[1] = (val >> 8) as u8;
+            }
+            4 => {
+                let val: u32 = self.bus_master.readl(offset);
+                data[0] = val as u8;
+                data[1] = (val >> 8) as u8;
+                data[2] = (val >> 16) as u8;
+                data[3] = (val >> 24) as u8;
+            }
+            l => error!("read length of {}", l),
+        }
+    }
+
+    fn write_bus_master(&mut self, offset: u64, data: &[u8]) {
+        match data.len() {
+            1 => self.bus_master.writeb(offset, data[0], &self.mixer),
+            2 => self
+                .bus_master
+                .writew(offset, u16::from(data[0]) | u16::from(data[1]) << 8),
+            4 => self.bus_master.writel(
+                offset,
+                (u32::from(data[0]))
+                    | (u32::from(data[1]) << 8)
+                    | (u32::from(data[2]) << 16)
+                    | (u32::from(data[3]) << 24),
+            ),
+            l => error!("write length of {}", l),
+        }
+    }
+}
+
+impl PciDevice for Ac97Dev {
+    fn debug_label(&self) -> String {
+        "AC97".to_owned()
+    }
+
+    fn assign_bus_dev(&mut self, bus: u8, device: u8) {
+        self.pci_bus_dev = Some((bus, device));
+    }
+
+    fn assign_irq(
+        &mut self,
+        irq_evt: EventFd,
+        irq_resample_evt: EventFd,
+        irq_num: u32,
+        irq_pin: PciInterruptPin,
+    ) {
+        self.config_regs.set_irq(irq_num as u8, irq_pin);
+        self.irq_evt = Some(irq_evt);
+        self.irq_resample_evt = Some(irq_resample_evt);
+    }
+
+    fn allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
+        let (bus, dev) = self
+            .pci_bus_dev
+            .expect("assign_bus_dev must be called prior to allocate_io_bars");
+        let mut ranges = Vec::new();
+        let mixer_regs_addr = resources
+            .mmio_allocator()
+            .allocate(
+                MIXER_REGS_SIZE,
+                Alloc::PciBar { bus, dev, bar: 0 },
+                "ac97-mixer_regs".to_string(),
+            )
+            .map_err(|e| pci_device::Error::IoAllocationFailed(MIXER_REGS_SIZE, e))?;
+        let mixer_config = PciBarConfiguration::default()
+            .set_register_index(0)
+            .set_address(mixer_regs_addr)
+            .set_size(MIXER_REGS_SIZE);
+        self.config_regs
+            .add_pci_bar(&mixer_config)
+            .map_err(|e| pci_device::Error::IoRegistrationFailed(mixer_regs_addr, e))?;
+        ranges.push((mixer_regs_addr, MIXER_REGS_SIZE));
+
+        let master_regs_addr = resources
+            .mmio_allocator()
+            .allocate(
+                MASTER_REGS_SIZE,
+                Alloc::PciBar { bus, dev, bar: 1 },
+                "ac97-master_regs".to_string(),
+            )
+            .map_err(|e| pci_device::Error::IoAllocationFailed(MASTER_REGS_SIZE, e))?;
+        let master_config = PciBarConfiguration::default()
+            .set_register_index(1)
+            .set_address(master_regs_addr)
+            .set_size(MASTER_REGS_SIZE);
+        self.config_regs
+            .add_pci_bar(&master_config)
+            .map_err(|e| pci_device::Error::IoRegistrationFailed(master_regs_addr, e))?;
+        ranges.push((master_regs_addr, MASTER_REGS_SIZE));
+        Ok(ranges)
+    }
+
+    fn config_registers(&self) -> &PciConfiguration {
+        &self.config_regs
+    }
+
+    fn config_registers_mut(&mut self) -> &mut PciConfiguration {
+        &mut self.config_regs
+    }
+
+    fn keep_fds(&self) -> Vec<RawFd> {
+        if let Some(server_fds) = self.bus_master.keep_fds() {
+            server_fds
+        } else {
+            Vec::new()
+        }
+    }
+
+    fn read_bar(&mut self, addr: u64, data: &mut [u8]) {
+        let bar0 = u64::from(self.config_regs.get_bar_addr(0));
+        let bar1 = u64::from(self.config_regs.get_bar_addr(1));
+        match addr {
+            a if a >= bar0 && a < bar0 + MIXER_REGS_SIZE => self.read_mixer(addr - bar0, data),
+            a if a >= bar1 && a < bar1 + MASTER_REGS_SIZE => {
+                self.read_bus_master(addr - bar1, data)
+            }
+            _ => (),
+        }
+    }
+
+    fn write_bar(&mut self, addr: u64, data: &[u8]) {
+        let bar0 = u64::from(self.config_regs.get_bar_addr(0));
+        let bar1 = u64::from(self.config_regs.get_bar_addr(1));
+        match addr {
+            a if a >= bar0 && a < bar0 + MIXER_REGS_SIZE => self.write_mixer(addr - bar0, data),
+            a if a >= bar1 && a < bar1 + MASTER_REGS_SIZE => {
+                // Check if the irq needs to be passed to the device.
+                if let (Some(irq_evt), Some(irq_resample_evt)) =
+                    (self.irq_evt.take(), self.irq_resample_evt.take())
+                {
+                    self.bus_master.set_irq_event_fd(irq_evt, irq_resample_evt);
+                }
+                self.write_bus_master(addr - bar1, data)
+            }
+            _ => (),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use audio_streams::DummyStreamSource;
+    use sys_util::GuestAddress;
+
+    #[test]
+    fn create() {
+        let mem = GuestMemory::new(&[(GuestAddress(0u64), 4 * 1024 * 1024)]).unwrap();
+        let mut ac97_dev = Ac97Dev::new(mem, Box::new(DummyStreamSource::new()));
+        let mut allocator = SystemAllocator::builder()
+            .add_io_addresses(0x1000_0000, 0x1000_0000)
+            .add_mmio_addresses(0x2000_0000, 0x1000_0000)
+            .add_device_addresses(0x3000_0000, 0x1000_0000)
+            .create_allocator(5, false)
+            .unwrap();
+        ac97_dev.assign_bus_dev(0, 0);
+        assert!(ac97_dev.allocate_io_bars(&mut allocator).is_ok());
+    }
+}
diff --git a/devices/src/pci/ac97_bus_master.rs b/devices/src/pci/ac97_bus_master.rs
new file mode 100644
index 0000000..bde5c90
--- /dev/null
+++ b/devices/src/pci/ac97_bus_master.rs
@@ -0,0 +1,1043 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std;
+use std::error::Error;
+use std::fmt::{self, Display};
+use std::io::Write;
+use std::os::unix::io::RawFd;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::Arc;
+use std::thread;
+use std::time::Instant;
+
+use audio_streams::{
+    capture::{CaptureBuffer, CaptureBufferStream},
+    PlaybackBuffer, PlaybackBufferStream, StreamControl, StreamSource,
+};
+use data_model::{VolatileMemory, VolatileSlice};
+use sync::Mutex;
+use sys_util::{
+    self, error, set_rt_prio_limit, set_rt_round_robin, warn, EventFd, GuestAddress, GuestMemory,
+};
+
+use crate::pci::ac97_mixer::Ac97Mixer;
+use crate::pci::ac97_regs::*;
+
+const DEVICE_SAMPLE_RATE: usize = 48000;
+
+// Bus Master registers. Keeps the state of the bus master register values. Used to share the state
+// between the main and audio threads.
+struct Ac97BusMasterRegs {
+    pi_regs: Ac97FunctionRegs,       // Input
+    po_regs: Ac97FunctionRegs,       // Output
+    po_pointer_update_time: Instant, // Time the picb and civ regs were last updated.
+    mc_regs: Ac97FunctionRegs,       // Microphone
+    glob_cnt: u32,
+    glob_sta: u32,
+
+    // IRQ event - driven by the glob_sta register.
+    irq_evt: Option<EventFd>,
+}
+
+impl Ac97BusMasterRegs {
+    fn new() -> Ac97BusMasterRegs {
+        Ac97BusMasterRegs {
+            pi_regs: Ac97FunctionRegs::new(),
+            po_regs: Ac97FunctionRegs::new(),
+            po_pointer_update_time: Instant::now(),
+            mc_regs: Ac97FunctionRegs::new(),
+            glob_cnt: 0,
+            glob_sta: GLOB_STA_RESET_VAL,
+            irq_evt: None,
+        }
+    }
+
+    fn func_regs(&self, func: Ac97Function) -> &Ac97FunctionRegs {
+        match func {
+            Ac97Function::Input => &self.pi_regs,
+            Ac97Function::Output => &self.po_regs,
+            Ac97Function::Microphone => &self.mc_regs,
+        }
+    }
+
+    fn func_regs_mut(&mut self, func: Ac97Function) -> &mut Ac97FunctionRegs {
+        match func {
+            Ac97Function::Input => &mut self.pi_regs,
+            Ac97Function::Output => &mut self.po_regs,
+            Ac97Function::Microphone => &mut self.mc_regs,
+        }
+    }
+}
+
+// Internal error type used for reporting errors from guest memory reading.
+#[derive(Debug)]
+enum GuestMemoryError {
+    // Failure getting the address of the audio buffer.
+    ReadingGuestBufferAddress(sys_util::GuestMemoryError),
+    // Failure reading samples from guest memory.
+    ReadingGuestSamples(data_model::VolatileMemoryError),
+}
+
+impl std::error::Error for GuestMemoryError {}
+
+impl Display for GuestMemoryError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::GuestMemoryError::*;
+
+        match self {
+            ReadingGuestBufferAddress(e) => {
+                write!(f, "Failed to get the address of the audio buffer: {}.", e)
+            }
+            ReadingGuestSamples(e) => write!(f, "Failed to read samples from guest memory: {}.", e),
+        }
+    }
+}
+
+impl From<GuestMemoryError> for PlaybackError {
+    fn from(err: GuestMemoryError) -> Self {
+        PlaybackError::ReadingGuestError(err)
+    }
+}
+
+impl From<GuestMemoryError> for CaptureError {
+    fn from(err: GuestMemoryError) -> Self {
+        CaptureError::ReadingGuestError(err)
+    }
+}
+
+type GuestMemoryResult<T> = std::result::Result<T, GuestMemoryError>;
+
+// Internal error type used for reporting errors from the audio playback thread.
+#[derive(Debug)]
+enum PlaybackError {
+    // Failure to read guest memory.
+    ReadingGuestError(GuestMemoryError),
+    // Failure to get an buffer from the stream.
+    StreamError(Box<dyn Error>),
+    // Failure writing to the audio output.
+    WritingOutput(std::io::Error),
+}
+
+impl std::error::Error for PlaybackError {}
+
+impl Display for PlaybackError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::PlaybackError::*;
+
+        match self {
+            ReadingGuestError(e) => write!(f, "Failed to read guest memory: {}.", e),
+            StreamError(e) => write!(f, "Failed to get a buffer from the stream: {}", e),
+            WritingOutput(e) => write!(f, "Failed to write audio output: {}.", e),
+        }
+    }
+}
+
+type PlaybackResult<T> = std::result::Result<T, PlaybackError>;
+
+// Internal error type used for reporting errors from the audio capture thread.
+#[derive(Debug)]
+enum CaptureError {
+    // Failure to read guest memory.
+    ReadingGuestError(GuestMemoryError),
+    // Failure to get an buffer from the stream.
+    StreamError(Box<dyn Error>),
+}
+
+impl std::error::Error for CaptureError {}
+
+impl Display for CaptureError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::CaptureError::*;
+
+        match self {
+            ReadingGuestError(e) => write!(f, "Failed to read guest memory: {}.", e),
+            StreamError(e) => write!(f, "Failed to get a buffer from the stream: {}", e),
+        }
+    }
+}
+
+type CaptureResult<T> = std::result::Result<T, CaptureError>;
+
+/// `Ac97BusMaster` emulates the bus master portion of AC97. It exposes a register read/write
+/// interface compliant with the ICH bus master.
+pub struct Ac97BusMaster {
+    // Keep guest memory as each function will use it for buffer descriptors.
+    mem: GuestMemory,
+    regs: Arc<Mutex<Ac97BusMasterRegs>>,
+    acc_sema: u8,
+
+    // Audio thread for capture stream.
+    audio_thread_pi: Option<thread::JoinHandle<()>>,
+    audio_thread_pi_run: Arc<AtomicBool>,
+    pi_stream_control: Option<Box<dyn StreamControl>>,
+
+    // Audio thread book keeping.
+    audio_thread_po: Option<thread::JoinHandle<()>>,
+    audio_thread_po_run: Arc<AtomicBool>,
+    po_stream_control: Option<Box<dyn StreamControl>>,
+
+    // Audio server used to create playback or capture streams.
+    audio_server: Box<dyn StreamSource>,
+
+    // Thread for hadlind IRQ resample events from the guest.
+    irq_resample_thread: Option<thread::JoinHandle<()>>,
+}
+
+impl Ac97BusMaster {
+    /// Creates an Ac97BusMaster` object that plays audio from `mem` to streams provided by
+    /// `audio_server`.
+    pub fn new(mem: GuestMemory, audio_server: Box<dyn StreamSource>) -> Self {
+        Ac97BusMaster {
+            mem,
+            regs: Arc::new(Mutex::new(Ac97BusMasterRegs::new())),
+            acc_sema: 0,
+
+            audio_thread_pi: None,
+            audio_thread_pi_run: Arc::new(AtomicBool::new(false)),
+            pi_stream_control: None,
+
+            audio_thread_po: None,
+            audio_thread_po_run: Arc::new(AtomicBool::new(false)),
+            po_stream_control: None,
+
+            audio_server,
+
+            irq_resample_thread: None,
+        }
+    }
+
+    /// Returns any file descriptors that need to be kept open when entering a jail.
+    pub fn keep_fds(&self) -> Option<Vec<RawFd>> {
+        self.audio_server.keep_fds()
+    }
+
+    /// Provides the events needed to raise interrupts in the guest.
+    pub fn set_irq_event_fd(&mut self, irq_evt: EventFd, irq_resample_evt: EventFd) {
+        let thread_regs = self.regs.clone();
+        self.regs.lock().irq_evt = Some(irq_evt);
+        self.irq_resample_thread = Some(thread::spawn(move || {
+            loop {
+                if let Err(e) = irq_resample_evt.read() {
+                    error!(
+                        "Failed to read the irq event from the resample thread: {}.",
+                        e,
+                    );
+                    break;
+                }
+                {
+                    // Scope for the lock on thread_regs.
+                    let regs = thread_regs.lock();
+                    // Check output irq
+                    let po_int_mask = regs.func_regs(Ac97Function::Output).int_mask();
+                    if regs.func_regs(Ac97Function::Output).sr & po_int_mask != 0 {
+                        if let Some(irq_evt) = regs.irq_evt.as_ref() {
+                            if let Err(e) = irq_evt.write(1) {
+                                error!("Failed to set the irq from the resample thread: {}.", e);
+                                break;
+                            }
+                        }
+                    }
+                    // Check input irq
+                    let pi_int_mask = regs.func_regs(Ac97Function::Input).int_mask();
+                    if regs.func_regs(Ac97Function::Input).sr & pi_int_mask != 0 {
+                        if let Some(irq_evt) = regs.irq_evt.as_ref() {
+                            if let Err(e) = irq_evt.write(1) {
+                                error!("Failed to set the irq from the resample thread: {}.", e);
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }));
+    }
+
+    /// Called when `mixer` has been changed and the new values should be applied to currently
+    /// active streams.
+    pub fn update_mixer_settings(&mut self, mixer: &Ac97Mixer) {
+        if let Some(control) = self.po_stream_control.as_mut() {
+            // The audio server only supports one volume, not separate left and right.
+            let (muted, left_volume, _right_volume) = mixer.get_master_volume();
+            control.set_volume(left_volume);
+            control.set_mute(muted);
+        }
+    }
+
+    /// Checks if the bus master is in the cold reset state.
+    pub fn is_cold_reset(&self) -> bool {
+        self.regs.lock().glob_cnt & GLOB_CNT_COLD_RESET == 0
+    }
+
+    /// Reads a byte from the given `offset`.
+    pub fn readb(&mut self, offset: u64) -> u8 {
+        fn readb_func_regs(func_regs: &Ac97FunctionRegs, offset: u64) -> u8 {
+            match offset {
+                CIV_OFFSET => func_regs.civ,
+                LVI_OFFSET => func_regs.lvi,
+                SR_OFFSET => func_regs.sr as u8,
+                PIV_OFFSET => func_regs.piv,
+                CR_OFFSET => func_regs.cr,
+                _ => 0,
+            }
+        }
+
+        let regs = self.regs.lock();
+        match offset {
+            PI_BASE_00...PI_CR_0B => readb_func_regs(&regs.pi_regs, offset - PI_BASE_00),
+            PO_BASE_10...PO_CR_1B => readb_func_regs(&regs.po_regs, offset - PO_BASE_10),
+            MC_BASE_20...MC_CR_2B => readb_func_regs(&regs.mc_regs, offset - MC_BASE_20),
+            ACC_SEMA_34 => self.acc_sema,
+            _ => 0,
+        }
+    }
+
+    /// Reads a word from the given `offset`.
+    pub fn readw(&mut self, offset: u64) -> u16 {
+        let regs = self.regs.lock();
+        match offset {
+            PI_SR_06 => regs.pi_regs.sr,
+            PI_PICB_08 => regs.pi_regs.picb,
+            PO_SR_16 => regs.po_regs.sr,
+            PO_PICB_18 => {
+                // PO PICB
+                if !self.audio_thread_po_run.load(Ordering::Relaxed) {
+                    // Not running, no need to estimate what has been consumed.
+                    regs.po_regs.picb
+                } else {
+                    // Estimate how many samples have been played since the last audio callback.
+                    let num_channels = 2;
+                    let micros = regs.po_pointer_update_time.elapsed().subsec_micros();
+                    // Round down to the next 10 millisecond boundary. The linux driver often
+                    // assumes that two rapid reads from picb will return the same value.
+                    let millis = micros / 1000 / 10 * 10;
+
+                    let frames_consumed = DEVICE_SAMPLE_RATE as u64 * u64::from(millis) / 1000;
+
+                    regs.po_regs
+                        .picb
+                        .saturating_sub((num_channels * frames_consumed) as u16)
+                }
+            }
+            MC_SR_26 => regs.mc_regs.sr,
+            MC_PICB_28 => regs.mc_regs.picb,
+            _ => 0,
+        }
+    }
+
+    /// Reads a 32-bit word from the given `offset`.
+    pub fn readl(&mut self, offset: u64) -> u32 {
+        let regs = self.regs.lock();
+        match offset {
+            PI_BDBAR_00 => regs.pi_regs.bdbar,
+            PI_CIV_04 => regs.pi_regs.atomic_status_regs(),
+            PO_BDBAR_10 => regs.po_regs.bdbar,
+            PO_CIV_14 => regs.po_regs.atomic_status_regs(),
+            MC_BDBAR_20 => regs.mc_regs.bdbar,
+            MC_CIV_24 => regs.mc_regs.atomic_status_regs(),
+            GLOB_CNT_2C => regs.glob_cnt,
+            GLOB_STA_30 => regs.glob_sta,
+            _ => 0,
+        }
+    }
+
+    /// Writes the byte `val` to the register specified by `offset`.
+    pub fn writeb(&mut self, offset: u64, val: u8, mixer: &Ac97Mixer) {
+        // Only process writes to the control register when cold reset is set.
+        if self.is_cold_reset() {
+            return;
+        }
+
+        match offset {
+            PI_CIV_04 => (), // RO
+            PI_LVI_05 => self.set_lvi(Ac97Function::Input, val),
+            PI_SR_06 => self.set_sr(Ac97Function::Input, u16::from(val)),
+            PI_PIV_0A => (), // RO
+            PI_CR_0B => self.set_cr(Ac97Function::Input, val, mixer),
+            PO_CIV_14 => (), // RO
+            PO_LVI_15 => self.set_lvi(Ac97Function::Output, val),
+            PO_SR_16 => self.set_sr(Ac97Function::Output, u16::from(val)),
+            PO_PIV_1A => (), // RO
+            PO_CR_1B => self.set_cr(Ac97Function::Output, val, mixer),
+            MC_CIV_24 => (), // RO
+            MC_LVI_25 => self.set_lvi(Ac97Function::Microphone, val),
+            MC_PIV_2A => (), // RO
+            MC_CR_2B => self.set_cr(Ac97Function::Microphone, val, mixer),
+            ACC_SEMA_34 => self.acc_sema = val,
+            o => warn!("write byte to 0x{:x}", o),
+        }
+    }
+
+    /// Writes the word `val` to the register specified by `offset`.
+    pub fn writew(&mut self, offset: u64, val: u16) {
+        // Only process writes to the control register when cold reset is set.
+        if self.is_cold_reset() {
+            return;
+        }
+        match offset {
+            PI_SR_06 => self.set_sr(Ac97Function::Input, val),
+            PI_PICB_08 => (), // RO
+            PO_SR_16 => self.set_sr(Ac97Function::Output, val),
+            PO_PICB_18 => (), // RO
+            MC_SR_26 => self.set_sr(Ac97Function::Microphone, val),
+            MC_PICB_28 => (), // RO
+            o => warn!("write word to 0x{:x}", o),
+        }
+    }
+
+    /// Writes the 32-bit `val` to the register specified by `offset`.
+    pub fn writel(&mut self, offset: u64, val: u32) {
+        // Only process writes to the control register when cold reset is set.
+        if self.is_cold_reset() && offset != 0x2c {
+            return;
+        }
+        match offset {
+            PI_BDBAR_00 => self.set_bdbar(Ac97Function::Input, val),
+            PO_BDBAR_10 => self.set_bdbar(Ac97Function::Output, val),
+            MC_BDBAR_20 => self.set_bdbar(Ac97Function::Microphone, val),
+            GLOB_CNT_2C => self.set_glob_cnt(val),
+            GLOB_STA_30 => (), // RO
+            o => warn!("write long to 0x{:x}", o),
+        }
+    }
+
+    fn set_bdbar(&mut self, func: Ac97Function, val: u32) {
+        self.regs.lock().func_regs_mut(func).bdbar = val & !0x07;
+    }
+
+    fn set_lvi(&mut self, func: Ac97Function, val: u8) {
+        let mut regs = self.regs.lock();
+        let func_regs = regs.func_regs_mut(func);
+        func_regs.lvi = val % 32; // LVI wraps at 32.
+
+        // If running and stalled waiting for more valid buffers, restart by clearing the "DMA
+        // stopped" bit.
+        if func_regs.cr & CR_RPBM == CR_RPBM
+            && func_regs.sr & SR_DCH == SR_DCH
+            && func_regs.civ != func_regs.lvi
+        {
+            func_regs.sr &= !SR_DCH;
+        }
+    }
+
+    fn set_sr(&mut self, func: Ac97Function, val: u16) {
+        let mut sr = self.regs.lock().func_regs(func).sr;
+        if val & SR_FIFOE != 0 {
+            sr &= !SR_FIFOE;
+        }
+        if val & SR_LVBCI != 0 {
+            sr &= !SR_LVBCI;
+        }
+        if val & SR_BCIS != 0 {
+            sr &= !SR_BCIS;
+        }
+        update_sr(&mut self.regs.lock(), func, sr);
+    }
+
+    fn set_cr(&mut self, func: Ac97Function, val: u8, mixer: &Ac97Mixer) {
+        if val & CR_RR != 0 {
+            self.stop_audio(func);
+            let mut regs = self.regs.lock();
+            regs.func_regs_mut(func).do_reset();
+        } else {
+            let cr = self.regs.lock().func_regs(func).cr;
+            if val & CR_RPBM == 0 {
+                // Run/Pause set to pause.
+                self.stop_audio(func);
+                let mut regs = self.regs.lock();
+                regs.func_regs_mut(func).sr |= SR_DCH;
+            } else if cr & CR_RPBM == 0 {
+                // Not already running.
+                // Run/Pause set to run.
+                {
+                    let mut regs = self.regs.lock();
+                    let func_regs = regs.func_regs_mut(func);
+                    func_regs.piv = 1;
+                    func_regs.civ = 0;
+                    func_regs.sr &= !SR_DCH;
+                }
+                if self.start_audio(func, mixer).is_err() {
+                    warn!("Failed to start audio");
+                }
+            }
+            let mut regs = self.regs.lock();
+            regs.func_regs_mut(func).cr = val & CR_VALID_MASK;
+        }
+    }
+
+    fn set_glob_cnt(&mut self, new_glob_cnt: u32) {
+        // Only the reset bits are emulated, the GPI and PCM formatting are not supported.
+        if new_glob_cnt & GLOB_CNT_COLD_RESET == 0 {
+            self.reset_audio_regs();
+
+            let mut regs = self.regs.lock();
+            regs.glob_cnt = new_glob_cnt & GLOB_CNT_STABLE_BITS;
+            self.acc_sema = 0;
+            return;
+        }
+        if new_glob_cnt & GLOB_CNT_WARM_RESET != 0 {
+            // Check if running and if so, ignore. Warm reset is specified to no-op when the device
+            // is playing or recording audio.
+            if !self.audio_thread_po_run.load(Ordering::Relaxed) {
+                self.stop_all_audio();
+                let mut regs = self.regs.lock();
+                regs.glob_cnt = new_glob_cnt & !GLOB_CNT_WARM_RESET; // Auto-cleared reset bit.
+                return;
+            }
+        }
+        self.regs.lock().glob_cnt = new_glob_cnt;
+    }
+
+    fn start_audio(&mut self, func: Ac97Function, mixer: &Ac97Mixer) -> Result<(), Box<dyn Error>> {
+        const AUDIO_THREAD_RTPRIO: u16 = 12; // Matches other cros audio clients.
+
+        match func {
+            Ac97Function::Input => {
+                let num_channels = 2;
+                let buffer_samples =
+                    current_buffer_size(self.regs.lock().func_regs(func), &self.mem)?;
+                let buffer_frames = buffer_samples / num_channels;
+                let (stream_control, input_stream) = self.audio_server.new_capture_stream(
+                    num_channels,
+                    DEVICE_SAMPLE_RATE,
+                    buffer_frames,
+                )?;
+                self.pi_stream_control = Some(stream_control);
+                self.update_mixer_settings(mixer);
+
+                self.audio_thread_pi_run.store(true, Ordering::Relaxed);
+                let thread_run = self.audio_thread_pi_run.clone();
+                let thread_mem = self.mem.clone();
+                let thread_regs = self.regs.clone();
+
+                self.audio_thread_pi = Some(thread::spawn(move || {
+                    if set_rt_prio_limit(u64::from(AUDIO_THREAD_RTPRIO)).is_err()
+                        || set_rt_round_robin(i32::from(AUDIO_THREAD_RTPRIO)).is_err()
+                    {
+                        warn!("Failed to set audio thread to real time.");
+                    }
+                    if let Err(e) =
+                        audio_in_thread(thread_regs, thread_mem, &thread_run, input_stream)
+                    {
+                        error!("Capture error: {}", e);
+                    }
+                    thread_run.store(false, Ordering::Relaxed);
+                }));
+            }
+            Ac97Function::Output => {
+                let num_channels = 2;
+
+                let buffer_samples =
+                    current_buffer_size(self.regs.lock().func_regs(func), &self.mem)?;
+
+                let buffer_frames = buffer_samples / num_channels;
+                let (stream_control, output_stream) = self.audio_server.new_playback_stream(
+                    num_channels,
+                    DEVICE_SAMPLE_RATE,
+                    buffer_frames,
+                )?;
+                self.po_stream_control = Some(stream_control);
+
+                self.update_mixer_settings(mixer);
+
+                self.audio_thread_po_run.store(true, Ordering::Relaxed);
+                let thread_run = self.audio_thread_po_run.clone();
+                let thread_mem = self.mem.clone();
+                let thread_regs = self.regs.clone();
+
+                self.audio_thread_po = Some(thread::spawn(move || {
+                    if set_rt_prio_limit(u64::from(AUDIO_THREAD_RTPRIO)).is_err()
+                        || set_rt_round_robin(i32::from(AUDIO_THREAD_RTPRIO)).is_err()
+                    {
+                        warn!("Failed to set audio thread to real time.");
+                    }
+                    if let Err(e) =
+                        audio_out_thread(thread_regs, thread_mem, &thread_run, output_stream)
+                    {
+                        error!("Playback error: {}", e);
+                    }
+                    thread_run.store(false, Ordering::Relaxed);
+                }));
+            }
+            Ac97Function::Microphone => (),
+        }
+        Ok(())
+    }
+
+    fn stop_audio(&mut self, func: Ac97Function) {
+        match func {
+            Ac97Function::Input => {
+                self.audio_thread_pi_run.store(false, Ordering::Relaxed);
+                if let Some(thread) = self.audio_thread_pi.take() {
+                    if let Err(e) = thread.join() {
+                        error!("Failed to join the capture thread: {:?}.", e);
+                    }
+                }
+            }
+            Ac97Function::Output => {
+                self.audio_thread_po_run.store(false, Ordering::Relaxed);
+                if let Some(thread) = self.audio_thread_po.take() {
+                    if let Err(e) = thread.join() {
+                        error!("Failed to join the playback thread: {:?}.", e);
+                    }
+                }
+            }
+            Ac97Function::Microphone => (),
+        };
+    }
+
+    fn stop_all_audio(&mut self) {
+        self.stop_audio(Ac97Function::Input);
+        self.stop_audio(Ac97Function::Output);
+        self.stop_audio(Ac97Function::Microphone);
+    }
+
+    fn reset_audio_regs(&mut self) {
+        self.stop_all_audio();
+        let mut regs = self.regs.lock();
+        regs.pi_regs.do_reset();
+        regs.po_regs.do_reset();
+        regs.mc_regs.do_reset();
+    }
+}
+
+// Gets the next buffer from the guest. This will return `None` if the DMA controlled stopped bit is
+// set, such as after an underrun where CIV hits LVI.
+fn next_guest_buffer<'a>(
+    func_regs: &mut Ac97FunctionRegs,
+    mem: &'a GuestMemory,
+) -> GuestMemoryResult<Option<VolatileSlice<'a>>> {
+    let sample_size = 2;
+
+    if func_regs.sr & SR_DCH != 0 {
+        return Ok(None);
+    }
+    let next_buffer = func_regs.civ;
+    let descriptor_addr = func_regs.bdbar + u32::from(next_buffer) * DESCRIPTOR_LENGTH as u32;
+    let buffer_addr_reg: u32 = mem
+        .read_obj_from_addr(GuestAddress(u64::from(descriptor_addr)))
+        .map_err(GuestMemoryError::ReadingGuestBufferAddress)?;
+    let buffer_addr = buffer_addr_reg & !0x03u32; // The address must be aligned to four bytes.
+    let control_reg: u32 = mem
+        .read_obj_from_addr(GuestAddress(u64::from(descriptor_addr) + 4))
+        .map_err(GuestMemoryError::ReadingGuestBufferAddress)?;
+    let buffer_samples: usize = control_reg as usize & 0x0000_ffff;
+
+    func_regs.picb = buffer_samples as u16;
+
+    let samples_remaining = func_regs.picb as usize;
+    if samples_remaining == 0 {
+        return Ok(None);
+    }
+    let read_pos = u64::from(buffer_addr);
+    Ok(Some(
+        mem.get_slice(read_pos, samples_remaining as u64 * sample_size)
+            .map_err(GuestMemoryError::ReadingGuestSamples)?,
+    ))
+}
+
+// Reads the next buffer from guest memory and writes it to `out_buffer`.
+fn play_buffer(
+    regs: &mut Ac97BusMasterRegs,
+    mem: &GuestMemory,
+    out_buffer: &mut PlaybackBuffer,
+) -> PlaybackResult<()> {
+    // If the current buffer had any samples in it, mark it as done.
+    if regs.func_regs_mut(Ac97Function::Output).picb > 0 {
+        buffer_completed(regs, mem, Ac97Function::Output)?
+    }
+    let func_regs = regs.func_regs_mut(Ac97Function::Output);
+    let buffer_len = func_regs.picb * 2;
+    if let Some(buffer) = next_guest_buffer(func_regs, mem)? {
+        out_buffer.copy_cb(buffer.size() as usize, |out| buffer.copy_to(out));
+    } else {
+        let zeros = vec![0u8; buffer_len as usize];
+        out_buffer
+            .write(&zeros)
+            .map_err(PlaybackError::WritingOutput)?;
+    }
+    Ok(())
+}
+
+// Moves to the next buffer for the given function and registers.
+fn buffer_completed(
+    regs: &mut Ac97BusMasterRegs,
+    mem: &GuestMemory,
+    func: Ac97Function,
+) -> GuestMemoryResult<()> {
+    // check if the completed descriptor wanted an interrupt on completion.
+    let civ = regs.func_regs(func).civ;
+    let descriptor_addr = regs.func_regs(func).bdbar + u32::from(civ) * DESCRIPTOR_LENGTH as u32;
+    let control_reg: u32 = mem
+        .read_obj_from_addr(GuestAddress(u64::from(descriptor_addr) + 4))
+        .map_err(GuestMemoryError::ReadingGuestBufferAddress)?;
+
+    let mut new_sr = regs.func_regs(func).sr;
+
+    if control_reg & BD_IOC != 0 {
+        new_sr |= SR_BCIS;
+    }
+
+    let lvi = regs.func_regs(func).lvi;
+    // if the current buffer was the last valid buffer, then update the status register to
+    // indicate that the end of audio was hit and possibly raise an interrupt.
+    if civ == lvi {
+        new_sr |= SR_DCH | SR_CELV | SR_LVBCI;
+    } else {
+        let func_regs = regs.func_regs_mut(func);
+        func_regs.civ = func_regs.piv;
+        func_regs.piv = (func_regs.piv + 1) % 32; // move piv to the next buffer.
+    }
+
+    if new_sr != regs.func_regs(func).sr {
+        update_sr(regs, func, new_sr);
+    }
+
+    regs.po_pointer_update_time = Instant::now();
+
+    Ok(())
+}
+
+// Runs, playing back audio from the guest to `output_stream` until stopped or an error occurs.
+fn audio_out_thread(
+    regs: Arc<Mutex<Ac97BusMasterRegs>>,
+    mem: GuestMemory,
+    thread_run: &AtomicBool,
+    mut output_stream: Box<dyn PlaybackBufferStream>,
+) -> PlaybackResult<()> {
+    while thread_run.load(Ordering::Relaxed) {
+        output_stream
+            .next_playback_buffer()
+            .map_err(PlaybackError::StreamError)
+            .and_then(|mut pb_buf| play_buffer(&mut regs.lock(), &mem, &mut pb_buf))?;
+    }
+    Ok(())
+}
+
+// Reads samples from `in_buffer` and writes it to the next buffer from guest memory.
+fn capture_buffer(
+    regs: &mut Ac97BusMasterRegs,
+    mem: &GuestMemory,
+    in_buffer: &mut CaptureBuffer,
+) -> CaptureResult<()> {
+    // If the current buffer had any samples in it, mark it as done.
+    if regs.func_regs_mut(Ac97Function::Input).picb > 0 {
+        buffer_completed(regs, mem, Ac97Function::Input)?
+    }
+    let func_regs = regs.func_regs_mut(Ac97Function::Input);
+    if let Some(buffer) = next_guest_buffer(func_regs, mem)? {
+        in_buffer.copy_cb(buffer.size() as usize, |inb| buffer.copy_from(inb))
+    }
+    Ok(())
+}
+
+// Runs, capturing audio from `input_stream` to the guest until stopped or an error occurs.
+fn audio_in_thread(
+    regs: Arc<Mutex<Ac97BusMasterRegs>>,
+    mem: GuestMemory,
+    thread_run: &AtomicBool,
+    mut input_stream: Box<dyn CaptureBufferStream>,
+) -> CaptureResult<()> {
+    while thread_run.load(Ordering::Relaxed) {
+        input_stream
+            .next_capture_buffer()
+            .map_err(CaptureError::StreamError)
+            .and_then(|mut cp_buf| capture_buffer(&mut regs.lock(), &mem, &mut cp_buf))?;
+    }
+    Ok(())
+}
+
+// Update the status register and if any interrupts need to fire, raise them.
+fn update_sr(regs: &mut Ac97BusMasterRegs, func: Ac97Function, val: u16) {
+    let int_mask = match func {
+        Ac97Function::Input => GS_PIINT,
+        Ac97Function::Output => GS_POINT,
+        Ac97Function::Microphone => GS_MINT,
+    };
+
+    let mut interrupt_high = false;
+
+    {
+        let func_regs = regs.func_regs_mut(func);
+        func_regs.sr = val;
+        if val & SR_INT_MASK != 0 {
+            if (val & SR_LVBCI) != 0 && (func_regs.cr & CR_LVBIE) != 0 {
+                interrupt_high = true;
+            }
+            if (val & SR_BCIS) != 0 && (func_regs.cr & CR_IOCE) != 0 {
+                interrupt_high = true;
+            }
+        }
+    }
+
+    if interrupt_high {
+        regs.glob_sta |= int_mask;
+        if let Some(irq_evt) = regs.irq_evt.as_ref() {
+            // Ignore write failure, nothing can be done about it from here.
+            let _ = irq_evt.write(1);
+        }
+    } else {
+        regs.glob_sta &= !int_mask;
+        if regs.glob_sta & (GS_PIINT | GS_POINT | GS_MINT) == 0 {
+            if let Some(irq_evt) = regs.irq_evt.as_ref() {
+                // Ignore write failure, nothing can be done about it from here.
+                let _ = irq_evt.write(0);
+            }
+        }
+    }
+}
+
+// Returns the size in samples of the buffer pointed to by the CIV register.
+fn current_buffer_size(
+    func_regs: &Ac97FunctionRegs,
+    mem: &GuestMemory,
+) -> GuestMemoryResult<usize> {
+    let civ = func_regs.civ;
+    let descriptor_addr = func_regs.bdbar + u32::from(civ) * DESCRIPTOR_LENGTH as u32;
+    let control_reg: u32 = mem
+        .read_obj_from_addr(GuestAddress(u64::from(descriptor_addr) + 4))
+        .map_err(GuestMemoryError::ReadingGuestBufferAddress)?;
+    let buffer_len: usize = control_reg as usize & 0x0000_ffff;
+    Ok(buffer_len)
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    use std::time;
+
+    use audio_streams::DummyStreamSource;
+
+    #[test]
+    fn bm_bdbar() {
+        let mut bm = Ac97BusMaster::new(
+            GuestMemory::new(&[]).expect("Creating guest memory failed."),
+            Box::new(DummyStreamSource::new()),
+        );
+
+        let bdbars = [0x00u64, 0x10, 0x20];
+
+        // Make sure writes have no affect during cold reset.
+        bm.writel(0x00, 0x5555_555f);
+        assert_eq!(bm.readl(0x00), 0x0000_0000);
+
+        // Relesase cold reset.
+        bm.writel(GLOB_CNT_2C, 0x0000_0002);
+
+        // Tests that the base address is writable and that the bottom three bits are read only.
+        for bdbar in &bdbars {
+            assert_eq!(bm.readl(*bdbar), 0x0000_0000);
+            bm.writel(*bdbar, 0x5555_555f);
+            assert_eq!(bm.readl(*bdbar), 0x5555_5558);
+        }
+    }
+
+    #[test]
+    fn bm_status_reg() {
+        let mut bm = Ac97BusMaster::new(
+            GuestMemory::new(&[]).expect("Creating guest memory failed."),
+            Box::new(DummyStreamSource::new()),
+        );
+
+        let sr_addrs = [0x06u64, 0x16, 0x26];
+
+        for sr in &sr_addrs {
+            assert_eq!(bm.readw(*sr), 0x0001);
+            bm.writew(*sr, 0xffff);
+            assert_eq!(bm.readw(*sr), 0x0001);
+        }
+    }
+
+    #[test]
+    fn bm_global_control() {
+        let mut bm = Ac97BusMaster::new(
+            GuestMemory::new(&[]).expect("Creating guest memory failed."),
+            Box::new(DummyStreamSource::new()),
+        );
+
+        assert_eq!(bm.readl(GLOB_CNT_2C), 0x0000_0000);
+
+        // Relesase cold reset.
+        bm.writel(GLOB_CNT_2C, 0x0000_0002);
+
+        // Check interrupt enable bits are writable.
+        bm.writel(GLOB_CNT_2C, 0x0000_0072);
+        assert_eq!(bm.readl(GLOB_CNT_2C), 0x0000_0072);
+
+        // A Warm reset should doesn't affect register state and is auto cleared.
+        bm.writel(0x00, 0x5555_5558);
+        bm.writel(GLOB_CNT_2C, 0x0000_0076);
+        assert_eq!(bm.readl(GLOB_CNT_2C), 0x0000_0072);
+        assert_eq!(bm.readl(0x00), 0x5555_5558);
+        // Check that a cold reset works, but setting bdbar and checking it is zeroed.
+        bm.writel(0x00, 0x5555_555f);
+        bm.writel(GLOB_CNT_2C, 0x000_0070);
+        assert_eq!(bm.readl(GLOB_CNT_2C), 0x0000_0070);
+        assert_eq!(bm.readl(0x00), 0x0000_0000);
+    }
+
+    #[test]
+    fn start_playback() {
+        const LVI_MASK: u8 = 0x1f; // Five bits for 32 total entries.
+        const IOC_MASK: u32 = 0x8000_0000; // Interrupt on completion.
+        let num_buffers = LVI_MASK as usize + 1;
+        const BUFFER_SIZE: usize = 32768;
+        const FRAGMENT_SIZE: usize = BUFFER_SIZE / 2;
+
+        const GUEST_ADDR_BASE: u32 = 0x100_0000;
+        let mem = GuestMemory::new(&[(GuestAddress(GUEST_ADDR_BASE as u64), 1024 * 1024 * 1024)])
+            .expect("Creating guest memory failed.");
+        let mut bm = Ac97BusMaster::new(mem.clone(), Box::new(DummyStreamSource::new()));
+        let mixer = Ac97Mixer::new();
+
+        // Release cold reset.
+        bm.writel(GLOB_CNT_2C, 0x0000_0002);
+
+        // Setup ping-pong buffers. A and B repeating for every possible index.
+        bm.writel(PO_BDBAR_10, GUEST_ADDR_BASE);
+        for i in 0..num_buffers {
+            let pointer_addr = GuestAddress(GUEST_ADDR_BASE as u64 + i as u64 * 8);
+            let control_addr = GuestAddress(GUEST_ADDR_BASE as u64 + i as u64 * 8 + 4);
+            if i % 2 == 0 {
+                mem.write_obj_at_addr(GUEST_ADDR_BASE, pointer_addr)
+                    .expect("Writing guest memory failed.");
+            } else {
+                mem.write_obj_at_addr(GUEST_ADDR_BASE + FRAGMENT_SIZE as u32, pointer_addr)
+                    .expect("Writing guest memory failed.");
+            };
+            mem.write_obj_at_addr(IOC_MASK | (FRAGMENT_SIZE as u32) / 2, control_addr)
+                .expect("Writing guest memory failed.");
+        }
+
+        bm.writeb(PO_LVI_15, LVI_MASK, &mixer);
+
+        // Start.
+        bm.writeb(PO_CR_1B, CR_RPBM, &mixer);
+
+        std::thread::sleep(time::Duration::from_millis(50));
+        let picb = bm.readw(PO_PICB_18);
+        let mut civ = bm.readb(PO_CIV_14);
+        assert_eq!(civ, 0);
+        let pos = (FRAGMENT_SIZE - (picb as usize * 2)) / 4;
+
+        // Check that frames are consumed at least at a reasonable rate.
+        // This wont be exact as during unit tests the thread scheduling is highly variable, so the
+        // test only checks that some samples are consumed.
+        assert!(pos > 1000);
+
+        assert!(bm.readw(PO_SR_16) & SR_DCH == 0); // DMA is running.
+
+        // civ should move eventually.
+        for _i in 0..30 {
+            if civ != 0 {
+                break;
+            }
+            std::thread::sleep(time::Duration::from_millis(20));
+            civ = bm.readb(PO_CIV_14);
+        }
+
+        assert_ne!(0, civ);
+
+        // Buffer complete should be set as the IOC bit was set in the descriptor.
+        assert!(bm.readw(PO_SR_16) & SR_BCIS != 0);
+        // Clear the BCIS bit
+        bm.writew(PO_SR_16, SR_BCIS);
+        assert!(bm.readw(PO_SR_16) & SR_BCIS == 0);
+
+        // Set last valid to the next and wait until it is hit.
+        bm.writeb(PO_LVI_15, civ + 1, &mixer);
+        std::thread::sleep(time::Duration::from_millis(500));
+        assert!(bm.readw(PO_SR_16) & SR_LVBCI != 0); // Hit last buffer
+        assert!(bm.readw(PO_SR_16) & SR_DCH == SR_DCH); // DMA stopped because of lack of buffers.
+        assert_eq!(bm.readb(PO_LVI_15), bm.readb(PO_CIV_14));
+        // Clear the LVB bit
+        bm.writeb(PO_SR_16, SR_LVBCI as u8, &mixer);
+        assert!(bm.readw(PO_SR_16) & SR_LVBCI == 0);
+        // Reset the LVI to the last buffer and check that playback resumes
+        bm.writeb(PO_LVI_15, LVI_MASK, &mixer);
+        assert!(bm.readw(PO_SR_16) & SR_DCH == 0); // DMA restarts.
+
+        let (restart_civ, restart_picb) = (bm.readb(PO_CIV_14), bm.readw(PO_PICB_18));
+        std::thread::sleep(time::Duration::from_millis(20));
+        assert!(bm.readw(PO_PICB_18) != restart_picb || bm.readb(PO_CIV_14) != restart_civ);
+
+        // Stop.
+        bm.writeb(PO_CR_1B, 0, &mixer);
+        assert!(bm.readw(PO_SR_16) & 0x01 != 0); // DMA is not running.
+    }
+
+    #[test]
+    fn start_capture() {
+        const LVI_MASK: u8 = 0x1f; // Five bits for 32 total entries.
+        const IOC_MASK: u32 = 0x8000_0000; // Interrupt on completion.
+        let num_buffers = LVI_MASK as usize + 1;
+        const BUFFER_SIZE: usize = 32768;
+        const FRAGMENT_SIZE: usize = BUFFER_SIZE / 2;
+
+        const GUEST_ADDR_BASE: u32 = 0x100_0000;
+        let mem = GuestMemory::new(&[(GuestAddress(GUEST_ADDR_BASE as u64), 1024 * 1024 * 1024)])
+            .expect("Creating guest memory failed.");
+        let mut bm = Ac97BusMaster::new(mem.clone(), Box::new(DummyStreamSource::new()));
+        let mixer = Ac97Mixer::new();
+
+        // Release cold reset.
+        bm.writel(GLOB_CNT_2C, 0x0000_0002);
+
+        // Setup ping-pong buffers.
+        bm.writel(PI_BDBAR_00, GUEST_ADDR_BASE);
+        for i in 0..num_buffers {
+            let pointer_addr = GuestAddress(GUEST_ADDR_BASE as u64 + i as u64 * 8);
+            let control_addr = GuestAddress(GUEST_ADDR_BASE as u64 + i as u64 * 8 + 4);
+            mem.write_obj_at_addr(GUEST_ADDR_BASE + FRAGMENT_SIZE as u32, pointer_addr)
+                .expect("Writing guest memory failed.");
+            mem.write_obj_at_addr(IOC_MASK | (FRAGMENT_SIZE as u32) / 2, control_addr)
+                .expect("Writing guest memory failed.");
+        }
+
+        bm.writeb(PI_LVI_05, LVI_MASK, &mixer);
+
+        // Start.
+        bm.writeb(PI_CR_0B, CR_RPBM, &mixer);
+        assert_eq!(bm.readw(PI_PICB_08), 0);
+
+        std::thread::sleep(time::Duration::from_millis(50));
+        let picb = bm.readw(PI_PICB_08);
+        assert!(picb > 1000);
+        assert!(bm.readw(PI_SR_06) & SR_DCH == 0); // DMA is running.
+
+        // civ should move eventually.
+        for _i in 0..10 {
+            let civ = bm.readb(PI_CIV_04);
+            if civ != 0 {
+                break;
+            }
+            std::thread::sleep(time::Duration::from_millis(20));
+        }
+        assert_ne!(bm.readb(PI_CIV_04), 0);
+
+        let civ = bm.readb(PI_CIV_04);
+        // Sets LVI to CIV + 1 to trigger last buffer hit
+        bm.writeb(PI_LVI_05, civ + 1, &mixer);
+        std::thread::sleep(time::Duration::from_millis(5000));
+        assert_ne!(bm.readw(PI_SR_06) & SR_LVBCI, 0); // Hit last buffer
+        assert_eq!(bm.readw(PI_SR_06) & SR_DCH, SR_DCH); // DMA stopped because of lack of buffers.
+        assert_eq!(bm.readb(PI_LVI_05), bm.readb(PI_CIV_04));
+
+        // Clear the LVB bit
+        bm.writeb(PI_SR_06, SR_LVBCI as u8, &mixer);
+        assert!(bm.readw(PI_SR_06) & SR_LVBCI == 0);
+        // Reset the LVI to the last buffer and check that playback resumes
+        bm.writeb(PI_LVI_05, LVI_MASK, &mixer);
+        assert!(bm.readw(PI_SR_06) & SR_DCH == 0); // DMA restarts.
+
+        let restart_civ = bm.readb(PI_CIV_04);
+        std::thread::sleep(time::Duration::from_millis(200));
+        assert_ne!(bm.readb(PI_CIV_04), restart_civ);
+
+        // Stop.
+        bm.writeb(PI_CR_0B, 0, &mixer);
+        assert!(bm.readw(PI_SR_06) & 0x01 != 0); // DMA is not running.
+    }
+}
diff --git a/devices/src/pci/ac97_mixer.rs b/devices/src/pci/ac97_mixer.rs
new file mode 100644
index 0000000..8c8e192
--- /dev/null
+++ b/devices/src/pci/ac97_mixer.rs
@@ -0,0 +1,164 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::pci::ac97_regs::*;
+
+// AC97 Vendor ID
+const AC97_VENDOR_ID1: u16 = 0x8086;
+const AC97_VENDOR_ID2: u16 = 0x8086;
+
+// Master volume register is specified in 1.5dB steps.
+const MASTER_VOLUME_STEP_DB: f64 = 1.5;
+
+/// `Ac97Mixer` holds the mixer state for the AC97 bus.
+/// The mixer is used by calling the `readb`/`readw`/`readl` functions to read register values and
+/// the `writeb`/`writew`/`writel` functions to set register values.
+pub struct Ac97Mixer {
+    // Mixer Registers
+    master_volume_l: u8,
+    master_volume_r: u8,
+    master_mute: bool,
+    mic_muted: bool,
+    mic_20db: bool,
+    mic_volume: u8,
+    record_gain_l: u8,
+    record_gain_r: u8,
+    record_gain_mute: bool,
+    pcm_out_vol_l: u16,
+    pcm_out_vol_r: u16,
+    pcm_out_mute: bool,
+    power_down_control: u16,
+}
+
+impl Ac97Mixer {
+    /// Creates an 'Ac97Mixer' with the standard default register values.
+    pub fn new() -> Self {
+        Ac97Mixer {
+            master_volume_l: 0,
+            master_volume_r: 0,
+            master_mute: true,
+            mic_muted: true,
+            mic_20db: false,
+            mic_volume: 0x8,
+            record_gain_l: 0,
+            record_gain_r: 0,
+            record_gain_mute: true,
+            pcm_out_vol_l: 0x8,
+            pcm_out_vol_r: 0x8,
+            pcm_out_mute: true,
+            power_down_control: PD_REG_STATUS_MASK, // Report everything is ready.
+        }
+    }
+
+    /// Reads a word from the register at `offset`.
+    pub fn readw(&self, offset: u64) -> u16 {
+        match offset {
+            MIXER_MASTER_VOL_MUTE_02 => self.get_master_reg(),
+            MIXER_MIC_VOL_MUTE_0E => self.get_mic_volume(),
+            MIXER_PCM_OUT_VOL_MUTE_18 => self.get_pcm_out_volume(),
+            MIXER_REC_VOL_MUTE_1C => self.get_record_gain_reg(),
+            MIXER_POWER_DOWN_CONTROL_26 => self.power_down_control,
+            MIXER_VENDOR_ID1_7C => AC97_VENDOR_ID1,
+            MIXER_VENDOR_ID2_7E => AC97_VENDOR_ID2,
+            _ => 0,
+        }
+    }
+
+    /// Writes a word `val` to the register `offset`.
+    pub fn writew(&mut self, offset: u64, val: u16) {
+        match offset {
+            MIXER_MASTER_VOL_MUTE_02 => self.set_master_reg(val),
+            MIXER_MIC_VOL_MUTE_0E => self.set_mic_volume(val),
+            MIXER_PCM_OUT_VOL_MUTE_18 => self.set_pcm_out_volume(val),
+            MIXER_REC_VOL_MUTE_1C => self.set_record_gain_reg(val),
+            MIXER_POWER_DOWN_CONTROL_26 => self.set_power_down_reg(val),
+            _ => (),
+        }
+    }
+
+    /// Returns the mute status and left and right attenuation from the master volume register.
+    pub fn get_master_volume(&self) -> (bool, f64, f64) {
+        (
+            self.master_mute,
+            f64::from(self.master_volume_l) * MASTER_VOLUME_STEP_DB,
+            f64::from(self.master_volume_r) * MASTER_VOLUME_STEP_DB,
+        )
+    }
+
+    // Returns the master mute and l/r volumes (reg 0x02).
+    fn get_master_reg(&self) -> u16 {
+        let reg = (u16::from(self.master_volume_l)) << 8 | u16::from(self.master_volume_r);
+        if self.master_mute {
+            reg | MUTE_REG_BIT
+        } else {
+            reg
+        }
+    }
+
+    // Handles writes to the master register (0x02).
+    fn set_master_reg(&mut self, val: u16) {
+        self.master_mute = val & MUTE_REG_BIT != 0;
+        self.master_volume_r = (val & VOL_REG_MASK) as u8;
+        self.master_volume_l = (val >> 8 & VOL_REG_MASK) as u8;
+    }
+
+    // Returns the value read in the Mic volume register (0x0e).
+    fn get_mic_volume(&self) -> u16 {
+        let mut reg = u16::from(self.mic_volume);
+        if self.mic_muted {
+            reg |= MUTE_REG_BIT;
+        }
+        if self.mic_20db {
+            reg |= MIXER_MIC_20DB;
+        }
+        reg
+    }
+
+    // Sets the mic input mute, boost, and volume settings (0x0e).
+    fn set_mic_volume(&mut self, val: u16) {
+        self.mic_volume = (val & MIXER_VOL_MASK) as u8;
+        self.mic_muted = val & MUTE_REG_BIT != 0;
+        self.mic_20db = val & MIXER_MIC_20DB != 0;
+    }
+
+    // Returns the value read in the Mic volume register (0x18).
+    fn get_pcm_out_volume(&self) -> u16 {
+        let reg = (self.pcm_out_vol_l as u16) << 8 | self.pcm_out_vol_r as u16;
+        if self.pcm_out_mute {
+            reg | MUTE_REG_BIT
+        } else {
+            reg
+        }
+    }
+
+    // Sets the pcm output mute and volume states (0x18).
+    fn set_pcm_out_volume(&mut self, val: u16) {
+        self.pcm_out_vol_r = val & MIXER_VOL_MASK;
+        self.pcm_out_vol_l = (val >> MIXER_VOL_LEFT_SHIFT) & MIXER_VOL_MASK;
+        self.pcm_out_mute = val & MUTE_REG_BIT != 0;
+    }
+
+    // Returns the record gain register (0x01c).
+    fn get_record_gain_reg(&self) -> u16 {
+        let reg = u16::from(self.record_gain_l) << 8 | u16::from(self.record_gain_r);
+        if self.record_gain_mute {
+            reg | MUTE_REG_BIT
+        } else {
+            reg
+        }
+    }
+
+    // Handles writes to the record_gain register (0x1c).
+    fn set_record_gain_reg(&mut self, val: u16) {
+        self.record_gain_mute = val & MUTE_REG_BIT != 0;
+        self.record_gain_r = (val & VOL_REG_MASK) as u8;
+        self.record_gain_l = (val >> 8 & VOL_REG_MASK) as u8;
+    }
+
+    // Handles writes to the powerdown ctrl/status register (0x26).
+    fn set_power_down_reg(&mut self, val: u16) {
+        self.power_down_control =
+            (val & !PD_REG_STATUS_MASK) | (self.power_down_control & PD_REG_STATUS_MASK);
+    }
+}
diff --git a/devices/src/pci/ac97_regs.rs b/devices/src/pci/ac97_regs.rs
new file mode 100644
index 0000000..bcca05b
--- /dev/null
+++ b/devices/src/pci/ac97_regs.rs
@@ -0,0 +1,247 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![allow(dead_code)]
+
+// Audio Mixer Registers
+// 00h Reset
+// 02h Master Volume Mute
+// 04h Headphone Volume Mute
+// 06h Master Volume Mono Mute
+// 08h Master Tone (R & L)
+// 0Ah PC_BEEP Volume Mute
+// 0Ch Phone Volume Mute
+// 0Eh Mic Volume Mute
+// 10h Line In Volume Mute
+// 12h CD Volume Mute
+// 14h Video Volume Mute
+// 16h Aux Volume Mute
+// 18h PCM Out Volume Mute
+// 1Ah Record Select
+// 1Ch Record Gain Mute
+// 1Eh Record Gain Mic Mute
+// 20h General Purpose
+// 22h 3D Control
+// 24h AC’97 RESERVED
+// 26h Powerdown Ctrl/Stat
+// 28h Extended Audio
+// 2Ah Extended Audio Ctrl/Stat
+
+// Size of IO register regions
+pub const MIXER_REGS_SIZE: u64 = 0x100;
+pub const MASTER_REGS_SIZE: u64 = 0x400;
+
+pub const MIXER_MASTER_VOL_MUTE_02: u64 = 0x02;
+pub const MIXER_MIC_VOL_MUTE_0E: u64 = 0x0e;
+pub const MIXER_PCM_OUT_VOL_MUTE_18: u64 = 0x18;
+pub const MIXER_REC_VOL_MUTE_1C: u64 = 0x1c;
+pub const MIXER_POWER_DOWN_CONTROL_26: u64 = 0x26;
+pub const MIXER_VENDOR_ID1_7C: u64 = 0x7c;
+pub const MIXER_VENDOR_ID2_7E: u64 = 0x7e;
+
+// Bus Master regs from ICH spec:
+// 00h PI_BDBAR PCM In Buffer Descriptor list Base Address Register
+// 04h PI_CIV PCM In Current Index Value
+// 05h PI_LVI PCM In Last Valid Index
+// 06h PI_SR PCM In Status Register
+// 08h PI_PICB PCM In Position In Current Buffer
+// 0Ah PI_PIV PCM In Prefetched Index Value
+// 0Bh PI_CR PCM In Control Register
+// 10h PO_BDBAR PCM Out Buffer Descriptor list Base Address Register
+// 14h PO_CIV PCM Out Current Index Value
+// 15h PO_LVI PCM Out Last Valid Index
+// 16h PO_SR PCM Out Status Register
+// 18h PO_PICB PCM Out Position In Current Buffer
+// 1Ah PO_PIV PCM Out Prefetched Index Value
+// 1Bh PO_CR PCM Out Control Register
+// 20h MC_BDBAR Mic. In Buffer Descriptor list Base Address Register
+// 24h PM_CIV Mic. In Current Index Value
+// 25h MC_LVI Mic. In Last Valid Index
+// 26h MC_SR Mic. In Status Register
+// 28h MC_PICB Mic In Position In Current Buffer
+// 2Ah MC_PIV Mic. In Prefetched Index Value
+// 2Bh MC_CR Mic. In Control Register
+// 2Ch GLOB_CNT Global Control
+// 30h GLOB_STA Global Status
+// 34h ACC_SEMA Codec Write Semaphore Register
+
+// Global Control
+pub const GLOB_CNT_2C: u64 = 0x2C;
+pub const GLOB_CNT_COLD_RESET: u32 = 0x0000_0002;
+pub const GLOB_CNT_WARM_RESET: u32 = 0x0000_0004;
+pub const GLOB_CNT_STABLE_BITS: u32 = 0x0000_007f; // Bits not affected by reset.
+
+// Global status
+pub const GLOB_STA_30: u64 = 0x30;
+pub const GLOB_STA_RESET_VAL: u32 = 0x0000_0100; // primary codec ready set.
+                                                 // glob_sta bits
+pub const GS_MD3: u32 = 1 << 17;
+pub const GS_AD3: u32 = 1 << 16;
+pub const GS_RCS: u32 = 1 << 15;
+pub const GS_B3S12: u32 = 1 << 14;
+pub const GS_B2S12: u32 = 1 << 13;
+pub const GS_B1S12: u32 = 1 << 12;
+pub const GS_S1R1: u32 = 1 << 11;
+pub const GS_S0R1: u32 = 1 << 10;
+pub const GS_S1CR: u32 = 1 << 9;
+pub const GS_S0CR: u32 = 1 << 8;
+pub const GS_MINT: u32 = 1 << 7;
+pub const GS_POINT: u32 = 1 << 6;
+pub const GS_PIINT: u32 = 1 << 5;
+pub const GS_RSRVD: u32 = 1 << 4 | 1 << 3;
+pub const GS_MOINT: u32 = 1 << 2;
+pub const GS_MIINT: u32 = 1 << 1;
+pub const GS_GSCI: u32 = 1;
+pub const GS_RO_MASK: u32 = GS_B3S12
+    | GS_B2S12
+    | GS_B1S12
+    | GS_S1CR
+    | GS_S0CR
+    | GS_MINT
+    | GS_POINT
+    | GS_PIINT
+    | GS_RSRVD
+    | GS_MOINT
+    | GS_MIINT;
+pub const GS_VALID_MASK: u32 = 0x0003_ffff;
+pub const GS_WCLEAR_MASK: u32 = GS_RCS | GS_S1R1 | GS_S0R1 | GS_GSCI;
+
+pub const ACC_SEMA_34: u64 = 0x34;
+
+// Audio funciton registers.
+pub const CIV_OFFSET: u64 = 0x04;
+pub const LVI_OFFSET: u64 = 0x05;
+pub const SR_OFFSET: u64 = 0x06;
+pub const PICB_OFFSET: u64 = 0x08;
+pub const PIV_OFFSET: u64 = 0x0a;
+pub const CR_OFFSET: u64 = 0x0b;
+
+// Capture
+pub const PI_BASE_00: u64 = 0x00;
+pub const PI_BDBAR_00: u64 = PI_BASE_00;
+pub const PI_CIV_04: u64 = PI_BASE_00 + CIV_OFFSET;
+pub const PI_LVI_05: u64 = PI_BASE_00 + LVI_OFFSET;
+pub const PI_SR_06: u64 = PI_BASE_00 + SR_OFFSET;
+pub const PI_PICB_08: u64 = PI_BASE_00 + PICB_OFFSET;
+pub const PI_PIV_0A: u64 = PI_BASE_00 + PIV_OFFSET;
+pub const PI_CR_0B: u64 = PI_BASE_00 + CR_OFFSET;
+
+// Play Out
+pub const PO_BASE_10: u64 = 0x10;
+pub const PO_BDBAR_10: u64 = PO_BASE_10;
+pub const PO_CIV_14: u64 = PO_BASE_10 + CIV_OFFSET;
+pub const PO_LVI_15: u64 = PO_BASE_10 + LVI_OFFSET;
+pub const PO_SR_16: u64 = PO_BASE_10 + SR_OFFSET;
+pub const PO_PICB_18: u64 = PO_BASE_10 + PICB_OFFSET;
+pub const PO_PIV_1A: u64 = PO_BASE_10 + PIV_OFFSET;
+pub const PO_CR_1B: u64 = PO_BASE_10 + CR_OFFSET;
+
+// Microphone
+pub const MC_BASE_20: u64 = 0x20;
+pub const MC_BDBAR_20: u64 = MC_BASE_20;
+pub const MC_CIV_24: u64 = MC_BASE_20 + CIV_OFFSET;
+pub const MC_LVI_25: u64 = MC_BASE_20 + LVI_OFFSET;
+pub const MC_SR_26: u64 = MC_BASE_20 + SR_OFFSET;
+pub const MC_PICB_28: u64 = MC_BASE_20 + PICB_OFFSET;
+pub const MC_PIV_2A: u64 = MC_BASE_20 + PIV_OFFSET;
+pub const MC_CR_2B: u64 = MC_BASE_20 + CR_OFFSET;
+
+// Status Register Bits.
+pub const SR_DCH: u16 = 0x01;
+pub const SR_CELV: u16 = 0x02;
+pub const SR_LVBCI: u16 = 0x04;
+pub const SR_BCIS: u16 = 0x08;
+pub const SR_FIFOE: u16 = 0x10;
+pub const SR_VALID_MASK: u16 = 0x1f;
+pub const SR_WCLEAR_MASK: u16 = SR_FIFOE | SR_BCIS | SR_LVBCI;
+pub const SR_RO_MASK: u16 = SR_DCH | SR_CELV;
+pub const SR_INT_MASK: u16 = SR_BCIS | SR_LVBCI;
+
+// Control Register Bits.
+pub const CR_RPBM: u8 = 0x01;
+pub const CR_RR: u8 = 0x02;
+pub const CR_LVBIE: u8 = 0x04;
+pub const CR_FEIE: u8 = 0x08;
+pub const CR_IOCE: u8 = 0x10;
+pub const CR_VALID_MASK: u8 = 0x1f;
+pub const CR_DONT_CLEAR_MASK: u8 = CR_IOCE | CR_FEIE | CR_LVBIE;
+
+// Mixer register bits
+pub const MUTE_REG_BIT: u16 = 0x8000;
+pub const VOL_REG_MASK: u16 = 0x003f;
+pub const MIXER_VOL_MASK: u16 = 0x001f;
+pub const MIXER_VOL_LEFT_SHIFT: usize = 8;
+pub const MIXER_MIC_20DB: u16 = 0x0040;
+// Powerdown reg
+pub const PD_REG_STATUS_MASK: u16 = 0x000f;
+pub const PD_REG_OUTPUT_MUTE_MASK: u16 = 0xb200;
+pub const PD_REG_INPUT_MUTE_MASK: u16 = 0x0d00;
+
+// Buffer descriptors are four bytes of pointer and 4 bytes of control/length.
+pub const DESCRIPTOR_LENGTH: usize = 8;
+pub const BD_IOC: u32 = 1 << 31;
+
+/// The functions that are supported by the Ac97 subsystem.
+#[derive(Copy, Clone)]
+pub enum Ac97Function {
+    Input,
+    Output,
+    Microphone,
+}
+
+/// Registers for individual audio functions.
+/// Each audio function in Ac97 gets a set of these registers.
+#[derive(Clone, Default)]
+pub struct Ac97FunctionRegs {
+    pub bdbar: u32,
+    pub civ: u8,
+    pub lvi: u8,
+    pub sr: u16,
+    pub picb: u16,
+    pub piv: u8,
+    pub cr: u8,
+}
+
+impl Ac97FunctionRegs {
+    /// Creates a new set of function registers, these can be used for the capture, playback, or
+    /// microphone functions.
+    pub fn new() -> Self {
+        let mut regs = Ac97FunctionRegs {
+            sr: SR_DCH,
+            ..Default::default()
+        };
+        regs.do_reset();
+        regs
+    }
+
+    /// Reset all the registers to the PoR defaults.
+    pub fn do_reset(&mut self) {
+        self.bdbar = 0;
+        self.civ = 0;
+        self.lvi = 0;
+        self.sr = SR_DCH;
+        self.picb = 0;
+        self.piv = 0;
+        self.cr &= CR_DONT_CLEAR_MASK;
+    }
+
+    /// Read register 4, 5, and 6 as one 32 bit word.
+    /// According to the ICH spec, reading these three with one 32 bit access is allowed.
+    pub fn atomic_status_regs(&self) -> u32 {
+        u32::from(self.civ) | u32::from(self.lvi) << 8 | u32::from(self.sr) << 16
+    }
+
+    /// Returns the mask for enabled interrupts. The returned mask represents the bits in the status
+    /// register that should trigger and interrupt.
+    pub fn int_mask(&self) -> u16 {
+        let mut int_mask = 0;
+        if self.cr & CR_LVBIE != 0 {
+            int_mask |= SR_LVBCI;
+        }
+        if self.cr & CR_IOCE != 0 {
+            int_mask |= SR_BCIS;
+        }
+        int_mask
+    }
+}
diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs
new file mode 100644
index 0000000..791161a
--- /dev/null
+++ b/devices/src/pci/mod.rs
@@ -0,0 +1,38 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Implements pci devices and busses.
+
+mod ac97;
+mod ac97_bus_master;
+mod ac97_mixer;
+mod ac97_regs;
+mod pci_configuration;
+mod pci_device;
+mod pci_root;
+
+pub use self::ac97::Ac97Dev;
+pub use self::pci_configuration::{
+    PciBarConfiguration, PciBarPrefetchable, PciBarRegionType, PciCapability, PciCapabilityID,
+    PciClassCode, PciConfiguration, PciHeaderType, PciProgrammingInterface, PciSerialBusSubClass,
+    PciSubclass,
+};
+pub use self::pci_device::Error as PciDeviceError;
+pub use self::pci_device::PciDevice;
+pub use self::pci_root::{PciConfigIo, PciConfigMmio, PciRoot};
+
+/// PCI has four interrupt pins A->D.
+#[derive(Copy, Clone)]
+pub enum PciInterruptPin {
+    IntA,
+    IntB,
+    IntC,
+    IntD,
+}
+
+impl PciInterruptPin {
+    pub fn to_mask(self) -> u32 {
+        self as u32
+    }
+}
diff --git a/devices/src/pci/pci_configuration.rs b/devices/src/pci/pci_configuration.rs
new file mode 100644
index 0000000..ab969f7
--- /dev/null
+++ b/devices/src/pci/pci_configuration.rs
@@ -0,0 +1,623 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fmt::{self, Display};
+
+use crate::pci::PciInterruptPin;
+use sys_util::warn;
+
+// The number of 32bit registers in the config space, 256 bytes.
+const NUM_CONFIGURATION_REGISTERS: usize = 64;
+
+const STATUS_REG: usize = 1;
+const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
+const BAR0_REG: usize = 4;
+const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
+const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
+const NUM_BAR_REGS: usize = 6;
+const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34;
+const FIRST_CAPABILITY_OFFSET: usize = 0x40;
+const CAPABILITY_MAX_OFFSET: usize = 192;
+
+const INTERRUPT_LINE_PIN_REG: usize = 15;
+
+/// Represents the types of PCI headers allowed in the configuration registers.
+#[derive(Copy, Clone)]
+pub enum PciHeaderType {
+    Device,
+    Bridge,
+}
+
+/// Classes of PCI nodes.
+#[allow(dead_code)]
+#[derive(Copy, Clone)]
+pub enum PciClassCode {
+    TooOld,
+    MassStorage,
+    NetworkController,
+    DisplayController,
+    MultimediaController,
+    MemoryController,
+    BridgeDevice,
+    SimpleCommunicationController,
+    BaseSystemPeripheral,
+    InputDevice,
+    DockingStation,
+    Processor,
+    SerialBusController,
+    WirelessController,
+    IntelligentIoController,
+    EncryptionController,
+    DataAcquisitionSignalProcessing,
+    Other = 0xff,
+}
+
+impl PciClassCode {
+    pub fn get_register_value(&self) -> u8 {
+        *self as u8
+    }
+}
+
+/// A PCI sublcass. Each class in `PciClassCode` can specify a unique set of subclasses. This trait
+/// is implemented by each subclass. It allows use of a trait object to generate configurations.
+pub trait PciSubclass {
+    /// Convert this subclass to the value used in the PCI specification.
+    fn get_register_value(&self) -> u8;
+}
+
+/// Subclasses of the MultimediaController class.
+#[allow(dead_code)]
+#[derive(Copy, Clone)]
+pub enum PciMultimediaSubclass {
+    VideoController = 0x00,
+    AudioController = 0x01,
+    TelephonyDevice = 0x02,
+    AudioDevice = 0x03,
+    Other = 0x80,
+}
+
+impl PciSubclass for PciMultimediaSubclass {
+    fn get_register_value(&self) -> u8 {
+        *self as u8
+    }
+}
+
+/// Subclasses of the BridgeDevice
+#[allow(dead_code)]
+#[derive(Copy, Clone)]
+pub enum PciBridgeSubclass {
+    HostBridge = 0x00,
+    IsaBridge = 0x01,
+    EisaBridge = 0x02,
+    McaBridge = 0x03,
+    PciToPciBridge = 0x04,
+    PcmciaBridge = 0x05,
+    NuBusBridge = 0x06,
+    CardBusBridge = 0x07,
+    RACEwayBridge = 0x08,
+    PciToPciSemiTransparentBridge = 0x09,
+    InfiniBrandToPciHostBridge = 0x0a,
+    OtherBridgeDevice = 0x80,
+}
+
+impl PciSubclass for PciBridgeSubclass {
+    fn get_register_value(&self) -> u8 {
+        *self as u8
+    }
+}
+
+/// Subclass of the SerialBus
+#[allow(dead_code)]
+#[derive(Copy, Clone)]
+pub enum PciSerialBusSubClass {
+    Firewire = 0x00,
+    ACCESSbus = 0x01,
+    SSA = 0x02,
+    USB = 0x03,
+}
+
+impl PciSubclass for PciSerialBusSubClass {
+    fn get_register_value(&self) -> u8 {
+        *self as u8
+    }
+}
+
+/// A PCI class programming interface. Each combination of `PciClassCode` and
+/// `PciSubclass` can specify a set of register-level programming interfaces.
+/// This trait is implemented by each programming interface.
+/// It allows use of a trait object to generate configurations.
+pub trait PciProgrammingInterface {
+    /// Convert this programming interface to the value used in the PCI specification.
+    fn get_register_value(&self) -> u8;
+}
+
+/// Types of PCI capabilities.
+pub enum PciCapabilityID {
+    ListID = 0,
+    PowerManagement = 0x01,
+    AcceleratedGraphicsPort = 0x02,
+    VitalProductData = 0x03,
+    SlotIdentification = 0x04,
+    MessageSignalledInterrupts = 0x05,
+    CompactPCIHotSwap = 0x06,
+    PCIX = 0x07,
+    HyperTransport = 0x08,
+    VendorSpecific = 0x09,
+    Debugport = 0x0A,
+    CompactPCICentralResourceControl = 0x0B,
+    PCIStandardHotPlugController = 0x0C,
+    BridgeSubsystemVendorDeviceID = 0x0D,
+    AGPTargetPCIPCIbridge = 0x0E,
+    SecureDevice = 0x0F,
+    PCIExpress = 0x10,
+    MSIX = 0x11,
+    SATADataIndexConf = 0x12,
+    PCIAdvancedFeatures = 0x13,
+    PCIEnhancedAllocation = 0x14,
+}
+
+/// A PCI capability list. Devices can optionally specify capabilities in their configuration space.
+pub trait PciCapability {
+    fn bytes(&self) -> &[u8];
+    fn id(&self) -> PciCapabilityID;
+}
+
+/// Contains the configuration space of a PCI node.
+/// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space).
+/// The configuration space is accessed with DWORD reads and writes from the guest.
+pub struct PciConfiguration {
+    registers: [u32; NUM_CONFIGURATION_REGISTERS],
+    writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register.
+    bar_used: [bool; NUM_BAR_REGS],
+    // Contains the byte offset and size of the last capability.
+    last_capability: Option<(usize, usize)>,
+}
+
+/// See pci_regs.h in kernel
+#[derive(Copy, Clone)]
+pub enum PciBarRegionType {
+    Memory32BitRegion = 0,
+    IORegion = 0x01,
+    Memory64BitRegion = 0x04,
+}
+
+#[derive(Copy, Clone)]
+pub enum PciBarPrefetchable {
+    NotPrefetchable = 0,
+    Prefetchable = 0x08,
+}
+
+#[derive(Copy, Clone)]
+pub struct PciBarConfiguration {
+    addr: u64,
+    size: u64,
+    reg_idx: usize,
+    region_type: PciBarRegionType,
+    prefetchable: PciBarPrefetchable,
+}
+
+#[derive(Debug)]
+pub enum Error {
+    BarAddressInvalid(u64, u64),
+    BarInUse(usize),
+    BarInUse64(usize),
+    BarInvalid(usize),
+    BarInvalid64(usize),
+    BarSizeInvalid(u64),
+    CapabilityEmpty,
+    CapabilityLengthInvalid(usize),
+    CapabilitySpaceFull(usize),
+}
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+        match self {
+            BarAddressInvalid(a, s) => write!(f, "address {} size {} too big", a, s),
+            BarInUse(b) => write!(f, "bar {} already used", b),
+            BarInUse64(b) => write!(f, "64bit bar {} already used(requires two regs)", b),
+            BarInvalid(b) => write!(f, "bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
+            BarInvalid64(b) => write!(
+                f,
+                "64bitbar {} invalid, requires two regs, max {}",
+                b,
+                NUM_BAR_REGS - 1
+            ),
+            BarSizeInvalid(s) => write!(f, "bar address {} not a power of two", s),
+            CapabilityEmpty => write!(f, "empty capabilities are invalid"),
+            CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {}", l),
+            CapabilitySpaceFull(s) => write!(f, "capability of size {} doesn't fit", s),
+        }
+    }
+}
+
+impl PciConfiguration {
+    pub fn new(
+        vendor_id: u16,
+        device_id: u16,
+        class_code: PciClassCode,
+        subclass: &dyn PciSubclass,
+        programming_interface: Option<&dyn PciProgrammingInterface>,
+        header_type: PciHeaderType,
+        subsystem_vendor_id: u16,
+        subsystem_id: u16,
+    ) -> Self {
+        let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
+        let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
+        registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
+        // TODO(dverkamp): Status should be write-1-to-clear
+        writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
+        let pi = if let Some(pi) = programming_interface {
+            pi.get_register_value()
+        } else {
+            0
+        };
+        registers[2] = u32::from(class_code.get_register_value()) << 24
+            | u32::from(subclass.get_register_value()) << 16
+            | u32::from(pi) << 8;
+        writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w)
+        match header_type {
+            PciHeaderType::Device => {
+                registers[3] = 0x0000_0000; // Header type 0 (device)
+                writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w)
+            }
+            PciHeaderType::Bridge => {
+                registers[3] = 0x0001_0000; // Header type 1 (bridge)
+                writable_bits[9] = 0xfff0_fff0; // Memory base and limit
+                writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
+            }
+        };
+        registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
+
+        PciConfiguration {
+            registers,
+            writable_bits,
+            bar_used: [false; NUM_BAR_REGS],
+            last_capability: None,
+        }
+    }
+
+    /// Reads a 32bit register from `reg_idx` in the register map.
+    pub fn read_reg(&self, reg_idx: usize) -> u32 {
+        *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff))
+    }
+
+    /// Writes a 32bit register to `reg_idx` in the register map.
+    pub fn write_reg(&mut self, reg_idx: usize, value: u32) {
+        if let Some(r) = self.registers.get_mut(reg_idx) {
+            *r = value & self.writable_bits[reg_idx];
+        } else {
+            warn!("bad PCI register write {}", reg_idx);
+        }
+    }
+
+    /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned.
+    pub fn write_word(&mut self, offset: usize, value: u16) {
+        let shift = match offset % 4 {
+            0 => 0,
+            2 => 16,
+            _ => {
+                warn!("bad PCI config write offset {}", offset);
+                return;
+            }
+        };
+        let reg_idx = offset / 4;
+
+        if let Some(r) = self.registers.get_mut(reg_idx) {
+            let writable_mask = self.writable_bits[reg_idx];
+            let mask = (0xffffu32 << shift) & writable_mask;
+            let shifted_value = (u32::from(value) << shift) & writable_mask;
+            *r = *r & !mask | shifted_value;
+        } else {
+            warn!("bad PCI config write offset {}", offset);
+        }
+    }
+
+    /// Writes a byte to `offset`.
+    pub fn write_byte(&mut self, offset: usize, value: u8) {
+        self.write_byte_internal(offset, value, true);
+    }
+
+    /// Writes a byte to `offset`, optionally enforcing read-only bits.
+    fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) {
+        let shift = (offset % 4) * 8;
+        let reg_idx = offset / 4;
+
+        if let Some(r) = self.registers.get_mut(reg_idx) {
+            let writable_mask = if apply_writable_mask {
+                self.writable_bits[reg_idx]
+            } else {
+                0xffff_ffff
+            };
+            let mask = (0xffu32 << shift) & writable_mask;
+            let shifted_value = (u32::from(value) << shift) & writable_mask;
+            *r = *r & !mask | shifted_value;
+        } else {
+            warn!("bad PCI config write offset {}", offset);
+        }
+    }
+
+    /// Adds a region specified by `config`.  Configures the specified BAR(s) to
+    /// report this region and size to the guest kernel.  Enforces a few constraints
+    /// (i.e, region size must be power of two, register not already used). Returns 'None' on
+    /// failure all, `Some(BarIndex)` on success.
+    pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<usize> {
+        if self.bar_used[config.reg_idx] {
+            return Err(Error::BarInUse(config.reg_idx));
+        }
+
+        if config.size.count_ones() != 1 {
+            return Err(Error::BarSizeInvalid(config.size));
+        }
+
+        if config.reg_idx >= NUM_BAR_REGS {
+            return Err(Error::BarInvalid(config.reg_idx));
+        }
+
+        let bar_idx = BAR0_REG + config.reg_idx;
+        let end_addr = config
+            .addr
+            .checked_add(config.size)
+            .ok_or(Error::BarAddressInvalid(config.addr, config.size))?;
+        match config.region_type {
+            PciBarRegionType::Memory32BitRegion | PciBarRegionType::IORegion => {
+                if end_addr > u64::from(u32::max_value()) {
+                    return Err(Error::BarAddressInvalid(config.addr, config.size));
+                }
+            }
+            PciBarRegionType::Memory64BitRegion => {
+                if config.reg_idx + 1 >= NUM_BAR_REGS {
+                    return Err(Error::BarInvalid64(config.reg_idx));
+                }
+
+                if end_addr > u64::max_value() {
+                    return Err(Error::BarAddressInvalid(config.addr, config.size));
+                }
+
+                if self.bar_used[config.reg_idx + 1] {
+                    return Err(Error::BarInUse64(config.reg_idx));
+                }
+
+                self.registers[bar_idx + 1] = (config.addr >> 32) as u32;
+                self.writable_bits[bar_idx + 1] = !((config.size >> 32).wrapping_sub(1)) as u32;
+                self.bar_used[config.reg_idx + 1] = true;
+            }
+        }
+
+        let (mask, lower_bits) = match config.region_type {
+            PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => (
+                BAR_MEM_ADDR_MASK,
+                config.prefetchable as u32 | config.region_type as u32,
+            ),
+            PciBarRegionType::IORegion => (BAR_IO_ADDR_MASK, config.region_type as u32),
+        };
+
+        self.registers[bar_idx] = ((config.addr as u32) & mask) | lower_bits;
+        self.writable_bits[bar_idx] = !(config.size - 1) as u32;
+        self.bar_used[config.reg_idx] = true;
+        Ok(config.reg_idx)
+    }
+
+    /// Returns the address of the given BAR region.
+    pub fn get_bar_addr(&self, bar_num: usize) -> u32 {
+        let bar_idx = BAR0_REG + bar_num;
+
+        self.registers[bar_idx] & BAR_MEM_ADDR_MASK
+    }
+
+    /// Configures the IRQ line and pin used by this device.
+    pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) {
+        // `pin` is 1-based in the pci config space.
+        let pin_idx = (pin as u32) + 1;
+        self.registers[INTERRUPT_LINE_PIN_REG] = (self.registers[INTERRUPT_LINE_PIN_REG]
+            & 0xffff_0000)
+            | (pin_idx << 8)
+            | u32::from(line);
+    }
+
+    /// Adds the capability `cap_data` to the list of capabilities.
+    /// `cap_data` should include the two-byte PCI capability header (type, next),
+    /// but not populate it. Correct values will be generated automatically based
+    /// on `cap_data.id()`.
+    pub fn add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize> {
+        let total_len = cap_data.bytes().len();
+        // Check that the length is valid.
+        if cap_data.bytes().is_empty() {
+            return Err(Error::CapabilityEmpty);
+        }
+        let (cap_offset, tail_offset) = match self.last_capability {
+            Some((offset, len)) => (Self::next_dword(offset, len), offset + 1),
+            None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET),
+        };
+        let end_offset = cap_offset
+            .checked_add(total_len)
+            .ok_or(Error::CapabilitySpaceFull(total_len))?;
+        if end_offset > CAPABILITY_MAX_OFFSET {
+            return Err(Error::CapabilitySpaceFull(total_len));
+        }
+        self.registers[STATUS_REG] |= STATUS_REG_CAPABILITIES_USED_MASK;
+        self.write_byte_internal(tail_offset, cap_offset as u8, false);
+        self.write_byte_internal(cap_offset, cap_data.id() as u8, false);
+        self.write_byte_internal(cap_offset + 1, 0, false); // Next pointer.
+        for (i, byte) in cap_data.bytes().iter().enumerate().skip(2) {
+            self.write_byte_internal(cap_offset + i, *byte, false);
+        }
+        self.last_capability = Some((cap_offset, total_len));
+        Ok(cap_offset)
+    }
+
+    // Find the next aligned offset after the one given.
+    fn next_dword(offset: usize, len: usize) -> usize {
+        let next = offset + len;
+        (next + 3) & !3
+    }
+}
+
+impl Default for PciBarConfiguration {
+    fn default() -> Self {
+        PciBarConfiguration {
+            reg_idx: 0,
+            addr: 0,
+            size: 0,
+            region_type: PciBarRegionType::Memory32BitRegion,
+            prefetchable: PciBarPrefetchable::NotPrefetchable,
+        }
+    }
+}
+
+impl PciBarConfiguration {
+    pub fn new(
+        reg_idx: usize,
+        size: u64,
+        region_type: PciBarRegionType,
+        prefetchable: PciBarPrefetchable,
+    ) -> Self {
+        PciBarConfiguration {
+            reg_idx,
+            addr: 0,
+            size,
+            region_type,
+            prefetchable,
+        }
+    }
+
+    pub fn set_register_index(mut self, reg_idx: usize) -> Self {
+        self.reg_idx = reg_idx;
+        self
+    }
+
+    pub fn get_register_index(&self) -> usize {
+        self.reg_idx
+    }
+
+    pub fn set_address(mut self, addr: u64) -> Self {
+        self.addr = addr;
+        self
+    }
+
+    pub fn set_size(mut self, size: u64) -> Self {
+        self.size = size;
+        self
+    }
+
+    pub fn get_size(&self) -> u64 {
+        self.size
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use data_model::DataInit;
+
+    use super::*;
+
+    #[repr(packed)]
+    #[derive(Clone, Copy)]
+    #[allow(dead_code)]
+    struct TestCap {
+        _vndr: u8,
+        _next: u8,
+        len: u8,
+        foo: u8,
+    }
+
+    // It is safe to implement DataInit; all members are simple numbers and any value is valid.
+    unsafe impl DataInit for TestCap {}
+
+    impl PciCapability for TestCap {
+        fn bytes(&self) -> &[u8] {
+            self.as_slice()
+        }
+
+        fn id(&self) -> PciCapabilityID {
+            PciCapabilityID::VendorSpecific
+        }
+    }
+
+    #[test]
+    fn add_capability() {
+        let mut cfg = PciConfiguration::new(
+            0x1234,
+            0x5678,
+            PciClassCode::MultimediaController,
+            &PciMultimediaSubclass::AudioController,
+            None,
+            PciHeaderType::Device,
+            0xABCD,
+            0x2468,
+        );
+
+        // Add two capabilities with different contents.
+        let cap1 = TestCap {
+            _vndr: 0,
+            _next: 0,
+            len: 4,
+            foo: 0xAA,
+        };
+        let cap1_offset = cfg.add_capability(&cap1).unwrap();
+        assert_eq!(cap1_offset % 4, 0);
+
+        let cap2 = TestCap {
+            _vndr: 0,
+            _next: 0,
+            len: 0x04,
+            foo: 0x55,
+        };
+        let cap2_offset = cfg.add_capability(&cap2).unwrap();
+        assert_eq!(cap2_offset % 4, 0);
+
+        // The capability list head should be pointing to cap1.
+        let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF;
+        assert_eq!(cap1_offset, cap_ptr as usize);
+
+        // Verify the contents of the capabilities.
+        let cap1_data = cfg.read_reg(cap1_offset / 4);
+        assert_eq!(cap1_data & 0xFF, 0x09); // capability ID
+        assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); // next capability pointer
+        assert_eq!((cap1_data >> 16) & 0xFF, 0x04); // cap1.len
+        assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); // cap1.foo
+
+        let cap2_data = cfg.read_reg(cap2_offset / 4);
+        assert_eq!(cap2_data & 0xFF, 0x09); // capability ID
+        assert_eq!((cap2_data >> 8) & 0xFF, 0x00); // next capability pointer
+        assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len
+        assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo
+    }
+
+    #[derive(Copy, Clone)]
+    enum TestPI {
+        Test = 0x5a,
+    }
+
+    impl PciProgrammingInterface for TestPI {
+        fn get_register_value(&self) -> u8 {
+            *self as u8
+        }
+    }
+
+    #[test]
+    fn class_code() {
+        let cfg = PciConfiguration::new(
+            0x1234,
+            0x5678,
+            PciClassCode::MultimediaController,
+            &PciMultimediaSubclass::AudioController,
+            Some(&TestPI::Test),
+            PciHeaderType::Device,
+            0xABCD,
+            0x2468,
+        );
+
+        let class_reg = cfg.read_reg(2);
+        let class_code = (class_reg >> 24) & 0xFF;
+        let subclass = (class_reg >> 16) & 0xFF;
+        let prog_if = (class_reg >> 8) & 0xFF;
+        assert_eq!(class_code, 0x04);
+        assert_eq!(subclass, 0x01);
+        assert_eq!(prog_if, 0x5a);
+    }
+}
diff --git a/devices/src/pci/pci_device.rs b/devices/src/pci/pci_device.rs
new file mode 100644
index 0000000..8ea3548
--- /dev/null
+++ b/devices/src/pci/pci_device.rs
@@ -0,0 +1,197 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use byteorder::{ByteOrder, LittleEndian};
+
+use std;
+use std::fmt::{self, Display};
+use std::os::unix::io::RawFd;
+
+use kvm::Datamatch;
+use resources::{Error as SystemAllocatorFaliure, SystemAllocator};
+use sys_util::EventFd;
+
+use crate::pci::pci_configuration::{self, PciConfiguration};
+use crate::pci::PciInterruptPin;
+use crate::BusDevice;
+
+#[derive(Debug)]
+pub enum Error {
+    /// Setup of the device capabilities failed.
+    CapabilitiesSetup(pci_configuration::Error),
+    /// Allocating space for an IO BAR failed.
+    IoAllocationFailed(u64, SystemAllocatorFaliure),
+    /// Registering an IO BAR failed.
+    IoRegistrationFailed(u64, pci_configuration::Error),
+}
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            CapabilitiesSetup(e) => write!(f, "failed to add capability {}", e),
+            IoAllocationFailed(size, e) => write!(
+                f,
+                "failed to allocate space for an IO BAR, size={}: {}",
+                size, e
+            ),
+            IoRegistrationFailed(addr, e) => {
+                write!(f, "failed to register an IO BAR, addr={} err={}", addr, e)
+            }
+        }
+    }
+}
+
+pub trait PciDevice: Send {
+    /// Returns a label suitable for debug output.
+    fn debug_label(&self) -> String;
+    /// Assign a unique bus and device number to this device.
+    fn assign_bus_dev(&mut self, _bus: u8, _device: u8 /*u5*/) {}
+    /// A vector of device-specific file descriptors that must be kept open
+    /// after jailing. Must be called before the process is jailed.
+    fn keep_fds(&self) -> Vec<RawFd>;
+    /// Assign a legacy PCI IRQ to this device.
+    /// The device may write to `irq_evt` to trigger an interrupt.
+    /// When `irq_resample_evt` is signaled, the device should re-assert `irq_evt` if necessary.
+    fn assign_irq(
+        &mut self,
+        _irq_evt: EventFd,
+        _irq_resample_evt: EventFd,
+        _irq_num: u32,
+        _irq_pin: PciInterruptPin,
+    ) {
+    }
+    /// Allocates the needed IO BAR space using the `allocate` function which takes a size and
+    /// returns an address. Returns a Vec of (address, length) tuples.
+    fn allocate_io_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
+        Ok(Vec::new())
+    }
+
+    /// Allocates the needed device BAR space. Returns a Vec of (address, length) tuples.
+    /// Unlike MMIO BARs (see allocate_io_bars), device BARs are not expected to incur VM exits
+    /// - these BARs represent normal memory.
+    fn allocate_device_bars(
+        &mut self,
+        _resources: &mut SystemAllocator,
+    ) -> Result<Vec<(u64, u64)>> {
+        Ok(Vec::new())
+    }
+
+    /// Register any capabilties specified by the device.
+    fn register_device_capabilities(&mut self) -> Result<()> {
+        Ok(())
+    }
+
+    /// Gets a list of ioeventfds that should be registered with the running VM. The list is
+    /// returned as a Vec of (eventfd, addr, datamatch) tuples.
+    fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> {
+        Vec::new()
+    }
+    /// Gets the configuration registers of the Pci Device.
+    fn config_registers(&self) -> &PciConfiguration; // TODO - remove these
+    /// Gets the configuration registers of the Pci Device for modification.
+    fn config_registers_mut(&mut self) -> &mut PciConfiguration;
+    /// Reads from a BAR region mapped in to the device.
+    /// * `addr` - The guest address inside the BAR.
+    /// * `data` - Filled with the data from `addr`.
+    fn read_bar(&mut self, addr: u64, data: &mut [u8]);
+    /// Writes to a BAR region mapped in to the device.
+    /// * `addr` - The guest address inside the BAR.
+    /// * `data` - The data to write.
+    fn write_bar(&mut self, addr: u64, data: &[u8]);
+    /// Invoked when the device is sandboxed.
+    fn on_device_sandboxed(&mut self) {}
+}
+
+impl<T: PciDevice> BusDevice for T {
+    fn debug_label(&self) -> String {
+        PciDevice::debug_label(self)
+    }
+
+    fn read(&mut self, offset: u64, data: &mut [u8]) {
+        self.read_bar(offset, data)
+    }
+
+    fn write(&mut self, offset: u64, data: &[u8]) {
+        self.write_bar(offset, data)
+    }
+
+    fn config_register_write(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
+        if offset as usize + data.len() > 4 {
+            return;
+        }
+
+        let regs = self.config_registers_mut();
+
+        match data.len() {
+            1 => regs.write_byte(reg_idx * 4 + offset as usize, data[0]),
+            2 => regs.write_word(
+                reg_idx * 4 + offset as usize,
+                (data[0] as u16) | (data[1] as u16) << 8,
+            ),
+            4 => regs.write_reg(reg_idx, LittleEndian::read_u32(data)),
+            _ => (),
+        }
+    }
+
+    fn config_register_read(&self, reg_idx: usize) -> u32 {
+        self.config_registers().read_reg(reg_idx)
+    }
+
+    fn on_sandboxed(&mut self) {
+        self.on_device_sandboxed();
+    }
+}
+
+impl<T: PciDevice + ?Sized> PciDevice for Box<T> {
+    /// Returns a label suitable for debug output.
+    fn debug_label(&self) -> String {
+        (**self).debug_label()
+    }
+    fn assign_bus_dev(&mut self, bus: u8, device: u8 /*u5*/) {
+        (**self).assign_bus_dev(bus, device)
+    }
+    fn keep_fds(&self) -> Vec<RawFd> {
+        (**self).keep_fds()
+    }
+    fn assign_irq(
+        &mut self,
+        irq_evt: EventFd,
+        irq_resample_evt: EventFd,
+        irq_num: u32,
+        irq_pin: PciInterruptPin,
+    ) {
+        (**self).assign_irq(irq_evt, irq_resample_evt, irq_num, irq_pin)
+    }
+    fn allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
+        (**self).allocate_io_bars(resources)
+    }
+    fn allocate_device_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
+        (**self).allocate_device_bars(resources)
+    }
+    fn register_device_capabilities(&mut self) -> Result<()> {
+        (**self).register_device_capabilities()
+    }
+    fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> {
+        (**self).ioeventfds()
+    }
+    fn config_registers(&self) -> &PciConfiguration {
+        (**self).config_registers()
+    }
+    fn config_registers_mut(&mut self) -> &mut PciConfiguration {
+        (**self).config_registers_mut()
+    }
+    fn read_bar(&mut self, addr: u64, data: &mut [u8]) {
+        (**self).read_bar(addr, data)
+    }
+    fn write_bar(&mut self, addr: u64, data: &[u8]) {
+        (**self).write_bar(addr, data)
+    }
+    /// Invoked when the device is sandboxed.
+    fn on_device_sandboxed(&mut self) {
+        (**self).on_device_sandboxed()
+    }
+}
diff --git a/devices/src/pci/pci_root.rs b/devices/src/pci/pci_root.rs
new file mode 100644
index 0000000..187b564
--- /dev/null
+++ b/devices/src/pci/pci_root.rs
@@ -0,0 +1,303 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::os::unix::io::RawFd;
+use std::sync::Arc;
+
+use byteorder::{ByteOrder, LittleEndian};
+use sync::Mutex;
+
+use crate::pci::pci_configuration::{
+    PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType,
+};
+use crate::pci::pci_device::PciDevice;
+use crate::BusDevice;
+
+// A PciDevice that holds the root hub's configuration.
+struct PciRootConfiguration {
+    config: PciConfiguration,
+}
+
+impl PciDevice for PciRootConfiguration {
+    fn debug_label(&self) -> String {
+        "pci root device".to_owned()
+    }
+    fn keep_fds(&self) -> Vec<RawFd> {
+        Vec::new()
+    }
+    fn config_registers(&self) -> &PciConfiguration {
+        &self.config
+    }
+
+    fn config_registers_mut(&mut self) -> &mut PciConfiguration {
+        &mut self.config
+    }
+
+    fn read_bar(&mut self, _addr: u64, _data: &mut [u8]) {}
+
+    fn write_bar(&mut self, _addr: u64, _data: &[u8]) {}
+}
+
+/// Emulates the PCI Root bridge.
+pub struct PciRoot {
+    /// Bus configuration for the root device.
+    root_configuration: PciRootConfiguration,
+    /// Devices attached to this bridge.
+    devices: Vec<Arc<Mutex<dyn BusDevice>>>,
+}
+
+impl PciRoot {
+    /// Create an empty PCI root bus.
+    pub fn new() -> Self {
+        PciRoot {
+            root_configuration: PciRootConfiguration {
+                config: PciConfiguration::new(
+                    0,
+                    0,
+                    PciClassCode::BridgeDevice,
+                    &PciBridgeSubclass::HostBridge,
+                    None,
+                    PciHeaderType::Bridge,
+                    0,
+                    0,
+                ),
+            },
+            devices: Vec::new(),
+        }
+    }
+
+    /// Add a `device` to this root PCI bus.
+    pub fn add_device(&mut self, device: Arc<Mutex<dyn BusDevice>>) {
+        self.devices.push(device);
+    }
+
+    pub fn config_space_read(
+        &self,
+        bus: usize,
+        device: usize,
+        _function: usize,
+        register: usize,
+    ) -> u32 {
+        // Only support one bus.
+        if bus != 0 {
+            return 0xffff_ffff;
+        }
+
+        match device {
+            0 => {
+                // If bus and device are both zero, then read from the root config.
+                self.root_configuration.config_register_read(register)
+            }
+            dev_num => self
+                .devices
+                .get(dev_num - 1)
+                .map_or(0xffff_ffff, |d| d.lock().config_register_read(register)),
+        }
+    }
+
+    pub fn config_space_write(
+        &mut self,
+        bus: usize,
+        device: usize,
+        _function: usize,
+        register: usize,
+        offset: u64,
+        data: &[u8],
+    ) {
+        if offset as usize + data.len() > 4 {
+            return;
+        }
+
+        // Only support one bus.
+        if bus != 0 {
+            return;
+        }
+
+        match device {
+            0 => {
+                // If bus and device are both zero, then read from the root config.
+                self.root_configuration
+                    .config_register_write(register, offset, data);
+            }
+            dev_num => {
+                // dev_num is 1-indexed here.
+                if let Some(d) = self.devices.get(dev_num - 1) {
+                    d.lock().config_register_write(register, offset, data);
+                }
+            }
+        }
+    }
+}
+
+/// Emulates PCI configuration access mechanism #1 (I/O ports 0xcf8 and 0xcfc).
+pub struct PciConfigIo {
+    /// PCI root bridge.
+    pci_root: PciRoot,
+    /// Current address to read/write from (0xcf8 register, litte endian).
+    config_address: u32,
+}
+
+impl PciConfigIo {
+    pub fn new(pci_root: PciRoot) -> Self {
+        PciConfigIo {
+            pci_root,
+            config_address: 0,
+        }
+    }
+
+    fn config_space_read(&self) -> u32 {
+        let enabled = (self.config_address & 0x8000_0000) != 0;
+        if !enabled {
+            return 0xffff_ffff;
+        }
+
+        let (bus, device, function, register) =
+            parse_config_address(self.config_address & !0x8000_0000);
+        self.pci_root
+            .config_space_read(bus, device, function, register)
+    }
+
+    fn config_space_write(&mut self, offset: u64, data: &[u8]) {
+        let enabled = (self.config_address & 0x8000_0000) != 0;
+        if !enabled {
+            return;
+        }
+
+        let (bus, device, function, register) =
+            parse_config_address(self.config_address & !0x8000_0000);
+        self.pci_root
+            .config_space_write(bus, device, function, register, offset, data)
+    }
+
+    fn set_config_address(&mut self, offset: u64, data: &[u8]) {
+        if offset as usize + data.len() > 4 {
+            return;
+        }
+        let (mask, value): (u32, u32) = match data.len() {
+            1 => (
+                0x0000_00ff << (offset * 8),
+                (data[0] as u32) << (offset * 8),
+            ),
+            2 => (
+                0x0000_ffff << (offset * 16),
+                ((data[1] as u32) << 8 | data[0] as u32) << (offset * 16),
+            ),
+            4 => (0xffff_ffff, LittleEndian::read_u32(data)),
+            _ => return,
+        };
+        self.config_address = (self.config_address & !mask) | value;
+    }
+}
+
+impl BusDevice for PciConfigIo {
+    fn debug_label(&self) -> String {
+        format!("pci config io-port 0x{:03x}", self.config_address)
+    }
+
+    fn read(&mut self, offset: u64, data: &mut [u8]) {
+        // `offset` is relative to 0xcf8
+        let value = match offset {
+            0...3 => self.config_address,
+            4...7 => self.config_space_read(),
+            _ => 0xffff_ffff,
+        };
+
+        // Only allow reads to the register boundary.
+        let start = offset as usize % 4;
+        let end = start + data.len();
+        if end <= 4 {
+            for i in start..end {
+                data[i - start] = (value >> (i * 8)) as u8;
+            }
+        } else {
+            for d in data {
+                *d = 0xff;
+            }
+        }
+    }
+
+    fn write(&mut self, offset: u64, data: &[u8]) {
+        // `offset` is relative to 0xcf8
+        match offset {
+            o @ 0...3 => self.set_config_address(o, data),
+            o @ 4...7 => self.config_space_write(o - 4, data),
+            _ => (),
+        };
+    }
+}
+
+/// Emulates PCI memory-mapped configuration access mechanism.
+pub struct PciConfigMmio {
+    /// PCI root bridge.
+    pci_root: PciRoot,
+}
+
+impl PciConfigMmio {
+    pub fn new(pci_root: PciRoot) -> Self {
+        PciConfigMmio { pci_root }
+    }
+
+    fn config_space_read(&self, config_address: u32) -> u32 {
+        let (bus, device, function, register) = parse_config_address(config_address);
+        self.pci_root
+            .config_space_read(bus, device, function, register)
+    }
+
+    fn config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8]) {
+        let (bus, device, function, register) = parse_config_address(config_address);
+        self.pci_root
+            .config_space_write(bus, device, function, register, offset, data)
+    }
+}
+
+impl BusDevice for PciConfigMmio {
+    fn debug_label(&self) -> String {
+        "pci config mmio".to_owned()
+    }
+
+    fn read(&mut self, offset: u64, data: &mut [u8]) {
+        // Only allow reads to the register boundary.
+        let start = offset as usize % 4;
+        let end = start + data.len();
+        if end > 4 || offset > u32::max_value() as u64 {
+            for d in data {
+                *d = 0xff;
+            }
+            return;
+        }
+
+        let value = self.config_space_read(offset as u32);
+        for i in start..end {
+            data[i - start] = (value >> (i * 8)) as u8;
+        }
+    }
+
+    fn write(&mut self, offset: u64, data: &[u8]) {
+        if offset > u32::max_value() as u64 {
+            return;
+        }
+        self.config_space_write(offset as u32, offset % 4, data)
+    }
+}
+
+// Parse the CONFIG_ADDRESS register to a (bus, device, function, register) tuple.
+fn parse_config_address(config_address: u32) -> (usize, usize, usize, usize) {
+    const BUS_NUMBER_OFFSET: usize = 16;
+    const BUS_NUMBER_MASK: u32 = 0x00ff;
+    const DEVICE_NUMBER_OFFSET: usize = 11;
+    const DEVICE_NUMBER_MASK: u32 = 0x1f;
+    const FUNCTION_NUMBER_OFFSET: usize = 8;
+    const FUNCTION_NUMBER_MASK: u32 = 0x07;
+    const REGISTER_NUMBER_OFFSET: usize = 2;
+    const REGISTER_NUMBER_MASK: u32 = 0x3f;
+
+    let bus_number = ((config_address >> BUS_NUMBER_OFFSET) & BUS_NUMBER_MASK) as usize;
+    let device_number = ((config_address >> DEVICE_NUMBER_OFFSET) & DEVICE_NUMBER_MASK) as usize;
+    let function_number =
+        ((config_address >> FUNCTION_NUMBER_OFFSET) & FUNCTION_NUMBER_MASK) as usize;
+    let register_number =
+        ((config_address >> REGISTER_NUMBER_OFFSET) & REGISTER_NUMBER_MASK) as usize;
+
+    (bus_number, device_number, function_number, register_number)
+}
diff --git a/devices/src/pic.rs b/devices/src/pic.rs
new file mode 100644
index 0000000..9b8235f
--- /dev/null
+++ b/devices/src/pic.rs
@@ -0,0 +1,1136 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Software implementation of an Intel 8259A Programmable Interrupt Controller
+// This is a legacy device used by older OSs and briefly during start-up by
+// modern OSs that use a legacy BIOS.
+// The PIC is connected to the Local APIC on CPU0.
+
+// Terminology note: The 8259A spec refers to "master" and "slave" PITs; the "slave"s are daisy
+// chained to the "master"s.
+// For the purposes of both using more descriptive terms and avoiding terms with lots of charged
+// emotional context, this file refers to them instead as "primary" and "secondary" PITs.
+
+use crate::BusDevice;
+use sys_util::{debug, warn};
+
+#[repr(usize)]
+#[derive(Debug, Clone, Copy, PartialEq)]
+enum PicSelect {
+    Primary = 0,
+    Secondary = 1,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+enum PicInitState {
+    Icw1 = 0,
+    Icw2 = 1,
+    Icw3 = 2,
+    Icw4 = 3,
+}
+
+#[derive(Debug, Default, Clone, Copy, PartialEq)]
+struct PicState {
+    last_irr: u8,     // Edge detection.
+    irr: u8,          // Interrupt Request Register.
+    imr: u8,          // Interrupt Mask Register.
+    isr: u8,          // Interrupt Service Register.
+    priority_add: u8, // Highest priority, for priority rotation.
+    irq_base: u8,
+    read_reg_select: bool,
+    poll: bool,
+    special_mask: bool,
+    auto_eoi: bool,
+    rotate_on_auto_eoi: bool,
+    special_fully_nested_mode: bool,
+    // PIC takes either 3 or 4 bytes of initialization command word during
+    // initialization. use_4_byte_icw is true if 4 bytes of ICW are needed.
+    use_4_byte_icw: bool,
+    // "Edge/Level Control Registers", for edge trigger selection.
+    // When a particular bit is set, the corresponding IRQ is in level-triggered mode. Otherwise it
+    // is in edge-triggered mode.
+    elcr: u8,
+    elcr_mask: u8,
+    init_state: Option<PicInitState>,
+}
+
+pub struct Pic {
+    // TODO(mutexlox): Implement an APIC and add necessary state to the Pic.
+
+    // index 0 (aka PicSelect::Primary) is the primary pic, the rest are secondary.
+    pics: [PicState; 2],
+}
+
+const PIC_NUM_PINS: u8 = 16;
+
+// Register offsets.
+const PIC_PRIMARY: u64 = 0x20;
+const PIC_PRIMARY_COMMAND: u64 = PIC_PRIMARY;
+const PIC_PRIMARY_DATA: u64 = PIC_PRIMARY + 1;
+const PIC_PRIMARY_ELCR: u64 = 0x4d0;
+
+const PIC_SECONDARY: u64 = 0xa0;
+const PIC_SECONDARY_COMMAND: u64 = PIC_SECONDARY;
+const PIC_SECONDARY_DATA: u64 = PIC_SECONDARY + 1;
+const PIC_SECONDARY_ELCR: u64 = 0x4d1;
+
+const LEVEL_HIGH: bool = true;
+const LEVEL_LOW: bool = false;
+const INVALID_PRIORITY: u8 = 8;
+const SPURIOUS_IRQ: u8 = 0x07;
+const PRIMARY_PIC_CASCADE_PIN: u8 = 2;
+const PRIMARY_PIC_CASCADE_PIN_MASK: u8 = 0x04;
+const PRIMARY_PIC_MAX_IRQ: u8 = 7;
+
+// Command Words
+const ICW1_MASK: u8 = 0x10;
+const OCW3_MASK: u8 = 0x08;
+
+// ICW1 bits
+const ICW1_NEED_ICW4: u8 = 0x01; // ICW4 needed
+const ICW1_SINGLE_PIC_MODE: u8 = 0x02;
+const ICW1_LEVEL_TRIGGER_MODE: u8 = 0x08;
+
+const ICW2_IRQ_BASE_MASK: u8 = 0xf8;
+
+const ICW4_SPECIAL_FULLY_NESTED_MODE: u8 = 0x10;
+const ICW4_AUTO_EOI: u8 = 0x02;
+
+// OCW2 bits
+const OCW2_IRQ_MASK: u8 = 0x07;
+const OCW2_COMMAND_MASK: u8 = 0xe0;
+#[derive(Debug, Clone, Copy, PartialEq, enumn::N)]
+enum Ocw2 {
+    RotateAutoEoiClear = 0x00,
+    NonSpecificEoi = 0x20,
+    NoOp = 0x40,
+    SpecificEoi = 0x60,
+    RotateAutoEoiSet = 0x80,
+    RotateNonSpecificEoi = 0xa0,
+    SetPriority = 0xc0,
+    RotateSpecificEoi = 0xe0,
+}
+
+// OCW3 bits
+const OCW3_POLL_COMMAND: u8 = 0x04;
+const OCW3_READ_REGISTER: u8 = 0x02;
+// OCW3_READ_IRR (0x00) intentionally omitted.
+const OCW3_READ_ISR: u8 = 0x01;
+const OCW3_SPECIAL_MASK: u8 = 0x40;
+const OCW3_SPECIAL_MASK_VALUE: u8 = 0x20;
+
+impl BusDevice for Pic {
+    fn debug_label(&self) -> String {
+        "userspace PIC".to_string()
+    }
+
+    fn write(&mut self, offset: u64, data: &[u8]) {
+        if data.len() != 1 {
+            warn!("PIC: Bad write size: {}", data.len());
+            return;
+        }
+        match offset {
+            PIC_PRIMARY_COMMAND => self.pic_write_command(PicSelect::Primary, data[0]),
+            PIC_PRIMARY_DATA => self.pic_write_data(PicSelect::Primary, data[0]),
+            PIC_PRIMARY_ELCR => self.pic_write_elcr(PicSelect::Primary, data[0]),
+            PIC_SECONDARY_COMMAND => self.pic_write_command(PicSelect::Secondary, data[0]),
+            PIC_SECONDARY_DATA => self.pic_write_data(PicSelect::Secondary, data[0]),
+            PIC_SECONDARY_ELCR => self.pic_write_elcr(PicSelect::Secondary, data[0]),
+            _ => warn!("PIC: Invalid write to offset {}", offset),
+        }
+    }
+
+    fn read(&mut self, offset: u64, data: &mut [u8]) {
+        if data.len() != 1 {
+            warn!("PIC: Bad read size: {}", data.len());
+            return;
+        }
+        data[0] = match offset {
+            PIC_PRIMARY_COMMAND => self.pic_read_command(PicSelect::Primary),
+            PIC_PRIMARY_DATA => self.pic_read_data(PicSelect::Primary),
+            PIC_PRIMARY_ELCR => self.pic_read_elcr(PicSelect::Primary),
+            PIC_SECONDARY_COMMAND => self.pic_read_command(PicSelect::Secondary),
+            PIC_SECONDARY_DATA => self.pic_read_data(PicSelect::Secondary),
+            PIC_SECONDARY_ELCR => self.pic_read_elcr(PicSelect::Secondary),
+            _ => {
+                warn!("PIC: Invalid read from offset {}", offset);
+                return;
+            }
+        };
+    }
+}
+
+impl Pic {
+    pub fn new() -> Pic {
+        let mut primary_pic: PicState = Default::default();
+        let mut secondary_pic: PicState = Default::default();
+        // These two masks are taken from KVM code (but do not appear in the 8259 specification).
+
+        // These IRQ lines are edge triggered, and so have 0 bits in the masks:
+        //   - IRQs 0, 1, 8, and 13 are dedicated to special I/O devices on the system board.
+        //   - IRQ 2 is the primary pic's cascade line.
+        // The primary pic has IRQs 0-7.
+        primary_pic.elcr_mask = !((1 << 0) | (1 << 1) | (1 << 2));
+        // The secondary PIC has IRQs 8-15, so we subtract 8 from the IRQ number to get the bit
+        // that should be masked here. In this case, bits 8 - 8 = 0 and 13 - 8 = 5.
+        secondary_pic.elcr_mask = !((1 << 0) | (1 << 5));
+        // TODO(mutexlox): Add logic to initialize APIC interrupt-related fields.
+
+        Pic {
+            pics: [primary_pic, secondary_pic],
+        }
+    }
+
+    pub fn service_irq(&mut self, irq: u8, level: bool) -> bool {
+        assert!(irq <= 15, "Unexpectedly high value irq: {} vs 15", irq);
+
+        let pic = if irq <= PRIMARY_PIC_MAX_IRQ {
+            PicSelect::Primary
+        } else {
+            PicSelect::Secondary
+        };
+        Pic::set_irq_internal(&mut self.pics[pic as usize], irq & 7, level);
+
+        self.update_irq()
+    }
+
+    /// Determines whether the (primary) PIC is completely masked.
+    pub fn masked(&self) -> bool {
+        self.pics[PicSelect::Primary as usize].imr == 0xFF
+    }
+
+    /// Determines whether the PIC has an interrupt ready.
+    pub fn has_interrupt(&self) -> bool {
+        self.get_irq(PicSelect::Primary).is_some()
+    }
+
+    /// Determines the external interrupt number that the PIC is prepared to inject, if any.
+    pub fn get_external_interrupt(&mut self) -> Option<u8> {
+        let irq_primary = if let Some(irq) = self.get_irq(PicSelect::Primary) {
+            irq
+        } else {
+            // The architecturally correct behavior in this case is to inject a spurious interrupt.
+            // Although this case only occurs as a result of a race condition where the interrupt
+            // might also be avoided entirely.  Here we return `None` to avoid the interrupt
+            // entirely.  The KVM unit test OS, which several unit tests rely upon, doesn't
+            // properly handle spurious interrupts.  Also spurious interrupts are much more common
+            // in this code than real hardware because the hardware race is much much much smaller.
+            return None;
+        };
+
+        Pic::interrupt_ack(&mut self.pics[PicSelect::Primary as usize], irq_primary);
+        let int_num = if irq_primary == PRIMARY_PIC_CASCADE_PIN {
+            // IRQ on secondary pic.
+            let irq_secondary = if let Some(irq) = self.get_irq(PicSelect::Secondary) {
+                Pic::interrupt_ack(&mut self.pics[PicSelect::Secondary as usize], irq);
+                irq
+            } else {
+                SPURIOUS_IRQ
+            };
+            self.pics[PicSelect::Secondary as usize].irq_base + irq_secondary
+        } else {
+            self.pics[PicSelect::Primary as usize].irq_base + irq_primary
+        };
+
+        self.update_irq();
+        Some(int_num)
+    }
+
+    fn pic_read_command(&mut self, pic_type: PicSelect) -> u8 {
+        if self.pics[pic_type as usize].poll {
+            let (ret, update_irq_needed) = self.poll_read(pic_type);
+            self.pics[pic_type as usize].poll = false;
+
+            if update_irq_needed {
+                self.update_irq();
+            }
+
+            ret
+        } else if self.pics[pic_type as usize].read_reg_select {
+            self.pics[pic_type as usize].isr
+        } else {
+            self.pics[pic_type as usize].irr
+        }
+    }
+
+    fn pic_read_data(&mut self, pic_type: PicSelect) -> u8 {
+        if self.pics[pic_type as usize].poll {
+            let (ret, update_needed) = self.poll_read(pic_type);
+            self.pics[pic_type as usize].poll = false;
+            if update_needed {
+                self.update_irq();
+            }
+            ret
+        } else {
+            self.pics[pic_type as usize].imr
+        }
+    }
+
+    fn pic_read_elcr(&mut self, pic_type: PicSelect) -> u8 {
+        self.pics[pic_type as usize].elcr
+    }
+
+    fn pic_write_command(&mut self, pic_type: PicSelect, value: u8) {
+        if value & ICW1_MASK != 0 {
+            Pic::init_command_word_1(&mut self.pics[pic_type as usize], value);
+        } else if value & OCW3_MASK != 0 {
+            Pic::operation_command_word_3(&mut self.pics[pic_type as usize], value);
+        } else {
+            self.operation_command_word_2(pic_type, value);
+        }
+    }
+
+    fn pic_write_data(&mut self, pic_type: PicSelect, value: u8) {
+        match self.pics[pic_type as usize].init_state {
+            Some(PicInitState::Icw1) | None => {
+                if self.pics[pic_type as usize].init_state.is_none() {
+                    debug!(
+                        "PIC: {:?}: Uninitialized data write of {:#x}",
+                        pic_type, value
+                    );
+                }
+                self.pics[pic_type as usize].imr = value;
+                self.update_irq();
+            }
+            Some(PicInitState::Icw2) => {
+                self.pics[pic_type as usize].irq_base = value & ICW2_IRQ_BASE_MASK;
+                self.pics[pic_type as usize].init_state = Some(PicInitState::Icw3);
+            }
+            Some(PicInitState::Icw3) => {
+                if self.pics[pic_type as usize].use_4_byte_icw {
+                    self.pics[pic_type as usize].init_state = Some(PicInitState::Icw4);
+                } else {
+                    self.pics[pic_type as usize].init_state = Some(PicInitState::Icw1);
+                }
+            }
+            Some(PicInitState::Icw4) => {
+                self.pics[pic_type as usize].special_fully_nested_mode =
+                    (value & ICW4_SPECIAL_FULLY_NESTED_MODE) != 0;
+                self.pics[pic_type as usize].auto_eoi = (value & ICW4_AUTO_EOI) != 0;
+                self.pics[pic_type as usize].init_state = Some(PicInitState::Icw1);
+            }
+        }
+    }
+
+    fn pic_write_elcr(&mut self, pic_type: PicSelect, value: u8) {
+        self.pics[pic_type as usize].elcr = value & !self.pics[pic_type as usize].elcr;
+    }
+
+    fn reset_pic(pic: &mut PicState) {
+        let edge_irr = pic.irr & !pic.elcr;
+
+        pic.last_irr = 0;
+        pic.irr &= pic.elcr;
+        pic.imr = 0;
+        pic.priority_add = 0;
+        pic.special_mask = false;
+        pic.read_reg_select = false;
+        if !pic.use_4_byte_icw {
+            pic.special_fully_nested_mode = false;
+            pic.auto_eoi = false;
+        }
+        pic.init_state = Some(PicInitState::Icw2);
+
+        for irq in 0..PIC_NUM_PINS / 2 {
+            if edge_irr & (1 << irq) != 0 {
+                Pic::clear_isr(pic, irq);
+            }
+        }
+    }
+
+    /// Determine the priority and whether an update_irq call is needed.
+    fn poll_read(&mut self, pic_type: PicSelect) -> (u8, bool) {
+        if let Some(mut irq) = self.get_irq(pic_type) {
+            irq &= 0xff;
+            if pic_type == PicSelect::Secondary {
+                self.pics[PicSelect::Primary as usize].isr &= !PRIMARY_PIC_CASCADE_PIN_MASK;
+                self.pics[PicSelect::Primary as usize].irr &= !PRIMARY_PIC_CASCADE_PIN_MASK;
+            }
+            self.pics[pic_type as usize].irr &= !(1 << irq);
+            Pic::clear_isr(&mut self.pics[pic_type as usize], irq);
+            let update_irq_needed =
+                pic_type == PicSelect::Secondary && irq != PRIMARY_PIC_CASCADE_PIN;
+            (irq, update_irq_needed)
+        } else {
+            // Spurious interrupt
+            (SPURIOUS_IRQ, true)
+        }
+    }
+
+    fn get_irq(&self, pic_type: PicSelect) -> Option<u8> {
+        let pic = &self.pics[pic_type as usize];
+        let mut irq_bitmap = pic.irr & !pic.imr;
+        let priority = if let Some(p) = Pic::get_priority(pic, irq_bitmap) {
+            p
+        } else {
+            return None;
+        };
+
+        // If the primary is in fully-nested mode, the IRQ coming from the secondary is not taken
+        // into account for the priority computation below.
+        irq_bitmap = pic.isr;
+        if pic_type == PicSelect::Primary && pic.special_fully_nested_mode {
+            irq_bitmap &= !PRIMARY_PIC_CASCADE_PIN_MASK;
+        }
+        let new_priority = Pic::get_priority(pic, irq_bitmap).unwrap_or(INVALID_PRIORITY);
+        if priority < new_priority {
+            // Higher priority found. IRQ should be generated.
+            Some((priority + pic.priority_add) & 7)
+        } else {
+            None
+        }
+    }
+
+    fn clear_isr(pic: &mut PicState, irq: u8) {
+        assert!(irq <= 7, "Unexpectedly high value for irq: {} vs 7", irq);
+        pic.isr &= !(1 << irq);
+    }
+
+    fn update_irq(&mut self) -> bool {
+        if self.get_irq(PicSelect::Secondary).is_some() {
+            // If secondary pic has an IRQ request, signal primary's cascade pin.
+            Pic::set_irq_internal(
+                &mut self.pics[PicSelect::Primary as usize],
+                PRIMARY_PIC_CASCADE_PIN,
+                LEVEL_HIGH,
+            );
+            Pic::set_irq_internal(
+                &mut self.pics[PicSelect::Primary as usize],
+                PRIMARY_PIC_CASCADE_PIN,
+                LEVEL_LOW,
+            );
+        }
+
+        if self.get_irq(PicSelect::Primary).is_some() {
+            // TODO(mutexlox): Signal local interrupt on APIC bus.
+            // Note: this does not check if the interrupt is succesfully injected into
+            // the CPU, just whether or not one is fired.
+            true
+        } else {
+            false
+        }
+    }
+
+    /// Set Irq level. If edge is detected, then IRR is set to 1.
+    fn set_irq_internal(pic: &mut PicState, irq: u8, level: bool) {
+        assert!(irq <= 7, "Unexpectedly high value for irq: {} vs 7", irq);
+        let irq_bitmap = 1 << irq;
+        if (pic.elcr & irq_bitmap) != 0 {
+            // Level-triggered.
+            if level {
+                // Same IRQ already requested.
+                pic.irr |= irq_bitmap;
+                pic.last_irr |= irq_bitmap;
+            } else {
+                pic.irr &= !irq_bitmap;
+                pic.last_irr &= !irq_bitmap;
+            }
+        } else {
+            // Edge-triggered
+            if level {
+                if (pic.last_irr & irq_bitmap) == 0 {
+                    // Raising edge detected.
+                    pic.irr |= irq_bitmap;
+                }
+                pic.last_irr |= irq_bitmap;
+            } else {
+                pic.last_irr &= !irq_bitmap;
+            }
+        }
+    }
+
+    fn get_priority(pic: &PicState, irq_bitmap: u8) -> Option<u8> {
+        if irq_bitmap == 0 {
+            None
+        } else {
+            // Find the highest priority bit in irq_bitmap considering the priority
+            // rotation mechanism (priority_add).
+            let mut priority = 0;
+            let mut priority_mask = 1 << ((priority + pic.priority_add) & 7);
+            while (irq_bitmap & priority_mask) == 0 {
+                priority += 1;
+                priority_mask = 1 << ((priority + pic.priority_add) & 7);
+            }
+            Some(priority)
+        }
+    }
+
+    /// Move interrupt from IRR to ISR to indicate that the interrupt is injected. If
+    /// auto EOI is set, then ISR is immediately cleared (since the purpose of EOI is
+    /// to clear ISR bit).
+    fn interrupt_ack(pic: &mut PicState, irq: u8) {
+        assert!(irq <= 7, "Unexpectedly high value for irq: {} vs 7", irq);
+
+        let irq_bitmap = 1 << irq;
+        pic.isr |= irq_bitmap;
+
+        if (pic.elcr & irq_bitmap) == 0 {
+            pic.irr &= !irq_bitmap;
+        }
+
+        if pic.auto_eoi {
+            if pic.rotate_on_auto_eoi {
+                pic.priority_add = (irq + 1) & 7;
+            }
+            Pic::clear_isr(pic, irq);
+        }
+    }
+
+    fn init_command_word_1(pic: &mut PicState, value: u8) {
+        pic.use_4_byte_icw = (value & ICW1_NEED_ICW4) != 0;
+        if (value & ICW1_SINGLE_PIC_MODE) != 0 {
+            debug!("PIC: Single PIC mode not supported.");
+        }
+        if (value & ICW1_LEVEL_TRIGGER_MODE) != 0 {
+            debug!("PIC: Level triggered IRQ not supported.");
+        }
+        Pic::reset_pic(pic);
+    }
+
+    fn operation_command_word_2(&mut self, pic_type: PicSelect, value: u8) {
+        let mut irq = value & OCW2_IRQ_MASK;
+        if let Some(cmd) = Ocw2::n(value & OCW2_COMMAND_MASK) {
+            match cmd {
+                Ocw2::RotateAutoEoiSet => self.pics[pic_type as usize].rotate_on_auto_eoi = true,
+                Ocw2::RotateAutoEoiClear => self.pics[pic_type as usize].rotate_on_auto_eoi = false,
+                Ocw2::NonSpecificEoi | Ocw2::RotateNonSpecificEoi => {
+                    if let Some(priority) = Pic::get_priority(
+                        &self.pics[pic_type as usize],
+                        self.pics[pic_type as usize].isr,
+                    ) {
+                        irq = (priority + self.pics[pic_type as usize].priority_add) & 7;
+                        if cmd == Ocw2::RotateNonSpecificEoi {
+                            self.pics[pic_type as usize].priority_add = (irq + 1) & 7;
+                        }
+                        Pic::clear_isr(&mut self.pics[pic_type as usize], irq);
+                        self.update_irq();
+                    }
+                }
+                Ocw2::SpecificEoi => {
+                    Pic::clear_isr(&mut self.pics[pic_type as usize], irq);
+                    self.update_irq();
+                }
+                Ocw2::SetPriority => {
+                    self.pics[pic_type as usize].priority_add = (irq + 1) & 7;
+                    self.update_irq();
+                }
+                Ocw2::RotateSpecificEoi => {
+                    self.pics[pic_type as usize].priority_add = (irq + 1) & 7;
+                    Pic::clear_isr(&mut self.pics[pic_type as usize], irq);
+                    self.update_irq();
+                }
+                Ocw2::NoOp => {} /* noop */
+            }
+        }
+    }
+
+    fn operation_command_word_3(pic: &mut PicState, value: u8) {
+        if value & OCW3_POLL_COMMAND != 0 {
+            pic.poll = true;
+        }
+        if value & OCW3_READ_REGISTER != 0 {
+            // Select to read ISR or IRR
+            pic.read_reg_select = value & OCW3_READ_ISR != 0;
+        }
+        if value & OCW3_SPECIAL_MASK != 0 {
+            pic.special_mask = value & OCW3_SPECIAL_MASK_VALUE != 0;
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    // ICW4: Special fully nested mode with no auto EOI.
+    const FULLY_NESTED_NO_AUTO_EOI: u8 = 0x11;
+    use super::*;
+
+    struct TestData {
+        pic: Pic,
+    }
+
+    fn set_up() -> TestData {
+        let mut pic = Pic::new();
+        // Use edge-triggered mode.
+        pic.write(PIC_PRIMARY_ELCR, &[0]);
+        pic.write(PIC_SECONDARY_ELCR, &[0]);
+        TestData { pic }
+    }
+
+    /// Convenience wrapper to initialize PIC using 4 ICWs. Validity of values is NOT checked.
+    fn icw_init(pic: &mut Pic, pic_type: PicSelect, icw1: u8, icw2: u8, icw3: u8, icw4: u8) {
+        let command_offset = match pic_type {
+            PicSelect::Primary => PIC_PRIMARY_COMMAND,
+            PicSelect::Secondary => PIC_SECONDARY_COMMAND,
+        };
+        let data_offset = match pic_type {
+            PicSelect::Primary => PIC_PRIMARY_DATA,
+            PicSelect::Secondary => PIC_SECONDARY_DATA,
+        };
+
+        pic.write(command_offset, &[icw1]);
+        pic.write(data_offset, &[icw2]);
+        pic.write(data_offset, &[icw3]);
+        pic.write(data_offset, &[icw4]);
+    }
+
+    /// Convenience function for primary ICW init.
+    fn icw_init_primary(pic: &mut Pic) {
+        // ICW1 0x11: Edge trigger, cascade mode, ICW4 needed.
+        // ICW2 0x08: Interrupt vector base address 0x08.
+        // ICW3 0xff: Value written does not matter.
+        // ICW4 0x13: Special fully nested mode, auto EOI.
+        icw_init(pic, PicSelect::Primary, 0x11, 0x08, 0xff, 0x13);
+    }
+
+    /// Convenience function for secondary ICW init.
+    fn icw_init_secondary(pic: &mut Pic) {
+        // ICW1 0x11: Edge trigger, cascade mode, ICW4 needed.
+        // ICW2 0x70: Interrupt vector base address 0x70.
+        // ICW3 0xff: Value written does not matter.
+        // ICW4 0x13: Special fully nested mode, auto EOI.
+        icw_init(pic, PicSelect::Secondary, 0x11, 0x70, 0xff, 0x13);
+    }
+
+    /// Convenience function for initializing ICW with custom value for ICW4.
+    fn icw_init_both_with_icw4(pic: &mut Pic, icw4: u8) {
+        // ICW1 0x11: Edge trigger, cascade mode, ICW4 needed.
+        // ICW2 0x08: Interrupt vector base address 0x08.
+        // ICW3 0xff: Value written does not matter.
+        icw_init(pic, PicSelect::Primary, 0x11, 0x08, 0xff, icw4);
+        // ICW1 0x11: Edge trigger, cascade mode, ICW4 needed.
+        // ICW2 0x70: Interrupt vector base address 0x70.
+        // ICW3 0xff: Value written does not matter.
+        icw_init(pic, PicSelect::Secondary, 0x11, 0x70, 0xff, icw4);
+    }
+
+    fn icw_init_both(pic: &mut Pic) {
+        icw_init_primary(pic);
+        icw_init_secondary(pic);
+    }
+
+    /// Test that elcr register can be written and read correctly.
+    #[test]
+    fn write_read_elcr() {
+        let mut data = set_up();
+        let data_write = [0x5f];
+        let mut data_read = [0];
+
+        data.pic.write(PIC_PRIMARY_ELCR, &data_write);
+        data.pic.read(PIC_PRIMARY_ELCR, &mut data_read);
+        assert_eq!(data_read, data_write);
+
+        data.pic.write(PIC_SECONDARY_ELCR, &data_write);
+        data.pic.read(PIC_SECONDARY_ELCR, &mut data_read);
+        assert_eq!(data_read, data_write);
+    }
+
+    /// Test the three-word ICW.
+    #[test]
+    fn icw_2_step() {
+        let mut data = set_up();
+
+        // ICW1
+        let mut data_write = [0x10];
+        data.pic.write(PIC_PRIMARY_COMMAND, &data_write);
+
+        data_write[0] = 0x08;
+        data.pic.write(PIC_PRIMARY_DATA, &data_write);
+
+        data_write[0] = 0xff;
+        data.pic.write(PIC_PRIMARY_DATA, &data_write);
+
+        assert_eq!(
+            data.pic.pics[PicSelect::Primary as usize].init_state,
+            Some(PicInitState::Icw1)
+        );
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].irq_base, 0x08);
+        assert_eq!(
+            data.pic.pics[PicSelect::Primary as usize].use_4_byte_icw,
+            false
+        );
+    }
+
+    /// Verify that PIC is in expected state after initialization.
+    #[test]
+    fn initial_values() {
+        let mut data = set_up();
+        icw_init_primary(&mut data.pic);
+
+        let primary_pic = &data.pic.pics[PicSelect::Primary as usize];
+        assert_eq!(primary_pic.last_irr, 0x00);
+        assert_eq!(primary_pic.irr, 0x00);
+        assert_eq!(primary_pic.imr, 0x00);
+        assert_eq!(primary_pic.isr, 0x00);
+        assert_eq!(primary_pic.priority_add, 0);
+        assert_eq!(primary_pic.irq_base, 0x08);
+        assert_eq!(primary_pic.read_reg_select, false);
+        assert_eq!(primary_pic.poll, false);
+        assert_eq!(primary_pic.special_mask, false);
+        assert_eq!(primary_pic.init_state, Some(PicInitState::Icw1));
+        assert_eq!(primary_pic.auto_eoi, true);
+        assert_eq!(primary_pic.rotate_on_auto_eoi, false);
+        assert_eq!(primary_pic.special_fully_nested_mode, true);
+        assert_eq!(primary_pic.use_4_byte_icw, true);
+        assert_eq!(primary_pic.elcr, 0x00);
+        assert_eq!(primary_pic.elcr_mask, 0xf8);
+    }
+
+    /// Verify effect that OCW has on PIC registers & state.
+    #[test]
+    fn ocw() {
+        let mut data = set_up();
+
+        icw_init_secondary(&mut data.pic);
+
+        // OCW1: Write to IMR.
+        data.pic.write(PIC_SECONDARY_DATA, &[0x5f]);
+
+        // OCW2: Set rotate on auto EOI.
+        data.pic.write(PIC_SECONDARY_COMMAND, &[0x80]);
+
+        // OCW2: Set priority.
+        data.pic.write(PIC_SECONDARY_COMMAND, &[0xc0]);
+
+        // OCW3: Change flags.
+        data.pic.write(PIC_SECONDARY_COMMAND, &[0x6b]);
+
+        let mut data_read = [0];
+        data.pic.read(PIC_SECONDARY_DATA, &mut data_read);
+        assert_eq!(data_read, [0x5f]);
+
+        let secondary_pic = &data.pic.pics[PicSelect::Secondary as usize];
+
+        // Check OCW1 result.
+        assert_eq!(secondary_pic.imr, 0x5f);
+
+        // Check OCW2 result.
+        assert!(secondary_pic.rotate_on_auto_eoi);
+        assert_eq!(secondary_pic.priority_add, 1);
+
+        // Check OCW3 result.
+        assert!(secondary_pic.special_mask);
+        assert_eq!(secondary_pic.poll, false);
+        assert!(secondary_pic.read_reg_select);
+    }
+
+    /// Verify that we can set and clear the AutoRotate bit in OCW.
+    #[test]
+    fn ocw_auto_rotate_set_and_clear() {
+        let mut data = set_up();
+
+        icw_init_secondary(&mut data.pic);
+
+        // OCW2: Set rotate on auto EOI.
+        data.pic.write(PIC_SECONDARY_COMMAND, &[0x80]);
+
+        let secondary_pic = &data.pic.pics[PicSelect::Secondary as usize];
+        assert!(secondary_pic.rotate_on_auto_eoi);
+
+        // OCW2: Clear rotate on auto EOI.
+        data.pic.write(PIC_SECONDARY_COMMAND, &[0x00]);
+
+        let secondary_pic = &data.pic.pics[PicSelect::Secondary as usize];
+        assert!(!secondary_pic.rotate_on_auto_eoi);
+    }
+
+    /// Test basic auto EOI case.
+    #[test]
+    fn auto_eoi() {
+        let mut data = set_up();
+
+        icw_init_both(&mut data.pic);
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.service_irq(/*irq=*/ 12, /*level=*/ true);
+
+        // Check that IRQ is requesting acknowledgment.
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, (1 << 4));
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, (1 << 2));
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
+
+        // 0x70 is interrupt base on secondary PIC. 0x70 + 4 is the interrupt entry number.
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 4));
+
+        // Check that IRQ is acknowledged and EOI is automatically done.
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
+    }
+
+    /// Test with fully-nested mode on. When the secondary PIC has an IRQ in service, it shouldn't
+    /// be locked out by the primary's priority logic.
+    /// This means that the secondary should still be able to request a higher-priority IRQ.
+    /// Auto EOI is off in order to keep IRQ in service.
+    #[test]
+    fn fully_nested_mode_on() {
+        let mut data = set_up();
+
+        icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.service_irq(/*irq=*/ 12, /*level=*/ true);
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 4));
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        // Request higher-priority IRQ on secondary.
+        data.pic.service_irq(/*irq=*/ 8, /*level=*/ true);
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 0));
+
+        // Check that IRQ is ack'd and EOI is automatically done.
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 0);
+        assert_eq!(
+            data.pic.pics[PicSelect::Secondary as usize].isr,
+            (1 << 4) + (1 << 0)
+        );
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 1 << 2);
+    }
+
+    /// Test with fully-nested mode off. When the secondary PIC has an IRQ in service, it should
+    /// NOT be able to request another higher-priority IRQ.
+    /// Auto EOI is off in order to keep IRQ in service.
+    #[test]
+    fn fully_nested_mode_off() {
+        let mut data = set_up();
+
+        // ICW4 0x01: No special fully nested mode, no auto EOI.
+        icw_init_both_with_icw4(&mut data.pic, 0x01);
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.service_irq(/*irq=*/ 12, /*level=*/ true);
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 4));
+
+        data.pic.service_irq(/*irq=*/ 8, /*level=*/ true);
+        // Primary cannot get any IRQ, so this should not provide any interrupt.
+        assert_eq!(data.pic.get_external_interrupt(), None);
+
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 1 << 0);
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 1 << 4);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 1 << 2);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 1 << 2);
+
+        // 2 EOIs will cause 2 interrupts.
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+
+        // OCW2: Non-specific EOI, one for primary and one for secondary.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0x20]);
+        data.pic.write(PIC_SECONDARY_COMMAND, &[0x20]);
+
+        // Now that the first IRQ is no longer in service, the second IRQ can be ack'd.
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 0));
+
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 1 << 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 1 << 2);
+    }
+
+    /// Write IMR to mask an IRQ. The masked IRQ can't be served until unmasked.
+    #[test]
+    fn mask_irq() {
+        let mut data = set_up();
+
+        icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
+
+        // OCW2: Mask IRQ line 6 on secondary (IRQ 14).
+        data.pic.write(PIC_SECONDARY_DATA, &[0x40]);
+
+        data.pic.service_irq(/*irq=*/ 14, /*level=*/ true);
+        assert_eq!(data.pic.get_external_interrupt(), None);
+
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 1 << 6);
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
+
+        // OCW2: Unmask IRQ line 6 on secondary (IRQ 14)
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.write(PIC_SECONDARY_DATA, &[0x00]);
+
+        // Previously-masked interrupt can now be served.
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 6));
+
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 1 << 6);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 1 << 2);
+    }
+
+    /// Write IMR to mask multiple IRQs. They masked IRQs cannot be served until they're unmasked.
+    /// The highest priority IRQ must be served first, no matter the original order of request.
+    /// (To simplify the test, we won't check irr and isr and so we'll leave auto EOI on.)
+    #[test]
+    fn mask_multiple_irq() {
+        let mut data = set_up();
+        icw_init_both(&mut data.pic);
+
+        // OCW2: Mask *all* IRQ lines on primary and secondary.
+        data.pic.write(PIC_PRIMARY_DATA, &[0xff]);
+        data.pic.write(PIC_SECONDARY_DATA, &[0xff]);
+
+        data.pic.service_irq(/*irq=*/ 14, /*level=*/ true);
+        data.pic.service_irq(/*irq=*/ 4, /*level=*/ true);
+        data.pic.service_irq(/*irq=*/ 12, /*level=*/ true);
+
+        // Primary cannot get any IRQs since they're all masked.
+        assert_eq!(data.pic.get_external_interrupt(), None);
+
+        // OCW2: Unmask IRQ lines on secondary.
+        data.pic.write(PIC_SECONDARY_DATA, &[0x00]);
+
+        // Cascade line is masked, so the primary *still* cannot get any IRQs.
+        assert_eq!(data.pic.get_external_interrupt(), None);
+
+        // Unmask cascade line on primary.
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.write(PIC_PRIMARY_DATA, &[0xfb]);
+
+        // Previously-masked IRQs should now be served in order of priority.
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 4));
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 6));
+
+        // Unmask all other IRQ lines on primary.
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.write(PIC_PRIMARY_DATA, &[0x00]);
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
+    }
+
+    /// Test OCW3 poll (reading irr and isr).
+    #[test]
+    fn ocw3() {
+        let mut data = set_up();
+        icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        // Poplate some data on irr/isr. IRQ4 will be in isr and IRQ5 in irr.
+        data.pic.service_irq(/*irq=*/ 5, /*level=*/ true);
+        data.pic.service_irq(/*irq=*/ 4, /*level=*/ true);
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
+
+        // Read primary IRR.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0x0a]);
+        let mut data_read = [0];
+        data.pic.read(PIC_PRIMARY_COMMAND, &mut data_read);
+        assert_eq!(data_read[0], 1 << 5);
+
+        // Read primary ISR.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0x0b]);
+        data_read = [0];
+        data.pic.read(PIC_PRIMARY_COMMAND, &mut data_read);
+        assert_eq!(data_read[0], 1 << 4);
+
+        // Non-sepcific EOI to end IRQ4.  Then, PIC should signal CPU about IRQ5.
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0x20]);
+
+        // Poll command on primary.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0x0c]);
+        data_read = [0];
+        data.pic.read(PIC_PRIMARY_COMMAND, &mut data_read);
+        assert_eq!(data_read[0], 5);
+    }
+
+    /// Assert on primary PIC's IRQ2 without any IRQ on secondary asserted. This should result in a
+    /// spurious IRQ on secondary.
+    #[test]
+    fn fake_irq_on_primary_irq2() {
+        let mut data = set_up();
+        icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.service_irq(/*irq=*/ 2, /*level=*/ true);
+        // 0x70 is secondary IRQ base, 7 is for a spurious IRQ.
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 7));
+    }
+
+    /// Raising the same IRQ line twice in edge trigger mode should only send one IRQ request out.
+    #[test]
+    fn edge_trigger_mode() {
+        let mut data = set_up();
+        icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.service_irq(/*irq=*/ 4, /*level=*/ true);
+        // get_external_interrupt clears the irr so it is possible to request the same IRQ again.
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
+
+        data.pic.service_irq(/*irq=*/ 4, /*level=*/ true);
+
+        // In edge triggered mode, there should be no IRQ after this EOI.
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0x20]);
+    }
+
+    /// Raising the same IRQ line twice in level-triggered mode should send two IRQ requests out.
+    #[test]
+    fn level_trigger_mode() {
+        let mut data = set_up();
+        icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
+
+        // Turn IRQ4 to level-triggered mode.
+        data.pic.write(PIC_PRIMARY_ELCR, &[0x10]);
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.service_irq(/*irq=*/ 4, /*level=*/ true);
+        // get_external_interrupt clears the irr so it is possible to request the same IRQ again.
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
+
+        data.pic.service_irq(/*irq=*/ 4, /*level=*/ true);
+
+        // In level-triggered mode, there should be another IRQ request after this EOI.
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0x20]);
+    }
+
+    /// Specific EOI command in OCW2.
+    #[test]
+    fn specific_eoi() {
+        let mut data = set_up();
+        icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.service_irq(/*irq=*/ 4, /*level=*/ true);
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
+
+        // Specific EOI command on IRQ3. Primary PIC's ISR should be unaffected since it's targeted
+        // at the wrong IRQ number.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0x63]);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 1 << 4);
+
+        // Specific EOI command on IRQ4. Primary PIC's ISR should now be cleared.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0x64]);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
+    }
+
+    /// Test rotate on auto EOI.
+    #[test]
+    fn rotate_on_auto_eoi() {
+        let mut data = set_up();
+        icw_init_both(&mut data.pic);
+
+        // OCW3: Clear rotate on auto EOI mode.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0x00]);
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.service_irq(/*irq=*/ 5, /*level=*/ true);
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5));
+        data.pic.service_irq(/*irq=*/ 5, /*level=*/ false);
+
+        // EOI automatically happened. Now priority should not be rotated.
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].imr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].last_irr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].priority_add, 0);
+
+        // OCW2: Set rotate on auto EOI mode.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0x80]);
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.service_irq(/*irq=*/ 5, /*level*/ true);
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5));
+        data.pic.service_irq(/*irq=*/ 5, /*level=*/ false);
+
+        // EOI automatically happened, and the priority *should* be rotated.
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].priority_add, 6);
+    }
+
+    /// Test rotate on specific (non-auto) EOI.
+    #[test]
+    fn rotate_on_specific_eoi() {
+        let mut data = set_up();
+        icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.service_irq(/*irq=*/ 5, /*level=*/ true);
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5));
+        data.pic.service_irq(/*irq=*/ 5, /*level=*/ false);
+
+        // Rotate on specific EOI IRQ4. Since this is a different IRQ number, Should not have an
+        // effect on isr.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0xe4]);
+
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 1 << 5);
+
+        // Rotate on specific EOI IRQ5. This should clear the isr.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0xe5]);
+
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].priority_add, 6);
+    }
+
+    /// Test rotate on non-specific EOI.
+    #[test]
+    fn rotate_non_specific_eoi() {
+        let mut data = set_up();
+        icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.service_irq(/*irq=*/ 5, /*level=*/ true);
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5));
+        data.pic.service_irq(/*irq=*/ 5, /*level=*/ false);
+
+        // Rotate on non-specific EOI.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0xa0]);
+
+        // The EOI should have cleared isr.
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].priority_add, 6);
+    }
+
+    /// Verify that no-op doesn't change state.
+    #[test]
+    fn no_op_ocw2() {
+        let mut data = set_up();
+        icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.service_irq(/*irq=*/ 5, /*level=*/ true);
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5));
+        data.pic.service_irq(/*irq=*/ 5, /*level=*/ false);
+
+        let orig = data.pic.pics[PicSelect::Primary as usize].clone();
+
+        // Run a no-op.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0x40]);
+
+        // Nothing should have changed.
+        assert_eq!(orig, data.pic.pics[PicSelect::Primary as usize]);
+    }
+
+    /// Tests cascade IRQ that happens on secondary PIC.
+    #[test]
+    fn cascade_irq() {
+        let mut data = set_up();
+        icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
+
+        // TODO(mutexlox): Verify APIC interaction when it is implemented.
+        data.pic.service_irq(/*irq=*/ 12, /*level=*/ true);
+
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 1 << 2);
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 1 << 4);
+
+        assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 4));
+
+        // Check that the IRQ is now acknowledged after get_external_interrupt().
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 1 << 4);
+
+        // OCW2: Two non-specific EOIs to primary rather than secondary.
+        // We need two non-specific EOIs:
+        //   - The first resets bit 2 in the primary isr (the highest-priority bit that was set
+        //     before the EOI)
+        //   - The second resets the secondary PIC's highest-priority isr bit.
+        data.pic.write(PIC_PRIMARY_COMMAND, &[0x20]);
+        // Rotate non-specific EOI.
+        data.pic.write(PIC_SECONDARY_COMMAND, &[0xa0]);
+
+        assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 0);
+        assert_eq!(data.pic.pics[PicSelect::Secondary as usize].priority_add, 5);
+    }
+}
diff --git a/devices/src/pit.rs b/devices/src/pit.rs
new file mode 100644
index 0000000..63f31f5
--- /dev/null
+++ b/devices/src/pit.rs
@@ -0,0 +1,1280 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Based heavily on GCE VMM's pit.cc.
+
+use std::fmt::{self, Display};
+use std::io::Error as IoError;
+use std::os::unix::io::AsRawFd;
+use std::sync::Arc;
+use std::thread;
+use std::time::Duration;
+
+use bit_field::BitField1;
+use bit_field::*;
+use sync::Mutex;
+use sys_util::{error, warn, Error as SysError, EventFd, Fd, PollContext, PollToken};
+
+#[cfg(not(test))]
+use sys_util::Clock;
+#[cfg(test)]
+use sys_util::FakeClock as Clock;
+
+#[cfg(test)]
+use sys_util::FakeTimerFd as TimerFd;
+#[cfg(not(test))]
+use sys_util::TimerFd;
+
+use crate::BusDevice;
+
+// Bitmask for areas of standard (non-ReadBack) Control Word Format. Constant
+// names are kept the same as Intel PIT data sheet.
+#[derive(Debug, Clone, Copy, PartialEq, enumn::N)]
+enum CommandBit {
+    CommandBCD = 0x01,  // Binary/BCD input. x86 only uses binary mode.
+    CommandMode = 0x0e, // Operating Mode (mode 0-5).
+    CommandRW = 0x30,   // Access mode: Choose high/low byte(s) to Read/Write.
+    CommandSC = 0xc0,   // Select Counter/Read-back command.
+}
+
+// Selects which counter is to be used by the associated command in the lower
+// six bits of the byte. However, if 0xc0 is specified, it indicates that the
+// command is a "Read-Back", which can latch count and/or status of the
+// counters selected in the lower bits. See Intel 8254 data sheet for details.
+#[allow(dead_code)]
+#[derive(Debug, Clone, Copy, PartialEq, enumn::N)]
+enum CommandCounter {
+    CommandCounter0 = 0x00, // Select counter 0.
+    CommandCounter1 = 0x40, // Select counter 1.
+    CommandCounter2 = 0x80, // Select counter 2.
+    CommandReadBack = 0xc0, // Execute Read-Back.
+}
+
+// Used for both CommandRW and ReadBackAccess.
+#[derive(Debug, Clone, Copy, PartialEq, enumn::N)]
+enum CommandAccess {
+    CommandLatch = 0x00,   // Latch specified counter.
+    CommandRWLeast = 0x10, // Read/Write least significant byte.
+    CommandRWMost = 0x20,  // Read/Write most significant byte.
+    CommandRWBoth = 0x30,  // Read/Write both bytes.
+}
+
+// Used for both CommandMode and ReadBackMode.
+// For mode 2 & 3, bit 3 is don't care bit (does not matter to be 0 or 1) but
+// per 8254 spec, should be 0 to insure compatibility with future Intel
+// products.
+#[derive(Debug, Clone, Copy, PartialEq, enumn::N)]
+enum CommandMode {
+    // NOTE:  No h/w modes are currently implemented.
+    CommandInterrupt = 0x00,     // Mode 0, interrupt on terminal count.
+    CommandHWOneShot = 0x02,     // Mode 1, h/w re-triggerable one-shot.
+    CommandRateGen = 0x04,       // Mode 2, rate generator.
+    CommandSquareWaveGen = 0x06, // Mode 3, square wave generator.
+    CommandSWStrobe = 0x08,      // Mode 4, s/w triggered strobe.
+    CommandHWStrobe = 0x0a,      // Mode 5, h/w triggered strobe.
+}
+
+// Bitmask for the latch portion of the ReadBack command.
+#[derive(Debug, Clone, Copy, PartialEq, enumn::N)]
+#[rustfmt::skip]  // rustfmt mangles comment indentation for trailing line comments.
+enum CommandReadBackLatch {
+    CommandRBLatchBits = 0x30,   // Mask bits that determine latching.
+    CommandRBLatchBoth = 0x00,   // Latch both count and status. This should
+                                 // never happen in device, since bit 4 and 5 in
+                                 // read back command are inverted.
+    CommandRBLatchCount = 0x10,  // Latch count.
+    CommandRBLatchStatus = 0x20, // Latch status.
+}
+
+// Bitmask for the counter portion of the ReadBack command.
+#[derive(Debug, Clone, Copy, PartialEq, enumn::N)]
+enum CommandReadBackCounters {
+    //CommandRBCounters = 0x0e, // Counters for which to provide ReadBack info.
+    CommandRBCounter2 = 0x08,
+    CommandRBCounter1 = 0x04,
+    CommandRBCounter0 = 0x02,
+}
+
+// Bitmask for the ReadBack status command.
+#[derive(Debug, Clone, Copy, PartialEq, enumn::N)]
+#[rustfmt::skip]  // rustfmt mangles comment indentation for last line of this enum.
+enum ReadBackData {
+    // Output format for ReadBack command.
+    ReadBackOutput = 0x80, // Output pin status.
+    ReadBackNullCount = 0x40, // Whether counter has value.
+    // ReadBackAccess, ReadBackMode, and ReadBackBCD intentionally omitted.
+}
+
+// I/O Port mappings in I/O bus.
+#[derive(Debug, Clone, Copy, PartialEq, enumn::N)]
+enum PortIOSpace {
+    PortCounter0Data = 0x40, // Read/write.
+    PortCounter1Data = 0x41, // Read/write.
+    PortCounter2Data = 0x42, // Read/write.
+    PortCommand = 0x43,      // Write only.
+    PortSpeaker = 0x61,      // Read/write.
+}
+
+#[bitfield]
+#[derive(Clone, Copy, PartialEq)]
+pub struct SpeakerPortFields {
+    // This field is documented in the chipset spec as NMI status and control
+    // register.  Bits 2, 3, 6, 7 and low level hardware bits that need no
+    // emulation for virtualized environments.  We call it speaker port because
+    // kvm, qemu, linux, and plan9 still call it speaker port, even though it
+    // has these other uses and is called something differently in the spec.
+    gate: BitField1,
+    speaker_on: BitField1,
+    pic_serr: BitField1,
+    iochk_enable: BitField1,
+    // This value changes as part of the refresh frequency of the board for
+    // piix4, this is about 1/15us.
+    refresh_clock: BitField1,
+    output: BitField1,
+    iochk_nmi: BitField1,
+    serr_nmi: BitField1,
+}
+
+// PIT frequency (in Hertz). See http://wiki.osdev.org/pit.
+const FREQUENCY_HZ: u64 = 1193182;
+
+const NUM_OF_COUNTERS: usize = 3;
+
+const NANOS_PER_SEC: u64 = 1_000_000_000;
+
+const MAX_TIMER_FREQ: u32 = 65536;
+
+#[derive(Debug)]
+pub enum PitError {
+    TimerFdCreateError(SysError),
+    /// Creating PollContext failed.
+    CreatePollContext(SysError),
+    /// Error while polling for events.
+    PollError(SysError),
+    /// Error while trying to create worker thread.
+    SpawnThread(IoError),
+    /// Error while creating event FD.
+    CreateEventFd(SysError),
+    /// Error while cloning event FD for worker thread.
+    CloneEventFd(SysError),
+}
+
+impl Display for PitError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::PitError::*;
+
+        match self {
+            TimerFdCreateError(e) => {
+                write!(f, "failed to create pit counter due to timer fd: {}", e)
+            }
+            CreatePollContext(e) => write!(f, "failed to create poll context: {}", e),
+            PollError(err) => write!(f, "failed to poll events: {}", err),
+            SpawnThread(err) => write!(f, "failed to spawn thread: {}", err),
+            CreateEventFd(err) => write!(f, "failed to create event fd: {}", err),
+            CloneEventFd(err) => write!(f, "failed to clone event fd: {}", err),
+        }
+    }
+}
+
+impl std::error::Error for PitError {}
+
+type PitResult<T> = std::result::Result<T, PitError>;
+
+pub struct Pit {
+    // Structs that store each counter's state.
+    counters: Vec<Arc<Mutex<PitCounter>>>,
+    // Worker thread to update counter 0's state asynchronously. Counter 0 needs to send interrupts
+    // when timers expire, so it needs asynchronous updates. All other counters need only update
+    // when queried directly by the guest.
+    worker_thread: Option<thread::JoinHandle<PitResult<()>>>,
+    kill_evt: EventFd,
+}
+
+impl Drop for Pit {
+    fn drop(&mut self) {
+        if let Err(e) = self.kill_evt.write(1) {
+            error!("failed to kill PIT worker threads: {}", e);
+            return;
+        }
+        if let Some(thread) = self.worker_thread.take() {
+            match thread.join() {
+                Ok(r) => {
+                    if let Err(e) = r {
+                        error!("pit worker thread exited with error: {}", e)
+                    }
+                }
+                Err(e) => error!("pit worker thread panicked: {:?}", e),
+            }
+        }
+    }
+}
+
+impl BusDevice for Pit {
+    fn debug_label(&self) -> String {
+        "userspace PIT".to_string()
+    }
+
+    fn write(&mut self, offset: u64, data: &[u8]) {
+        if data.len() != 1 {
+            warn!("Bad write size for Pit: {}", data.len());
+            return;
+        }
+        match PortIOSpace::n(offset as i64) {
+            Some(PortIOSpace::PortCounter0Data) => self.counters[0].lock().write_counter(data[0]),
+            Some(PortIOSpace::PortCounter1Data) => self.counters[1].lock().write_counter(data[0]),
+            Some(PortIOSpace::PortCounter2Data) => self.counters[2].lock().write_counter(data[0]),
+            Some(PortIOSpace::PortCommand) => self.command_write(data[0]),
+            Some(PortIOSpace::PortSpeaker) => self.counters[2].lock().write_speaker(data[0]),
+            None => warn!("PIT: bad write to offset {}", offset),
+        }
+    }
+
+    fn read(&mut self, offset: u64, data: &mut [u8]) {
+        if data.len() != 1 {
+            warn!("Bad read size for Pit: {}", data.len());
+            return;
+        }
+        data[0] = match PortIOSpace::n(offset as i64) {
+            Some(PortIOSpace::PortCounter0Data) => self.counters[0].lock().read_counter(),
+            Some(PortIOSpace::PortCounter1Data) => self.counters[1].lock().read_counter(),
+            Some(PortIOSpace::PortCounter2Data) => self.counters[2].lock().read_counter(),
+            // This should function as a no-op, since the specification doesn't allow the
+            // command register to be read. However, software is free to ask for it to
+            // to be read.
+            Some(PortIOSpace::PortCommand) => {
+                warn!("Ignoring read to command reg");
+                0
+            }
+            Some(PortIOSpace::PortSpeaker) => self.counters[2].lock().read_speaker(),
+            None => {
+                warn!("PIT: bad read from offset {}", offset);
+                return;
+            }
+        };
+    }
+}
+
+impl Pit {
+    pub fn new(interrupt_evt: EventFd, clock: Arc<Mutex<Clock>>) -> PitResult<Pit> {
+        let mut counters = Vec::new();
+        let mut interrupt = Some(interrupt_evt);
+        for i in 0..NUM_OF_COUNTERS {
+            let pit_counter = PitCounter::new(i, interrupt, clock.clone())?;
+            counters.push(Arc::new(Mutex::new(pit_counter)));
+            // pass interrupt IrqFd ONLY to counter 0; the rest do not deliver interrupts.
+            interrupt = None;
+        }
+        // We asssert here because:
+        // (a) this code only gets invoked at VM startup
+        // (b) the assert is very loud and would be easy to notice in tests
+        // (c) if we have the wrong number of counters, something is very wrong with the PIT and it
+        // may not make sense to continue operation.
+        assert_eq!(counters.len(), NUM_OF_COUNTERS);
+        let (self_kill_evt, kill_evt) = EventFd::new()
+            .and_then(|e| Ok((e.try_clone()?, e)))
+            .map_err(PitError::CreateEventFd)?;
+        let mut worker = Worker {
+            pit_counter: counters[0].clone(),
+            fd: Fd(counters[0].lock().timer.as_raw_fd()),
+        };
+        let evt = kill_evt.try_clone().map_err(PitError::CloneEventFd)?;
+        let worker_thread = thread::Builder::new()
+            .name("pit counter worker".to_string())
+            .spawn(move || worker.run(evt))
+            .map_err(PitError::SpawnThread)?;
+        Ok(Pit {
+            counters,
+            worker_thread: Some(worker_thread),
+            kill_evt: self_kill_evt,
+        })
+    }
+
+    fn command_write(&mut self, control_word: u8) {
+        let command: u16 = (control_word & CommandBit::CommandSC as u8).into();
+        let counter_index: usize = (command >> 6).into();
+        if command == (CommandCounter::CommandReadBack as u16) {
+            // ReadBack commands can apply to multiple counters.
+            if (control_word & (CommandReadBackCounters::CommandRBCounter0 as u8)) != 0 {
+                self.counters[0].lock().read_back_command(control_word);
+            }
+            if (control_word & (CommandReadBackCounters::CommandRBCounter1 as u8)) != 0 {
+                self.counters[1].lock().read_back_command(control_word);
+            }
+            if (control_word & (CommandReadBackCounters::CommandRBCounter2 as u8)) != 0 {
+                self.counters[2].lock().read_back_command(control_word);
+            }
+        } else if (control_word & (CommandBit::CommandRW as u8))
+            == (CommandAccess::CommandLatch as u8)
+        {
+            self.counters[counter_index].lock().latch_counter();
+        } else {
+            self.counters[counter_index]
+                .lock()
+                .store_command(control_word);
+        }
+    }
+}
+
+// Each instance of this represents one of the PIT counters. They are used to
+// implement one-shot and repeating timer alarms. An 8254 has three counters.
+struct PitCounter {
+    // EventFd to write when asserting an interrupt.
+    interrupt_evt: Option<EventFd>,
+    // Stores the value with which the counter was initialized. Counters are 16-
+    // bit values with an effective range of 1-65536 (65536 represented by 0).
+    reload_value: u16,
+    // Stores value when latch was called.
+    latched_value: u16,
+    // Stores last command from command register.
+    command: u8,
+    // Stores status from readback command
+    status: u8,
+    // Stores time of starting timer. Used for calculating remaining count, if an alarm is
+    // scheduled.
+    start: Option<Clock>,
+    // Current time.
+    clock: Arc<Mutex<Clock>>,
+    // Time when object was created. Used for a 15us counter.
+    creation_time: Clock,
+    // The number of the counter. The behavior for each counter is slightly different.
+    // Note that once a PitCounter is created, this value should never change.
+    counter_id: usize,
+    // Indicates if the low byte has been written in RWBoth.
+    wrote_low_byte: bool,
+    // Indicates if the low byte has been read in RWBoth.
+    read_low_byte: bool,
+    // Indicates whether counter has been latched.
+    latched: bool,
+    // Indicates whether ReadBack status has been latched.
+    status_latched: bool,
+    // Only should be used for counter 2. See http://wiki.osdev.org/PIT.
+    gate: bool,
+    speaker_on: bool,
+    // The starting value for the counter.
+    count: u32,
+    // Indicates whether the current timer is valid.
+    timer_valid: bool,
+    // Timer to set and receive periodic notifications.
+    timer: TimerFd,
+}
+
+impl Drop for PitCounter {
+    fn drop(&mut self) {
+        if self.timer_valid {
+            // This should not fail - timer.clear() only fails if timerfd_settime fails, which
+            // only happens due to invalid arguments or bad file descriptors. The arguments to
+            // timerfd_settime are constant, so its arguments won't be invalid, and it manages
+            // the file descriptor safely (we don't use the unsafe FromRawFd) so its file
+            // descriptor will be valid.
+            self.timer.clear().unwrap();
+        }
+    }
+}
+
+fn adjust_count(count: u32) -> u32 {
+    // As per spec 0 means max.
+    if count == 0 {
+        MAX_TIMER_FREQ
+    } else {
+        count
+    }
+}
+
+impl PitCounter {
+    fn new(
+        counter_id: usize,
+        interrupt_evt: Option<EventFd>,
+        clock: Arc<Mutex<Clock>>,
+    ) -> PitResult<PitCounter> {
+        #[cfg(not(test))]
+        let timer = TimerFd::new().map_err(PitError::TimerFdCreateError)?;
+        #[cfg(test)]
+        let timer = TimerFd::new(clock.clone());
+        Ok(PitCounter {
+            interrupt_evt,
+            reload_value: 0,
+            latched_value: 0,
+            command: 0,
+            status: 0,
+            start: None,
+            clock: clock.clone(),
+            creation_time: clock.lock().now(),
+            counter_id,
+            wrote_low_byte: false,
+            read_low_byte: false,
+            latched: false,
+            status_latched: false,
+            gate: false,
+            speaker_on: false,
+            // `count` is undefined in real hardware and can't ever be programmed to 0, so we
+            // initialize it to max to prevent a misbehaving guest from triggering a divide by 0.
+            count: MAX_TIMER_FREQ,
+            timer_valid: false,
+            timer,
+        })
+    }
+
+    fn get_access_mode(&self) -> Option<CommandAccess> {
+        CommandAccess::n(self.command & (CommandBit::CommandRW as u8))
+    }
+
+    fn get_command_mode(&self) -> Option<CommandMode> {
+        CommandMode::n(self.command & CommandBit::CommandMode as u8)
+    }
+
+    fn read_counter(&mut self) -> u8 {
+        if self.status_latched {
+            self.status_latched = false;
+            return self.status;
+        };
+        let data_value: u16 = if self.latched {
+            self.latched_value
+        } else {
+            self.get_read_value()
+        };
+
+        let access_mode = self.get_access_mode();
+        // Latch may be true without being indicated by the access mode if
+        // a ReadBack was issued.
+        match (access_mode, self.read_low_byte) {
+            (Some(CommandAccess::CommandRWLeast), _) => {
+                self.latched = false; // Unlatch if only reading the low byte.
+                (data_value & 0xff) as u8
+            }
+            (Some(CommandAccess::CommandRWBoth), false) => {
+                self.read_low_byte = true;
+                (data_value & 0xff) as u8
+            }
+            (Some(CommandAccess::CommandRWBoth), true)
+            | (Some(CommandAccess::CommandRWMost), _) => {
+                self.read_low_byte = false; // Allow for future reads for RWBoth.
+                self.latched = false;
+                (data_value >> 8) as u8
+            }
+            (_, _) => 0, // Default for erroneous call
+        }
+    }
+
+    fn write_counter(&mut self, written_datum: u8) {
+        let access_mode = self.get_access_mode();
+        let datum: u16 = written_datum.into();
+        let mut should_start_timer = true;
+        self.reload_value = match access_mode {
+            Some(CommandAccess::CommandRWLeast) => datum,
+            Some(CommandAccess::CommandRWMost) => datum << 8,
+            Some(CommandAccess::CommandRWBoth) => {
+                // In kCommandRWBoth mode, the first guest write is the low byte and the
+                // the second guest write is the high byte.  The timer isn't started
+                // until after the second byte is written.
+                if self.wrote_low_byte {
+                    self.wrote_low_byte = false;
+                    self.reload_value | (datum << 8)
+                } else {
+                    self.wrote_low_byte = true;
+                    should_start_timer = false; // Don't start until high byte written.
+                    datum
+                }
+            }
+            _ => {
+                should_start_timer = false;
+                self.reload_value
+            }
+        };
+        if should_start_timer {
+            let reload: u32 = self.reload_value.into();
+            self.load_and_start_timer(reload);
+        }
+    }
+
+    fn get_output(&self) -> bool {
+        let ticks_passed = self.get_ticks_passed();
+        let count: u64 = self.count.into();
+        match self.get_command_mode() {
+            Some(CommandMode::CommandInterrupt) => ticks_passed >= count,
+            Some(CommandMode::CommandHWOneShot) => ticks_passed < count,
+            Some(CommandMode::CommandRateGen) => ticks_passed != 0 && ticks_passed % count == 0,
+            Some(CommandMode::CommandSquareWaveGen) => ticks_passed < (count + 1) / 2,
+            Some(CommandMode::CommandSWStrobe) | Some(CommandMode::CommandHWStrobe) => {
+                ticks_passed == count
+            }
+            None => {
+                warn!("Invalid command mode based on command: {:#x}", self.command);
+                false
+            }
+        }
+    }
+
+    fn read_speaker(&self) -> u8 {
+        // Refresh clock is a value independent of the actual
+        // counter that goes up and down approx every 15 us (~66000/s).
+        let us = self
+            .clock
+            .lock()
+            .now()
+            .duration_since(&self.creation_time)
+            .subsec_micros();
+        let refresh_clock = us % 15 == 0;
+        let mut speaker = SpeakerPortFields::new();
+        speaker.set_gate(self.gate.into());
+        speaker.set_speaker_on(self.speaker_on.into());
+        speaker.set_iochk_enable(0);
+        speaker.set_refresh_clock(refresh_clock.into());
+        speaker.set_output(self.get_output().into());
+        speaker.set_iochk_nmi(0);
+        speaker.set_serr_nmi(0);
+        speaker.get(/*offset=*/ 0, /*width=*/ 8) as u8
+    }
+
+    fn write_speaker(&mut self, datum: u8) {
+        let mut speaker = SpeakerPortFields::new();
+        speaker.set(/*offset=*/ 0, /*width=*/ 8, datum.into());
+        let new_gate = speaker.get_gate() != 0;
+        match self.get_command_mode() {
+            Some(CommandMode::CommandInterrupt) | Some(CommandMode::CommandSWStrobe) => (),
+            Some(_) => {
+                if new_gate && !self.gate {
+                    self.start = Some(self.clock.lock().now());
+                }
+            }
+            None => {
+                warn!("Invalid command mode based on command {:#x}", self.command);
+                return;
+            }
+        }
+        self.speaker_on = speaker.get_speaker_on() != 0;
+        self.gate = new_gate;
+    }
+
+    fn load_and_start_timer(&mut self, initial_count: u32) {
+        self.count = adjust_count(initial_count);
+        self.start_timer();
+    }
+
+    fn start_timer(&mut self) {
+        self.start = Some(self.clock.lock().now());
+
+        // Counter 0 is the only counter that generates interrupts, so we
+        // don't need to set a timer for the other two counters.
+        if self.counter_id != 0 {
+            return;
+        }
+
+        let timer_len = Duration::from_nanos(u64::from(self.count) * NANOS_PER_SEC / FREQUENCY_HZ);
+
+        let period_ns = match self.get_command_mode() {
+            Some(CommandMode::CommandInterrupt)
+            | Some(CommandMode::CommandHWOneShot)
+            | Some(CommandMode::CommandSWStrobe)
+            | Some(CommandMode::CommandHWStrobe) => Duration::new(0, 0),
+            Some(CommandMode::CommandRateGen) | Some(CommandMode::CommandSquareWaveGen) => {
+                timer_len
+            }
+            // Don't arm timer if invalid mode.
+            None => {
+                // This will still result in start being set to the current time.
+                // Per spec:
+                //   A new initial count may be written to a Counter at any time without affecting
+                //   the Counter’s programmed Mode in any way. Counting will be affected as
+                //   described in the Mode definitions. The new count must follow the programmed
+                //   count format
+                // It's unclear whether setting `self.start` in this case is entirely compliant,
+                // but the spec is fairly quiet on expected behavior in error cases, so OSs
+                // shouldn't enter invalid modes in the first place.  If they do, and then try to
+                // get out of it by first setting the counter then the command, this behavior will
+                // (perhaps) be minimally surprising, but arguments can be made for other behavior.
+                // It's uncertain if this behavior matches real PIT hardware.
+                warn!("Invalid command mode based on command {:#x}", self.command);
+                return;
+            }
+        };
+
+        self.safe_arm_timer(timer_len, period_ns);
+        self.timer_valid = true;
+    }
+
+    fn read_back_command(&mut self, control_word: u8) {
+        let latch_cmd =
+            CommandReadBackLatch::n(control_word & CommandReadBackLatch::CommandRBLatchBits as u8);
+        match latch_cmd {
+            Some(CommandReadBackLatch::CommandRBLatchCount) => {
+                self.latch_counter();
+            }
+            Some(CommandReadBackLatch::CommandRBLatchStatus) => {
+                self.latch_status();
+            }
+            _ => warn!(
+                "Unexpected ReadBackLatch. control_word: {:#x}",
+                control_word
+            ),
+        };
+    }
+
+    fn latch_counter(&mut self) {
+        if self.latched {
+            return;
+        }
+
+        self.latched_value = self.get_read_value();
+        self.latched = true;
+        self.read_low_byte = false;
+    }
+
+    fn latch_status(&mut self) {
+        // Including BCD here, even though it currently never gets used.
+        self.status = self.command
+            & (CommandBit::CommandRW as u8
+                | CommandBit::CommandMode as u8
+                | CommandBit::CommandBCD as u8);
+        if self.start.is_none() {
+            self.status |= ReadBackData::ReadBackNullCount as u8;
+        }
+        if self.get_output() {
+            self.status |= ReadBackData::ReadBackOutput as u8;
+        }
+        self.status_latched = true;
+    }
+
+    fn store_command(&mut self, datum: u8) {
+        self.command = datum;
+        self.latched = false;
+
+        // If a new RW command is written, cancel the current timer.
+        if self.timer_valid {
+            self.start = None;
+            self.timer_valid = false;
+            // See the comment in the impl of Drop for PitCounter for justification of the unwrap()
+            self.timer.clear().unwrap();
+        }
+
+        self.wrote_low_byte = false;
+        self.read_low_byte = false;
+    }
+
+    fn timer_handler(&mut self) {
+        if let Err(e) = self.timer.wait() {
+            // Under the current timerfd implementation (as of Jan 2019), this failure shouldn't
+            // happen but implementation details may change in the future, and the failure
+            // cases are complex to reason about. Because of this, avoid unwrap().
+            error!("pit: timer wait unexpectedly failed: {}", e);
+            return;
+        }
+        let mode = self.get_command_mode();
+        if mode == Some(CommandMode::CommandRateGen)
+            || mode == Some(CommandMode::CommandSquareWaveGen)
+        {
+            // Reset the start time for timer modes that repeat.
+            self.start = Some(self.clock.lock().now());
+        }
+
+        // For square wave mode, this isn't quite accurate to the spec, but the
+        // difference isn't meaningfully visible to the guest in any important way,
+        // and the code is simpler without the special case.
+        if let Some(interrupt) = &mut self.interrupt_evt {
+            // This is safe because the file descriptor is nonblocking and we're writing 1.
+            interrupt.write(1).unwrap();
+        }
+    }
+
+    fn safe_arm_timer(&mut self, mut due: Duration, period: Duration) {
+        if due == Duration::new(0, 0) {
+            due = Duration::from_nanos(1);
+        }
+
+        if let Err(e) = self.timer.reset(due, Some(period)) {
+            error!("failed to reset timer: {}", e);
+        }
+    }
+
+    fn get_ticks_passed(&self) -> u64 {
+        match &self.start {
+            None => 0,
+            Some(t) => {
+                let dur = self.clock.lock().now().duration_since(t);
+                let dur_ns: u64 = dur.as_secs() * NANOS_PER_SEC + u64::from(dur.subsec_nanos());
+                (dur_ns * FREQUENCY_HZ / NANOS_PER_SEC)
+            }
+        }
+    }
+
+    fn get_read_value(&self) -> u16 {
+        match self.start {
+            None => 0,
+            Some(_) => {
+                let count: u64 = adjust_count(self.reload_value.into()).into();
+                let ticks_passed = self.get_ticks_passed();
+                match self.get_command_mode() {
+                    Some(CommandMode::CommandInterrupt)
+                    | Some(CommandMode::CommandHWOneShot)
+                    | Some(CommandMode::CommandSWStrobe)
+                    | Some(CommandMode::CommandHWStrobe) => {
+                        if ticks_passed > count {
+                            // Some risk of raciness here in that the count may return a value
+                            // indicating that the count has expired when the interrupt hasn't
+                            // yet been injected.
+                            0
+                        } else {
+                            ((count - ticks_passed) & 0xFFFF) as u16
+                        }
+                    }
+                    Some(CommandMode::CommandRateGen) => (count - (ticks_passed % count)) as u16,
+                    Some(CommandMode::CommandSquareWaveGen) => {
+                        (count - ((ticks_passed * 2) % count)) as u16
+                    }
+                    None => {
+                        warn!("Invalid command mode: command = {:#x}", self.command);
+                        0
+                    }
+                }
+            }
+        }
+    }
+}
+
+struct Worker {
+    pit_counter: Arc<Mutex<PitCounter>>,
+    fd: Fd,
+}
+
+impl Worker {
+    fn run(&mut self, kill_evt: EventFd) -> PitResult<()> {
+        #[derive(PollToken)]
+        enum Token {
+            // The timer expired.
+            TimerExpire,
+            // The parent thread requested an exit.
+            Kill,
+        }
+
+        let poll_ctx: PollContext<Token> = PollContext::new()
+            .and_then(|pc| pc.add(&self.fd, Token::TimerExpire).and(Ok(pc)))
+            .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc)))
+            .map_err(PitError::CreatePollContext)?;
+
+        loop {
+            let events = poll_ctx.wait().map_err(PitError::PollError)?;
+            for event in events.iter_readable() {
+                match event.token() {
+                    Token::TimerExpire => {
+                        let mut pit = self.pit_counter.lock();
+                        pit.timer_handler();
+                    }
+                    Token::Kill => return Ok(()),
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    struct TestData {
+        pit: Pit,
+        irqfd: EventFd,
+        clock: Arc<Mutex<Clock>>,
+    }
+
+    /// Utility method for writing a command word to a command register.
+    fn write_command(pit: &mut Pit, command: u8) {
+        pit.write(PortIOSpace::PortCommand as u64, &[command])
+    }
+
+    /// Utility method for writing a command word to the speaker register.
+    fn write_speaker(pit: &mut Pit, command: u8) {
+        pit.write(PortIOSpace::PortSpeaker as u64, &[command])
+    }
+
+    /// Utility method for writing to a counter.
+    fn write_counter(pit: &mut Pit, counter_idx: usize, data: u16, access_mode: CommandAccess) {
+        let port = match counter_idx {
+            0 => PortIOSpace::PortCounter0Data,
+            1 => PortIOSpace::PortCounter1Data,
+            2 => PortIOSpace::PortCounter2Data,
+            _ => panic!("Invalid counter_idx: {}", counter_idx),
+        } as u64;
+        // Write the least, then the most, significant byte.
+        if access_mode == CommandAccess::CommandRWLeast
+            || access_mode == CommandAccess::CommandRWBoth
+        {
+            pit.write(port, &[(data & 0xff) as u8]);
+        }
+        if access_mode == CommandAccess::CommandRWMost
+            || access_mode == CommandAccess::CommandRWBoth
+        {
+            pit.write(port, &[(data >> 8) as u8]);
+        }
+    }
+
+    /// Utility method for reading a counter. Check if the read value matches expected_value.
+    fn read_counter(pit: &mut Pit, counter_idx: usize, expected: u16, access_mode: CommandAccess) {
+        let port = match counter_idx {
+            0 => PortIOSpace::PortCounter0Data,
+            1 => PortIOSpace::PortCounter1Data,
+            2 => PortIOSpace::PortCounter2Data,
+            _ => panic!("Invalid counter_idx: {}", counter_idx),
+        } as u64;
+        let mut result: u16 = 0;
+        if access_mode == CommandAccess::CommandRWLeast
+            || access_mode == CommandAccess::CommandRWBoth
+        {
+            let mut buffer = [0];
+            pit.read(port, &mut buffer);
+            result = buffer[0].into();
+        }
+        if access_mode == CommandAccess::CommandRWMost
+            || access_mode == CommandAccess::CommandRWBoth
+        {
+            let mut buffer = [0];
+            pit.read(port, &mut buffer);
+            result |= u16::from(buffer[0]) << 8;
+        }
+        assert_eq!(result, expected);
+    }
+
+    fn set_up() -> TestData {
+        let irqfd = EventFd::new().unwrap();
+        let clock = Arc::new(Mutex::new(Clock::new()));
+        TestData {
+            pit: Pit::new(irqfd.try_clone().unwrap(), clock.clone()).unwrap(),
+            irqfd,
+            clock,
+        }
+    }
+
+    fn advance_by_tick(data: &mut TestData) {
+        advance_by_ticks(data, 1);
+    }
+
+    fn advance_by_ticks(data: &mut TestData, ticks: u64) {
+        println!(
+            "Advancing by {:#x} ticks ({} ns)",
+            ticks,
+            (NANOS_PER_SEC * ticks) / FREQUENCY_HZ + 1
+        );
+        let mut lock = data.clock.lock();
+        lock.add_ns((NANOS_PER_SEC * ticks) / FREQUENCY_HZ + 1);
+    }
+
+    /// Tests the ability to write a command and data and read the data back using latch.
+    #[test]
+    fn write_and_latch() {
+        let mut data = set_up();
+        let both_interrupt =
+            CommandAccess::CommandRWBoth as u8 | CommandMode::CommandInterrupt as u8;
+        // Issue a command to write both digits of counter 0 in interrupt mode.
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8 | both_interrupt,
+        );
+        write_counter(&mut data.pit, 0, 24, CommandAccess::CommandRWBoth);
+        // Advance time by one tick -- value read back should decrease.
+        advance_by_tick(&mut data);
+
+        // Latch and read back the value written.
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
+        );
+        // Advance again after latching to verify that value read back doesn't change.
+        advance_by_tick(&mut data);
+        read_counter(&mut data.pit, 0, 23, CommandAccess::CommandRWBoth);
+
+        // Repeat with counter 1.
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter1 as u8 | both_interrupt,
+        );
+        write_counter(&mut data.pit, 1, 314, CommandAccess::CommandRWBoth);
+        advance_by_tick(&mut data);
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter1 as u8 | CommandAccess::CommandLatch as u8,
+        );
+        advance_by_tick(&mut data);
+        read_counter(&mut data.pit, 1, 313, CommandAccess::CommandRWBoth);
+
+        // Repeat with counter 2.
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter2 as u8 | both_interrupt,
+        );
+        write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
+        advance_by_tick(&mut data);
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter2 as u8 | CommandAccess::CommandLatch as u8,
+        );
+        advance_by_tick(&mut data);
+        read_counter(&mut data.pit, 2, 0xfffe, CommandAccess::CommandRWBoth);
+    }
+
+    /// Tests the ability to read only the least significant byte.
+    #[test]
+    fn write_and_read_least() {
+        let mut data = set_up();
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8
+                | CommandAccess::CommandRWLeast as u8
+                | CommandMode::CommandInterrupt as u8,
+        );
+        write_counter(&mut data.pit, 0, 0x3424, CommandAccess::CommandRWLeast);
+        read_counter(&mut data.pit, 0, 0x0024, CommandAccess::CommandRWLeast);
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
+        );
+        advance_by_tick(&mut data);
+        read_counter(&mut data.pit, 0, 0x0024, CommandAccess::CommandRWLeast);
+    }
+
+    /// Tests the ability to read only the most significant byte.
+    #[test]
+    fn write_and_read_most() {
+        let mut data = set_up();
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8
+                | CommandAccess::CommandRWMost as u8
+                | CommandMode::CommandInterrupt as u8,
+        );
+        write_counter(&mut data.pit, 0, 0x3424, CommandAccess::CommandRWMost);
+        read_counter(&mut data.pit, 0, 0x3400, CommandAccess::CommandRWMost);
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
+        );
+        advance_by_tick(&mut data);
+        read_counter(&mut data.pit, 0, 0x3400, CommandAccess::CommandRWMost);
+    }
+
+    /// Tests that reading the command register does nothing.
+    #[test]
+    fn read_command() {
+        let mut data = set_up();
+        let mut buf = [0];
+        data.pit.read(PortIOSpace::PortCommand as u64, &mut buf);
+        assert_eq!(buf, [0]);
+    }
+
+    /// Tests that latching prevents the read time from actually advancing.
+    #[test]
+    fn test_timed_latch() {
+        let mut data = set_up();
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8
+                | CommandAccess::CommandRWBoth as u8
+                | CommandMode::CommandInterrupt as u8,
+        );
+        write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
+        );
+        data.clock.lock().add_ns(25_000_000);
+        // The counter should ignore this second latch.
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
+        );
+        read_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
+        // It should, however, store the count for this latch.
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
+        );
+        read_counter(
+            &mut data.pit,
+            0,
+            0xffff - ((25_000_000 * FREQUENCY_HZ) / NANOS_PER_SEC) as u16,
+            CommandAccess::CommandRWBoth,
+        );
+    }
+
+    /// Tests Mode 0 (Interrupt on terminal count); checks whether IRQ has been asserted.
+    #[test]
+    fn interrupt_mode() {
+        let mut data = set_up();
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8
+                | CommandAccess::CommandRWBoth as u8
+                | CommandMode::CommandInterrupt as u8,
+        );
+        write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
+        // Advance clock enough to trigger interrupt.
+        advance_by_ticks(&mut data, 0xffff);
+        assert_eq!(data.irqfd.read().unwrap(), 1);
+    }
+
+    /// Tests that Rate Generator mode (mode 2) handls the interrupt properly when the timer
+    /// expires and that it resets the timer properly.
+    #[test]
+    fn rate_gen_mode() {
+        let mut data = set_up();
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8
+                | CommandAccess::CommandRWBoth as u8
+                | CommandMode::CommandRateGen as u8,
+        );
+        write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
+        // Repatedly advance clock and expect interrupt.
+        advance_by_ticks(&mut data, 0xffff);
+        assert_eq!(data.irqfd.read().unwrap(), 1);
+
+        // Repatedly advance clock and expect interrupt.
+        advance_by_ticks(&mut data, 0xffff);
+        assert_eq!(data.irqfd.read().unwrap(), 1);
+
+        // Repatedly advance clock and expect interrupt.
+        advance_by_ticks(&mut data, 0xffff);
+        assert_eq!(data.irqfd.read().unwrap(), 1);
+    }
+
+    /// Tests that square wave mode advances the counter correctly.
+    #[test]
+    fn square_wave_counter_read() {
+        let mut data = set_up();
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8
+                | CommandAccess::CommandRWBoth as u8
+                | CommandMode::CommandSquareWaveGen as u8,
+        );
+        write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
+
+        advance_by_ticks(&mut data, 10_000);
+        read_counter(
+            &mut data.pit,
+            0,
+            0xffff - 10_000 * 2,
+            CommandAccess::CommandRWBoth,
+        );
+    }
+
+    /// Tests that rategen mode updates the counter correctly.
+    #[test]
+    fn rate_gen_counter_read() {
+        let mut data = set_up();
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8
+                | CommandAccess::CommandRWBoth as u8
+                | CommandMode::CommandRateGen as u8,
+        );
+        write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
+
+        advance_by_ticks(&mut data, 10_000);
+        read_counter(
+            &mut data.pit,
+            0,
+            0xffff - 10_000,
+            CommandAccess::CommandRWBoth,
+        );
+    }
+
+    /// Tests that interrupt counter mode updates the counter correctly.
+    #[test]
+    fn interrupt_counter_read() {
+        let mut data = set_up();
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8
+                | CommandAccess::CommandRWBoth as u8
+                | CommandMode::CommandInterrupt as u8,
+        );
+        write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
+
+        advance_by_ticks(&mut data, 10_000);
+        read_counter(
+            &mut data.pit,
+            0,
+            0xffff - 10_000,
+            CommandAccess::CommandRWBoth,
+        );
+
+        advance_by_ticks(&mut data, (3 * FREQUENCY_HZ).into());
+        read_counter(&mut data.pit, 0, 0, CommandAccess::CommandRWBoth);
+    }
+
+    /// Tests that ReadBack count works properly for `low` access mode.
+    #[test]
+    fn read_back_count_access_low() {
+        let mut data = set_up();
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8
+                | CommandAccess::CommandRWLeast as u8
+                | CommandMode::CommandInterrupt as u8,
+        );
+        write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWLeast);
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandReadBack as u8
+                | CommandReadBackLatch::CommandRBLatchCount as u8
+                | CommandReadBackCounters::CommandRBCounter0 as u8,
+        );
+
+        // Advance 100 ticks and verify that low byte of counter is appropriately updated.
+        advance_by_ticks(&mut data, 100);
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandReadBack as u8
+                | CommandReadBackLatch::CommandRBLatchCount as u8
+                | CommandReadBackCounters::CommandRBCounter0 as u8,
+        );
+        read_counter(&mut data.pit, 0, 0x00ff, CommandAccess::CommandRWLeast);
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandReadBack as u8
+                | CommandReadBackLatch::CommandRBLatchCount as u8
+                | CommandReadBackCounters::CommandRBCounter0 as u8,
+        );
+        read_counter(
+            &mut data.pit,
+            0,
+            (0xffff - 100) & 0x00ff,
+            CommandAccess::CommandRWLeast,
+        );
+    }
+
+    /// Tests that ReadBack count works properly for `high` access mode.
+    #[test]
+    fn read_back_count_access_high() {
+        let mut data = set_up();
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8
+                | CommandAccess::CommandRWMost as u8
+                | CommandMode::CommandInterrupt as u8,
+        );
+        write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWLeast);
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandReadBack as u8
+                | CommandReadBackLatch::CommandRBLatchCount as u8
+                | CommandReadBackCounters::CommandRBCounter0 as u8,
+        );
+
+        // Advance 100 ticks and verify that low byte of counter is appropriately updated.
+        advance_by_ticks(&mut data, 512);
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandReadBack as u8
+                | CommandReadBackLatch::CommandRBLatchCount as u8
+                | CommandReadBackCounters::CommandRBCounter0 as u8,
+        );
+        read_counter(&mut data.pit, 0, 0xff00, CommandAccess::CommandRWMost);
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandReadBack as u8
+                | CommandReadBackLatch::CommandRBLatchCount as u8
+                | CommandReadBackCounters::CommandRBCounter0 as u8,
+        );
+        read_counter(
+            &mut data.pit,
+            0,
+            (0xffff - 512) & 0xff00,
+            CommandAccess::CommandRWMost,
+        );
+    }
+
+    /// Tests that ReadBack status returns the expected values.
+    #[test]
+    fn read_back_status() {
+        let mut data = set_up();
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter0 as u8
+                | CommandAccess::CommandRWBoth as u8
+                | CommandMode::CommandSWStrobe as u8,
+        );
+        write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandReadBack as u8
+                | CommandReadBackLatch::CommandRBLatchStatus as u8
+                | CommandReadBackCounters::CommandRBCounter0 as u8,
+        );
+
+        read_counter(
+            &mut data.pit,
+            0,
+            CommandAccess::CommandRWBoth as u16 | CommandMode::CommandSWStrobe as u16,
+            CommandAccess::CommandRWLeast,
+        );
+    }
+
+    #[test]
+    fn speaker_square_wave() {
+        let mut data = set_up();
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter2 as u8
+                | CommandAccess::CommandRWBoth as u8
+                | CommandMode::CommandSquareWaveGen as u8,
+        );
+        write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
+
+        advance_by_ticks(&mut data, 128);
+        read_counter(
+            &mut data.pit,
+            2,
+            0xffff - 128 * 2,
+            CommandAccess::CommandRWBoth,
+        );
+    }
+
+    #[test]
+    fn speaker_rate_gen() {
+        let mut data = set_up();
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter2 as u8
+                | CommandAccess::CommandRWBoth as u8
+                | CommandMode::CommandRateGen as u8,
+        );
+        write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
+
+        // In Rate Gen mode, the counter should start over when the gate is
+        // set to high using SpeakerWrite.
+        advance_by_ticks(&mut data, 128);
+        read_counter(&mut data.pit, 2, 0xffff - 128, CommandAccess::CommandRWBoth);
+
+        write_speaker(&mut data.pit, 0x1);
+        advance_by_ticks(&mut data, 128);
+        read_counter(&mut data.pit, 2, 0xffff - 128, CommandAccess::CommandRWBoth);
+    }
+
+    #[test]
+    fn speaker_interrupt() {
+        let mut data = set_up();
+
+        write_command(
+            &mut data.pit,
+            CommandCounter::CommandCounter2 as u8
+                | CommandAccess::CommandRWBoth as u8
+                | CommandMode::CommandInterrupt as u8,
+        );
+        write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
+
+        // In Interrupt mode, the counter should NOT start over when the gate is
+        // set to high using SpeakerWrite.
+        advance_by_ticks(&mut data, 128);
+        read_counter(&mut data.pit, 2, 0xffff - 128, CommandAccess::CommandRWBoth);
+
+        write_speaker(&mut data.pit, 0x1);
+        advance_by_ticks(&mut data, 128);
+        read_counter(&mut data.pit, 2, 0xffff - 256, CommandAccess::CommandRWBoth);
+    }
+
+    /// Verify that invalid reads and writes do not cause crashes.
+    #[test]
+    fn invalid_write_and_read() {
+        let mut data = set_up();
+        data.pit.write(0x44, &[0]);
+        data.pit.read(0x55, &mut [0]);
+    }
+}
diff --git a/devices/src/pl030.rs b/devices/src/pl030.rs
new file mode 100644
index 0000000..b5338ac
--- /dev/null
+++ b/devices/src/pl030.rs
@@ -0,0 +1,145 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::time::{SystemTime, UNIX_EPOCH};
+use sys_util::{warn, EventFd};
+
+use crate::BusDevice;
+
+// Register offsets
+// Data register
+const RTCDR: u64 = 0x0;
+// Match register
+const RTCMR: u64 = 0x4;
+// Interrupt status register
+const RTCSTAT: u64 = 0x8;
+// Interrupt clear register
+const RTCEOI: u64 = 0x8;
+// Counter load register
+const RTCLR: u64 = 0xC;
+// Counter register
+const RTCCR: u64 = 0x10;
+
+// A single 4K page is mapped for this device
+pub const PL030_AMBA_IOMEM_SIZE: u64 = 0x1000;
+
+// AMBA id registers are at the end of the allocated memory space
+const AMBA_ID_OFFSET: u64 = PL030_AMBA_IOMEM_SIZE - 0x20;
+const AMBA_MASK_OFFSET: u64 = PL030_AMBA_IOMEM_SIZE - 0x28;
+
+// This is the AMBA id for this device
+pub const PL030_AMBA_ID: u32 = 0x00041030;
+pub const PL030_AMBA_MASK: u32 = 0x000FFFFF;
+
+/// An emulated ARM pl030 RTC
+pub struct Pl030 {
+    // EventFD to be used to interrupt the guest for an alarm event
+    alarm_evt: EventFd,
+
+    // This is the delta we subtract from current time to get the
+    // counter value
+    counter_delta_time: u32,
+
+    // This is the value that triggers an alarm interrupt when it
+    // matches with the rtc time
+    match_value: u32,
+
+    // status flag to keep track of whether the interrupt is cleared
+    // or not
+    interrupt_active: bool,
+}
+
+fn get_epoch_time() -> u32 {
+    let epoch_time = SystemTime::now()
+        .duration_since(UNIX_EPOCH)
+        .expect("SystemTime::duration_since failed");
+    epoch_time.as_secs() as u32
+}
+
+impl Pl030 {
+    /// Constructs a Pl030 device
+    pub fn new(evt: EventFd) -> Pl030 {
+        Pl030 {
+            alarm_evt: evt,
+            counter_delta_time: get_epoch_time(),
+            match_value: 0,
+            interrupt_active: false,
+        }
+    }
+}
+
+impl BusDevice for Pl030 {
+    fn debug_label(&self) -> String {
+        "Pl030".to_owned()
+    }
+
+    fn write(&mut self, offset: u64, data: &[u8]) {
+        if data.len() != 4 {
+            warn!("bad write size: {} for pl030", data.len());
+            return;
+        }
+
+        let reg_val: u32 = (data[0] as u32) << 24
+            | (data[1] as u32) << 16
+            | (data[2] as u32) << 8
+            | (data[3] as u32);
+        match offset {
+            RTCDR => {
+                warn!("invalid write to read-only RTCDR register");
+            }
+            RTCMR => {
+                self.match_value = reg_val;
+                // TODO(sonnyrao): here we need to set up a timer for
+                // when host time equals the value written here and
+                // fire the interrupt
+                warn!("Not implemented: VM tried to set an RTC alarm");
+            }
+            RTCEOI => {
+                if reg_val == 0 {
+                    self.interrupt_active = false;
+                } else {
+                    self.alarm_evt.write(1).unwrap();
+                    self.interrupt_active = true;
+                }
+            }
+            RTCLR => {
+                // TODO(sonnyrao): if we ever need to let the VM set it's own time
+                // then we'll need to keep track of the delta between
+                // the rtc time it sets and the host's rtc time and
+                // record that here
+                warn!("Not implemented: VM tried to set the RTC");
+            }
+            RTCCR => {
+                self.counter_delta_time = get_epoch_time();
+            }
+            o => panic!("pl030: bad write offset {}", o),
+        }
+    }
+
+    fn read(&mut self, offset: u64, data: &mut [u8]) {
+        if data.len() != 4 {
+            warn!("bad read size: {} for pl030", data.len());
+            return;
+        }
+
+        let reg_content: u32 = match offset {
+            RTCDR => get_epoch_time(),
+            RTCMR => self.match_value,
+            RTCSTAT => self.interrupt_active as u32,
+            RTCLR => {
+                warn!("invalid read of RTCLR register");
+                0
+            }
+            RTCCR => get_epoch_time() - self.counter_delta_time,
+            AMBA_ID_OFFSET => PL030_AMBA_ID,
+            AMBA_MASK_OFFSET => PL030_AMBA_MASK,
+
+            o => panic!("pl030: bad read offset {}", o),
+        };
+        data[0] = reg_content as u8;
+        data[1] = (reg_content >> 8) as u8;
+        data[2] = (reg_content >> 16) as u8;
+        data[3] = (reg_content >> 24) as u8;
+    }
+}
diff --git a/devices/src/proxy.rs b/devices/src/proxy.rs
new file mode 100644
index 0000000..dc64212
--- /dev/null
+++ b/devices/src/proxy.rs
@@ -0,0 +1,251 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Runs hardware devices in child processes.
+
+use std::fmt::{self, Display};
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::process;
+use std::time::Duration;
+use std::{self, io};
+
+use io_jail::{self, Minijail};
+use libc::pid_t;
+use msg_socket::{MsgOnSocket, MsgReceiver, MsgSender, MsgSocket};
+use sys_util::{error, net::UnixSeqpacket};
+
+use crate::BusDevice;
+
+/// Errors for proxy devices.
+#[derive(Debug)]
+pub enum Error {
+    ForkingJail(io_jail::Error),
+    Io(io::Error),
+}
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            ForkingJail(e) => write!(f, "Failed to fork jail process: {}", e),
+            Io(e) => write!(f, "IO error configuring proxy device {}.", e),
+        }
+    }
+}
+
+const SOCKET_TIMEOUT_MS: u64 = 2000;
+
+#[derive(MsgOnSocket)]
+enum Command {
+    Read {
+        len: u32,
+        offset: u64,
+    },
+    Write {
+        len: u32,
+        offset: u64,
+        data: [u8; 8],
+    },
+    ReadConfig(u32),
+    WriteConfig {
+        reg_idx: u32,
+        offset: u32,
+        len: u32,
+        data: [u8; 4],
+    },
+    Shutdown,
+}
+
+#[derive(MsgOnSocket)]
+enum CommandResult {
+    Ok,
+    ReadResult([u8; 8]),
+    ReadConfigResult(u32),
+}
+
+fn child_proc(sock: UnixSeqpacket, device: &mut dyn BusDevice) {
+    let mut running = true;
+    let sock = MsgSocket::<CommandResult, Command>::new(sock);
+
+    while running {
+        let cmd = match sock.recv() {
+            Ok(cmd) => cmd,
+            Err(err) => {
+                error!("child device process failed recv: {}", err);
+                break;
+            }
+        };
+
+        let res = match cmd {
+            Command::Read { len, offset } => {
+                let mut buffer = [0u8; 8];
+                device.read(offset, &mut buffer[0..len as usize]);
+                sock.send(&CommandResult::ReadResult(buffer))
+            }
+            Command::Write { len, offset, data } => {
+                let len = len as usize;
+                device.write(offset, &data[0..len]);
+                sock.send(&CommandResult::Ok)
+            }
+            Command::ReadConfig(idx) => {
+                let val = device.config_register_read(idx as usize);
+                sock.send(&CommandResult::ReadConfigResult(val))
+            }
+            Command::WriteConfig {
+                reg_idx,
+                offset,
+                len,
+                data,
+            } => {
+                let len = len as usize;
+                device.config_register_write(reg_idx as usize, offset as u64, &data[0..len]);
+                sock.send(&CommandResult::Ok)
+            }
+            Command::Shutdown => {
+                running = false;
+                sock.send(&CommandResult::Ok)
+            }
+        };
+        if let Err(e) = res {
+            error!("child device process failed send: {}", e);
+        }
+    }
+}
+
+/// Wraps an inner `BusDevice` that is run inside a child process via fork.
+///
+/// Because forks are very unfriendly to destructors and all memory mappings and file descriptors
+/// are inherited, this should be used as early as possible in the main process.
+pub struct ProxyDevice {
+    sock: MsgSocket<Command, CommandResult>,
+    pid: pid_t,
+    debug_label: String,
+}
+
+impl ProxyDevice {
+    /// Takes the given device and isolates it into another process via fork before returning.
+    ///
+    /// The forked process will automatically be terminated when this is dropped, so be sure to keep
+    /// a reference.
+    ///
+    /// # Arguments
+    /// * `device` - The device to isolate to another process.
+    /// * `keep_fds` - File descriptors that will be kept open in the child
+    pub fn new<D: BusDevice>(
+        mut device: D,
+        jail: &Minijail,
+        mut keep_fds: Vec<RawFd>,
+    ) -> Result<ProxyDevice> {
+        let debug_label = device.debug_label();
+        let (child_sock, parent_sock) = UnixSeqpacket::pair().map_err(Error::Io)?;
+
+        keep_fds.push(child_sock.as_raw_fd());
+        // Forking here is safe as long as the program is still single threaded.
+        let pid = unsafe {
+            match jail.fork(Some(&keep_fds)).map_err(Error::ForkingJail)? {
+                0 => {
+                    device.on_sandboxed();
+                    child_proc(child_sock, &mut device);
+                    // ! Never returns
+                    process::exit(0);
+                }
+                p => p,
+            }
+        };
+
+        parent_sock
+            .set_write_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
+            .map_err(Error::Io)?;
+        parent_sock
+            .set_read_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
+            .map_err(Error::Io)?;
+        Ok(ProxyDevice {
+            sock: MsgSocket::<Command, CommandResult>::new(parent_sock),
+            pid,
+            debug_label,
+        })
+    }
+
+    pub fn pid(&self) -> pid_t {
+        self.pid
+    }
+
+    fn sync_send(&self, cmd: Command) -> Option<CommandResult> {
+        let res = self.sock.send(&cmd);
+        if let Err(e) = res {
+            error!(
+                "failed write to child device process {}: {}",
+                self.debug_label, e,
+            );
+        };
+        match self.sock.recv() {
+            Err(e) => {
+                error!(
+                    "failed read from child device process {}: {}",
+                    self.debug_label, e,
+                );
+                None
+            }
+            Ok(r) => Some(r),
+        }
+    }
+}
+
+impl BusDevice for ProxyDevice {
+    fn debug_label(&self) -> String {
+        self.debug_label.clone()
+    }
+
+    fn config_register_write(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
+        let len = data.len() as u32;
+        let mut buffer = [0u8; 4];
+        buffer[0..data.len()].clone_from_slice(data);
+        let reg_idx = reg_idx as u32;
+        let offset = offset as u32;
+        self.sync_send(Command::WriteConfig {
+            reg_idx,
+            offset,
+            len,
+            data: buffer,
+        });
+    }
+
+    fn config_register_read(&self, reg_idx: usize) -> u32 {
+        let res = self.sync_send(Command::ReadConfig(reg_idx as u32));
+        if let Some(CommandResult::ReadConfigResult(val)) = res {
+            val
+        } else {
+            0
+        }
+    }
+
+    fn read(&mut self, offset: u64, data: &mut [u8]) {
+        let len = data.len() as u32;
+        if let Some(CommandResult::ReadResult(buffer)) =
+            self.sync_send(Command::Read { len, offset })
+        {
+            let len = data.len();
+            data.clone_from_slice(&buffer[0..len]);
+        }
+    }
+
+    fn write(&mut self, offset: u64, data: &[u8]) {
+        let mut buffer = [0u8; 8];
+        let len = data.len() as u32;
+        buffer[0..data.len()].clone_from_slice(data);
+        self.sync_send(Command::Write {
+            len,
+            offset,
+            data: buffer,
+        });
+    }
+}
+
+impl Drop for ProxyDevice {
+    fn drop(&mut self) {
+        self.sync_send(Command::Shutdown);
+    }
+}
diff --git a/devices/src/register_space/mod.rs b/devices/src/register_space/mod.rs
new file mode 100644
index 0000000..58d35e3
--- /dev/null
+++ b/devices/src/register_space/mod.rs
@@ -0,0 +1,10 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#[macro_use]
+mod register;
+mod register_space;
+
+pub use self::register::*;
+pub use self::register_space::*;
diff --git a/devices/src/register_space/register.rs b/devices/src/register_space/register.rs
new file mode 100644
index 0000000..268b945
--- /dev/null
+++ b/devices/src/register_space/register.rs
@@ -0,0 +1,589 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std;
+use std::boxed::Box;
+use std::cmp::{max, min, Ord, Ordering, PartialOrd};
+use std::mem::size_of;
+use std::sync::{Arc, MutexGuard};
+use sync::Mutex;
+
+use data_model::DataInit;
+use sys_util::error;
+
+/// Type of offset in the register space.
+pub type RegisterOffset = u64;
+
+/// This represents a range of memory in the register space starting.
+/// Both from and to are inclusive.
+#[derive(Debug, Eq, PartialEq, Copy, Clone)]
+pub struct RegisterRange {
+    pub from: RegisterOffset,
+    pub to: RegisterOffset,
+}
+
+impl Ord for RegisterRange {
+    fn cmp(&self, other: &RegisterRange) -> Ordering {
+        self.from.cmp(&other.from)
+    }
+}
+
+impl PartialOrd for RegisterRange {
+    fn partial_cmp(&self, other: &RegisterRange) -> Option<Ordering> {
+        self.from.partial_cmp(&other.from)
+    }
+}
+
+impl RegisterRange {
+    /// Return true if those range overlaps.
+    pub fn overlap_with(&self, other: &RegisterRange) -> bool {
+        !(self.from > other.to || self.to < other.from)
+    }
+
+    /// Get the overlapping part of two RegisterRange.
+    /// Return is Option(overlap_from, overlap_to).
+    /// For example, (4,7).overlap_range(5, 8) will be Some(5, 7).
+    pub fn overlap_range(&self, other: &RegisterRange) -> Option<RegisterRange> {
+        if !self.overlap_with(other) {
+            return None;
+        }
+        Some(RegisterRange {
+            from: max(self.from, other.from),
+            to: min(self.to, other.to),
+        })
+    }
+}
+
+/// RegisterValue trait should be satisfied by register value types.
+pub trait RegisterValue:
+    'static
+    + Into<u64>
+    + Clone
+    + DataInit
+    + std::ops::BitOr<Self, Output = Self>
+    + std::ops::BitAnd<Self, Output = Self>
+    + std::ops::Not<Output = Self>
+    + std::fmt::LowerHex
+{
+    // Get byte of the offset.
+    fn get_byte(&self, offset: usize) -> u8 {
+        let val: u64 = self.clone().into();
+        (val >> (offset * 8)) as u8
+    }
+    // Set masked bits.
+    fn set_bits(&mut self, mask: Self) {
+        *self = *self | mask;
+    }
+    // Clear masked bits.
+    fn clear_bits(&mut self, mask: Self) {
+        *self = *self & (!mask);
+    }
+}
+impl RegisterValue for u8 {}
+impl RegisterValue for u16 {}
+impl RegisterValue for u32 {}
+impl RegisterValue for u64 {}
+
+// Helper function to read a register. If the read range overlaps with value's range, it will load
+// corresponding bytes into data.
+fn read_reg_helper<T: RegisterValue>(
+    val: T,
+    val_range: RegisterRange,
+    addr: RegisterOffset,
+    data: &mut [u8],
+) {
+    let read_range = RegisterRange {
+        from: addr,
+        to: addr + data.len() as u64 - 1,
+    };
+
+    let overlap = match val_range.overlap_range(&read_range) {
+        Some(overlap) => overlap,
+        None => {
+            error!("calling read_reg_helper with non overlapping range. mmio_register might have a bug");
+            return;
+        }
+    };
+    let val_start_idx = (overlap.from - val_range.from) as usize;
+    let read_start_idx = (overlap.from - read_range.from) as usize;
+    let total_size = (overlap.to - overlap.from) as usize + 1;
+    for i in 0..total_size {
+        data[read_start_idx + i] = val.get_byte(val_start_idx + i);
+    }
+}
+
+/// Interface for register, as seen by guest driver.
+pub trait RegisterInterface: Send {
+    /// Range of this register.
+    fn range(&self) -> RegisterRange;
+    /// Handle read.
+    fn read(&self, addr: RegisterOffset, data: &mut [u8]);
+    /// Handle write.
+    fn write(&self, _addr: RegisterOffset, _data: &[u8]) {}
+    /// Reset this register to default value.
+    fn reset(&self) {}
+}
+
+// Spec for hardware init Read Only Registers.
+// The value of this register won't change.
+pub struct StaticRegisterSpec<T: RegisterValue> {
+    pub offset: RegisterOffset,
+    pub value: T,
+}
+
+/// A static register is a register inited by hardware. The value won't change in it's lifetime.
+/// All functions implemented on this one is thread safe.
+#[derive(Clone)]
+pub struct StaticRegister<T>
+where
+    T: RegisterValue,
+{
+    spec: &'static StaticRegisterSpec<T>,
+}
+
+impl<T> StaticRegister<T>
+where
+    T: RegisterValue,
+{
+    /// Create an new static register from spec.
+    pub fn new(spec: &'static StaticRegisterSpec<T>) -> StaticRegister<T> {
+        StaticRegister { spec }
+    }
+}
+
+impl<T> RegisterInterface for StaticRegister<T>
+where
+    T: RegisterValue,
+{
+    fn range(&self) -> RegisterRange {
+        RegisterRange {
+            from: self.spec.offset,
+            to: self.spec.offset + (size_of::<T>() as u64) - 1,
+        }
+    }
+
+    fn read(&self, addr: RegisterOffset, data: &mut [u8]) {
+        let val_range = self.range();
+        read_reg_helper(self.spec.value, val_range, addr, data);
+    }
+}
+
+/// Macro helps to build a static register.
+#[macro_export]
+macro_rules! static_register {
+    (ty: $ty:ty,offset: $offset:expr,value: $value:expr,) => {{
+        use crate::register_space::*;
+        static REG_SPEC: StaticRegisterSpec<$ty> = StaticRegisterSpec::<$ty> {
+            offset: $offset,
+            value: $value,
+        };
+        StaticRegister::new(&REG_SPEC)
+    }};
+}
+
+/// Spec for a regular register. It specifies it's location on register space, guest writable mask
+/// and guest write to clear mask.
+pub struct RegisterSpec<T> {
+    pub name: String,
+    pub offset: RegisterOffset,
+    pub reset_value: T,
+    /// Only masked bits could be written by guest.
+    pub guest_writeable_mask: T,
+    /// When write 1 to bits masked, those bits will be cleared. See Xhci spec 5.1
+    /// for more details.
+    pub guest_write_1_to_clear_mask: T,
+}
+
+struct RegisterInner<T: RegisterValue> {
+    spec: RegisterSpec<T>,
+    value: T,
+    write_cb: Option<Box<dyn Fn(T) -> T + Send>>,
+}
+
+/// Register is a thread safe struct. It can be safely changed from any thread.
+#[derive(Clone)]
+pub struct Register<T: RegisterValue> {
+    inner: Arc<Mutex<RegisterInner<T>>>,
+}
+
+impl<T: RegisterValue> Register<T> {
+    pub fn new(spec: RegisterSpec<T>, val: T) -> Self {
+        Register {
+            inner: Arc::new(Mutex::new(RegisterInner {
+                spec,
+                value: val,
+                write_cb: None,
+            })),
+        }
+    }
+
+    fn lock(&self) -> MutexGuard<RegisterInner<T>> {
+        self.inner.lock()
+    }
+}
+
+// All functions implemented on this one is thread safe.
+impl<T: RegisterValue> RegisterInterface for Register<T> {
+    fn range(&self) -> RegisterRange {
+        let locked = self.lock();
+        let spec = &locked.spec;
+        RegisterRange {
+            from: spec.offset,
+            to: spec.offset + (size_of::<T>() as u64) - 1,
+        }
+    }
+
+    fn read(&self, addr: RegisterOffset, data: &mut [u8]) {
+        let val_range = self.range();
+        let value = self.lock().value;
+        read_reg_helper(value, val_range, addr, data);
+    }
+
+    fn write(&self, addr: RegisterOffset, data: &[u8]) {
+        let my_range = self.range();
+        let write_range = RegisterRange {
+            from: addr,
+            to: addr + data.len() as u64 - 1,
+        };
+
+        let overlap = match my_range.overlap_range(&write_range) {
+            Some(range) => range,
+            None => {
+                error!("write should not be invoked on this register");
+                return;
+            }
+        };
+        let my_start_idx = (overlap.from - my_range.from) as usize;
+        let write_start_idx = (overlap.from - write_range.from) as usize;
+        let total_size = (overlap.to - overlap.from) as usize + 1;
+
+        let mut reg_value: T = self.lock().value;
+        let value: &mut [u8] = reg_value.as_mut_slice();
+        for i in 0..total_size {
+            value[my_start_idx + i] = self.apply_write_masks_to_byte(
+                value[my_start_idx + i],
+                data[write_start_idx + i],
+                my_start_idx + i,
+            );
+        }
+
+        // A single u64 register is done by write to lower 32 bit and then higher 32 bit. Callback
+        // should only be invoked when higher is written.
+        if my_range.to != overlap.to {
+            self.lock().value = reg_value;
+            return;
+        }
+
+        // Taking the callback out of register when executing it. This prevent dead lock if
+        // callback want to read current register value.
+        // Note that the only source of callback comes from mmio writing, which is synchronized.
+        let cb = {
+            let mut inner = self.lock();
+            match inner.write_cb.take() {
+                Some(cb) => cb,
+                None => {
+                    // Write value if there is no callback.
+                    inner.value = reg_value;
+                    return;
+                }
+            }
+        };
+        // Callback is invoked without holding any lock.
+        let value = cb(reg_value);
+        let mut inner = self.lock();
+        inner.value = value;
+        inner.write_cb = Some(cb);
+    }
+
+    fn reset(&self) {
+        let mut locked = self.lock();
+        locked.value = locked.spec.reset_value;
+    }
+}
+
+impl<T: RegisterValue> Register<T> {
+    /// Get current value of this register.
+    pub fn get_value(&self) -> T {
+        self.lock().value
+    }
+
+    /// This function apply "write 1 to clear mask" and "guest writeable mask".
+    /// All write operations should go through this, the result of this function
+    /// is the new state of correspoding byte.
+    pub fn apply_write_masks_to_byte(&self, old_byte: u8, write_byte: u8, offset: usize) -> u8 {
+        let locked = self.lock();
+        let spec = &locked.spec;
+        let guest_write_1_to_clear_mask: u64 = spec.guest_write_1_to_clear_mask.into();
+        let guest_writeable_mask: u64 = spec.guest_writeable_mask.into();
+        // Mask with w1c mask.
+        let w1c_mask = (guest_write_1_to_clear_mask >> (offset * 8)) as u8;
+        let val = (!w1c_mask & write_byte) | (w1c_mask & old_byte & !write_byte);
+        // Mask with writable mask.
+        let w_mask = (guest_writeable_mask >> (offset * 8)) as u8;
+        (old_byte & (!w_mask)) | (val & w_mask)
+    }
+
+    /// Set a callback. It will be invoked when write happens.
+    pub fn set_write_cb<C: 'static + Fn(T) -> T + Send>(&self, callback: C) {
+        self.lock().write_cb = Some(Box::new(callback));
+    }
+
+    /// Set value from device side. Callback won't be invoked.
+    pub fn set_value(&self, val: T) {
+        self.lock().value = val;
+    }
+
+    /// Set masked bits.
+    pub fn set_bits(&self, mask: T) {
+        self.lock().value.set_bits(mask);
+    }
+
+    /// Clear masked bits.
+    pub fn clear_bits(&self, mask: T) {
+        self.lock().value.clear_bits(mask);
+    }
+}
+
+#[macro_export]
+macro_rules! register {
+    (
+        name: $name:tt,
+        ty: $ty:ty,
+        offset: $offset:expr,
+        reset_value: $rv:expr,
+        guest_writeable_mask: $mask:expr,
+        guest_write_1_to_clear_mask: $w1tcm:expr,
+    ) => {{
+        use crate::register_space::*;
+        let spec: RegisterSpec<$ty> = RegisterSpec::<$ty> {
+            name: String::from($name),
+            offset: $offset,
+            reset_value: $rv,
+            guest_writeable_mask: $mask,
+            guest_write_1_to_clear_mask: $w1tcm,
+        };
+        Register::<$ty>::new(spec, $rv)
+    }};
+    (name: $name:tt, ty: $ty:ty,offset: $offset:expr,reset_value: $rv:expr,) => {{
+        use crate::register_space::*;
+        let spec: RegisterSpec<$ty> = RegisterSpec::<$ty> {
+            name: String::from($name),
+            offset: $offset,
+            reset_value: $rv,
+            guest_writeable_mask: !0,
+            guest_write_1_to_clear_mask: 0,
+        };
+        Register::<$ty>::new(spec, $rv)
+    }};
+}
+
+#[macro_export]
+macro_rules! register_array {
+    (
+        name: $name:tt,
+        ty:
+        $ty:ty,cnt:
+        $cnt:expr,base_offset:
+        $base_offset:expr,stride:
+        $stride:expr,reset_value:
+        $rv:expr,guest_writeable_mask:
+        $gwm:expr,guest_write_1_to_clear_mask:
+        $gw1tcm:expr,
+    ) => {{
+        use crate::register_space::*;
+        let mut v: Vec<Register<$ty>> = Vec::new();
+        for i in 0..$cnt {
+            let offset = $base_offset + ($stride * i) as RegisterOffset;
+            let spec: RegisterSpec<$ty> = RegisterSpec::<$ty> {
+                name: format!("{}-{}", $name, i),
+                offset,
+                reset_value: $rv,
+                guest_writeable_mask: $gwm,
+                guest_write_1_to_clear_mask: $gw1tcm,
+            };
+            v.push(Register::<$ty>::new(spec, $rv));
+        }
+        v
+    }};
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    static REG_SPEC0: StaticRegisterSpec<u8> = StaticRegisterSpec::<u8> {
+        offset: 3,
+        value: 32,
+    };
+
+    static REG_SPEC1: StaticRegisterSpec<u16> = StaticRegisterSpec::<u16> {
+        offset: 3,
+        value: 32,
+    };
+
+    #[test]
+    fn static_register_basic_test_u8() {
+        let r = StaticRegister::<u8> { spec: &REG_SPEC0 };
+        let mut data: [u8; 4] = [0, 0, 0, 0];
+        assert_eq!(r.range().from, 3);
+        assert_eq!(r.range().to, 3);
+        r.read(0, &mut data);
+        assert_eq!(data, [0, 0, 0, 32]);
+        r.read(2, &mut data);
+        assert_eq!(data, [0, 32, 0, 32]);
+    }
+
+    #[test]
+    fn static_register_basic_test_u16() {
+        let r = StaticRegister::<u16> { spec: &REG_SPEC1 };
+        let mut data: [u8; 4] = [0, 0, 0, 0];
+        assert_eq!(r.range().from, 3);
+        assert_eq!(r.range().to, 4);
+        r.read(0, &mut data);
+        assert_eq!(data, [0, 0, 0, 32]);
+        r.read(2, &mut data);
+        assert_eq!(data, [0, 32, 0, 32]);
+    }
+
+    #[test]
+    fn static_register_interface_test() {
+        let r: Box<RegisterInterface> = Box::new(static_register! {
+            ty: u8,
+            offset: 3,
+            value: 32,
+        });
+        let mut data: [u8; 4] = [0, 0, 0, 0];
+        assert_eq!(r.range().from, 3);
+        assert_eq!(r.range().to, 3);
+        r.read(0, &mut data);
+        assert_eq!(data, [0, 0, 0, 32]);
+        r.read(2, &mut data);
+        assert_eq!(data, [0, 32, 0, 32]);
+    }
+
+    #[test]
+    fn register_basic_rw_test() {
+        let r = register! {
+            name: "",
+            ty: u8,
+            offset: 3,
+            reset_value: 0xf1,
+            guest_writeable_mask: 0xff,
+            guest_write_1_to_clear_mask: 0x0,
+        };
+        let mut data: [u8; 4] = [0, 0, 0, 0];
+        assert_eq!(r.range().from, 3);
+        assert_eq!(r.range().to, 3);
+        r.read(0, &mut data);
+        assert_eq!(data, [0, 0, 0, 0xf1]);
+        r.read(2, &mut data);
+        assert_eq!(data, [0, 0xf1, 0, 0xf1]);
+        data = [0, 0, 0, 0xab];
+        r.write(0, &data);
+        assert_eq!(r.get_value(), 0xab);
+        r.reset();
+        assert_eq!(r.get_value(), 0xf1);
+        r.set_value(0xcc);
+        assert_eq!(r.get_value(), 0xcc);
+    }
+
+    #[test]
+    fn register_basic_writeable_mask_test() {
+        let r = register! {
+            name: "",
+            ty: u8,
+            offset: 3,
+            reset_value: 0x0,
+            guest_writeable_mask: 0xf,
+            guest_write_1_to_clear_mask: 0x0,
+        };
+        let mut data: [u8; 4] = [0, 0, 0, 0];
+        assert_eq!(r.range().from, 3);
+        assert_eq!(r.range().to, 3);
+        r.read(0, &mut data);
+        assert_eq!(data, [0, 0, 0, 0]);
+        data = [0, 0, 0, 0xab];
+        r.write(0, &data);
+        assert_eq!(r.get_value(), 0x0b);
+        r.reset();
+        assert_eq!(r.get_value(), 0x0);
+        r.set_value(0xcc);
+        assert_eq!(r.get_value(), 0xcc);
+    }
+
+    #[test]
+    fn register_basic_write_1_to_clear_mask_test() {
+        let r = register! {
+            name: "",
+            ty: u8,
+            offset: 3,
+            reset_value: 0xf1,
+            guest_writeable_mask: 0xff,
+            guest_write_1_to_clear_mask: 0xf0,
+        };
+        let mut data: [u8; 4] = [0, 0, 0, 0];
+        assert_eq!(r.range().from, 3);
+        assert_eq!(r.range().to, 3);
+        r.read(0, &mut data);
+        assert_eq!(data, [0, 0, 0, 0xf1]);
+        data = [0, 0, 0, 0xfa];
+        r.write(0, &data);
+        assert_eq!(r.get_value(), 0x0a);
+        r.reset();
+        assert_eq!(r.get_value(), 0xf1);
+        r.set_value(0xcc);
+        assert_eq!(r.get_value(), 0xcc);
+    }
+
+    #[test]
+    fn register_basic_write_1_to_clear_mask_test_u32() {
+        let r = register! {
+            name: "",
+            ty: u32,
+            offset: 0,
+            reset_value: 0xfff1,
+            guest_writeable_mask: 0xff,
+            guest_write_1_to_clear_mask: 0xf0,
+        };
+        let mut data: [u8; 4] = [0, 0, 0, 0];
+        assert_eq!(r.range().from, 0);
+        assert_eq!(r.range().to, 3);
+        r.read(0, &mut data);
+        assert_eq!(data, [0xf1, 0xff, 0, 0]);
+        data = [0xfa, 0, 0, 0];
+        r.write(0, &data);
+        assert_eq!(r.get_value(), 0xff0a);
+        r.reset();
+        assert_eq!(r.get_value(), 0xfff1);
+        r.set_value(0xcc);
+        assert_eq!(r.get_value(), 0xcc);
+    }
+
+    #[test]
+    fn register_callback_test() {
+        let state = Arc::new(Mutex::new(0u8));
+        let r = register! {
+            name: "",
+            ty: u8,
+            offset: 3,
+            reset_value: 0xf1,
+            guest_writeable_mask: 0xff,
+            guest_write_1_to_clear_mask: 0xf0,
+        };
+
+        let s2 = state.clone();
+        r.set_write_cb(move |val: u8| {
+            *s2.lock() = val as u8;
+            val
+        });
+        let data: [u8; 4] = [0, 0, 0, 0xff];
+        r.write(0, &data);
+        assert_eq!(*state.lock(), 0xf);
+        r.set_value(0xab);
+        assert_eq!(*state.lock(), 0xf);
+        let data: [u8; 1] = [0xfc];
+        r.write(3, &data);
+        assert_eq!(*state.lock(), 0xc);
+    }
+}
diff --git a/devices/src/register_space/register_space.rs b/devices/src/register_space/register_space.rs
new file mode 100644
index 0000000..892961a
--- /dev/null
+++ b/devices/src/register_space/register_space.rs
@@ -0,0 +1,297 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::register::{Register, RegisterInterface, RegisterOffset, RegisterRange, RegisterValue};
+use std::collections::btree_map::BTreeMap;
+
+/// Register space repesents a set of registers. It can handle read/write operations.
+pub struct RegisterSpace {
+    regs: BTreeMap<RegisterRange, Box<dyn RegisterInterface>>,
+}
+
+impl RegisterSpace {
+    /// Creates a new empty RegisterSpace.
+    pub fn new() -> RegisterSpace {
+        RegisterSpace {
+            regs: BTreeMap::new(),
+        }
+    }
+
+    /// Add a register to register space.
+    pub fn add_register<T: RegisterInterface + 'static>(&mut self, reg: T) {
+        let range = reg.range();
+        debug_assert!(self.get_register(range.from).is_none());
+        if cfg!(debug_assertions) {
+            if let Some(r) = self.first_before(range.to) {
+                debug_assert!(r.range().to < range.to);
+            }
+        }
+
+        let insert_result = self.regs.insert(range, Box::new(reg)).is_none();
+        debug_assert!(insert_result);
+    }
+
+    /// Add an array of registers.
+    pub fn add_register_array<T: RegisterValue>(&mut self, regs: &[Register<T>]) {
+        for r in regs {
+            self.add_register(r.clone());
+        }
+    }
+
+    /// Read range.
+    pub fn read(&self, addr: RegisterOffset, data: &mut [u8]) {
+        let mut current_addr: RegisterOffset = addr;
+        while current_addr < addr + data.len() as RegisterOffset {
+            if let Some(r) = self.get_register(current_addr) {
+                // Next addr to read is.
+                current_addr = r.range().to + 1;
+                r.read(addr, data);
+            } else {
+                // TODO(jkwang) Add logging for debug here.
+                current_addr += 1;
+            }
+        }
+    }
+
+    /// Write range. If the targeted register has a callback, it will be invoked with the new
+    /// value.
+    pub fn write(&self, addr: RegisterOffset, data: &[u8]) {
+        let mut current_addr: RegisterOffset = addr;
+        while current_addr < addr + data.len() as RegisterOffset {
+            if let Some(r) = self.get_register(current_addr) {
+                // Next addr to read is, range is inclusive.
+                current_addr = r.range().to + 1;
+                r.write(addr, data);
+            } else {
+                current_addr += 1;
+            }
+        }
+    }
+
+    /// Get first register before this addr.
+    fn first_before(&self, addr: RegisterOffset) -> Option<&dyn RegisterInterface> {
+        for (range, r) in self.regs.iter().rev() {
+            if range.from <= addr {
+                return Some(r.as_ref());
+            }
+        }
+        None
+    }
+
+    /// Get register at this addr.
+    fn get_register(&self, addr: RegisterOffset) -> Option<&dyn RegisterInterface> {
+        let r = self.first_before(addr)?;
+        let range = r.range();
+        if addr <= range.to {
+            Some(r)
+        } else {
+            None
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::sync::Arc;
+    use sync::Mutex;
+
+    #[test]
+    fn regs_no_reg() {
+        let regs = RegisterSpace::new();
+        let mut data: [u8; 4] = [4, 3, 2, 1];
+        // Read should be no op cause no register.
+        regs.read(0, &mut data);
+        assert_eq!([4, 3, 2, 1], data);
+        // Write should be no op.
+        regs.write(0, &[0, 0, 0, 0]);
+        regs.read(0, &mut data);
+        assert_eq!([4, 3, 2, 1], data);
+    }
+
+    #[test]
+    #[should_panic]
+    #[cfg(debug_assertions)]
+    fn regs_reg_overlap() {
+        let mut regs = RegisterSpace::new();
+        regs.add_register(static_register!(
+        ty: u32,
+        offset: 4,
+        value: 11,
+        ));
+
+        regs.add_register(static_register!(
+        ty: u16,
+        offset: 7,
+        value: 11,
+        ));
+    }
+
+    #[test]
+    fn regs_static_reg() {
+        let mut regs = RegisterSpace::new();
+        regs.add_register(static_register!(
+            ty: u8,
+            offset: 0,
+            value: 11,
+        ));
+        let mut data: [u8; 4] = [4, 3, 2, 1];
+        regs.read(0, &mut data);
+        assert_eq!([11, 3, 2, 1], data);
+        // Write should be no op.
+        regs.write(0, &[0, 0, 0, 0]);
+        let mut data: [u8; 4] = [4, 3, 2, 1];
+        regs.read(0, &mut data);
+        assert_eq!([11, 3, 2, 1], data);
+    }
+
+    #[test]
+    fn regs_static_reg_offset() {
+        let mut regs = RegisterSpace::new();
+        regs.add_register(static_register!(
+            ty: u32,
+            offset: 2,
+            value: 0xaabbccdd,
+        ));
+        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
+        regs.read(0, &mut data);
+        assert_eq!([8, 7, 0xdd, 0xcc, 0xbb, 0xaa, 2, 1], data);
+        // Write should be no op.
+        regs.write(0, &[0, 0, 0, 0, 0, 0, 0, 0]);
+        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
+        regs.read(0, &mut data);
+        assert_eq!([8, 7, 0xdd, 0xcc, 0xbb, 0xaa, 2, 1], data);
+    }
+
+    #[test]
+    fn regs_reg_write() {
+        let mut regs = RegisterSpace::new();
+        regs.add_register(register!(
+            name: "",
+            ty: u32,
+            offset: 2,
+            reset_value: 0xaabbccdd,
+        ));
+        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
+        regs.read(0, &mut data);
+        assert_eq!([8, 7, 0xdd, 0xcc, 0xbb, 0xaa, 2, 1], data);
+        regs.write(0, &[0, 0, 0, 0, 0, 0, 0, 0]);
+        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
+        regs.read(0, &mut data);
+        assert_eq!([8, 7, 0, 0, 0, 0, 2, 1], data);
+    }
+
+    #[test]
+    fn regs_reg_writeable() {
+        let mut regs = RegisterSpace::new();
+        regs.add_register(register!(
+            name: "",
+            ty: u32,
+            offset: 2,
+            reset_value: 0xaabbccdd,
+            guest_writeable_mask: 0x00f0000f,
+            guest_write_1_to_clear_mask: 0,
+        ));
+        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
+        regs.read(0, &mut data);
+        assert_eq!([8, 7, 0xdd, 0xcc, 0xbb, 0xaa, 2, 1], data);
+        regs.write(0, &[0, 0, 0, 0, 0, 0, 0, 0]);
+        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
+        regs.read(0, &mut data);
+        assert_eq!([8, 7, 0xd0, 0xcc, 0x0b, 0xaa, 2, 1], data);
+    }
+
+    #[test]
+    fn regs_reg_writeable_callback() {
+        let state = Arc::new(Mutex::new(0u32));
+        let mut regs = RegisterSpace::new();
+        let reg = register!(
+            name: "",
+            ty: u32,
+            offset: 2,
+            reset_value: 0xaabbccdd,
+            guest_writeable_mask: 0x00f0000f,
+            guest_write_1_to_clear_mask: 0,
+        );
+        regs.add_register(reg.clone());
+        let state_clone = state.clone();
+        reg.set_write_cb(move |val: u32| {
+            *state_clone.lock() = val;
+            val
+        });
+
+        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
+        regs.read(0, &mut data);
+        assert_eq!([8, 7, 0xdd, 0xcc, 0xbb, 0xaa, 2, 1], data);
+        regs.write(0, &[0, 0, 0, 0, 0, 0, 0, 0]);
+        assert_eq!(0xaa0bccd0, *state.lock());
+    }
+
+    #[test]
+    fn regs_reg_write_to_clear() {
+        let mut regs = RegisterSpace::new();
+        regs.add_register(register!(
+        name: "",
+        ty: u32,
+        offset: 2,
+        reset_value: 0xaabbccdd,
+        guest_writeable_mask: 0xfff0000f,
+        guest_write_1_to_clear_mask: 0xf0000000,
+        ));
+        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
+        regs.read(0, &mut data);
+        assert_eq!([8, 7, 0xdd, 0xcc, 0xbb, 0xaa, 2, 1], data);
+        regs.write(0, &[0, 0, 0, 0, 0, 0xad, 0, 0]);
+        let mut data: [u8; 8] = [8, 7, 6, 5, 4, 3, 2, 1];
+        regs.read(0, &mut data);
+        assert_eq!([8, 7, 0xd0, 0xcc, 0x0b, 0x0d, 2, 1], data);
+    }
+
+    #[test]
+    fn regs_reg_array() {
+        let mut regs = RegisterSpace::new();
+        regs.add_register_array(&register_array!(
+            name: "",
+            ty: u8,
+            cnt: 8,
+            base_offset: 10,
+            stride: 2,
+            reset_value: 0xff,
+            guest_writeable_mask: !0,
+            guest_write_1_to_clear_mask: 0,
+        ));
+        let mut data: [u8; 8] = [0; 8];
+        regs.read(8, &mut data);
+        assert_eq!([0, 0, 0xff, 0, 0xff, 0, 0xff, 0], data);
+    }
+
+    #[test]
+    fn regs_reg_multi_array() {
+        let mut regs = RegisterSpace::new();
+        regs.add_register_array(&register_array!(
+        name: "",
+        ty: u8,
+        cnt: 8,
+        base_offset: 10,
+        stride: 2,
+        reset_value: 0xff,
+        guest_writeable_mask: !0,
+        guest_write_1_to_clear_mask: 0,
+        ));
+        regs.add_register_array(&register_array!(
+        name: "",
+        ty: u8,
+        cnt: 8,
+        base_offset: 11,
+        stride: 2,
+        reset_value: 0xee,
+        guest_writeable_mask: !0,
+        guest_write_1_to_clear_mask: 0,
+        ));
+        let mut data: [u8; 8] = [0; 8];
+        regs.read(8, &mut data);
+        assert_eq!([0, 0, 0xff, 0xee, 0xff, 0xee, 0xff, 0xee], data);
+    }
+
+}
diff --git a/devices/src/serial.rs b/devices/src/serial.rs
new file mode 100644
index 0000000..0bf5642
--- /dev/null
+++ b/devices/src/serial.rs
@@ -0,0 +1,485 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::collections::VecDeque;
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::io::{self, stdout};
+use std::path::PathBuf;
+use std::str::FromStr;
+
+use sys_util::{error, syslog, EventFd, Result};
+
+use crate::BusDevice;
+
+const LOOP_SIZE: usize = 0x40;
+
+const DATA: u8 = 0;
+const IER: u8 = 1;
+const IIR: u8 = 2;
+const LCR: u8 = 3;
+const MCR: u8 = 4;
+const LSR: u8 = 5;
+const MSR: u8 = 6;
+const SCR: u8 = 7;
+const DLAB_LOW: u8 = 0;
+const DLAB_HIGH: u8 = 1;
+
+const IER_RECV_BIT: u8 = 0x1;
+const IER_THR_BIT: u8 = 0x2;
+const IER_FIFO_BITS: u8 = 0x0f;
+
+const IIR_FIFO_BITS: u8 = 0xc0;
+const IIR_NONE_BIT: u8 = 0x1;
+const IIR_THR_BIT: u8 = 0x2;
+const IIR_RECV_BIT: u8 = 0x4;
+
+const LSR_DATA_BIT: u8 = 0x1;
+const LSR_EMPTY_BIT: u8 = 0x20;
+const LSR_IDLE_BIT: u8 = 0x40;
+
+const MCR_DTR_BIT: u8 = 0x01; // Data Terminal Ready
+const MCR_RTS_BIT: u8 = 0x02; // Request to Send
+const MCR_OUT1_BIT: u8 = 0x04;
+const MCR_OUT2_BIT: u8 = 0x08;
+const MCR_LOOP_BIT: u8 = 0x10;
+
+const MSR_CTS_BIT: u8 = 0x10; // Clear to Send
+const MSR_DSR_BIT: u8 = 0x20; // Data Set Ready
+const MSR_RI_BIT: u8 = 0x40; // Ring Indicator
+const MSR_DCD_BIT: u8 = 0x80; // Data Carrier Detect
+
+const DEFAULT_INTERRUPT_IDENTIFICATION: u8 = IIR_NONE_BIT; // no pending interrupt
+const DEFAULT_LINE_STATUS: u8 = LSR_EMPTY_BIT | LSR_IDLE_BIT; // THR empty and line is idle
+const DEFAULT_LINE_CONTROL: u8 = 0x3; // 8-bits per character
+const DEFAULT_MODEM_CONTROL: u8 = MCR_OUT2_BIT;
+const DEFAULT_MODEM_STATUS: u8 = MSR_DSR_BIT | MSR_CTS_BIT | MSR_DCD_BIT;
+const DEFAULT_BAUD_DIVISOR: u16 = 12; // 9600 bps
+
+#[derive(Debug)]
+pub enum Error {
+    CloneEventFd(sys_util::Error),
+    InvalidSerialType(String),
+    PathRequired,
+    FileError(std::io::Error),
+    Unimplemented(SerialType),
+}
+
+impl Display for Error {
+    #[remain::check]
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        #[sorted]
+        match self {
+            CloneEventFd(e) => write!(f, "unable to clone an EventFd: {}", e),
+            FileError(e) => write!(f, "Unable to open/create file: {}", e),
+            InvalidSerialType(e) => write!(f, "invalid serial type: {}", e),
+            PathRequired => write!(f, "serial device type file requires a path"),
+            Unimplemented(e) => write!(f, "serial device type {} not implemented", e.to_string()),
+        }
+    }
+}
+
+/// Enum for possible type of serial devices
+#[derive(Debug)]
+pub enum SerialType {
+    File,
+    Stdout,
+    Sink,
+    Syslog,
+    UnixSocket, // NOT IMPLEMENTED
+}
+
+impl Display for SerialType {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let s = match &self {
+            SerialType::File => "File".to_string(),
+            SerialType::Stdout => "Stdout".to_string(),
+            SerialType::Sink => "Sink".to_string(),
+            SerialType::Syslog => "Syslog".to_string(),
+            SerialType::UnixSocket => "UnixSocket".to_string(),
+        };
+
+        write!(f, "{}", s)
+    }
+}
+
+impl FromStr for SerialType {
+    type Err = Error;
+    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+        match s {
+            "file" | "File" => Ok(SerialType::File),
+            "stdout" | "Stdout" => Ok(SerialType::Stdout),
+            "sink" | "Sink" => Ok(SerialType::Sink),
+            "syslog" | "Syslog" => Ok(SerialType::Syslog),
+            "unix" | "UnixSocket" => Ok(SerialType::UnixSocket),
+            _ => Err(Error::InvalidSerialType(s.to_string())),
+        }
+    }
+}
+
+/// Holds the parameters for a serial device
+#[derive(Debug)]
+pub struct SerialParameters {
+    pub type_: SerialType,
+    pub path: Option<PathBuf>,
+    pub num: u8,
+    pub console: bool,
+}
+
+impl SerialParameters {
+    /// Helper function to create a serial device from the defined parameters.
+    ///
+    /// # Arguments
+    /// * `evt_fd` - eventfd used for interrupt events
+    pub fn create_serial_device(&self, evt_fd: &EventFd) -> std::result::Result<Serial, Error> {
+        match self.type_ {
+            SerialType::Stdout => Ok(Serial::new_out(
+                evt_fd.try_clone().map_err(Error::CloneEventFd)?,
+                Box::new(stdout()),
+            )),
+            SerialType::Sink => Ok(Serial::new_sink(
+                evt_fd.try_clone().map_err(Error::CloneEventFd)?,
+            )),
+            SerialType::Syslog => Ok(Serial::new_out(
+                evt_fd.try_clone().map_err(Error::CloneEventFd)?,
+                Box::new(syslog::Syslogger::new(
+                    syslog::Priority::Info,
+                    syslog::Facility::Daemon,
+                )),
+            )),
+            SerialType::File => match &self.path {
+                None => Err(Error::PathRequired),
+                Some(path) => Ok(Serial::new_out(
+                    evt_fd.try_clone().map_err(Error::CloneEventFd)?,
+                    Box::new(File::create(path.as_path()).map_err(Error::FileError)?),
+                )),
+            },
+            SerialType::UnixSocket => Err(Error::Unimplemented(SerialType::UnixSocket)),
+        }
+    }
+}
+
+// Structure for holding the default configuration of the serial devices.
+pub const DEFAULT_SERIAL_PARAMS: [SerialParameters; 4] = [
+    SerialParameters {
+        type_: SerialType::Stdout,
+        path: None,
+        num: 1,
+        console: true,
+    },
+    SerialParameters {
+        type_: SerialType::Sink,
+        path: None,
+        num: 2,
+        console: false,
+    },
+    SerialParameters {
+        type_: SerialType::Sink,
+        path: None,
+        num: 3,
+        console: false,
+    },
+    SerialParameters {
+        type_: SerialType::Sink,
+        path: None,
+        num: 4,
+        console: false,
+    },
+];
+
+/// Address for Serial ports in x86
+pub const SERIAL_ADDR: [u64; 4] = [0x3f8, 0x2f8, 0x3e8, 0x2e8];
+
+/// String representations of serial devices
+pub const SERIAL_TTY_STRINGS: [&str; 4] = ["ttyS0", "ttyS1", "ttyS2", "ttyS3"];
+
+/// Helper function to get the tty string of a serial device based on the port number. Will default
+///  to ttyS0 if an invalid number is given.
+pub fn get_serial_tty_string(stdio_serial_num: u8) -> String {
+    match stdio_serial_num {
+        1 => SERIAL_TTY_STRINGS[0].to_string(),
+        2 => SERIAL_TTY_STRINGS[1].to_string(),
+        3 => SERIAL_TTY_STRINGS[2].to_string(),
+        4 => SERIAL_TTY_STRINGS[3].to_string(),
+        _ => SERIAL_TTY_STRINGS[0].to_string(),
+    }
+}
+
+/// Emulates serial COM ports commonly seen on x86 I/O ports 0x3f8/0x2f8/0x3e8/0x2e8.
+///
+/// This can optionally write the guest's output to a Write trait object. To send input to the
+/// guest, use `queue_input_bytes`.
+pub struct Serial {
+    interrupt_enable: u8,
+    interrupt_identification: u8,
+    interrupt_evt: EventFd,
+    line_control: u8,
+    line_status: u8,
+    modem_control: u8,
+    modem_status: u8,
+    scratch: u8,
+    baud_divisor: u16,
+    in_buffer: VecDeque<u8>,
+    out: Option<Box<dyn io::Write + Send>>,
+}
+
+impl Serial {
+    fn new(interrupt_evt: EventFd, out: Option<Box<dyn io::Write + Send>>) -> Serial {
+        Serial {
+            interrupt_enable: 0,
+            interrupt_identification: DEFAULT_INTERRUPT_IDENTIFICATION,
+            interrupt_evt,
+            line_control: DEFAULT_LINE_CONTROL,
+            line_status: DEFAULT_LINE_STATUS,
+            modem_control: DEFAULT_MODEM_CONTROL,
+            modem_status: DEFAULT_MODEM_STATUS,
+            scratch: 0,
+            baud_divisor: DEFAULT_BAUD_DIVISOR,
+            in_buffer: VecDeque::new(),
+            out,
+        }
+    }
+
+    /// Constructs a Serial port ready for output.
+    pub fn new_out(interrupt_evt: EventFd, out: Box<dyn io::Write + Send>) -> Serial {
+        Self::new(interrupt_evt, Some(out))
+    }
+
+    /// Constructs a Serial port with no connected output.
+    pub fn new_sink(interrupt_evt: EventFd) -> Serial {
+        Self::new(interrupt_evt, None)
+    }
+
+    /// Queues raw bytes for the guest to read and signals the interrupt if the line status would
+    /// change.
+    pub fn queue_input_bytes(&mut self, c: &[u8]) -> Result<()> {
+        if !self.is_loop() {
+            self.in_buffer.extend(c);
+            self.recv_data()?;
+        }
+        Ok(())
+    }
+
+    fn is_dlab_set(&self) -> bool {
+        (self.line_control & 0x80) != 0
+    }
+
+    fn is_recv_intr_enabled(&self) -> bool {
+        (self.interrupt_enable & IER_RECV_BIT) != 0
+    }
+
+    fn is_thr_intr_enabled(&self) -> bool {
+        (self.interrupt_enable & IER_THR_BIT) != 0
+    }
+
+    fn is_loop(&self) -> bool {
+        (self.modem_control & MCR_LOOP_BIT) != 0
+    }
+
+    fn add_intr_bit(&mut self, bit: u8) {
+        self.interrupt_identification &= !IIR_NONE_BIT;
+        self.interrupt_identification |= bit;
+    }
+
+    fn del_intr_bit(&mut self, bit: u8) {
+        self.interrupt_identification &= !bit;
+        if self.interrupt_identification == 0x0 {
+            self.interrupt_identification = IIR_NONE_BIT;
+        }
+    }
+
+    fn thr_empty(&mut self) -> Result<()> {
+        if self.is_thr_intr_enabled() {
+            self.add_intr_bit(IIR_THR_BIT);
+            self.trigger_interrupt()?
+        }
+        Ok(())
+    }
+
+    fn recv_data(&mut self) -> Result<()> {
+        if self.is_recv_intr_enabled() {
+            self.add_intr_bit(IIR_RECV_BIT);
+            self.trigger_interrupt()?
+        }
+        self.line_status |= LSR_DATA_BIT;
+        Ok(())
+    }
+
+    fn trigger_interrupt(&mut self) -> Result<()> {
+        self.interrupt_evt.write(1)
+    }
+
+    fn iir_reset(&mut self) {
+        self.interrupt_identification = DEFAULT_INTERRUPT_IDENTIFICATION;
+    }
+
+    fn handle_write(&mut self, offset: u8, v: u8) -> Result<()> {
+        match offset as u8 {
+            DLAB_LOW if self.is_dlab_set() => {
+                self.baud_divisor = (self.baud_divisor & 0xff00) | v as u16
+            }
+            DLAB_HIGH if self.is_dlab_set() => {
+                self.baud_divisor = (self.baud_divisor & 0x00ff) | ((v as u16) << 8)
+            }
+            DATA => {
+                if self.is_loop() {
+                    if self.in_buffer.len() < LOOP_SIZE {
+                        self.in_buffer.push_back(v);
+                        self.recv_data()?;
+                    }
+                } else {
+                    if let Some(out) = self.out.as_mut() {
+                        out.write_all(&[v])?;
+                        out.flush()?;
+                    }
+                    self.thr_empty()?;
+                }
+            }
+            IER => self.interrupt_enable = v & IER_FIFO_BITS,
+            LCR => self.line_control = v,
+            MCR => self.modem_control = v,
+            SCR => self.scratch = v,
+            _ => {}
+        }
+        Ok(())
+    }
+}
+
+impl BusDevice for Serial {
+    fn debug_label(&self) -> String {
+        "serial".to_owned()
+    }
+
+    fn write(&mut self, offset: u64, data: &[u8]) {
+        if data.len() != 1 {
+            return;
+        }
+
+        if let Err(e) = self.handle_write(offset as u8, data[0]) {
+            error!("serial failed write: {}", e);
+        }
+    }
+
+    fn read(&mut self, offset: u64, data: &mut [u8]) {
+        if data.len() != 1 {
+            return;
+        }
+
+        data[0] = match offset as u8 {
+            DLAB_LOW if self.is_dlab_set() => self.baud_divisor as u8,
+            DLAB_HIGH if self.is_dlab_set() => (self.baud_divisor >> 8) as u8,
+            DATA => {
+                self.del_intr_bit(IIR_RECV_BIT);
+                if self.in_buffer.len() <= 1 {
+                    self.line_status &= !LSR_DATA_BIT;
+                }
+                self.in_buffer.pop_front().unwrap_or_default()
+            }
+            IER => self.interrupt_enable,
+            IIR => {
+                let v = self.interrupt_identification | IIR_FIFO_BITS;
+                self.iir_reset();
+                v
+            }
+            LCR => self.line_control,
+            MCR => self.modem_control,
+            LSR => self.line_status,
+            MSR => {
+                if self.is_loop() {
+                    let mut msr =
+                        self.modem_status & !(MSR_DSR_BIT | MSR_CTS_BIT | MSR_RI_BIT | MSR_DCD_BIT);
+                    if self.modem_control & MCR_DTR_BIT != 0 {
+                        msr |= MSR_DSR_BIT;
+                    }
+                    if self.modem_control & MCR_RTS_BIT != 0 {
+                        msr |= MSR_CTS_BIT;
+                    }
+                    if self.modem_control & MCR_OUT1_BIT != 0 {
+                        msr |= MSR_RI_BIT;
+                    }
+                    if self.modem_control & MCR_OUT2_BIT != 0 {
+                        msr |= MSR_DCD_BIT;
+                    }
+                    msr
+                } else {
+                    self.modem_status
+                }
+            }
+            SCR => self.scratch,
+            _ => 0,
+        };
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::io;
+    use std::sync::Arc;
+
+    use sync::Mutex;
+
+    #[derive(Clone)]
+    struct SharedBuffer {
+        buf: Arc<Mutex<Vec<u8>>>,
+    }
+
+    impl SharedBuffer {
+        fn new() -> SharedBuffer {
+            SharedBuffer {
+                buf: Arc::new(Mutex::new(Vec::new())),
+            }
+        }
+    }
+
+    impl io::Write for SharedBuffer {
+        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+            self.buf.lock().write(buf)
+        }
+        fn flush(&mut self) -> io::Result<()> {
+            self.buf.lock().flush()
+        }
+    }
+
+    #[test]
+    fn serial_output() {
+        let intr_evt = EventFd::new().unwrap();
+        let serial_out = SharedBuffer::new();
+
+        let mut serial = Serial::new_out(intr_evt, Box::new(serial_out.clone()));
+
+        serial.write(DATA as u64, &['a' as u8]);
+        serial.write(DATA as u64, &['b' as u8]);
+        serial.write(DATA as u64, &['c' as u8]);
+        assert_eq!(
+            serial_out.buf.lock().as_slice(),
+            &['a' as u8, 'b' as u8, 'c' as u8]
+        );
+    }
+
+    #[test]
+    fn serial_input() {
+        let intr_evt = EventFd::new().unwrap();
+        let serial_out = SharedBuffer::new();
+
+        let mut serial =
+            Serial::new_out(intr_evt.try_clone().unwrap(), Box::new(serial_out.clone()));
+
+        serial.write(IER as u64, &[IER_RECV_BIT]);
+        serial
+            .queue_input_bytes(&['a' as u8, 'b' as u8, 'c' as u8])
+            .unwrap();
+
+        assert_eq!(intr_evt.read(), Ok(1));
+        let mut data = [0u8; 1];
+        serial.read(DATA as u64, &mut data[..]);
+        assert_eq!(data[0], 'a' as u8);
+        serial.read(DATA as u64, &mut data[..]);
+        assert_eq!(data[0], 'b' as u8);
+        serial.read(DATA as u64, &mut data[..]);
+        assert_eq!(data[0], 'c' as u8);
+    }
+}
diff --git a/devices/src/split_irqchip_common.rs b/devices/src/split_irqchip_common.rs
new file mode 100644
index 0000000..65ba809
--- /dev/null
+++ b/devices/src/split_irqchip_common.rs
@@ -0,0 +1,60 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Common constants and types used for Split IRQ chip devices (e.g. PIC, PIT, IOAPIC).
+
+use bit_field::*;
+
+#[bitfield]
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum DestinationMode {
+    Physical = 0,
+    Logical = 1,
+}
+
+#[bitfield]
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum TriggerMode {
+    Edge = 0,
+    Level = 1,
+}
+
+#[bitfield]
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum DeliveryMode {
+    Fixed = 0b000,
+    Lowest = 0b001,
+    SMI = 0b010,        // System management interrupt
+    RemoteRead = 0b011, // This is no longer supported by intel.
+    NMI = 0b100,        // Non maskable interrupt
+    Init = 0b101,
+    Startup = 0b110,
+    External = 0b111,
+}
+
+#[bitfield]
+#[derive(Clone, Copy, PartialEq)]
+pub struct MsiAddressMessage {
+    reserved: BitField2,
+    #[bits = 1]
+    destination_mode: DestinationMode,
+    redirection_hint: BitField1,
+    reserved_2: BitField8,
+    destination_id: BitField8,
+    // According to Intel's implementation of MSI, these bits must always be 0xfee.
+    always_0xfee: BitField12,
+}
+
+#[bitfield]
+#[derive(Clone, Copy, PartialEq)]
+struct MsiDataMessage {
+    vector: BitField8,
+    #[bits = 3]
+    delivery_mode: DeliveryMode,
+    reserved: BitField3,
+    level: BitField1,
+    #[bits = 1]
+    trigger: TriggerMode,
+    reserved2: BitField16,
+}
diff --git a/devices/src/usb/host_backend/context.rs b/devices/src/usb/host_backend/context.rs
new file mode 100644
index 0000000..960d066
--- /dev/null
+++ b/devices/src/usb/host_backend/context.rs
@@ -0,0 +1,157 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::error::*;
+use crate::utils::{EventHandler, EventLoop};
+use std::os::raw::c_short;
+use std::os::unix::io::RawFd;
+use std::sync::{Arc, Weak};
+use sys_util::{error, WatchingEvents};
+use usb_util::hotplug::UsbHotplugHandler;
+use usb_util::libusb_context::{LibUsbContext, LibUsbPollfdChangeHandler};
+use usb_util::libusb_device::LibUsbDevice;
+use vm_control::MaybeOwnedFd;
+
+/// Context wraps libusb context with libusb event handling.
+pub struct Context {
+    context: LibUsbContext,
+    event_loop: Arc<EventLoop>,
+    event_handler: Arc<dyn EventHandler>,
+}
+
+impl Context {
+    /// Create a new context.
+    #[cfg(not(feature = "sandboxed-libusb"))]
+    pub fn new(event_loop: Arc<EventLoop>) -> Result<Context> {
+        let context = LibUsbContext::new().map_err(Error::CreateLibUsbContext)?;
+        let ctx = Context {
+            context: context.clone(),
+            event_loop,
+            event_handler: Arc::new(LibUsbEventHandler {
+                context: context.clone(),
+            }),
+        };
+        ctx.init_event_handler()?;
+        Ok(ctx)
+    }
+
+    #[cfg(feature = "sandboxed-libusb")]
+    pub fn new(event_loop: Arc<EventLoop>) -> Result<Context> {
+        let context = LibUsbContext::new_jailed().map_err(Error::CreateLibUsbContext)?;
+        let ctx = Context {
+            context: context.clone(),
+            event_loop,
+            event_handler: Arc::new(LibUsbEventHandler {
+                context: context.clone(),
+            }),
+        };
+        ctx.init_event_handler()?;
+        Ok(ctx)
+    }
+
+    pub fn set_hotplug_handler<H: UsbHotplugHandler + Sized>(&self, handler: H) {
+        if let Err(e) = self.context.set_hotplug_cb(handler) {
+            error!("cannot set hotplug handler: {:?}", e);
+        }
+    }
+
+    fn init_event_handler(&self) -> Result<()> {
+        for pollfd in self.context.get_pollfd_iter() {
+            usb_debug!("event loop add event {} events handler", pollfd.fd);
+            self.event_loop
+                .add_event(
+                    &MaybeOwnedFd::Borrowed(pollfd.fd),
+                    WatchingEvents::new(pollfd.events as u32),
+                    Arc::downgrade(&self.event_handler),
+                )
+                .map_err(Error::AddToEventLoop)?;
+        }
+
+        self.context
+            .set_pollfd_notifiers(Box::new(PollfdChangeHandler {
+                event_loop: self.event_loop.clone(),
+                event_handler: Arc::downgrade(&self.event_handler),
+            }));
+        Ok(())
+    }
+
+    /// Get libusb device with matching bus, addr, vid and pid.
+    #[cfg(not(feature = "sandboxed-libusb"))]
+    pub fn get_device(&self, bus: u8, addr: u8, vid: u16, pid: u16) -> Option<LibUsbDevice> {
+        let device_iter = match self.context.get_device_iter() {
+            Ok(iter) => iter,
+            Err(e) => {
+                error!("could not get libusb device iterator: {:?}", e);
+                return None;
+            }
+        };
+        for device in device_iter {
+            if device.get_bus_number() == bus && device.get_address() == addr {
+                if let Ok(descriptor) = device.get_device_descriptor() {
+                    if descriptor.idProduct == pid && descriptor.idVendor == vid {
+                        return Some(device);
+                    }
+                }
+            }
+        }
+        error!("device not found bus {}, addr {}", bus, addr);
+        None
+    }
+
+    #[cfg(feature = "sandboxed-libusb")]
+    pub fn get_device(&self, fd: std::fs::File) -> Option<LibUsbDevice> {
+        match self.context.get_device_from_fd(fd) {
+            Ok(dev) => Some(dev),
+            Err(e) => {
+                error!("could not build device from fd: {:?}", e);
+                None
+            }
+        }
+    }
+}
+
+struct LibUsbEventHandler {
+    context: LibUsbContext,
+}
+
+impl EventHandler for LibUsbEventHandler {
+    fn on_event(&self) -> std::result::Result<(), ()> {
+        self.context.handle_events_nonblock();
+        Ok(())
+    }
+}
+
+struct PollfdChangeHandler {
+    event_loop: Arc<EventLoop>,
+    event_handler: Weak<dyn EventHandler>,
+}
+
+impl LibUsbPollfdChangeHandler for PollfdChangeHandler {
+    fn add_poll_fd(&self, fd: RawFd, events: c_short) {
+        if let Err(e) = self.event_loop.add_event(
+            &MaybeOwnedFd::Borrowed(fd),
+            WatchingEvents::new(events as u32),
+            self.event_handler.clone(),
+        ) {
+            error!("cannot add event to event loop: {}", e);
+        }
+    }
+
+    fn remove_poll_fd(&self, fd: RawFd) {
+        if let Some(h) = self.event_handler.upgrade() {
+            if let Err(e) = h.on_event() {
+                error!("cannot handle event: {:?}", e);
+            }
+        }
+        if let Err(e) = self
+            .event_loop
+            .remove_event_for_fd(&MaybeOwnedFd::Borrowed(fd))
+        {
+            error!(
+                "failed to remove poll change handler from event loop: {}",
+                e
+            );
+        }
+    }
+}
diff --git a/devices/src/usb/host_backend/error.rs b/devices/src/usb/host_backend/error.rs
new file mode 100644
index 0000000..ef097f9
--- /dev/null
+++ b/devices/src/usb/host_backend/error.rs
@@ -0,0 +1,76 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::usb::xhci::scatter_gather_buffer::Error as BufferError;
+use crate::usb::xhci::xhci_transfer::Error as XhciTransferError;
+use crate::utils::Error as UtilsError;
+use msg_socket::MsgError;
+use std::fmt::{self, Display};
+use usb_util::error::Error as UsbUtilError;
+
+#[derive(Debug)]
+pub enum Error {
+    AddToEventLoop(UtilsError),
+    StartAsyncJobQueue(UtilsError),
+    QueueAsyncJob(UtilsError),
+    CreateLibUsbContext(UsbUtilError),
+    GetActiveConfig(UsbUtilError),
+    SetActiveConfig(UsbUtilError),
+    SetInterfaceAltSetting(UsbUtilError),
+    ClearHalt(UsbUtilError),
+    GetEndpointType,
+    CreateControlSock(std::io::Error),
+    SetupControlSock(std::io::Error),
+    ReadControlSock(MsgError),
+    WriteControlSock(MsgError),
+    GetXhciTransferType(XhciTransferError),
+    TransferComplete(XhciTransferError),
+    ReadBuffer(BufferError),
+    WriteBuffer(BufferError),
+    BufferLen(BufferError),
+    /// Cannot get interface descriptor for (interface, altsetting).
+    GetInterfaceDescriptor((i32, u16)),
+    GetEndpointDescriptor(u8),
+    BadXhciTransferState,
+    BadBackendProviderState,
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            AddToEventLoop(e) => write!(f, "failed to add to event loop: {}", e),
+            StartAsyncJobQueue(e) => write!(f, "failed to start async job queue: {}", e),
+            QueueAsyncJob(e) => write!(f, "failed to queue async job: {}", e),
+            CreateLibUsbContext(e) => write!(f, "failed to create libusb context: {:?}", e),
+            GetActiveConfig(e) => write!(f, "failed to get active config: {:?}", e),
+            SetActiveConfig(e) => write!(f, "failed to set active config: {:?}", e),
+            SetInterfaceAltSetting(e) => write!(f, "failed to set interface alt setting: {:?}", e),
+            ClearHalt(e) => write!(f, "failed to clear halt: {:?}", e),
+            GetEndpointType => write!(f, "failed to get endpoint type"),
+            CreateControlSock(e) => write!(f, "failed to create contro sock: {}", e),
+            SetupControlSock(e) => write!(f, "failed to setup control sock: {}", e),
+            ReadControlSock(e) => write!(f, "failed to read control sock: {}", e),
+            WriteControlSock(e) => write!(f, "failed to write control sock: {}", e),
+            GetXhciTransferType(e) => write!(f, "failed to get xhci transfer type: {}", e),
+            TransferComplete(e) => write!(f, "xhci transfer completed: {}", e),
+            ReadBuffer(e) => write!(f, "failed to read buffer: {}", e),
+            WriteBuffer(e) => write!(f, "failed to write buffer: {}", e),
+            BufferLen(e) => write!(f, "failed to get buffer length: {}", e),
+            GetInterfaceDescriptor((i, alt_setting)) => write!(
+                f,
+                "failed to get interface descriptor for interface {}, alt setting {}",
+                i, alt_setting
+            ),
+            GetEndpointDescriptor(ep_idx) => {
+                write!(f, "failed to get endpoint descriptor for ep: {}", ep_idx)
+            }
+            BadXhciTransferState => write!(f, "xhci transfer is in a bad state"),
+            BadBackendProviderState => write!(f, "backend provider is in a bad state"),
+        }
+    }
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
diff --git a/devices/src/usb/host_backend/host_backend_device_provider.rs b/devices/src/usb/host_backend/host_backend_device_provider.rs
new file mode 100644
index 0000000..01fd84c
--- /dev/null
+++ b/devices/src/usb/host_backend/host_backend_device_provider.rs
@@ -0,0 +1,337 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::sync::Arc;
+
+use super::context::Context;
+use super::error::*;
+use super::host_device::HostDevice;
+use super::hotplug::HotplugHandler;
+use crate::usb::xhci::usb_hub::UsbHub;
+use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
+use crate::utils::AsyncJobQueue;
+use crate::utils::{EventHandler, EventLoop, FailHandle};
+use msg_socket::{MsgReceiver, MsgSender, MsgSocket};
+use std::mem;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::time::Duration;
+use sys_util::net::UnixSeqpacket;
+use sys_util::{error, WatchingEvents};
+use vm_control::{
+    UsbControlAttachedDevice, UsbControlCommand, UsbControlResult, UsbControlSocket,
+    USB_CONTROL_MAX_PORTS,
+};
+
+const SOCKET_TIMEOUT_MS: u64 = 2000;
+
+/// Host backend device provider is a xhci backend device provider that would provide pass through
+/// devices.
+pub enum HostBackendDeviceProvider {
+    // The provider is created but not yet started.
+    Created {
+        sock: MsgSocket<UsbControlResult, UsbControlCommand>,
+    },
+    // The provider is started on an event loop.
+    Started {
+        inner: Arc<ProviderInner>,
+    },
+    // The provider has failed.
+    Failed,
+}
+
+impl HostBackendDeviceProvider {
+    pub fn new() -> Result<(UsbControlSocket, HostBackendDeviceProvider)> {
+        let (child_sock, control_sock) = UnixSeqpacket::pair().map_err(Error::CreateControlSock)?;
+        control_sock
+            .set_write_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
+            .map_err(Error::SetupControlSock)?;
+        control_sock
+            .set_read_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
+            .map_err(Error::SetupControlSock)?;
+
+        let provider = HostBackendDeviceProvider::Created {
+            sock: MsgSocket::new(child_sock),
+        };
+        Ok((MsgSocket::new(control_sock), provider))
+    }
+
+    fn start_helper(
+        &mut self,
+        fail_handle: Arc<dyn FailHandle>,
+        event_loop: Arc<EventLoop>,
+        hub: Arc<UsbHub>,
+    ) -> Result<()> {
+        match mem::replace(self, HostBackendDeviceProvider::Failed) {
+            HostBackendDeviceProvider::Created { sock } => {
+                let ctx = Context::new(event_loop.clone())?;
+                let hotplug_handler = HotplugHandler::new(hub.clone());
+                ctx.set_hotplug_handler(hotplug_handler);
+                let job_queue =
+                    AsyncJobQueue::init(&event_loop).map_err(Error::StartAsyncJobQueue)?;
+                let inner = Arc::new(ProviderInner::new(fail_handle, job_queue, ctx, sock, hub));
+                let handler: Arc<dyn EventHandler> = inner.clone();
+                event_loop
+                    .add_event(
+                        &inner.sock,
+                        WatchingEvents::empty().set_read(),
+                        Arc::downgrade(&handler),
+                    )
+                    .map_err(Error::AddToEventLoop)?;
+                *self = HostBackendDeviceProvider::Started { inner };
+                Ok(())
+            }
+            HostBackendDeviceProvider::Started { .. } => {
+                error!("Host backend provider has already started");
+                Err(Error::BadBackendProviderState)
+            }
+            HostBackendDeviceProvider::Failed => {
+                error!("Host backend provider has already failed");
+                Err(Error::BadBackendProviderState)
+            }
+        }
+    }
+}
+
+impl XhciBackendDeviceProvider for HostBackendDeviceProvider {
+    fn start(
+        &mut self,
+        fail_handle: Arc<dyn FailHandle>,
+        event_loop: Arc<EventLoop>,
+        hub: Arc<UsbHub>,
+    ) -> std::result::Result<(), ()> {
+        self.start_helper(fail_handle, event_loop, hub)
+            .map_err(|e| {
+                error!("failed to start host backend device provider: {}", e);
+            })
+    }
+
+    fn keep_fds(&self) -> Vec<RawFd> {
+        match self {
+            HostBackendDeviceProvider::Created { sock } => vec![sock.as_raw_fd()],
+            _ => {
+                error!(
+                    "Trying to get keepfds when HostBackendDeviceProvider is not in created state"
+                );
+                vec![]
+            }
+        }
+    }
+}
+
+/// ProviderInner listens to control socket.
+pub struct ProviderInner {
+    fail_handle: Arc<dyn FailHandle>,
+    job_queue: Arc<AsyncJobQueue>,
+    ctx: Context,
+    sock: MsgSocket<UsbControlResult, UsbControlCommand>,
+    usb_hub: Arc<UsbHub>,
+}
+
+impl ProviderInner {
+    fn new(
+        fail_handle: Arc<dyn FailHandle>,
+        job_queue: Arc<AsyncJobQueue>,
+        ctx: Context,
+        sock: MsgSocket<UsbControlResult, UsbControlCommand>,
+        usb_hub: Arc<UsbHub>,
+    ) -> ProviderInner {
+        ProviderInner {
+            fail_handle,
+            job_queue,
+            ctx,
+            sock,
+            usb_hub,
+        }
+    }
+
+    fn handle_list_devices(&self, ports: [u8; USB_CONTROL_MAX_PORTS]) -> UsbControlResult {
+        let mut devices: [UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS] = Default::default();
+        for (result_index, &port_id) in ports.iter().enumerate() {
+            match self.usb_hub.get_port(port_id).and_then(|p| {
+                p.get_backend_device()
+                    .as_ref()
+                    .map(|d| (d.get_vid(), d.get_pid()))
+            }) {
+                Some((vendor_id, product_id)) => {
+                    devices[result_index] = UsbControlAttachedDevice {
+                        port: port_id,
+                        vendor_id,
+                        product_id,
+                    }
+                }
+                None => continue,
+            }
+        }
+        UsbControlResult::Devices(devices)
+    }
+
+    fn on_event_helper(&self) -> Result<()> {
+        let cmd = self.sock.recv().map_err(Error::ReadControlSock)?;
+        match cmd {
+            UsbControlCommand::AttachDevice {
+                bus,
+                addr,
+                vid,
+                pid,
+                fd: usb_fd,
+            } => {
+                let _ = usb_fd;
+                #[cfg(not(feature = "sandboxed-libusb"))]
+                let device = match self.ctx.get_device(bus, addr, vid, pid) {
+                    Some(d) => d,
+                    None => {
+                        error!(
+                            "cannot get device bus: {}, addr: {}, vid: {}, pid: {}",
+                            bus, addr, vid, pid
+                        );
+                        // The send failure will be logged, but event loop still think the event is
+                        // handled.
+                        let _ = self
+                            .sock
+                            .send(&UsbControlResult::NoSuchDevice)
+                            .map_err(Error::WriteControlSock)?;
+                        return Ok(());
+                    }
+                };
+                #[cfg(feature = "sandboxed-libusb")]
+                let (device, device_handle) = {
+                    use vm_control::MaybeOwnedFd;
+
+                    let usb_file = match usb_fd {
+                        Some(MaybeOwnedFd::Owned(file)) => file,
+                        _ => {
+                            let _ = self
+                                .sock
+                                .send(&UsbControlResult::FailedToOpenDevice)
+                                .map_err(Error::WriteControlSock);
+                            return Ok(());
+                        }
+                    };
+
+                    let device_fd = usb_file.as_raw_fd();
+
+                    let device = match self.ctx.get_device(usb_file) {
+                        Some(d) => d,
+                        None => {
+                            error!(
+                                "cannot get device bus: {}, addr: {}, vid: {}, pid: {}",
+                                bus, addr, vid, pid
+                            );
+                            // The send failure will be logged, but event loop still think the event
+                            // is handled.
+                            let _ = self
+                                .sock
+                                .send(&UsbControlResult::NoSuchDevice)
+                                .map_err(Error::WriteControlSock);
+                            return Ok(());
+                        }
+                    };
+
+                    let device_handle = {
+                        // This is safe only when fd is an fd of the current device.
+                        match unsafe { device.open_fd(device_fd) } {
+                            Ok(handle) => handle,
+                            Err(e) => {
+                                error!("fail to open device: {:?}", e);
+                                // The send failure will be logged, but event loop still think
+                                // the event is handled.
+                                let _ = self
+                                    .sock
+                                    .send(&UsbControlResult::FailedToOpenDevice)
+                                    .map_err(Error::WriteControlSock);
+                                return Ok(());
+                            }
+                        }
+                    };
+
+                    // Resetting the device is used to make sure it is in a known state, but it may
+                    // still function if the reset fails.
+                    if let Err(e) = device_handle.reset() {
+                        error!("failed to reset device after attach: {:?}", e);
+                    }
+                    (device, device_handle)
+                };
+
+                #[cfg(not(feature = "sandboxed-libusb"))]
+                let device_handle = match device.open() {
+                    Ok(handle) => handle,
+                    Err(e) => {
+                        error!("fail to open device: {:?}", e);
+                        // The send failure will be logged, but event loop still think the event is
+                        // handled.
+                        let _ = self
+                            .sock
+                            .send(&UsbControlResult::FailedToOpenDevice)
+                            .map_err(Error::WriteControlSock);
+                        return Ok(());
+                    }
+                };
+                let device = Box::new(HostDevice::new(
+                    self.fail_handle.clone(),
+                    self.job_queue.clone(),
+                    device,
+                    device_handle,
+                ));
+                let port = self.usb_hub.connect_backend(device);
+                match port {
+                    Ok(port) => {
+                        // The send failure will be logged, but event loop still think the event is
+                        // handled.
+                        let _ = self
+                            .sock
+                            .send(&UsbControlResult::Ok { port })
+                            .map_err(Error::WriteControlSock);
+                    }
+                    Err(e) => {
+                        error!("failed to connect device to hub: {}", e);
+                        // The send failure will be logged, but event loop still think the event is
+                        // handled.
+                        let _ = self
+                            .sock
+                            .send(&UsbControlResult::NoAvailablePort)
+                            .map_err(Error::WriteControlSock);
+                    }
+                }
+                Ok(())
+            }
+            UsbControlCommand::DetachDevice { port } => {
+                match self.usb_hub.disconnect_port(port) {
+                    Ok(()) => {
+                        // The send failure will be logged, but event loop still think the event is
+                        // handled.
+                        let _ = self
+                            .sock
+                            .send(&UsbControlResult::Ok { port })
+                            .map_err(Error::WriteControlSock);
+                    }
+                    Err(e) => {
+                        error!("failed to disconnect device from port {}: {}", port, e);
+                        // The send failure will be logged, but event loop still think the event is
+                        // handled.
+                        let _ = self
+                            .sock
+                            .send(&UsbControlResult::NoSuchDevice)
+                            .map_err(Error::WriteControlSock);
+                    }
+                }
+                Ok(())
+            }
+            UsbControlCommand::ListDevice { ports } => {
+                let result = self.handle_list_devices(ports);
+                // The send failure will be logged, but event loop still think the event is
+                // handled.
+                let _ = self.sock.send(&result).map_err(Error::WriteControlSock);
+                Ok(())
+            }
+        }
+    }
+}
+
+impl EventHandler for ProviderInner {
+    fn on_event(&self) -> std::result::Result<(), ()> {
+        self.on_event_helper().map_err(|e| {
+            error!("host backend device provider failed: {}", e);
+        })
+    }
+}
diff --git a/devices/src/usb/host_backend/host_device.rs b/devices/src/usb/host_backend/host_device.rs
new file mode 100644
index 0000000..8841f00
--- /dev/null
+++ b/devices/src/usb/host_backend/host_device.rs
@@ -0,0 +1,503 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::mem::drop;
+use std::sync::Arc;
+use sync::Mutex;
+
+use super::error::*;
+use super::usb_endpoint::UsbEndpoint;
+use super::utils::{submit_transfer, update_transfer_state};
+use crate::usb::xhci::scatter_gather_buffer::ScatterGatherBuffer;
+use crate::usb::xhci::xhci_backend_device::{BackendType, UsbDeviceAddress, XhciBackendDevice};
+use crate::usb::xhci::xhci_transfer::{XhciTransfer, XhciTransferState, XhciTransferType};
+use crate::utils::AsyncJobQueue;
+use crate::utils::FailHandle;
+use std::collections::HashMap;
+use sys_util::{error, warn};
+use usb_util::device_handle::DeviceHandle;
+use usb_util::error::Error as LibUsbError;
+use usb_util::libusb_device::LibUsbDevice;
+use usb_util::types::{
+    ControlRequestDataPhaseTransferDirection, ControlRequestRecipient, StandardControlRequest,
+    UsbRequestSetup,
+};
+use usb_util::usb_transfer::{
+    control_transfer, ControlTransferBuffer, TransferStatus, UsbTransfer,
+};
+
+#[derive(PartialEq)]
+pub enum ControlEndpointState {
+    /// Control endpoint should receive setup stage next.
+    SetupStage,
+    /// Control endpoint should receive data stage next.
+    DataStage,
+    /// Control endpoint should receive status stage next.
+    StatusStage,
+}
+
+/// Host device is a device connected to host.
+pub struct HostDevice {
+    fail_handle: Arc<dyn FailHandle>,
+    // Endpoints only contains data endpoints (1 to 30). Control transfers are handled at device
+    // level.
+    endpoints: Vec<UsbEndpoint>,
+    device: LibUsbDevice,
+    device_handle: Arc<Mutex<DeviceHandle>>,
+    ctl_ep_state: ControlEndpointState,
+    alt_settings: HashMap<u16, u16>,
+    claimed_interfaces: Vec<i32>,
+    control_request_setup: UsbRequestSetup,
+    executed: bool,
+    job_queue: Arc<AsyncJobQueue>,
+}
+
+impl Drop for HostDevice {
+    fn drop(&mut self) {
+        self.release_interfaces();
+    }
+}
+
+impl HostDevice {
+    /// Create a new host device.
+    pub fn new(
+        fail_handle: Arc<dyn FailHandle>,
+        job_queue: Arc<AsyncJobQueue>,
+        device: LibUsbDevice,
+        device_handle: DeviceHandle,
+    ) -> HostDevice {
+        HostDevice {
+            fail_handle,
+            endpoints: vec![],
+            device,
+            device_handle: Arc::new(Mutex::new(device_handle)),
+            ctl_ep_state: ControlEndpointState::SetupStage,
+            alt_settings: HashMap::new(),
+            claimed_interfaces: vec![],
+            control_request_setup: UsbRequestSetup::new(0, 0, 0, 0, 0),
+            executed: false,
+            job_queue,
+        }
+    }
+
+    fn get_interface_number_of_active_config(&self) -> i32 {
+        match self.device.get_active_config_descriptor() {
+            Err(LibUsbError::NotFound) => {
+                usb_debug!("device is in unconfigured state");
+                0
+            }
+            Err(e) => {
+                // device might be disconnected now.
+                error!("unexpected error: {:?}", e);
+                0
+            }
+            Ok(descriptor) => descriptor.bNumInterfaces as i32,
+        }
+    }
+
+    fn release_interfaces(&mut self) {
+        for i in &self.claimed_interfaces {
+            if let Err(e) = self.device_handle.lock().release_interface(*i) {
+                error!("could not release interface: {:?}", e);
+            }
+        }
+        self.claimed_interfaces = Vec::new();
+    }
+
+    // Check for requests that should be intercepted and emulated using libusb
+    // functions rather than passed directly to the device.
+    // Returns true if the request has been intercepted or false if the request
+    // should be passed through to the device.
+    fn intercepted_control_transfer(&mut self, xhci_transfer: &XhciTransfer) -> Result<bool> {
+        let direction = self.control_request_setup.get_direction();
+        let recipient = self.control_request_setup.get_recipient();
+        let standard_request = self.control_request_setup.get_standard_request();
+
+        if direction != ControlRequestDataPhaseTransferDirection::HostToDevice {
+            // Only host to device requests are intercepted currently.
+            return Ok(false);
+        }
+
+        let status = match standard_request {
+            Some(StandardControlRequest::SetAddress) => {
+                if recipient != ControlRequestRecipient::Device {
+                    return Ok(false);
+                }
+                usb_debug!("host device handling set address");
+                let addr = self.control_request_setup.value as u32;
+                self.set_address(addr);
+                TransferStatus::Completed
+            }
+            Some(StandardControlRequest::SetConfiguration) => {
+                if recipient != ControlRequestRecipient::Device {
+                    return Ok(false);
+                }
+                usb_debug!("host device handling set config");
+                self.set_config()?
+            }
+            Some(StandardControlRequest::SetInterface) => {
+                if recipient != ControlRequestRecipient::Interface {
+                    return Ok(false);
+                }
+                usb_debug!("host device handling set interface");
+                self.set_interface()?
+            }
+            Some(StandardControlRequest::ClearFeature) => {
+                if recipient != ControlRequestRecipient::Endpoint {
+                    return Ok(false);
+                }
+                usb_debug!("host device handling clear feature");
+                self.clear_feature()?
+            }
+            _ => {
+                // Other requests will be passed through to the device.
+                return Ok(false);
+            }
+        };
+
+        xhci_transfer
+            .on_transfer_complete(&status, 0)
+            .map_err(Error::TransferComplete)?;
+        Ok(true)
+    }
+
+    fn execute_control_transfer(
+        &mut self,
+        xhci_transfer: Arc<XhciTransfer>,
+        buffer: Option<ScatterGatherBuffer>,
+    ) -> Result<()> {
+        let mut control_transfer = control_transfer(0);
+        control_transfer
+            .buffer_mut()
+            .set_request_setup(&self.control_request_setup);
+
+        if self.intercepted_control_transfer(&xhci_transfer)? {
+            return Ok(());
+        }
+
+        let direction = self.control_request_setup.get_direction();
+        let buffer = if direction == ControlRequestDataPhaseTransferDirection::HostToDevice {
+            if let Some(buffer) = buffer {
+                buffer
+                    .read(&mut control_transfer.buffer_mut().data_buffer)
+                    .map_err(Error::ReadBuffer)?;
+            }
+            // buffer is consumed here for HostToDevice transfers.
+            None
+        } else {
+            // buffer will be used later in the callback for DeviceToHost transfers.
+            buffer
+        };
+
+        let tmp_transfer = xhci_transfer.clone();
+        let callback = move |t: UsbTransfer<ControlTransferBuffer>| {
+            usb_debug!("setup token control transfer callback invoked");
+            update_transfer_state(&xhci_transfer, &t)?;
+            let state = xhci_transfer.state().lock();
+            match *state {
+                XhciTransferState::Cancelled => {
+                    usb_debug!("transfer cancelled");
+                    drop(state);
+                    xhci_transfer
+                        .on_transfer_complete(&TransferStatus::Cancelled, 0)
+                        .map_err(Error::TransferComplete)?;
+                }
+                XhciTransferState::Completed => {
+                    let status = t.status();
+                    let actual_length = t.actual_length();
+                    if direction == ControlRequestDataPhaseTransferDirection::DeviceToHost {
+                        if let Some(buffer) = &buffer {
+                            buffer
+                                .write(&t.buffer().data_buffer)
+                                .map_err(Error::WriteBuffer)?;
+                        }
+                    }
+                    drop(state);
+                    usb_debug!("transfer completed with actual length {}", actual_length);
+                    xhci_transfer
+                        .on_transfer_complete(&status, actual_length as u32)
+                        .map_err(Error::TransferComplete)?;
+                }
+                _ => {
+                    // update_transfer_state is already invoked before match.
+                    // This transfer could only be `Cancelled` or `Completed`.
+                    // Any other state means there is a bug in crosvm implementation.
+                    error!("should not take this branch");
+                    return Err(Error::BadXhciTransferState);
+                }
+            }
+            Ok(())
+        };
+
+        let fail_handle = self.fail_handle.clone();
+        control_transfer.set_callback(
+            move |t: UsbTransfer<ControlTransferBuffer>| match callback(t) {
+                Ok(_) => {}
+                Err(e) => {
+                    error!("control transfer callback failed {:?}", e);
+                    fail_handle.fail();
+                }
+            },
+        );
+        submit_transfer(
+            self.fail_handle.clone(),
+            &self.job_queue,
+            tmp_transfer,
+            &self.device_handle,
+            control_transfer,
+        )
+    }
+
+    fn handle_control_transfer(&mut self, transfer: XhciTransfer) -> Result<()> {
+        let xhci_transfer = Arc::new(transfer);
+        match xhci_transfer
+            .get_transfer_type()
+            .map_err(Error::GetXhciTransferType)?
+        {
+            XhciTransferType::SetupStage(setup) => {
+                if self.ctl_ep_state != ControlEndpointState::SetupStage {
+                    error!("Control endpoint is in an inconsistant state");
+                    return Ok(());
+                }
+                usb_debug!("setup stage setup buffer: {:?}", setup);
+                self.control_request_setup = setup;
+                xhci_transfer
+                    .on_transfer_complete(&TransferStatus::Completed, 0)
+                    .map_err(Error::TransferComplete)?;
+                self.ctl_ep_state = ControlEndpointState::DataStage;
+            }
+            XhciTransferType::DataStage(buffer) => {
+                if self.ctl_ep_state != ControlEndpointState::DataStage {
+                    error!("Control endpoint is in an inconsistant state");
+                    return Ok(());
+                }
+                // Requests with a DataStage will be executed here.
+                // Requests without a DataStage will be executed in StatusStage.
+                self.execute_control_transfer(xhci_transfer, Some(buffer))?;
+                self.executed = true;
+                self.ctl_ep_state = ControlEndpointState::StatusStage;
+            }
+            XhciTransferType::StatusStage => {
+                if self.ctl_ep_state == ControlEndpointState::SetupStage {
+                    error!("Control endpoint is in an inconsistant state");
+                    return Ok(());
+                }
+                if self.executed {
+                    // Request was already executed during DataStage.
+                    // Just complete the StatusStage transfer.
+                    xhci_transfer
+                        .on_transfer_complete(&TransferStatus::Completed, 0)
+                        .map_err(Error::TransferComplete)?;
+                } else {
+                    // Execute the request now since there was no DataStage.
+                    self.execute_control_transfer(xhci_transfer, None)?;
+                }
+                self.executed = false;
+                self.ctl_ep_state = ControlEndpointState::SetupStage;
+            }
+            _ => {
+                // Non control transfer should not be handled in this function.
+                error!("Non control (could be noop) transfer sent to control endpoint.");
+                xhci_transfer
+                    .on_transfer_complete(&TransferStatus::Completed, 0)
+                    .map_err(Error::TransferComplete)?;
+            }
+        }
+        Ok(())
+    }
+
+    fn set_config(&mut self) -> Result<TransferStatus> {
+        // It's a standard, set_config, device request.
+        let config = (self.control_request_setup.value & 0xff) as i32;
+        usb_debug!(
+            "Set config control transfer is received with config: {}",
+            config
+        );
+        self.release_interfaces();
+        let cur_config = self
+            .device_handle
+            .lock()
+            .get_active_configuration()
+            .map_err(Error::GetActiveConfig)?;
+        usb_debug!("current config is: {}", cur_config);
+        if config != cur_config {
+            self.device_handle
+                .lock()
+                .set_active_configuration(config)
+                .map_err(Error::SetActiveConfig)?;
+        }
+        self.claim_interfaces();
+        self.create_endpoints()?;
+        Ok(TransferStatus::Completed)
+    }
+
+    fn set_interface(&mut self) -> Result<TransferStatus> {
+        usb_debug!("set interface");
+        // It's a standard, set_interface, interface request.
+        let interface = self.control_request_setup.index;
+        let alt_setting = self.control_request_setup.value;
+        self.device_handle
+            .lock()
+            .set_interface_alt_setting(interface as i32, alt_setting as i32)
+            .map_err(Error::SetInterfaceAltSetting)?;
+        self.alt_settings.insert(interface, alt_setting);
+        self.create_endpoints()?;
+        Ok(TransferStatus::Completed)
+    }
+
+    fn clear_feature(&mut self) -> Result<TransferStatus> {
+        usb_debug!("clear feature");
+        let request_setup = &self.control_request_setup;
+        // It's a standard, clear_feature, endpoint request.
+        const STD_FEATURE_ENDPOINT_HALT: u16 = 0;
+        if request_setup.value == STD_FEATURE_ENDPOINT_HALT {
+            self.device_handle
+                .lock()
+                .clear_halt(request_setup.index as u8)
+                .map_err(Error::ClearHalt)?;
+        }
+        Ok(TransferStatus::Completed)
+    }
+
+    fn claim_interfaces(&mut self) {
+        for i in 0..self.get_interface_number_of_active_config() {
+            match self.device_handle.lock().claim_interface(i) {
+                Ok(()) => {
+                    usb_debug!("claimed interface {}", i);
+                    self.claimed_interfaces.push(i);
+                }
+                Err(e) => {
+                    error!("unable to claim interface {}: {:?}", i, e);
+                }
+            }
+        }
+    }
+
+    fn create_endpoints(&mut self) -> Result<()> {
+        self.endpoints = Vec::new();
+        let config_descriptor = match self.device.get_active_config_descriptor() {
+            Err(e) => {
+                error!("device might be disconnected: {:?}", e);
+                return Ok(());
+            }
+            Ok(descriptor) => descriptor,
+        };
+        for i in &self.claimed_interfaces {
+            let alt_setting = self.alt_settings.get(&(*i as u16)).unwrap_or(&0);
+            let interface = config_descriptor
+                .get_interface_descriptor(*i as u8, *alt_setting as i32)
+                .ok_or(Error::GetInterfaceDescriptor((*i, *alt_setting)))?;
+            for ep_idx in 0..interface.bNumEndpoints {
+                let ep_dp = interface
+                    .endpoint_descriptor(ep_idx)
+                    .ok_or(Error::GetEndpointDescriptor(ep_idx))?;
+                let ep_num = ep_dp.get_endpoint_number();
+                if ep_num == 0 {
+                    usb_debug!("endpoint 0 in endpoint descriptors");
+                    continue;
+                }
+                let direction = ep_dp.get_direction();
+                let ty = ep_dp.get_endpoint_type().ok_or(Error::GetEndpointType)?;
+                self.endpoints.push(UsbEndpoint::new(
+                    self.fail_handle.clone(),
+                    self.job_queue.clone(),
+                    self.device_handle.clone(),
+                    ep_num,
+                    direction,
+                    ty,
+                ));
+            }
+        }
+        Ok(())
+    }
+
+    fn submit_transfer_helper(&mut self, transfer: XhciTransfer) -> Result<()> {
+        if transfer.get_endpoint_number() == 0 {
+            return self.handle_control_transfer(transfer);
+        }
+        for ep in &self.endpoints {
+            if ep.match_ep(transfer.get_endpoint_number(), transfer.get_transfer_dir()) {
+                return ep.handle_transfer(transfer);
+            }
+        }
+        warn!("Could not find endpoint for transfer");
+        transfer
+            .on_transfer_complete(&TransferStatus::Error, 0)
+            .map_err(Error::TransferComplete)
+    }
+}
+
+impl XhciBackendDevice for HostDevice {
+    fn get_backend_type(&self) -> BackendType {
+        let d = match self.device.get_device_descriptor() {
+            Ok(d) => d,
+            Err(_) => return BackendType::Usb2,
+        };
+
+        // See definition of bcdUsb.
+        const USB3_MASK: u16 = 0x0300;
+        match d.bcdUSB & USB3_MASK {
+            USB3_MASK => BackendType::Usb3,
+            _ => BackendType::Usb2,
+        }
+    }
+
+    fn host_bus(&self) -> u8 {
+        self.device.get_bus_number()
+    }
+
+    fn host_address(&self) -> u8 {
+        self.device.get_address()
+    }
+
+    fn get_vid(&self) -> u16 {
+        match self.device.get_device_descriptor() {
+            Ok(d) => d.idVendor,
+            Err(e) => {
+                error!("cannot get device descriptor: {:?}", e);
+                0
+            }
+        }
+    }
+
+    fn get_pid(&self) -> u16 {
+        match self.device.get_device_descriptor() {
+            Ok(d) => d.idProduct,
+            Err(e) => {
+                error!("cannot get device descriptor: {:?}", e);
+                0
+            }
+        }
+    }
+
+    fn submit_transfer(&mut self, transfer: XhciTransfer) -> std::result::Result<(), ()> {
+        self.submit_transfer_helper(transfer).map_err(|e| {
+            error!("failed to submit transfer: {}", e);
+        })
+    }
+
+    fn set_address(&mut self, _address: UsbDeviceAddress) {
+        // It's a standard, set_address, device request. We do nothing here. As described in XHCI
+        // spec. See set address command ring trb.
+        usb_debug!(
+            "Set address control transfer is received with address: {}",
+            _address
+        );
+    }
+
+    fn reset(&mut self) -> std::result::Result<(), ()> {
+        usb_debug!("resetting host device");
+        let result = self.device_handle.lock().reset();
+        match result {
+            Err(LibUsbError::NotFound) => {
+                // libusb will return NotFound if it fails to re-claim
+                // the interface after the reset.
+                Ok(())
+            }
+            _ => result.map_err(|e| {
+                error!("failed to reset device: {:?}", e);
+            }),
+        }
+    }
+}
diff --git a/devices/src/usb/host_backend/hotplug.rs b/devices/src/usb/host_backend/hotplug.rs
new file mode 100644
index 0000000..0764660
--- /dev/null
+++ b/devices/src/usb/host_backend/hotplug.rs
@@ -0,0 +1,45 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::sync::Arc;
+
+use crate::usb::xhci::usb_hub::UsbHub;
+use sys_util::error;
+use usb_util::hotplug::{HotplugEvent, UsbHotplugHandler};
+use usb_util::libusb_device::LibUsbDevice;
+
+pub struct HotplugHandler {
+    hub: Arc<UsbHub>,
+}
+
+impl HotplugHandler {
+    pub fn new(hub: Arc<UsbHub>) -> Self {
+        HotplugHandler { hub }
+    }
+}
+
+impl UsbHotplugHandler for HotplugHandler {
+    fn hotplug_event(&self, device: LibUsbDevice, event: HotplugEvent) {
+        if event != HotplugEvent::DeviceLeft {
+            return;
+        }
+
+        let bus = device.get_bus_number();
+        let address = device.get_address();
+        let descriptor = match device.get_device_descriptor() {
+            Ok(d) => d,
+            Err(e) => {
+                error!("cannot get device descriptor: {:?}", e);
+                return;
+            }
+        };
+        let vid = descriptor.idVendor;
+        let pid = descriptor.idProduct;
+
+        if let Err(e) = self.hub.try_detach(bus, address, vid, pid) {
+            error!("device left event triggered failed detach from hub: {}", e);
+            return;
+        }
+    }
+}
diff --git a/devices/src/usb/host_backend/mod.rs b/devices/src/usb/host_backend/mod.rs
new file mode 100644
index 0000000..ea0f44c
--- /dev/null
+++ b/devices/src/usb/host_backend/mod.rs
@@ -0,0 +1,11 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+pub mod context;
+pub mod error;
+pub mod host_backend_device_provider;
+pub mod host_device;
+mod hotplug;
+pub mod usb_endpoint;
+mod utils;
diff --git a/devices/src/usb/host_backend/usb_endpoint.rs b/devices/src/usb/host_backend/usb_endpoint.rs
new file mode 100644
index 0000000..329d6ff
--- /dev/null
+++ b/devices/src/usb/host_backend/usb_endpoint.rs
@@ -0,0 +1,254 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::cmp;
+use std::sync::Arc;
+use sync::Mutex;
+
+use super::error::*;
+use super::utils::{submit_transfer, update_transfer_state};
+use crate::usb::xhci::scatter_gather_buffer::ScatterGatherBuffer;
+use crate::usb::xhci::xhci_transfer::{
+    TransferDirection, XhciTransfer, XhciTransferState, XhciTransferType,
+};
+use crate::utils::AsyncJobQueue;
+use crate::utils::FailHandle;
+use sys_util::error;
+use usb_util::device_handle::DeviceHandle;
+use usb_util::types::{EndpointDirection, EndpointType, ENDPOINT_DIRECTION_OFFSET};
+use usb_util::usb_transfer::{
+    bulk_transfer, interrupt_transfer, BulkTransferBuffer, TransferStatus, UsbTransfer,
+};
+
+/// Isochronous, Bulk or Interrupt endpoint.
+pub struct UsbEndpoint {
+    fail_handle: Arc<dyn FailHandle>,
+    job_queue: Arc<AsyncJobQueue>,
+    device_handle: Arc<Mutex<DeviceHandle>>,
+    endpoint_number: u8,
+    direction: EndpointDirection,
+    ty: EndpointType,
+}
+
+impl UsbEndpoint {
+    /// Create new endpoint. This function will panic if endpoint type is control.
+    pub fn new(
+        fail_handle: Arc<dyn FailHandle>,
+        job_queue: Arc<AsyncJobQueue>,
+        device_handle: Arc<Mutex<DeviceHandle>>,
+        endpoint_number: u8,
+        direction: EndpointDirection,
+        ty: EndpointType,
+    ) -> UsbEndpoint {
+        assert!(ty != EndpointType::Control);
+        UsbEndpoint {
+            fail_handle,
+            job_queue,
+            device_handle,
+            endpoint_number,
+            direction,
+            ty,
+        }
+    }
+
+    fn ep_addr(&self) -> u8 {
+        self.endpoint_number | ((self.direction as u8) << ENDPOINT_DIRECTION_OFFSET)
+    }
+
+    /// Returns true is this endpoint matches number and direction.
+    pub fn match_ep(&self, endpoint_number: u8, dir: TransferDirection) -> bool {
+        let self_dir = match self.direction {
+            EndpointDirection::HostToDevice => TransferDirection::Out,
+            EndpointDirection::DeviceToHost => TransferDirection::In,
+        };
+        self.endpoint_number == endpoint_number && self_dir == dir
+    }
+
+    /// Handle a xhci transfer.
+    pub fn handle_transfer(&self, transfer: XhciTransfer) -> Result<()> {
+        let buffer = match transfer
+            .get_transfer_type()
+            .map_err(Error::GetXhciTransferType)?
+        {
+            XhciTransferType::Normal(buffer) => buffer,
+            XhciTransferType::Noop => {
+                return transfer
+                    .on_transfer_complete(&TransferStatus::Completed, 0)
+                    .map_err(Error::TransferComplete);
+            }
+            _ => {
+                error!("unhandled xhci transfer type by usb endpoint");
+                return transfer
+                    .on_transfer_complete(&TransferStatus::Error, 0)
+                    .map_err(Error::TransferComplete);
+            }
+        };
+
+        match self.ty {
+            EndpointType::Bulk => {
+                self.handle_bulk_transfer(transfer, buffer)?;
+            }
+            EndpointType::Interrupt => {
+                self.handle_interrupt_transfer(transfer, buffer)?;
+            }
+            _ => {
+                return transfer
+                    .on_transfer_complete(&TransferStatus::Error, 0)
+                    .map_err(Error::TransferComplete);
+            }
+        }
+        Ok(())
+    }
+
+    fn handle_bulk_transfer(
+        &self,
+        xhci_transfer: XhciTransfer,
+        buffer: ScatterGatherBuffer,
+    ) -> Result<()> {
+        let usb_transfer =
+            bulk_transfer(self.ep_addr(), 0, buffer.len().map_err(Error::BufferLen)?);
+        self.do_handle_transfer(xhci_transfer, usb_transfer, buffer)
+    }
+
+    fn handle_interrupt_transfer(
+        &self,
+        xhci_transfer: XhciTransfer,
+        buffer: ScatterGatherBuffer,
+    ) -> Result<()> {
+        let usb_transfer =
+            interrupt_transfer(self.ep_addr(), 0, buffer.len().map_err(Error::BufferLen)?);
+        self.do_handle_transfer(xhci_transfer, usb_transfer, buffer)
+    }
+
+    fn do_handle_transfer(
+        &self,
+        xhci_transfer: XhciTransfer,
+        mut usb_transfer: UsbTransfer<BulkTransferBuffer>,
+        buffer: ScatterGatherBuffer,
+    ) -> Result<()> {
+        let xhci_transfer = Arc::new(xhci_transfer);
+        let tmp_transfer = xhci_transfer.clone();
+        match self.direction {
+            EndpointDirection::HostToDevice => {
+                // Read data from ScatterGatherBuffer to a continuous memory.
+                buffer
+                    .read(usb_transfer.buffer_mut().as_mut_slice())
+                    .map_err(Error::ReadBuffer)?;
+                usb_debug!(
+                    "out transfer ep_addr {:#x}, buffer len {:?}, data {:#x?}",
+                    self.ep_addr(),
+                    buffer.len(),
+                    usb_transfer.buffer_mut().as_mut_slice()
+                );
+                let callback = move |t: UsbTransfer<BulkTransferBuffer>| {
+                    usb_debug!("out transfer callback");
+                    update_transfer_state(&xhci_transfer, &t)?;
+                    let state = xhci_transfer.state().lock();
+                    match *state {
+                        XhciTransferState::Cancelled => {
+                            usb_debug!("transfer has been cancelled");
+                            drop(state);
+                            xhci_transfer
+                                .on_transfer_complete(&TransferStatus::Cancelled, 0)
+                                .map_err(Error::TransferComplete)
+                        }
+                        XhciTransferState::Completed => {
+                            let status = t.status();
+                            let actual_length = t.actual_length();
+                            drop(state);
+                            xhci_transfer
+                                .on_transfer_complete(&status, actual_length as u32)
+                                .map_err(Error::TransferComplete)
+                        }
+                        _ => {
+                            error!("xhci trasfer state (host to device) is invalid");
+                            Err(Error::BadXhciTransferState)
+                        }
+                    }
+                };
+                let fail_handle = self.fail_handle.clone();
+                usb_transfer.set_callback(
+                    move |t: UsbTransfer<BulkTransferBuffer>| match callback(t) {
+                        Ok(_) => {}
+                        Err(e) => {
+                            error!("bulk transfer callback failed: {:?}", e);
+                            fail_handle.fail();
+                        }
+                    },
+                );
+                submit_transfer(
+                    self.fail_handle.clone(),
+                    &self.job_queue,
+                    tmp_transfer,
+                    &self.device_handle,
+                    usb_transfer,
+                )?;
+            }
+            EndpointDirection::DeviceToHost => {
+                usb_debug!(
+                    "in transfer ep_addr {:#x}, buffer len {:?}",
+                    self.ep_addr(),
+                    buffer.len()
+                );
+                let _addr = self.ep_addr();
+                let callback = move |t: UsbTransfer<BulkTransferBuffer>| {
+                    usb_debug!(
+                        "ep {:#x} in transfer data {:?}",
+                        _addr,
+                        t.buffer().as_slice()
+                    );
+                    update_transfer_state(&xhci_transfer, &t)?;
+                    let state = xhci_transfer.state().lock();
+                    match *state {
+                        XhciTransferState::Cancelled => {
+                            usb_debug!("transfer has been cancelled");
+                            drop(state);
+                            xhci_transfer
+                                .on_transfer_complete(&TransferStatus::Cancelled, 0)
+                                .map_err(Error::TransferComplete)
+                        }
+                        XhciTransferState::Completed => {
+                            let status = t.status();
+                            let actual_length = t.actual_length() as usize;
+                            let copied_length = buffer
+                                .write(t.buffer().as_slice())
+                                .map_err(Error::WriteBuffer)?;
+                            let actual_length = cmp::min(actual_length, copied_length);
+                            drop(state);
+                            xhci_transfer
+                                .on_transfer_complete(&status, actual_length as u32)
+                                .map_err(Error::TransferComplete)
+                        }
+                        _ => {
+                            // update state is already invoked. This match should not be in any
+                            // other state.
+                            error!("xhci trasfer state (device to host) is invalid");
+                            Err(Error::BadXhciTransferState)
+                        }
+                    }
+                };
+                let fail_handle = self.fail_handle.clone();
+
+                usb_transfer.set_callback(
+                    move |t: UsbTransfer<BulkTransferBuffer>| match callback(t) {
+                        Ok(_) => {}
+                        Err(e) => {
+                            error!("bulk transfer callback {:?}", e);
+                            fail_handle.fail();
+                        }
+                    },
+                );
+
+                submit_transfer(
+                    self.fail_handle.clone(),
+                    &self.job_queue,
+                    tmp_transfer,
+                    &self.device_handle,
+                    usb_transfer,
+                )?;
+            }
+        }
+        Ok(())
+    }
+}
diff --git a/devices/src/usb/host_backend/utils.rs b/devices/src/usb/host_backend/utils.rs
new file mode 100644
index 0000000..7d23bd4
--- /dev/null
+++ b/devices/src/usb/host_backend/utils.rs
@@ -0,0 +1,110 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::mem;
+use std::sync::Arc;
+use sync::Mutex;
+
+use super::error::*;
+use crate::usb::xhci::xhci_transfer::{XhciTransfer, XhciTransferState};
+use crate::utils::AsyncJobQueue;
+use crate::utils::FailHandle;
+use sys_util::{error, warn};
+use usb_util::device_handle::DeviceHandle;
+use usb_util::usb_transfer::{TransferStatus, UsbTransfer, UsbTransferBuffer};
+
+/// Helper function to update xhci_transfer state.
+pub fn update_transfer_state<T: UsbTransferBuffer>(
+    xhci_transfer: &Arc<XhciTransfer>,
+    usb_transfer: &UsbTransfer<T>,
+) -> Result<()> {
+    let status = usb_transfer.status();
+    let mut state = xhci_transfer.state().lock();
+
+    if status == TransferStatus::Cancelled {
+        *state = XhciTransferState::Cancelled;
+        return Ok(());
+    }
+
+    match *state {
+        XhciTransferState::Cancelling => {
+            *state = XhciTransferState::Cancelled;
+        }
+        XhciTransferState::Submitted { .. } => {
+            *state = XhciTransferState::Completed;
+        }
+        _ => {
+            error!("xhci trasfer state is invalid");
+            *state = XhciTransferState::Completed;
+            return Err(Error::BadXhciTransferState);
+        }
+    }
+    Ok(())
+}
+
+/// Helper function to submit usb_transfer to device handle.
+pub fn submit_transfer<T: UsbTransferBuffer>(
+    fail_handle: Arc<dyn FailHandle>,
+    job_queue: &Arc<AsyncJobQueue>,
+    xhci_transfer: Arc<XhciTransfer>,
+    device_handle: &Arc<Mutex<DeviceHandle>>,
+    usb_transfer: UsbTransfer<T>,
+) -> Result<()> {
+    let transfer_status = {
+        // We need to hold the lock to avoid race condition.
+        // While we are trying to submit the transfer, another thread might want to cancel the same
+        // transfer. Holding the lock here makes sure one of them is cancelled.
+        let mut state = xhci_transfer.state().lock();
+        match mem::replace(&mut *state, XhciTransferState::Cancelled) {
+            XhciTransferState::Created => {
+                let canceller = usb_transfer.get_canceller();
+                // TODO(jkwang) refactor canceller to return Cancel::Ok or Cancel::Err.
+                let cancel_callback = Box::new(move || match canceller.try_cancel() {
+                    true => {
+                        usb_debug!("cancel issued to libusb backend");
+                    }
+                    false => {
+                        usb_debug!("fail to cancel");
+                    }
+                });
+                *state = XhciTransferState::Submitted { cancel_callback };
+                match device_handle.lock().submit_async_transfer(usb_transfer) {
+                    Err(e) => {
+                        error!("fail to submit transfer {:?}", e);
+                        *state = XhciTransferState::Completed;
+                        TransferStatus::NoDevice
+                    }
+                    // If it's submitted, we don't need to send on_transfer_complete now.
+                    Ok(_) => return Ok(()),
+                }
+            }
+            XhciTransferState::Cancelled => {
+                warn!("Transfer is already cancelled");
+                TransferStatus::Cancelled
+            }
+            _ => {
+                // The transfer could not be in the following states:
+                // Submitted: A transfer should only be submitted once.
+                // Cancelling: Transfer is cancelling only when it's submitted and someone is
+                // trying to cancel it.
+                // Completed: A completed transfer should not be submitted again.
+                error!("xhci trasfer state is invalid");
+                return Err(Error::BadXhciTransferState);
+            }
+        }
+    };
+    // We are holding locks to of backends, we want to call on_transfer_complete
+    // without any lock.
+    job_queue
+        .queue_job(
+            move || match xhci_transfer.on_transfer_complete(&transfer_status, 0) {
+                Ok(_) => {}
+                Err(e) => {
+                    error!("transfer complete failed: {:?}", e);
+                    fail_handle.fail();
+                }
+            },
+        )
+        .map_err(Error::QueueAsyncJob)
+}
diff --git a/devices/src/usb/log.rs b/devices/src/usb/log.rs
new file mode 100644
index 0000000..4cb906b
--- /dev/null
+++ b/devices/src/usb/log.rs
@@ -0,0 +1,14 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// TODO(jkwang) remove this macro once we have a proper tracing system.
+#[macro_export]
+macro_rules! usb_debug {
+    ($($args:tt)+) => {
+        // Set true to enable logging.
+        if false {
+            sys_util::debug!($($args)*);
+        }
+    };
+}
diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs
new file mode 100644
index 0000000..dde6189
--- /dev/null
+++ b/devices/src/usb/mod.rs
@@ -0,0 +1,8 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#[macro_use]
+mod log;
+pub mod host_backend;
+pub mod xhci;
diff --git a/devices/src/usb/xhci/command_ring_controller.rs b/devices/src/usb/xhci/command_ring_controller.rs
new file mode 100644
index 0000000..e893194
--- /dev/null
+++ b/devices/src/usb/xhci/command_ring_controller.rs
@@ -0,0 +1,395 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::device_slot::{DeviceSlot, DeviceSlots, Error as DeviceSlotError};
+use super::interrupter::{Error as InterrupterError, Interrupter};
+use super::ring_buffer_controller::{
+    Error as RingBufferControllerError, RingBufferController, TransferDescriptorHandler,
+};
+use super::xhci_abi::{
+    AddressDeviceCommandTrb, AddressedTrb, ConfigureEndpointCommandTrb, DisableSlotCommandTrb,
+    Error as TrbError, EvaluateContextCommandTrb, ResetDeviceCommandTrb,
+    SetTRDequeuePointerCommandTrb, StopEndpointCommandTrb, TransferDescriptor, TrbCast,
+    TrbCompletionCode, TrbType,
+};
+use super::xhci_regs::{valid_slot_id, MAX_SLOTS};
+use crate::utils::EventLoop;
+use std::fmt::{self, Display};
+use std::sync::Arc;
+use sync::Mutex;
+use sys_util::{error, warn, Error as SysError, EventFd, GuestAddress, GuestMemory};
+
+#[derive(Debug)]
+pub enum Error {
+    WriteEventFd(SysError),
+    SendInterrupt(InterrupterError),
+    CastTrb(TrbError),
+    BadSlotId(u8),
+    StopEndpoint(DeviceSlotError),
+    ConfigEndpoint(DeviceSlotError),
+    SetAddress(DeviceSlotError),
+    SetDequeuePointer(DeviceSlotError),
+    EvaluateContext(DeviceSlotError),
+    DisableSlot(DeviceSlotError),
+    ResetSlot(DeviceSlotError),
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            WriteEventFd(e) => write!(f, "failed to write event fd: {}", e),
+            SendInterrupt(e) => write!(f, "failed to send interrupt: {}", e),
+            CastTrb(e) => write!(f, "failed to cast trb: {}", e),
+            BadSlotId(id) => write!(f, "bad slot id: {}", id),
+            StopEndpoint(e) => write!(f, "failed to stop endpoint: {}", e),
+            ConfigEndpoint(e) => write!(f, "failed to config endpoint: {}", e),
+            SetAddress(e) => write!(f, "failed to set address: {}", e),
+            SetDequeuePointer(e) => write!(f, "failed to set dequeue pointer: {}", e),
+            EvaluateContext(e) => write!(f, "failed to evaluate context: {}", e),
+            DisableSlot(e) => write!(f, "failed to disable slot: {}", e),
+            ResetSlot(e) => write!(f, "failed to reset slot: {}", e),
+        }
+    }
+}
+
+pub type CommandRingController = RingBufferController<CommandRingTrbHandler>;
+pub type CommandRingControllerError = RingBufferControllerError;
+
+impl CommandRingController {
+    pub fn new(
+        mem: GuestMemory,
+        event_loop: Arc<EventLoop>,
+        slots: DeviceSlots,
+        interrupter: Arc<Mutex<Interrupter>>,
+    ) -> std::result::Result<Arc<CommandRingController>, RingBufferControllerError> {
+        RingBufferController::new_with_handler(
+            String::from("command ring"),
+            mem,
+            event_loop,
+            CommandRingTrbHandler::new(slots, interrupter),
+        )
+    }
+}
+
+pub struct CommandRingTrbHandler {
+    slots: DeviceSlots,
+    interrupter: Arc<Mutex<Interrupter>>,
+}
+
+impl CommandRingTrbHandler {
+    fn new(slots: DeviceSlots, interrupter: Arc<Mutex<Interrupter>>) -> Self {
+        CommandRingTrbHandler { slots, interrupter }
+    }
+
+    fn slot(&self, slot_id: u8) -> Result<Arc<DeviceSlot>> {
+        self.slots.slot(slot_id).ok_or(Error::BadSlotId(slot_id))
+    }
+
+    fn command_completion_callback(
+        interrupter: &Arc<Mutex<Interrupter>>,
+        completion_code: TrbCompletionCode,
+        slot_id: u8,
+        trb_addr: u64,
+        event_fd: &EventFd,
+    ) -> Result<()> {
+        interrupter
+            .lock()
+            .send_command_completion_trb(completion_code, slot_id, GuestAddress(trb_addr))
+            .map_err(Error::SendInterrupt)?;
+        event_fd.write(1).map_err(Error::WriteEventFd)
+    }
+
+    fn enable_slot(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> {
+        for slot_id in 1..=MAX_SLOTS {
+            if self.slot(slot_id)?.enable() {
+                return CommandRingTrbHandler::command_completion_callback(
+                    &self.interrupter,
+                    TrbCompletionCode::Success,
+                    slot_id,
+                    atrb.gpa,
+                    &event_fd,
+                );
+            }
+        }
+
+        CommandRingTrbHandler::command_completion_callback(
+            &self.interrupter,
+            TrbCompletionCode::NoSlotsAvailableError,
+            0,
+            atrb.gpa,
+            &event_fd,
+        )
+    }
+
+    fn disable_slot(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> {
+        let trb = atrb
+            .trb
+            .cast::<DisableSlotCommandTrb>()
+            .map_err(Error::CastTrb)?;
+        let slot_id = trb.get_slot_id();
+        if valid_slot_id(slot_id) {
+            let gpa = atrb.gpa;
+            let interrupter = self.interrupter.clone();
+            self.slots
+                .disable_slot(slot_id, move |completion_code| {
+                    CommandRingTrbHandler::command_completion_callback(
+                        &interrupter,
+                        completion_code,
+                        slot_id,
+                        gpa,
+                        &event_fd,
+                    )
+                    .map_err(|e| {
+                        error!("failed to run command completion callback: {}", e);
+                    })
+                })
+                .map_err(Error::DisableSlot)
+        } else {
+            CommandRingTrbHandler::command_completion_callback(
+                &self.interrupter,
+                TrbCompletionCode::TrbError,
+                slot_id,
+                atrb.gpa,
+                &event_fd,
+            )
+        }
+    }
+
+    fn address_device(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> {
+        let trb = atrb
+            .trb
+            .cast::<AddressDeviceCommandTrb>()
+            .map_err(Error::CastTrb)?;
+        let slot_id = trb.get_slot_id();
+        let completion_code = {
+            if valid_slot_id(slot_id) {
+                self.slot(slot_id)?
+                    .set_address(trb)
+                    .map_err(Error::SetAddress)?
+            } else {
+                TrbCompletionCode::TrbError
+            }
+        };
+        CommandRingTrbHandler::command_completion_callback(
+            &self.interrupter,
+            completion_code,
+            slot_id,
+            atrb.gpa,
+            &event_fd,
+        )
+    }
+
+    fn configure_endpoint(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> {
+        let trb = atrb
+            .trb
+            .cast::<ConfigureEndpointCommandTrb>()
+            .map_err(Error::CastTrb)?;
+        let slot_id = trb.get_slot_id();
+        let completion_code = {
+            if valid_slot_id(slot_id) {
+                self.slot(slot_id)?
+                    .configure_endpoint(trb)
+                    .map_err(Error::ConfigEndpoint)?
+            } else {
+                TrbCompletionCode::TrbError
+            }
+        };
+        CommandRingTrbHandler::command_completion_callback(
+            &self.interrupter,
+            completion_code,
+            slot_id,
+            atrb.gpa,
+            &event_fd,
+        )
+    }
+
+    fn evaluate_context(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> {
+        let trb = atrb
+            .trb
+            .cast::<EvaluateContextCommandTrb>()
+            .map_err(Error::CastTrb)?;
+        let slot_id = trb.get_slot_id();
+        let completion_code = {
+            if valid_slot_id(slot_id) {
+                self.slot(slot_id)?
+                    .evaluate_context(trb)
+                    .map_err(Error::EvaluateContext)?
+            } else {
+                TrbCompletionCode::TrbError
+            }
+        };
+        CommandRingTrbHandler::command_completion_callback(
+            &self.interrupter,
+            completion_code,
+            slot_id,
+            atrb.gpa,
+            &event_fd,
+        )
+    }
+
+    fn reset_device(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> {
+        let trb = atrb
+            .trb
+            .cast::<ResetDeviceCommandTrb>()
+            .map_err(Error::CastTrb)?;
+        let slot_id = trb.get_slot_id();
+        if valid_slot_id(slot_id) {
+            let gpa = atrb.gpa;
+            let interrupter = self.interrupter.clone();
+            self.slots
+                .reset_slot(slot_id, move |completion_code| {
+                    CommandRingTrbHandler::command_completion_callback(
+                        &interrupter,
+                        completion_code,
+                        slot_id,
+                        gpa,
+                        &event_fd,
+                    )
+                    .map_err(|e| {
+                        error!("command completion callback failed: {}", e);
+                    })
+                })
+                .map_err(Error::ResetSlot)
+        } else {
+            CommandRingTrbHandler::command_completion_callback(
+                &self.interrupter,
+                TrbCompletionCode::TrbError,
+                slot_id,
+                atrb.gpa,
+                &event_fd,
+            )
+        }
+    }
+
+    fn stop_endpoint(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> {
+        let trb = atrb
+            .trb
+            .cast::<StopEndpointCommandTrb>()
+            .map_err(Error::CastTrb)?;
+        let slot_id = trb.get_slot_id();
+        let endpoint_id = trb.get_endpoint_id();
+        if valid_slot_id(slot_id) {
+            let gpa = atrb.gpa;
+            let interrupter = self.interrupter.clone();
+            self.slots
+                .stop_endpoint(slot_id, endpoint_id, move |completion_code| {
+                    CommandRingTrbHandler::command_completion_callback(
+                        &interrupter,
+                        completion_code,
+                        slot_id,
+                        gpa,
+                        &event_fd,
+                    )
+                    .map_err(|e| {
+                        error!("command completion callback failed: {}", e);
+                    })
+                })
+                .map_err(Error::StopEndpoint)?;
+            Ok(())
+        } else {
+            error!("stop endpoint trb has invalid slot id {}", slot_id);
+            CommandRingTrbHandler::command_completion_callback(
+                &self.interrupter,
+                TrbCompletionCode::TrbError,
+                slot_id,
+                atrb.gpa,
+                &event_fd,
+            )
+        }
+    }
+
+    fn set_tr_dequeue_ptr(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> {
+        let trb = atrb
+            .trb
+            .cast::<SetTRDequeuePointerCommandTrb>()
+            .map_err(Error::CastTrb)?;
+        let slot_id = trb.get_slot_id();
+        let endpoint_id = trb.get_endpoint_id();
+        // See Set TR Dequeue Pointer Trb in spec.
+        let dequeue_ptr = trb.get_dequeue_ptr().get_gpa().offset();
+        let completion_code = {
+            if valid_slot_id(slot_id) {
+                self.slot(slot_id)?
+                    .set_tr_dequeue_ptr(endpoint_id, dequeue_ptr)
+                    .map_err(Error::SetDequeuePointer)?
+            } else {
+                error!("stop endpoint trb has invalid slot id {}", slot_id);
+                TrbCompletionCode::TrbError
+            }
+        };
+        CommandRingTrbHandler::command_completion_callback(
+            &self.interrupter,
+            completion_code,
+            slot_id,
+            atrb.gpa,
+            &event_fd,
+        )
+    }
+}
+
+impl TransferDescriptorHandler for CommandRingTrbHandler {
+    fn handle_transfer_descriptor(
+        &self,
+        descriptor: TransferDescriptor,
+        complete_event: EventFd,
+    ) -> std::result::Result<(), ()> {
+        // Command descriptor always consist of a single TRB.
+        assert_eq!(descriptor.len(), 1);
+        let atrb = &descriptor[0];
+        let command_result = match atrb.trb.get_trb_type() {
+            Ok(TrbType::EnableSlotCommand) => self.enable_slot(atrb, complete_event),
+            Ok(TrbType::DisableSlotCommand) => self.disable_slot(atrb, complete_event),
+            Ok(TrbType::AddressDeviceCommand) => self.address_device(atrb, complete_event),
+            Ok(TrbType::ConfigureEndpointCommand) => self.configure_endpoint(atrb, complete_event),
+            Ok(TrbType::EvaluateContextCommand) => self.evaluate_context(atrb, complete_event),
+            Ok(TrbType::ResetDeviceCommand) => self.reset_device(atrb, complete_event),
+            Ok(TrbType::NoopCommand) => CommandRingTrbHandler::command_completion_callback(
+                &self.interrupter,
+                TrbCompletionCode::Success,
+                0,
+                atrb.gpa,
+                &complete_event,
+            ),
+            Ok(TrbType::ResetEndpointCommand) => {
+                error!(
+                    "Receiving reset endpoint command. \
+                     It should only happen when cmd ring stall"
+                );
+                CommandRingTrbHandler::command_completion_callback(
+                    &self.interrupter,
+                    TrbCompletionCode::TrbError,
+                    0,
+                    atrb.gpa,
+                    &complete_event,
+                )
+            }
+            Ok(TrbType::StopEndpointCommand) => self.stop_endpoint(atrb, complete_event),
+            Ok(TrbType::SetTRDequeuePointerCommand) => {
+                self.set_tr_dequeue_ptr(atrb, complete_event)
+            }
+            _ => {
+                warn!(
+                    // We are not handling type 14,15,16. See table 6.4.6.
+                    "Unexpected command ring trb type: {}",
+                    atrb.trb
+                );
+                match self.interrupter.lock().send_command_completion_trb(
+                    TrbCompletionCode::TrbError,
+                    0,
+                    GuestAddress(atrb.gpa),
+                ) {
+                    Err(e) => Err(Error::SendInterrupt(e)),
+                    Ok(_) => complete_event.write(1).map_err(Error::WriteEventFd),
+                }
+            }
+        };
+        command_result.map_err(|e| {
+            error!("command failed: {}", e);
+        })
+    }
+}
diff --git a/devices/src/usb/xhci/device_slot.rs b/devices/src/usb/xhci/device_slot.rs
new file mode 100644
index 0000000..e2b5e5d
--- /dev/null
+++ b/devices/src/usb/xhci/device_slot.rs
@@ -0,0 +1,778 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::interrupter::Interrupter;
+use super::transfer_ring_controller::{TransferRingController, TransferRingControllerError};
+use super::usb_hub::{self, UsbHub};
+use super::xhci_abi::{
+    AddressDeviceCommandTrb, ConfigureEndpointCommandTrb, DequeuePtr, DeviceContext,
+    DeviceSlotState, EndpointContext, EndpointState, EvaluateContextCommandTrb,
+    InputControlContext, SlotContext, TrbCompletionCode, DEVICE_CONTEXT_ENTRY_SIZE,
+};
+use super::xhci_regs::{valid_slot_id, MAX_PORTS, MAX_SLOTS};
+use crate::register_space::Register;
+use crate::usb::xhci::ring_buffer_stop_cb::{fallible_closure, RingBufferStopCallback};
+use crate::utils::{EventLoop, FailHandle};
+use bit_field::Error as BitFieldError;
+use std::fmt::{self, Display};
+use std::mem::size_of;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::Arc;
+use sync::Mutex;
+use sys_util::{error, GuestAddress, GuestMemory, GuestMemoryError};
+
+#[derive(Debug)]
+pub enum Error {
+    BadPortId(u8),
+    ReadGuestMemory(GuestMemoryError),
+    WriteGuestMemory(GuestMemoryError),
+    WeakReferenceUpgrade,
+    CallbackFailed,
+    GetSlotContextState(BitFieldError),
+    GetEndpointState(BitFieldError),
+    GetPort(u8),
+    GetTrc(u8),
+    BadInputContextAddr(GuestAddress),
+    BadDeviceContextAddr(GuestAddress),
+    CreateTransferController(TransferRingControllerError),
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            BadPortId(id) => write!(f, "device slot get a bad port id: {}", id),
+            ReadGuestMemory(e) => write!(f, "failed to read guest memory: {}", e),
+            WriteGuestMemory(e) => write!(f, "failed to write guest memory: {}", e),
+            WeakReferenceUpgrade => write!(f, "failed to upgrade weak reference"),
+            CallbackFailed => write!(f, "callback failed"),
+            GetSlotContextState(e) => write!(f, "failed to get slot context state: {}", e),
+            GetEndpointState(e) => write!(f, "failed to get endpoint state: {}", e),
+            GetPort(v) => write!(f, "failed to get port: {}", v),
+            GetTrc(v) => write!(f, "failed to get trc: {}", v),
+            BadInputContextAddr(addr) => write!(f, "bad input context address: {}", addr),
+            BadDeviceContextAddr(addr) => write!(f, "bad device context: {}", addr),
+            CreateTransferController(e) => write!(f, "failed to create transfer controller: {}", e),
+        }
+    }
+}
+
+/// See spec 4.5.1 for dci.
+/// index 0: Control endpoint. Device Context Index: 1.
+/// index 1: Endpoint 1 out. Device Context Index: 2
+/// index 2: Endpoint 1 in. Device Context Index: 3.
+/// index 3: Endpoint 2 out. Device Context Index: 4
+/// ...
+/// index 30: Endpoint 15 in. Device Context Index: 31
+pub const TRANSFER_RING_CONTROLLERS_INDEX_END: usize = 31;
+/// End of device context index.
+pub const DCI_INDEX_END: u8 = (TRANSFER_RING_CONTROLLERS_INDEX_END + 1) as u8;
+/// Device context index of first transfer endpoint.
+pub const FIRST_TRANSFER_ENDPOINT_DCI: u8 = 2;
+
+fn valid_endpoint_id(endpoint_id: u8) -> bool {
+    endpoint_id < DCI_INDEX_END && endpoint_id > 0
+}
+
+#[derive(Clone)]
+pub struct DeviceSlots {
+    fail_handle: Arc<dyn FailHandle>,
+    hub: Arc<UsbHub>,
+    slots: Vec<Arc<DeviceSlot>>,
+}
+
+impl DeviceSlots {
+    pub fn new(
+        fail_handle: Arc<dyn FailHandle>,
+        dcbaap: Register<u64>,
+        hub: Arc<UsbHub>,
+        interrupter: Arc<Mutex<Interrupter>>,
+        event_loop: Arc<EventLoop>,
+        mem: GuestMemory,
+    ) -> DeviceSlots {
+        let mut slots = Vec::new();
+        for slot_id in 1..=MAX_SLOTS {
+            slots.push(Arc::new(DeviceSlot::new(
+                slot_id,
+                dcbaap.clone(),
+                hub.clone(),
+                interrupter.clone(),
+                event_loop.clone(),
+                mem.clone(),
+            )));
+        }
+        DeviceSlots {
+            fail_handle,
+            hub,
+            slots,
+        }
+    }
+
+    /// Note that slot id starts from 1. Slot index start from 0.
+    pub fn slot(&self, slot_id: u8) -> Option<Arc<DeviceSlot>> {
+        if valid_slot_id(slot_id) {
+            Some(self.slots[slot_id as usize - 1].clone())
+        } else {
+            error!(
+                "trying to index a wrong slot id {}, max slot = {}",
+                slot_id, MAX_SLOTS
+            );
+            None
+        }
+    }
+
+    /// Reset the device connected to a specific port.
+    pub fn reset_port(&self, port_id: u8) -> std::result::Result<(), ()> {
+        if let Some(port) = self.hub.get_port(port_id) {
+            if let Some(backend_device) = port.get_backend_device().as_mut() {
+                backend_device.reset()?;
+            }
+        }
+
+        // No device on port, so nothing to reset.
+        Ok(())
+    }
+
+    /// Stop all device slots and reset them.
+    pub fn stop_all_and_reset<C: FnMut() + 'static + Send>(&self, mut callback: C) {
+        usb_debug!("stopping all device slots and resetting host hub");
+        let slots = self.slots.clone();
+        let hub = self.hub.clone();
+        let auto_callback = RingBufferStopCallback::new(fallible_closure(
+            self.fail_handle.clone(),
+            move || -> std::result::Result<(), usb_hub::Error> {
+                for slot in &slots {
+                    slot.reset();
+                }
+                hub.reset()?;
+                callback();
+                Ok(())
+            },
+        ));
+        self.stop_all(auto_callback);
+    }
+
+    /// Stop all devices. The auto callback will be executed when all trc is stopped. It could
+    /// happen asynchronously, if there are any pending transfers.
+    pub fn stop_all(&self, auto_callback: RingBufferStopCallback) {
+        for slot in &self.slots {
+            slot.stop_all_trc(auto_callback.clone());
+        }
+    }
+
+    /// Disable a slot. This might happen asynchronously, if there is any pending transfers. The
+    /// callback will be invoked when slot is actually disabled.
+    pub fn disable_slot<
+        C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
+    >(
+        &self,
+        slot_id: u8,
+        cb: C,
+    ) -> Result<()> {
+        usb_debug!("device slot {} is being disabled", slot_id);
+        DeviceSlot::disable(
+            self.fail_handle.clone(),
+            &self.slots[slot_id as usize - 1],
+            cb,
+        )
+    }
+
+    /// Reset a slot. This is a shortcut call for DeviceSlot::reset_slot.
+    pub fn reset_slot<
+        C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
+    >(
+        &self,
+        slot_id: u8,
+        cb: C,
+    ) -> Result<()> {
+        usb_debug!("device slot {} is resetting", slot_id);
+        DeviceSlot::reset_slot(
+            self.fail_handle.clone(),
+            &self.slots[slot_id as usize - 1],
+            cb,
+        )
+    }
+
+    pub fn stop_endpoint<
+        C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
+    >(
+        &self,
+        slot_id: u8,
+        endpoint_id: u8,
+        cb: C,
+    ) -> Result<()> {
+        self.slots[slot_id as usize - 1].stop_endpoint(self.fail_handle.clone(), endpoint_id, cb)
+    }
+}
+
+// Usb port id. Valid ids starts from 1, to MAX_PORTS.
+struct PortId(Mutex<u8>);
+
+impl PortId {
+    fn new() -> Self {
+        PortId(Mutex::new(0))
+    }
+
+    fn set(&self, value: u8) -> Result<()> {
+        if value < 1 || value > MAX_PORTS {
+            return Err(Error::BadPortId(value));
+        }
+        *self.0.lock() = value;
+        Ok(())
+    }
+
+    fn reset(&self) {
+        *self.0.lock() = 0;
+    }
+
+    fn get(&self) -> Result<(u8)> {
+        let val = *self.0.lock();
+        if val == 0 {
+            return Err(Error::BadPortId(val));
+        }
+        Ok(val)
+    }
+}
+
+pub struct DeviceSlot {
+    slot_id: u8,
+    port_id: PortId, // Valid port id starts from 1, to MAX_PORTS.
+    dcbaap: Register<u64>,
+    hub: Arc<UsbHub>,
+    interrupter: Arc<Mutex<Interrupter>>,
+    event_loop: Arc<EventLoop>,
+    mem: GuestMemory,
+    enabled: AtomicBool,
+    transfer_ring_controllers: Mutex<Vec<Option<Arc<TransferRingController>>>>,
+}
+
+impl DeviceSlot {
+    /// Create a new device slot.
+    pub fn new(
+        slot_id: u8,
+        dcbaap: Register<u64>,
+        hub: Arc<UsbHub>,
+        interrupter: Arc<Mutex<Interrupter>>,
+        event_loop: Arc<EventLoop>,
+        mem: GuestMemory,
+    ) -> Self {
+        let transfer_ring_controllers = vec![None; TRANSFER_RING_CONTROLLERS_INDEX_END];
+        DeviceSlot {
+            slot_id,
+            port_id: PortId::new(),
+            dcbaap,
+            hub,
+            interrupter,
+            event_loop,
+            mem,
+            enabled: AtomicBool::new(false),
+            transfer_ring_controllers: Mutex::new(transfer_ring_controllers),
+        }
+    }
+
+    fn get_trc(&self, i: usize) -> Option<Arc<TransferRingController>> {
+        let trcs = self.transfer_ring_controllers.lock();
+        trcs[i].clone()
+    }
+
+    fn set_trc(&self, i: usize, trc: Option<Arc<TransferRingController>>) {
+        let mut trcs = self.transfer_ring_controllers.lock();
+        trcs[i] = trc;
+    }
+
+    fn trc_len(&self) -> usize {
+        self.transfer_ring_controllers.lock().len()
+    }
+
+    /// The arguments are identical to the fields in each doorbell register. The
+    /// target value:
+    /// 1: Reserved
+    /// 2: Control endpoint
+    /// 3: Endpoint 1 out
+    /// 4: Endpoint 1 in
+    /// 5: Endpoint 2 out
+    /// ...
+    /// 32: Endpoint 15 in
+    ///
+    /// Steam ID will be useful when host controller support streams.
+    /// The stream ID must be zero for endpoints that do not have streams
+    /// configured.
+    /// This function will return false if it fails to trigger transfer ring start.
+    pub fn ring_doorbell(&self, target: u8, _stream_id: u16) -> Result<bool> {
+        if !valid_endpoint_id(target) {
+            error!(
+                "device slot {}: Invalid target written to doorbell register. target: {}",
+                self.slot_id, target
+            );
+            return Ok(false);
+        }
+        usb_debug!(
+            "device slot {}: ding-dong. who is that? target = {}",
+            self.slot_id,
+            target
+        );
+        // See DCI in spec.
+        let endpoint_index = (target - 1) as usize;
+        let transfer_ring_controller = match self.get_trc(endpoint_index) {
+            Some(tr) => tr,
+            None => {
+                error!("Device endpoint is not inited");
+                return Ok(false);
+            }
+        };
+        let context = self.get_device_context()?;
+        if context.endpoint_context[endpoint_index]
+            .get_endpoint_state()
+            .map_err(Error::GetEndpointState)?
+            == EndpointState::Running
+        {
+            usb_debug!("endpoint is started, start transfer ring");
+            transfer_ring_controller.start();
+        } else {
+            error!("doorbell rung when endpoint is not started");
+        }
+        Ok(true)
+    }
+
+    /// Enable the slot. This function returns false if it's already enabled.
+    pub fn enable(&self) -> bool {
+        let was_already_enabled = self.enabled.swap(true, Ordering::SeqCst);
+        if was_already_enabled {
+            error!("device slot is already enabled");
+        } else {
+            usb_debug!("device slot {} enabled", self.slot_id);
+        }
+        !was_already_enabled
+    }
+
+    /// Disable this device slot. If the slot is not enabled, callback will be invoked immediately
+    /// with error. Otherwise, callback will be invoked when all trc is stopped.
+    pub fn disable<C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send>(
+        fail_handle: Arc<dyn FailHandle>,
+        slot: &Arc<DeviceSlot>,
+        mut callback: C,
+    ) -> Result<()> {
+        if slot.enabled.load(Ordering::SeqCst) {
+            let slot_weak = Arc::downgrade(slot);
+            let auto_callback =
+                RingBufferStopCallback::new(fallible_closure(fail_handle, move || {
+                    // Slot should still be alive when the callback is invoked. If it's not, there
+                    // must be a bug somewhere.
+                    let slot = slot_weak.upgrade().ok_or(Error::WeakReferenceUpgrade)?;
+                    let mut device_context = slot.get_device_context()?;
+                    device_context
+                        .slot_context
+                        .set_slot_state(DeviceSlotState::DisabledOrEnabled);
+                    slot.set_device_context(device_context)?;
+                    slot.reset();
+                    usb_debug!(
+                        "device slot {}: all trc disabled, sending trb",
+                        slot.slot_id
+                    );
+                    callback(TrbCompletionCode::Success).map_err(|_| Error::CallbackFailed)
+                }));
+            slot.stop_all_trc(auto_callback);
+            Ok(())
+        } else {
+            callback(TrbCompletionCode::SlotNotEnabledError).map_err(|_| Error::CallbackFailed)
+        }
+    }
+
+    // Assigns the device address and initializes slot and endpoint 0 context.
+    pub fn set_address(&self, trb: &AddressDeviceCommandTrb) -> Result<TrbCompletionCode> {
+        if !self.enabled.load(Ordering::SeqCst) {
+            error!(
+                "trying to set address to a disabled device slot {}",
+                self.slot_id
+            );
+            return Ok(TrbCompletionCode::SlotNotEnabledError);
+        }
+        let device_context = self.get_device_context()?;
+        let state = device_context
+            .slot_context
+            .get_slot_state()
+            .map_err(Error::GetSlotContextState)?;
+        match state {
+            DeviceSlotState::DisabledOrEnabled => {}
+            DeviceSlotState::Default if !trb.get_block_set_address_request() => {}
+            _ => {
+                error!("slot {} has unexpected slot state", self.slot_id);
+                return Ok(TrbCompletionCode::ContextStateError);
+            }
+        }
+
+        // Copy all fields of the slot context and endpoint 0 context from the input context
+        // to the output context.
+        let input_context_ptr = GuestAddress(trb.get_input_context_pointer());
+        // Copy slot context.
+        self.copy_context(input_context_ptr, 0)?;
+        // Copy control endpoint context.
+        self.copy_context(input_context_ptr, 1)?;
+
+        // Read back device context.
+        let mut device_context = self.get_device_context()?;
+        let port_id = device_context.slot_context.get_root_hub_port_number();
+        self.port_id.set(port_id)?;
+        usb_debug!(
+            "port id {} is assigned to slot id {}",
+            port_id,
+            self.slot_id
+        );
+
+        // Initialize the control endpoint. Endpoint id = 1.
+        self.set_trc(
+            0,
+            Some(
+                TransferRingController::new(
+                    self.mem.clone(),
+                    self.hub.get_port(port_id).ok_or(Error::GetPort(port_id))?,
+                    self.event_loop.clone(),
+                    self.interrupter.clone(),
+                    self.slot_id,
+                    1,
+                )
+                .map_err(Error::CreateTransferController)?,
+            ),
+        );
+
+        // Assign slot ID as device address if block_set_address_request is not set.
+        if trb.get_block_set_address_request() {
+            device_context
+                .slot_context
+                .set_slot_state(DeviceSlotState::Default);
+        } else {
+            let port = self.hub.get_port(port_id).ok_or(Error::GetPort(port_id))?;
+            match port.get_backend_device().as_mut() {
+                Some(backend) => {
+                    backend.set_address(self.slot_id as u32);
+                }
+                None => {
+                    return Ok(TrbCompletionCode::TransactionError);
+                }
+            }
+
+            device_context
+                .slot_context
+                .set_usb_device_address(self.slot_id);
+            device_context
+                .slot_context
+                .set_slot_state(DeviceSlotState::Addressed);
+        }
+
+        // TODO(jkwang) trc should always exists. Fix this.
+        self.get_trc(0)
+            .ok_or(Error::GetTrc(0))?
+            .set_dequeue_pointer(
+                device_context.endpoint_context[0]
+                    .get_tr_dequeue_pointer()
+                    .get_gpa(),
+            );
+
+        self.get_trc(0)
+            .ok_or(Error::GetTrc(0))?
+            .set_consumer_cycle_state(device_context.endpoint_context[0].get_dequeue_cycle_state());
+
+        usb_debug!("Setting endpoint 0 to running");
+        device_context.endpoint_context[0].set_endpoint_state(EndpointState::Running);
+        self.set_device_context(device_context)?;
+        Ok(TrbCompletionCode::Success)
+    }
+
+    // Adds or drops multiple endpoints in the device slot.
+    pub fn configure_endpoint(
+        &self,
+        trb: &ConfigureEndpointCommandTrb,
+    ) -> Result<TrbCompletionCode> {
+        usb_debug!("configuring endpoint");
+        let input_control_context = if trb.get_deconfigure() {
+            // From section 4.6.6 of the xHCI spec:
+            // Setting the deconfigure (DC) flag to '1' in the Configure Endpoint Command
+            // TRB is equivalent to setting Input Context Drop Context flags 2-31 to '1'
+            // and Add Context 2-31 flags to '0'.
+            let mut c = InputControlContext::new();
+            c.set_add_context_flags(0);
+            c.set_drop_context_flags(0xfffffffc);
+            c
+        } else {
+            self.mem
+                .read_obj_from_addr(GuestAddress(trb.get_input_context_pointer()))
+                .map_err(Error::ReadGuestMemory)?
+        };
+
+        for device_context_index in 1..DCI_INDEX_END {
+            if input_control_context.drop_context_flag(device_context_index) {
+                self.drop_one_endpoint(device_context_index)?;
+            }
+            if input_control_context.add_context_flag(device_context_index) {
+                self.copy_context(
+                    GuestAddress(trb.get_input_context_pointer()),
+                    device_context_index,
+                )?;
+                self.add_one_endpoint(device_context_index)?;
+            }
+        }
+
+        if trb.get_deconfigure() {
+            self.set_state(DeviceSlotState::Addressed)?;
+        } else {
+            self.set_state(DeviceSlotState::Configured)?;
+        }
+        Ok(TrbCompletionCode::Success)
+    }
+
+    // Evaluates the device context by reading new values for certain fields of
+    // the slot context and/or control endpoint context.
+    pub fn evaluate_context(&self, trb: &EvaluateContextCommandTrb) -> Result<TrbCompletionCode> {
+        if !self.enabled.load(Ordering::SeqCst) {
+            return Ok(TrbCompletionCode::SlotNotEnabledError);
+        }
+        // TODO(jkwang) verify this
+        // The spec has multiple contradictions about validating context parameters in sections
+        // 4.6.7, 6.2.3.3. To keep things as simple as possible we do no further validation here.
+        let input_control_context: InputControlContext = self
+            .mem
+            .read_obj_from_addr(GuestAddress(trb.get_input_context_pointer()))
+            .map_err(Error::ReadGuestMemory)?;
+
+        let mut device_context = self.get_device_context()?;
+        if input_control_context.add_context_flag(0) {
+            let input_slot_context: SlotContext = self
+                .mem
+                .read_obj_from_addr(GuestAddress(
+                    trb.get_input_context_pointer() + DEVICE_CONTEXT_ENTRY_SIZE as u64,
+                ))
+                .map_err(Error::ReadGuestMemory)?;
+            device_context
+                .slot_context
+                .set_interrupter_target(input_slot_context.get_interrupter_target());
+
+            device_context
+                .slot_context
+                .set_max_exit_latency(input_slot_context.get_max_exit_latency());
+        }
+
+        // From 6.2.3.3: "Endpoint Contexts 2 throught 31 shall not be evaluated by the Evaluate
+        // Context Command".
+        if input_control_context.add_context_flag(1) {
+            let ep0_context: EndpointContext = self
+                .mem
+                .read_obj_from_addr(GuestAddress(
+                    trb.get_input_context_pointer() + 2 * DEVICE_CONTEXT_ENTRY_SIZE as u64,
+                ))
+                .map_err(Error::ReadGuestMemory)?;
+            device_context.endpoint_context[0]
+                .set_max_packet_size(ep0_context.get_max_packet_size());
+        }
+        self.set_device_context(device_context)?;
+        Ok(TrbCompletionCode::Success)
+    }
+
+    /// Reset the device slot to default state and deconfigures all but the
+    /// control endpoint.
+    pub fn reset_slot<
+        C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
+    >(
+        fail_handle: Arc<dyn FailHandle>,
+        slot: &Arc<DeviceSlot>,
+        mut callback: C,
+    ) -> Result<()> {
+        let weak_s = Arc::downgrade(&slot);
+        let auto_callback =
+            RingBufferStopCallback::new(fallible_closure(fail_handle, move || -> Result<()> {
+                let s = weak_s.upgrade().ok_or(Error::WeakReferenceUpgrade)?;
+                for i in FIRST_TRANSFER_ENDPOINT_DCI..DCI_INDEX_END {
+                    s.drop_one_endpoint(i)?;
+                }
+                let mut ctx = s.get_device_context()?;
+                ctx.slot_context.set_slot_state(DeviceSlotState::Default);
+                ctx.slot_context.set_context_entries(1);
+                ctx.slot_context.set_root_hub_port_number(0);
+                s.set_device_context(ctx)?;
+                callback(TrbCompletionCode::Success).map_err(|_| Error::CallbackFailed)?;
+                Ok(())
+            }));
+        slot.stop_all_trc(auto_callback);
+        Ok(())
+    }
+
+    /// Stop all transfer ring controllers.
+    pub fn stop_all_trc(&self, auto_callback: RingBufferStopCallback) {
+        for i in 0..self.trc_len() {
+            if let Some(trc) = self.get_trc(i) {
+                trc.stop(auto_callback.clone());
+            }
+        }
+    }
+
+    /// Stop a endpoint.
+    pub fn stop_endpoint<
+        C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
+    >(
+        &self,
+        fail_handle: Arc<dyn FailHandle>,
+        endpoint_id: u8,
+        mut cb: C,
+    ) -> Result<()> {
+        if !valid_endpoint_id(endpoint_id) {
+            error!("trb indexing wrong endpoint id");
+            return cb(TrbCompletionCode::TrbError).map_err(|_| Error::CallbackFailed);
+        }
+        let index = endpoint_id - 1;
+        match self.get_trc(index as usize) {
+            Some(trc) => {
+                usb_debug!("stopping endpoint");
+                let auto_cb = RingBufferStopCallback::new(fallible_closure(
+                    fail_handle,
+                    move || -> Result<()> {
+                        cb(TrbCompletionCode::Success).map_err(|_| Error::CallbackFailed)
+                    },
+                ));
+                trc.stop(auto_cb);
+            }
+            None => {
+                error!("endpoint at index {} is not started", index);
+                cb(TrbCompletionCode::ContextStateError).map_err(|_| Error::CallbackFailed)?;
+            }
+        }
+        Ok(())
+    }
+
+    /// Set transfer ring dequeue pointer.
+    pub fn set_tr_dequeue_ptr(&self, endpoint_id: u8, ptr: u64) -> Result<TrbCompletionCode> {
+        if !valid_endpoint_id(endpoint_id) {
+            error!("trb indexing wrong endpoint id");
+            return Ok(TrbCompletionCode::TrbError);
+        }
+        let index = (endpoint_id - 1) as usize;
+        match self.get_trc(index) {
+            Some(trc) => {
+                trc.set_dequeue_pointer(GuestAddress(ptr));
+                let mut ctx = self.get_device_context()?;
+                ctx.endpoint_context[index]
+                    .set_tr_dequeue_pointer(DequeuePtr::new(GuestAddress(ptr)));
+                self.set_device_context(ctx)?;
+                Ok(TrbCompletionCode::Success)
+            }
+            None => {
+                error!("set tr dequeue ptr failed due to no trc started");
+                Ok(TrbCompletionCode::ContextStateError)
+            }
+        }
+    }
+
+    // Reset and reset_slot are different.
+    // Reset_slot handles command ring `reset slot` command. It will reset the slot state.
+    // Reset handles xhci reset. It will destroy everything.
+    fn reset(&self) {
+        for i in 0..self.trc_len() {
+            self.set_trc(i, None);
+        }
+        usb_debug!("reseting device slot {}!", self.slot_id);
+        self.enabled.store(false, Ordering::SeqCst);
+        self.port_id.reset();
+    }
+
+    fn add_one_endpoint(&self, device_context_index: u8) -> Result<()> {
+        usb_debug!(
+            "adding one endpoint, device context index {}",
+            device_context_index
+        );
+        let mut device_context = self.get_device_context()?;
+        let transfer_ring_index = (device_context_index - 1) as usize;
+        let trc = TransferRingController::new(
+            self.mem.clone(),
+            self.hub
+                .get_port(self.port_id.get()?)
+                .ok_or(Error::GetPort(self.port_id.get()?))?,
+            self.event_loop.clone(),
+            self.interrupter.clone(),
+            self.slot_id,
+            device_context_index,
+        )
+        .map_err(Error::CreateTransferController)?;
+        trc.set_dequeue_pointer(
+            device_context.endpoint_context[transfer_ring_index]
+                .get_tr_dequeue_pointer()
+                .get_gpa(),
+        );
+        trc.set_consumer_cycle_state(
+            device_context.endpoint_context[transfer_ring_index].get_dequeue_cycle_state(),
+        );
+        self.set_trc(transfer_ring_index, Some(trc));
+        device_context.endpoint_context[transfer_ring_index]
+            .set_endpoint_state(EndpointState::Running);
+        self.set_device_context(device_context)
+    }
+
+    fn drop_one_endpoint(&self, device_context_index: u8) -> Result<()> {
+        let endpoint_index = (device_context_index - 1) as usize;
+        self.set_trc(endpoint_index, None);
+        let mut ctx = self.get_device_context()?;
+        ctx.endpoint_context[endpoint_index].set_endpoint_state(EndpointState::Disabled);
+        self.set_device_context(ctx)
+    }
+
+    fn get_device_context(&self) -> Result<DeviceContext> {
+        let ctx = self
+            .mem
+            .read_obj_from_addr(self.get_device_context_addr()?)
+            .map_err(Error::ReadGuestMemory)?;
+        usb_debug!("read device ctx: {:?}", ctx);
+        Ok(ctx)
+    }
+
+    fn set_device_context(&self, device_context: DeviceContext) -> Result<()> {
+        self.mem
+            .write_obj_at_addr(device_context, self.get_device_context_addr()?)
+            .map_err(Error::WriteGuestMemory)
+    }
+
+    fn copy_context(
+        &self,
+        input_context_ptr: GuestAddress,
+        device_context_index: u8,
+    ) -> Result<()> {
+        // Note that it could be slot context or device context. They have the same size. Won't
+        // make a difference here.
+        let ctx: EndpointContext = self
+            .mem
+            .read_obj_from_addr(
+                input_context_ptr
+                    .checked_add(
+                        (device_context_index as u64 + 1) * DEVICE_CONTEXT_ENTRY_SIZE as u64,
+                    )
+                    .ok_or(Error::BadInputContextAddr(input_context_ptr))?,
+            )
+            .map_err(Error::ReadGuestMemory)?;
+        usb_debug!("context being copied {:?}", ctx);
+        let device_context_ptr = self.get_device_context_addr()?;
+        self.mem
+            .write_obj_at_addr(
+                ctx,
+                device_context_ptr
+                    .checked_add(device_context_index as u64 * DEVICE_CONTEXT_ENTRY_SIZE as u64)
+                    .ok_or(Error::BadDeviceContextAddr(device_context_ptr))?,
+            )
+            .map_err(Error::WriteGuestMemory)
+    }
+
+    fn get_device_context_addr(&self) -> Result<GuestAddress> {
+        let addr: u64 = self
+            .mem
+            .read_obj_from_addr(GuestAddress(
+                self.dcbaap.get_value() + size_of::<u64>() as u64 * self.slot_id as u64,
+            ))
+            .map_err(Error::ReadGuestMemory)?;
+        Ok(GuestAddress(addr))
+    }
+
+    fn set_state(&self, state: DeviceSlotState) -> Result<()> {
+        let mut ctx = self.get_device_context()?;
+        ctx.slot_context.set_slot_state(state);
+        self.set_device_context(ctx)
+    }
+}
diff --git a/devices/src/usb/xhci/event_ring.rs b/devices/src/usb/xhci/event_ring.rs
new file mode 100644
index 0000000..fcaff23
--- /dev/null
+++ b/devices/src/usb/xhci/event_ring.rs
@@ -0,0 +1,413 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use data_model::DataInit;
+use std;
+use std::fmt::{self, Display};
+use std::mem::size_of;
+use std::sync::atomic::{fence, Ordering};
+use sys_util::{GuestAddress, GuestMemory, GuestMemoryError};
+
+use super::xhci_abi::*;
+
+#[derive(Debug)]
+pub enum Error {
+    Uninitialized,
+    EventRingFull,
+    BadEnqueuePointer(GuestAddress),
+    BadSegTableIndex(u16),
+    BadSegTableAddress(GuestAddress),
+    MemoryRead(GuestMemoryError),
+    MemoryWrite(GuestMemoryError),
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            Uninitialized => write!(f, "event ring is uninitialized"),
+            EventRingFull => write!(f, "event ring is full"),
+            BadEnqueuePointer(addr) => write!(f, "event ring has a bad enqueue pointer: {}", addr),
+            BadSegTableIndex(i) => write!(f, "event ring has a bad seg table index: {}", i),
+            BadSegTableAddress(addr) => write!(f, "event ring has a bad seg table addr: {}", addr),
+            MemoryRead(e) => write!(f, "event ring cannot read from guest memory: {}", e),
+            MemoryWrite(e) => write!(f, "event ring cannot write to guest memory: {}", e),
+        }
+    }
+}
+
+/// Event rings are segmented circular buffers used to pass event TRBs from the xHCI device back to
+/// the guest.  Each event ring is associated with a single interrupter.  See section 4.9.4 of the
+/// xHCI specification for more details.
+/// This implementation is only for primary interrupter. Please review xhci spec before using it
+/// for secondary.
+pub struct EventRing {
+    mem: GuestMemory,
+    segment_table_size: u16,
+    segment_table_base_address: GuestAddress,
+    current_segment_index: u16,
+    trb_count: u16,
+    enqueue_pointer: GuestAddress,
+    dequeue_pointer: GuestAddress,
+    producer_cycle_state: bool,
+}
+
+impl EventRing {
+    /// Create an empty, uninitialized event ring.
+    pub fn new(mem: GuestMemory) -> Self {
+        EventRing {
+            mem,
+            segment_table_size: 0,
+            segment_table_base_address: GuestAddress(0),
+            current_segment_index: 0,
+            enqueue_pointer: GuestAddress(0),
+            dequeue_pointer: GuestAddress(0),
+            trb_count: 0,
+            // As specified in xHCI spec 4.9.4, cycle state should be initialized to 1.
+            producer_cycle_state: true,
+        }
+    }
+
+    /// This function implements left side of xHCI spec, Figure 4-12.
+    pub fn add_event(&mut self, mut trb: Trb) -> Result<()> {
+        self.check_inited()?;
+        if self.is_full()? {
+            return Err(Error::EventRingFull);
+        }
+        // Event is write twice to avoid race condition.
+        // Guest kernel use cycle bit to check ownership, thus we should write cycle last.
+        trb.set_cycle(!self.producer_cycle_state);
+        self.mem
+            .write_obj_at_addr(trb, self.enqueue_pointer)
+            .map_err(Error::MemoryWrite)?;
+
+        // Updating the cycle state bit should always happen after updating other parts.
+        fence(Ordering::SeqCst);
+
+        trb.set_cycle(self.producer_cycle_state);
+
+        // Offset of cycle state byte.
+        const CYCLE_STATE_OFFSET: usize = 12usize;
+        let data = trb.as_slice();
+        // Trb contains 4 dwords, the last one contains cycle bit.
+        let cycle_bit_dword = &data[CYCLE_STATE_OFFSET..];
+        let address = self.enqueue_pointer;
+        let address = address
+            .checked_add(CYCLE_STATE_OFFSET as u64)
+            .ok_or(Error::BadEnqueuePointer(self.enqueue_pointer))?;
+        self.mem
+            .write_all_at_addr(cycle_bit_dword, address)
+            .map_err(Error::MemoryWrite)?;
+
+        usb_debug!(
+            "event write to pointer {:#x}, trb_count {}, {}",
+            self.enqueue_pointer.0,
+            self.trb_count,
+            trb
+        );
+        self.enqueue_pointer = match self.enqueue_pointer.checked_add(size_of::<Trb>() as u64) {
+            Some(addr) => addr,
+            None => return Err(Error::BadEnqueuePointer(self.enqueue_pointer)),
+        };
+        self.trb_count -= 1;
+        if self.trb_count == 0 {
+            self.current_segment_index += 1;
+            if self.current_segment_index == self.segment_table_size {
+                self.producer_cycle_state ^= true;
+                self.current_segment_index = 0;
+            }
+            self.load_current_seg_table_entry()?;
+        }
+        Ok(())
+    }
+
+    /// Set segment table size.
+    pub fn set_seg_table_size(&mut self, size: u16) -> Result<()> {
+        usb_debug!("event ring seg table size is set to {}", size);
+        self.segment_table_size = size;
+        self.try_reconfigure_event_ring()
+    }
+
+    /// Set segment table base addr.
+    pub fn set_seg_table_base_addr(&mut self, addr: GuestAddress) -> Result<()> {
+        usb_debug!("event ring seg table base addr is set to {:#x}", addr.0);
+        self.segment_table_base_address = addr;
+        self.try_reconfigure_event_ring()
+    }
+
+    /// Set dequeue pointer.
+    pub fn set_dequeue_pointer(&mut self, addr: GuestAddress) {
+        usb_debug!("event ring dequeue pointer set to {:#x}", addr.0);
+        self.dequeue_pointer = addr;
+    }
+
+    /// Get the enqueue pointer.
+    pub fn get_enqueue_pointer(&self) -> GuestAddress {
+        self.enqueue_pointer
+    }
+
+    /// Check if event ring is empty.
+    pub fn is_empty(&self) -> bool {
+        self.enqueue_pointer == self.dequeue_pointer
+    }
+
+    /// Event ring is considered full when there is only space for one last TRB. In this case, xHC
+    /// should write an error Trb and do a bunch of handlings. See spec, figure 4-12 for more
+    /// details.
+    /// For now, we just check event ring full and fail (as it's unlikely to happen).
+    pub fn is_full(&self) -> Result<bool> {
+        if self.trb_count == 1 {
+            // erst == event ring segment table
+            let next_erst_idx = (self.current_segment_index + 1) % self.segment_table_size;
+            let erst_entry = self.read_seg_table_entry(next_erst_idx)?;
+            Ok(self.dequeue_pointer.0 == erst_entry.get_ring_segment_base_address())
+        } else {
+            Ok(self.dequeue_pointer.0 == self.enqueue_pointer.0 + size_of::<Trb>() as u64)
+        }
+    }
+
+    /// Try to init event ring. Will fail if seg table size/address are invalid.
+    fn try_reconfigure_event_ring(&mut self) -> Result<()> {
+        if self.segment_table_size == 0 || self.segment_table_base_address.0 == 0 {
+            return Ok(());
+        }
+        self.load_current_seg_table_entry()
+    }
+
+    // Check if this event ring is inited.
+    fn check_inited(&self) -> Result<()> {
+        if self.segment_table_size == 0
+            || self.segment_table_base_address == GuestAddress(0)
+            || self.enqueue_pointer == GuestAddress(0)
+        {
+            return Err(Error::Uninitialized);
+        }
+        Ok(())
+    }
+
+    // Load entry of current seg table.
+    fn load_current_seg_table_entry(&mut self) -> Result<()> {
+        let entry = self.read_seg_table_entry(self.current_segment_index)?;
+        self.enqueue_pointer = GuestAddress(entry.get_ring_segment_base_address());
+        self.trb_count = entry.get_ring_segment_size();
+        Ok(())
+    }
+
+    // Get seg table entry at index.
+    fn read_seg_table_entry(&self, index: u16) -> Result<EventRingSegmentTableEntry> {
+        let seg_table_addr = self.get_seg_table_addr(index)?;
+        // TODO(jkwang) We can refactor GuestMemory to allow in-place memory operation.
+        self.mem
+            .read_obj_from_addr(seg_table_addr)
+            .map_err(Error::MemoryRead)
+    }
+
+    // Get seg table addr at index.
+    fn get_seg_table_addr(&self, index: u16) -> Result<GuestAddress> {
+        if index > self.segment_table_size {
+            return Err(Error::BadSegTableIndex(index));
+        }
+        self.segment_table_base_address
+            .checked_add(((size_of::<EventRingSegmentTableEntry>() as u16) * index) as u64)
+            .ok_or(Error::BadSegTableAddress(self.segment_table_base_address))
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::mem::size_of;
+
+    #[test]
+    fn test_uninited() {
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x1000)]).unwrap();
+        let mut er = EventRing::new(gm.clone());
+        let trb = Trb::new();
+        match er.add_event(trb).err().unwrap() {
+            Error::Uninitialized => {}
+            _ => panic!("unexpected error"),
+        }
+        assert_eq!(er.is_empty(), true);
+        assert_eq!(er.is_full().unwrap(), false);
+    }
+
+    #[test]
+    fn test_event_ring() {
+        let trb_size = size_of::<Trb>() as u64;
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x1000)]).unwrap();
+        let mut er = EventRing::new(gm.clone());
+        let mut st_entries = [EventRingSegmentTableEntry::new(); 3];
+        st_entries[0].set_ring_segment_base_address(0x100);
+        st_entries[0].set_ring_segment_size(3);
+        st_entries[1].set_ring_segment_base_address(0x200);
+        st_entries[1].set_ring_segment_size(3);
+        st_entries[2].set_ring_segment_base_address(0x300);
+        st_entries[2].set_ring_segment_size(3);
+        gm.write_obj_at_addr(st_entries[0], GuestAddress(0x8))
+            .unwrap();
+        gm.write_obj_at_addr(
+            st_entries[1],
+            GuestAddress(0x8 + size_of::<EventRingSegmentTableEntry>() as u64),
+        )
+        .unwrap();
+        gm.write_obj_at_addr(
+            st_entries[2],
+            GuestAddress(0x8 + 2 * size_of::<EventRingSegmentTableEntry>() as u64),
+        )
+        .unwrap();
+        // Init event ring. Must init after segment tables writting.
+        er.set_seg_table_size(3).unwrap();
+        er.set_seg_table_base_addr(GuestAddress(0x8)).unwrap();
+        er.set_dequeue_pointer(GuestAddress(0x100));
+
+        let mut trb = Trb::new();
+
+        // Fill first table.
+        trb.set_control(1);
+        assert_eq!(er.is_empty(), true);
+        assert_eq!(er.is_full().unwrap(), false);
+        assert_eq!(er.add_event(trb.clone()).unwrap(), ());
+        assert_eq!(er.is_full().unwrap(), false);
+        assert_eq!(er.is_empty(), false);
+        let t: Trb = gm.read_obj_from_addr(GuestAddress(0x100)).unwrap();
+        assert_eq!(t.get_control(), 1);
+        assert_eq!(t.get_cycle(), true);
+
+        trb.set_control(2);
+        assert_eq!(er.add_event(trb.clone()).unwrap(), ());
+        assert_eq!(er.is_full().unwrap(), false);
+        assert_eq!(er.is_empty(), false);
+        let t: Trb = gm
+            .read_obj_from_addr(GuestAddress(0x100 + trb_size))
+            .unwrap();
+        assert_eq!(t.get_control(), 2);
+        assert_eq!(t.get_cycle(), true);
+
+        trb.set_control(3);
+        assert_eq!(er.add_event(trb.clone()).unwrap(), ());
+        assert_eq!(er.is_full().unwrap(), false);
+        assert_eq!(er.is_empty(), false);
+        let t: Trb = gm
+            .read_obj_from_addr(GuestAddress(0x100 + 2 * trb_size))
+            .unwrap();
+        assert_eq!(t.get_control(), 3);
+        assert_eq!(t.get_cycle(), true);
+
+        // Fill second table.
+        trb.set_control(4);
+        assert_eq!(er.add_event(trb.clone()).unwrap(), ());
+        assert_eq!(er.is_full().unwrap(), false);
+        assert_eq!(er.is_empty(), false);
+        let t: Trb = gm.read_obj_from_addr(GuestAddress(0x200)).unwrap();
+        assert_eq!(t.get_control(), 4);
+        assert_eq!(t.get_cycle(), true);
+
+        trb.set_control(5);
+        assert_eq!(er.add_event(trb.clone()).unwrap(), ());
+        assert_eq!(er.is_full().unwrap(), false);
+        assert_eq!(er.is_empty(), false);
+        let t: Trb = gm
+            .read_obj_from_addr(GuestAddress(0x200 + trb_size))
+            .unwrap();
+        assert_eq!(t.get_control(), 5);
+        assert_eq!(t.get_cycle(), true);
+
+        trb.set_control(6);
+        assert_eq!(er.add_event(trb.clone()).unwrap(), ());
+        assert_eq!(er.is_full().unwrap(), false);
+        assert_eq!(er.is_empty(), false);
+        let t: Trb = gm
+            .read_obj_from_addr(GuestAddress(0x200 + 2 * trb_size as u64))
+            .unwrap();
+        assert_eq!(t.get_control(), 6);
+        assert_eq!(t.get_cycle(), true);
+
+        // Fill third table.
+        trb.set_control(7);
+        assert_eq!(er.add_event(trb.clone()).unwrap(), ());
+        assert_eq!(er.is_full().unwrap(), false);
+        assert_eq!(er.is_empty(), false);
+        let t: Trb = gm.read_obj_from_addr(GuestAddress(0x300)).unwrap();
+        assert_eq!(t.get_control(), 7);
+        assert_eq!(t.get_cycle(), true);
+
+        trb.set_control(8);
+        assert_eq!(er.add_event(trb.clone()).unwrap(), ());
+        // There is only one last trb. Considered full.
+        assert_eq!(er.is_full().unwrap(), true);
+        assert_eq!(er.is_empty(), false);
+        let t: Trb = gm
+            .read_obj_from_addr(GuestAddress(0x300 + trb_size))
+            .unwrap();
+        assert_eq!(t.get_control(), 8);
+        assert_eq!(t.get_cycle(), true);
+
+        // Add the last trb will result in error.
+        match er.add_event(trb.clone()) {
+            Err(Error::EventRingFull) => {}
+            _ => panic!("er should be full"),
+        };
+
+        // Dequeue one trb.
+        er.set_dequeue_pointer(GuestAddress(0x100 + trb_size));
+        assert_eq!(er.is_full().unwrap(), false);
+        assert_eq!(er.is_empty(), false);
+
+        // Fill the last trb of the third table.
+        trb.set_control(9);
+        assert_eq!(er.add_event(trb.clone()).unwrap(), ());
+        // There is only one last trb. Considered full.
+        assert_eq!(er.is_full().unwrap(), true);
+        assert_eq!(er.is_empty(), false);
+        let t: Trb = gm
+            .read_obj_from_addr(GuestAddress(0x300 + trb_size))
+            .unwrap();
+        assert_eq!(t.get_control(), 8);
+        assert_eq!(t.get_cycle(), true);
+
+        // Add the last trb will result in error.
+        match er.add_event(trb.clone()) {
+            Err(Error::EventRingFull) => {}
+            _ => panic!("er should be full"),
+        };
+
+        // Dequeue until empty.
+        er.set_dequeue_pointer(GuestAddress(0x100));
+        assert_eq!(er.is_full().unwrap(), false);
+        assert_eq!(er.is_empty(), true);
+
+        // Fill first table again.
+        trb.set_control(10);
+        assert_eq!(er.add_event(trb.clone()).unwrap(), ());
+        assert_eq!(er.is_full().unwrap(), false);
+        assert_eq!(er.is_empty(), false);
+        let t: Trb = gm.read_obj_from_addr(GuestAddress(0x100)).unwrap();
+        assert_eq!(t.get_control(), 10);
+        // cycle bit should be reversed.
+        assert_eq!(t.get_cycle(), false);
+
+        trb.set_control(11);
+        assert_eq!(er.add_event(trb.clone()).unwrap(), ());
+        assert_eq!(er.is_full().unwrap(), false);
+        assert_eq!(er.is_empty(), false);
+        let t: Trb = gm
+            .read_obj_from_addr(GuestAddress(0x100 + trb_size))
+            .unwrap();
+        assert_eq!(t.get_control(), 11);
+        assert_eq!(t.get_cycle(), false);
+
+        trb.set_control(12);
+        assert_eq!(er.add_event(trb.clone()).unwrap(), ());
+        assert_eq!(er.is_full().unwrap(), false);
+        assert_eq!(er.is_empty(), false);
+        let t: Trb = gm
+            .read_obj_from_addr(GuestAddress(0x100 + 2 * trb_size))
+            .unwrap();
+        assert_eq!(t.get_control(), 12);
+        assert_eq!(t.get_cycle(), false);
+    }
+}
diff --git a/devices/src/usb/xhci/interrupter.rs b/devices/src/usb/xhci/interrupter.rs
new file mode 100644
index 0000000..c58ae59
--- /dev/null
+++ b/devices/src/usb/xhci/interrupter.rs
@@ -0,0 +1,202 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::event_ring::{Error as EventRingError, EventRing};
+use super::xhci_abi::{
+    CommandCompletionEventTrb, Error as TrbError, PortStatusChangeEventTrb, TransferEventTrb, Trb,
+    TrbCast, TrbCompletionCode, TrbType,
+};
+use super::xhci_regs::*;
+use crate::register_space::Register;
+use std::fmt::{self, Display};
+use sys_util::{Error as SysError, EventFd, GuestAddress, GuestMemory};
+
+#[derive(Debug)]
+pub enum Error {
+    CastTrb(TrbError),
+    AddEvent(EventRingError),
+    SetSegTableSize(EventRingError),
+    SetSegTableBaseAddr(EventRingError),
+    SendInterrupt(SysError),
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+        match self {
+            CastTrb(e) => write!(f, "cannot cast trb: {}", e),
+            AddEvent(e) => write!(f, "cannot add event: {}", e),
+            SetSegTableSize(e) => write!(f, "cannot set seg table size: {}", e),
+            SetSegTableBaseAddr(e) => write!(f, "cannot set seg table base addr: {}", e),
+            SendInterrupt(e) => write!(f, "cannot send interrupt: {}", e),
+        }
+    }
+}
+
+/// See spec 4.17 for interrupters. Controller can send an event back to guest kernel driver
+/// through interrupter.
+pub struct Interrupter {
+    interrupt_fd: EventFd,
+    usbsts: Register<u32>,
+    iman: Register<u32>,
+    erdp: Register<u64>,
+    event_handler_busy: bool,
+    enabled: bool,
+    pending: bool,
+    moderation_interval: u16,
+    moderation_counter: u16,
+    event_ring: EventRing,
+}
+
+impl Interrupter {
+    /// Create a new interrupter.
+    pub fn new(mem: GuestMemory, irq_evt: EventFd, regs: &XhciRegs) -> Self {
+        Interrupter {
+            interrupt_fd: irq_evt,
+            usbsts: regs.usbsts.clone(),
+            iman: regs.iman.clone(),
+            erdp: regs.erdp.clone(),
+            event_handler_busy: false,
+            enabled: false,
+            pending: false,
+            moderation_interval: 0,
+            moderation_counter: 0,
+            event_ring: EventRing::new(mem),
+        }
+    }
+
+    /// Returns true if event ring is empty.
+    pub fn event_ring_is_empty(&self) -> bool {
+        self.event_ring.is_empty()
+    }
+
+    /// Add event to event ring.
+    fn add_event(&mut self, trb: Trb) -> Result<()> {
+        self.event_ring.add_event(trb).map_err(Error::AddEvent)?;
+        self.pending = true;
+        self.interrupt_if_needed()
+    }
+
+    /// Send port status change trb for port.
+    pub fn send_port_status_change_trb(&mut self, port_id: u8) -> Result<()> {
+        let mut trb = Trb::new();
+        let psctrb = trb
+            .cast_mut::<PortStatusChangeEventTrb>()
+            .map_err(Error::CastTrb)?;
+        psctrb.set_port_id(port_id);
+        psctrb.set_completion_code(TrbCompletionCode::Success);
+        psctrb.set_trb_type(TrbType::PortStatusChangeEvent);
+        self.add_event(trb)
+    }
+
+    /// Send command completion trb.
+    pub fn send_command_completion_trb(
+        &mut self,
+        completion_code: TrbCompletionCode,
+        slot_id: u8,
+        trb_addr: GuestAddress,
+    ) -> Result<()> {
+        let mut trb = Trb::new();
+        let ctrb = trb
+            .cast_mut::<CommandCompletionEventTrb>()
+            .map_err(Error::CastTrb)?;
+        ctrb.set_trb_pointer(trb_addr.0);
+        ctrb.set_command_completion_parameter(0);
+        ctrb.set_completion_code(completion_code);
+        ctrb.set_trb_type(TrbType::CommandCompletionEvent);
+        ctrb.set_vf_id(0);
+        ctrb.set_slot_id(slot_id);
+        self.add_event(trb)
+    }
+
+    /// Send transfer event trb.
+    pub fn send_transfer_event_trb(
+        &mut self,
+        completion_code: TrbCompletionCode,
+        trb_pointer: u64,
+        transfer_length: u32,
+        event_data: bool,
+        slot_id: u8,
+        endpoint_id: u8,
+    ) -> Result<()> {
+        let mut trb = Trb::new();
+        let event_trb = trb.cast_mut::<TransferEventTrb>().map_err(Error::CastTrb)?;
+        event_trb.set_trb_pointer(trb_pointer);
+        event_trb.set_trb_transfer_length(transfer_length);
+        event_trb.set_completion_code(completion_code);
+        event_trb.set_event_data(event_data.into());
+        event_trb.set_trb_type(TrbType::TransferEvent);
+        event_trb.set_endpoint_id(endpoint_id);
+        event_trb.set_slot_id(slot_id);
+        self.add_event(trb)
+    }
+
+    /// Enable/Disable this interrupter.
+    pub fn set_enabled(&mut self, enabled: bool) -> Result<()> {
+        usb_debug!("interrupter set enabled {}", enabled);
+        self.enabled = enabled;
+        self.interrupt_if_needed()
+    }
+
+    /// Set interrupt moderation.
+    pub fn set_moderation(&mut self, interval: u16, counter: u16) -> Result<()> {
+        // TODO(jkwang) Moderation is not implemented yet.
+        self.moderation_interval = interval;
+        self.moderation_counter = counter;
+        self.interrupt_if_needed()
+    }
+
+    /// Set event ring seg table size.
+    pub fn set_event_ring_seg_table_size(&mut self, size: u16) -> Result<()> {
+        usb_debug!("interrupter set seg table size {}", size);
+        self.event_ring
+            .set_seg_table_size(size)
+            .map_err(Error::SetSegTableSize)
+    }
+
+    /// Set event ring segment table base address.
+    pub fn set_event_ring_seg_table_base_addr(&mut self, addr: GuestAddress) -> Result<()> {
+        usb_debug!("interrupter set table base addr {:#x}", addr.0);
+        self.event_ring
+            .set_seg_table_base_addr(addr)
+            .map_err(Error::SetSegTableBaseAddr)
+    }
+
+    /// Set event ring dequeue pointer.
+    pub fn set_event_ring_dequeue_pointer(&mut self, addr: GuestAddress) -> Result<()> {
+        usb_debug!("interrupter set dequeue ptr addr {:#x}", addr.0);
+        self.event_ring.set_dequeue_pointer(addr);
+        if addr == self.event_ring.get_enqueue_pointer() {
+            self.pending = false;
+        }
+        self.interrupt_if_needed()
+    }
+
+    /// Set event hander busy.
+    pub fn set_event_handler_busy(&mut self, busy: bool) -> Result<()> {
+        usb_debug!("set event handler busy {}", busy);
+        self.event_handler_busy = busy;
+        self.interrupt_if_needed()
+    }
+
+    /// Send and interrupt.
+    pub fn interrupt(&mut self) -> Result<()> {
+        usb_debug!("sending interrupt");
+        self.event_handler_busy = true;
+        self.pending = false;
+        self.usbsts.set_bits(USB_STS_EVENT_INTERRUPT);
+        self.iman.set_bits(IMAN_INTERRUPT_PENDING);
+        self.erdp.set_bits(ERDP_EVENT_HANDLER_BUSY);
+        self.interrupt_fd.write(1).map_err(Error::SendInterrupt)
+    }
+
+    fn interrupt_if_needed(&mut self) -> Result<()> {
+        if self.enabled && self.pending && !self.event_handler_busy {
+            self.interrupt()?;
+        }
+        Ok(())
+    }
+}
diff --git a/devices/src/usb/xhci/intr_resample_handler.rs b/devices/src/usb/xhci/intr_resample_handler.rs
new file mode 100644
index 0000000..a2a40bb
--- /dev/null
+++ b/devices/src/usb/xhci/intr_resample_handler.rs
@@ -0,0 +1,64 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::interrupter::Interrupter;
+use crate::utils::{EventHandler, EventLoop};
+use std::sync::Arc;
+use sync::Mutex;
+use sys_util::{error, EventFd, WatchingEvents};
+
+/// Interrupt Resample handler handles resample event. It will reassert interrupt if needed.
+pub struct IntrResampleHandler {
+    interrupter: Arc<Mutex<Interrupter>>,
+    resample_evt: EventFd,
+}
+
+impl IntrResampleHandler {
+    /// Start resample handler.
+    pub fn start(
+        event_loop: &EventLoop,
+        interrupter: Arc<Mutex<Interrupter>>,
+        resample_evt: EventFd,
+    ) -> Option<Arc<IntrResampleHandler>> {
+        let handler = Arc::new(IntrResampleHandler {
+            interrupter,
+            resample_evt,
+        });
+        let tmp_handler: Arc<dyn EventHandler> = handler.clone();
+        if let Err(e) = event_loop.add_event(
+            &handler.resample_evt,
+            WatchingEvents::empty().set_read(),
+            Arc::downgrade(&tmp_handler),
+        ) {
+            error!("cannot add intr resample handler to event loop: {}", e);
+            return None;
+        }
+        Some(handler)
+    }
+}
+impl EventHandler for IntrResampleHandler {
+    fn on_event(&self) -> Result<(), ()> {
+        match self.resample_evt.read() {
+            Ok(_) => {}
+            Err(e) => {
+                error!("cannot read resample evt: {}", e);
+                return Err(());
+            }
+        }
+        usb_debug!("resample triggered");
+        let mut interrupter = self.interrupter.lock();
+        if !interrupter.event_ring_is_empty() {
+            usb_debug!("irq resample re-assert irq event");
+            // There could be a race condition. When we get resample_evt and other
+            // component is sending interrupt at the same time.
+            // This might result in one more interrupt than we want. It's handled by
+            // kernel correctly.
+            if let Err(e) = interrupter.interrupt() {
+                error!("cannot send interrupt: {}", e);
+                return Err(());
+            }
+        }
+        Ok(())
+    }
+}
diff --git a/devices/src/usb/xhci/mod.rs b/devices/src/usb/xhci/mod.rs
new file mode 100644
index 0000000..42cdef5
--- /dev/null
+++ b/devices/src/usb/xhci/mod.rs
@@ -0,0 +1,25 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+mod command_ring_controller;
+mod device_slot;
+mod event_ring;
+mod interrupter;
+mod intr_resample_handler;
+mod ring_buffer;
+mod ring_buffer_controller;
+mod ring_buffer_stop_cb;
+mod transfer_ring_controller;
+mod xhci;
+#[allow(dead_code)]
+mod xhci_abi;
+#[allow(dead_code)]
+mod xhci_regs;
+
+pub mod scatter_gather_buffer;
+pub mod usb_hub;
+pub mod xhci_backend_device;
+pub mod xhci_backend_device_provider;
+pub mod xhci_controller;
+pub mod xhci_transfer;
diff --git a/devices/src/usb/xhci/ring_buffer.rs b/devices/src/usb/xhci/ring_buffer.rs
new file mode 100644
index 0000000..a178ebb
--- /dev/null
+++ b/devices/src/usb/xhci/ring_buffer.rs
@@ -0,0 +1,268 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::xhci_abi::{
+    AddressedTrb, Error as TrbError, LinkTrb, TransferDescriptor, Trb, TrbCast, TrbType,
+};
+use std::fmt::{self, Display};
+use std::mem::size_of;
+use sys_util::{GuestAddress, GuestMemory, GuestMemoryError};
+
+#[derive(Debug)]
+pub enum Error {
+    ReadGuestMemory(GuestMemoryError),
+    BadDequeuePointer(GuestAddress),
+    CastTrb(TrbError),
+    TrbChain(TrbError),
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            ReadGuestMemory(e) => write!(f, "cannot read guest memory: {}", e),
+            BadDequeuePointer(addr) => write!(f, "bad dequeue pointer: {}", addr),
+            CastTrb(e) => write!(f, "cannot cast trb: {}", e),
+            TrbChain(e) => write!(f, "cannot get trb chain bit: {}", e),
+        }
+    }
+}
+
+/// Ring Buffer is segmented circular buffer in guest memory containing work items
+/// called transfer descriptors, each of which consists of one or more TRBs.
+/// Ring buffer logic is shared between transfer ring and command ring.
+/// Transfer Ring management is defined in xHCI spec 4.9.2.
+pub struct RingBuffer {
+    name: String,
+    mem: GuestMemory,
+    dequeue_pointer: GuestAddress,
+    // Used to check if the ring is empty. Toggled when looping back to the begining
+    // of the buffer.
+    consumer_cycle_state: bool,
+}
+
+impl Display for RingBuffer {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "RingBuffer `{}`", self.name)
+    }
+}
+
+// Public interfaces for Ring buffer.
+impl RingBuffer {
+    /// Create a new RingBuffer.
+    pub fn new(name: String, mem: GuestMemory) -> Self {
+        RingBuffer {
+            name,
+            mem,
+            dequeue_pointer: GuestAddress(0),
+            consumer_cycle_state: false,
+        }
+    }
+
+    /// Dequeue next transfer descriptor from the transfer ring.
+    pub fn dequeue_transfer_descriptor(&mut self) -> Result<Option<TransferDescriptor>> {
+        let mut td: TransferDescriptor = TransferDescriptor::new();
+        while let Some(addressed_trb) = self.get_current_trb()? {
+            if let Ok(TrbType::Link) = addressed_trb.trb.get_trb_type() {
+                let link_trb = addressed_trb
+                    .trb
+                    .cast::<LinkTrb>()
+                    .map_err(Error::CastTrb)?;
+                self.dequeue_pointer = GuestAddress(link_trb.get_ring_segment_pointer());
+                self.consumer_cycle_state =
+                    self.consumer_cycle_state != link_trb.get_toggle_cycle();
+                continue;
+            }
+
+            self.dequeue_pointer = match self.dequeue_pointer.checked_add(size_of::<Trb>() as u64) {
+                Some(addr) => addr,
+                None => {
+                    return Err(Error::BadDequeuePointer(self.dequeue_pointer));
+                }
+            };
+
+            usb_debug!(
+                "{}: adding trb to td {}",
+                self.name.as_str(),
+                addressed_trb.trb
+            );
+            td.push(addressed_trb);
+            if !addressed_trb.trb.get_chain_bit().map_err(Error::TrbChain)? {
+                usb_debug!("trb chain is false returning");
+                break;
+            }
+        }
+        // A valid transfer descriptor contains at least one addressed trb and the last trb has
+        // chain bit != 0.
+        match td.last() {
+            Some(t) => {
+                if t.trb.get_chain_bit().map_err(Error::TrbChain)? {
+                    return Ok(None);
+                }
+            }
+            None => return Ok(None),
+        }
+        Ok(Some(td))
+    }
+
+    /// Set dequeue pointer of the ring buffer.
+    pub fn set_dequeue_pointer(&mut self, addr: GuestAddress) {
+        usb_debug!("{}: set dequeue pointer {:x}", self.name.as_str(), addr.0);
+
+        self.dequeue_pointer = addr;
+    }
+
+    /// Set consumer cycle state of the ring buffer.
+    pub fn set_consumer_cycle_state(&mut self, state: bool) {
+        usb_debug!("{}: set consumer cycle state {}", self.name.as_str(), state);
+        self.consumer_cycle_state = state;
+    }
+
+    // Read trb pointed by dequeue pointer. Does not proceed dequeue pointer.
+    fn get_current_trb(&self) -> Result<Option<AddressedTrb>> {
+        let trb: Trb = self
+            .mem
+            .read_obj_from_addr(self.dequeue_pointer)
+            .map_err(Error::ReadGuestMemory)?;
+        usb_debug!("{}: trb read from memory {:?}", self.name.as_str(), trb);
+        // If cycle bit of trb does not equal consumer cycle state, the ring is empty.
+        // This trb is invalid.
+        if trb.get_cycle() != self.consumer_cycle_state {
+            usb_debug!(
+                "cycle bit does not match, self cycle {}",
+                self.consumer_cycle_state
+            );
+            Ok(None)
+        } else {
+            Ok(Some(AddressedTrb {
+                trb,
+                gpa: self.dequeue_pointer.0,
+            }))
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use crate::usb::xhci::xhci_abi::*;
+
+    #[test]
+    fn ring_test_dequeue() {
+        let trb_size = size_of::<Trb>() as u64;
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x1000)]).unwrap();
+        let mut transfer_ring = RingBuffer::new(String::new(), gm.clone());
+
+        // Structure of ring buffer:
+        //  0x100  --> 0x200  --> 0x300
+        //  trb 1  |   trb 3  |   trb 5
+        //  trb 2  |   trb 4  |   trb 6
+        //  l trb  -   l trb  -   l trb to 0x100
+        let mut trb = NormalTrb::new();
+        trb.set_trb_type(TrbType::Normal);
+        trb.set_data_buffer(1);
+        trb.set_chain(true);
+        gm.write_obj_at_addr(trb.clone(), GuestAddress(0x100))
+            .unwrap();
+
+        trb.set_data_buffer(2);
+        gm.write_obj_at_addr(trb, GuestAddress(0x100 + trb_size))
+            .unwrap();
+
+        let mut ltrb = LinkTrb::new();
+        ltrb.set_trb_type(TrbType::Link);
+        ltrb.set_ring_segment_pointer(0x200);
+        gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + 2 * trb_size))
+            .unwrap();
+
+        trb.set_data_buffer(3);
+        gm.write_obj_at_addr(trb, GuestAddress(0x200)).unwrap();
+
+        // Chain bit is false.
+        trb.set_data_buffer(4);
+        trb.set_chain(false);
+        gm.write_obj_at_addr(trb, GuestAddress(0x200 + 1 * trb_size))
+            .unwrap();
+
+        ltrb.set_ring_segment_pointer(0x300);
+        gm.write_obj_at_addr(ltrb, GuestAddress(0x200 + 2 * trb_size))
+            .unwrap();
+
+        trb.set_data_buffer(5);
+        trb.set_chain(true);
+        gm.write_obj_at_addr(trb, GuestAddress(0x300)).unwrap();
+
+        // Chain bit is false.
+        trb.set_data_buffer(6);
+        trb.set_chain(false);
+        gm.write_obj_at_addr(trb, GuestAddress(0x300 + 1 * trb_size))
+            .unwrap();
+
+        ltrb.set_ring_segment_pointer(0x100);
+        gm.write_obj_at_addr(ltrb, GuestAddress(0x300 + 2 * trb_size))
+            .unwrap();
+
+        transfer_ring.set_dequeue_pointer(GuestAddress(0x100));
+        transfer_ring.set_consumer_cycle_state(false);
+
+        // Read first transfer descriptor.
+        let descriptor = transfer_ring
+            .dequeue_transfer_descriptor()
+            .unwrap()
+            .unwrap();
+        assert_eq!(descriptor.len(), 4);
+        assert_eq!(descriptor[0].trb.get_parameter(), 1);
+        assert_eq!(descriptor[1].trb.get_parameter(), 2);
+        assert_eq!(descriptor[2].trb.get_parameter(), 3);
+        assert_eq!(descriptor[3].trb.get_parameter(), 4);
+
+        // Read second transfer descriptor.
+        let descriptor = transfer_ring
+            .dequeue_transfer_descriptor()
+            .unwrap()
+            .unwrap();
+        assert_eq!(descriptor.len(), 2);
+        assert_eq!(descriptor[0].trb.get_parameter(), 5);
+        assert_eq!(descriptor[1].trb.get_parameter(), 6);
+    }
+
+    #[test]
+    fn transfer_ring_test_dequeue_failure() {
+        let trb_size = size_of::<Trb>() as u64;
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x1000)]).unwrap();
+        let mut transfer_ring = RingBuffer::new(String::new(), gm.clone());
+
+        let mut trb = NormalTrb::new();
+        trb.set_trb_type(TrbType::Normal);
+        trb.set_data_buffer(1);
+        trb.set_chain(true);
+        gm.write_obj_at_addr(trb.clone(), GuestAddress(0x100))
+            .unwrap();
+
+        trb.set_data_buffer(2);
+        gm.write_obj_at_addr(trb, GuestAddress(0x100 + trb_size))
+            .unwrap();
+
+        let mut ltrb = LinkTrb::new();
+        ltrb.set_trb_type(TrbType::Link);
+        ltrb.set_ring_segment_pointer(0x200);
+        ltrb.set_toggle_cycle(true);
+        gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + 2 * trb_size))
+            .unwrap();
+
+        trb.set_data_buffer(3);
+        gm.write_obj_at_addr(trb, GuestAddress(0x200)).unwrap();
+
+        transfer_ring.set_dequeue_pointer(GuestAddress(0x100));
+        transfer_ring.set_consumer_cycle_state(false);
+
+        // Read first transfer descriptor.
+        let descriptor = transfer_ring.dequeue_transfer_descriptor().unwrap();
+        assert_eq!(descriptor.is_none(), true);
+    }
+
+}
diff --git a/devices/src/usb/xhci/ring_buffer_controller.rs b/devices/src/usb/xhci/ring_buffer_controller.rs
new file mode 100644
index 0000000..8dd5426
--- /dev/null
+++ b/devices/src/usb/xhci/ring_buffer_controller.rs
@@ -0,0 +1,343 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::ring_buffer_stop_cb::RingBufferStopCallback;
+use super::xhci_abi::*;
+use crate::utils::{self, EventHandler, EventLoop};
+use std::fmt::{self, Display};
+use std::sync::{Arc, MutexGuard};
+use sync::Mutex;
+
+use sys_util::{error, Error as SysError, EventFd, GuestAddress, GuestMemory, WatchingEvents};
+
+use super::ring_buffer::RingBuffer;
+
+#[derive(Debug)]
+pub enum Error {
+    AddEvent(utils::Error),
+    CreateEventFd(SysError),
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            AddEvent(e) => write!(f, "failed to add event to event loop: {}", e),
+            CreateEventFd(e) => write!(f, "failed to create event fd: {}", e),
+        }
+    }
+}
+
+#[derive(PartialEq, Copy, Clone)]
+enum RingBufferState {
+    /// Running: RingBuffer is running, consuming transfer descriptor.
+    Running,
+    /// Stopping: Some thread requested RingBuffer stop. It will stop when current descriptor is
+    /// handled.
+    Stopping,
+    /// Stopped: RingBuffer already stopped.
+    Stopped,
+}
+
+/// TransferDescriptorHandler handles transfer descriptor. User should implement this trait and
+/// build a ring buffer controller with the struct.
+pub trait TransferDescriptorHandler {
+    /// Process descriptor asynchronously, write complete_event when done.
+    fn handle_transfer_descriptor(
+        &self,
+        descriptor: TransferDescriptor,
+        complete_event: EventFd,
+    ) -> std::result::Result<(), ()>;
+    /// Stop is called when trying to stop ring buffer controller. Returns true when stop must be
+    /// performed asynchronously. This happens because the handler is handling some descriptor
+    /// asynchronously, the stop callback of ring buffer controller must be called after the
+    /// `async` part is handled or canceled. If the TransferDescriptorHandler decide it could stop
+    /// immediately, it could return false.
+    /// For example, if a handler submitted a transfer but the transfer has not yet finished. Then
+    /// guest kernel requests to stop the ring buffer controller. Transfer descriptor handler will
+    /// return true, thus RingBufferController would transfer to Stopping state. It will be stopped
+    /// when all pending transfer completed.
+    /// On the other hand, if hander does not have any pending transfers, it would return false.
+    fn stop(&self) -> bool {
+        true
+    }
+}
+
+/// RingBufferController owns a ring buffer. It lives on a event_loop. It will pop out transfer
+/// descriptor and let TransferDescriptorHandler handle it.
+pub struct RingBufferController<T: 'static + TransferDescriptorHandler> {
+    name: String,
+    state: Mutex<RingBufferState>,
+    stop_callback: Mutex<Vec<RingBufferStopCallback>>,
+    ring_buffer: Mutex<RingBuffer>,
+    handler: Mutex<T>,
+    event_loop: Arc<EventLoop>,
+    event: EventFd,
+}
+
+impl<T: 'static + TransferDescriptorHandler> Display for RingBufferController<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "RingBufferController `{}`", self.name)
+    }
+}
+
+impl<T: Send> RingBufferController<T>
+where
+    T: 'static + TransferDescriptorHandler,
+{
+    /// Create a ring buffer controller and add it to event loop.
+    pub fn new_with_handler(
+        name: String,
+        mem: GuestMemory,
+        event_loop: Arc<EventLoop>,
+        handler: T,
+    ) -> Result<Arc<RingBufferController<T>>> {
+        let evt = EventFd::new().map_err(Error::CreateEventFd)?;
+        let controller = Arc::new(RingBufferController {
+            name: name.clone(),
+            state: Mutex::new(RingBufferState::Stopped),
+            stop_callback: Mutex::new(Vec::new()),
+            ring_buffer: Mutex::new(RingBuffer::new(name.clone(), mem)),
+            handler: Mutex::new(handler),
+            event_loop: event_loop.clone(),
+            event: evt,
+        });
+        let event_handler: Arc<dyn EventHandler> = controller.clone();
+        event_loop
+            .add_event(
+                &controller.event,
+                WatchingEvents::empty().set_read(),
+                Arc::downgrade(&event_handler),
+            )
+            .map_err(Error::AddEvent)?;
+        Ok(controller)
+    }
+
+    fn lock_ring_buffer(&self) -> MutexGuard<RingBuffer> {
+        self.ring_buffer.lock()
+    }
+
+    /// Set dequeue pointer of the internal ring buffer.
+    pub fn set_dequeue_pointer(&self, ptr: GuestAddress) {
+        usb_debug!("{}: set dequeue pointer: {:x}", self.name, ptr.0);
+        // Fast because this should only happen during xhci setup.
+        self.lock_ring_buffer().set_dequeue_pointer(ptr);
+    }
+
+    /// Set consumer cycle state.
+    pub fn set_consumer_cycle_state(&self, state: bool) {
+        usb_debug!("{}: set consumer cycle state: {}", self.name, state);
+        // Fast because this should only happen during xhci setup.
+        self.lock_ring_buffer().set_consumer_cycle_state(state);
+    }
+
+    /// Start the ring buffer.
+    pub fn start(&self) {
+        usb_debug!("{} started", self.name);
+        let mut state = self.state.lock();
+        if *state != RingBufferState::Running {
+            *state = RingBufferState::Running;
+            if let Err(e) = self.event.write(1) {
+                error!("cannot start event ring: {}", e);
+            }
+        }
+    }
+
+    /// Stop the ring buffer asynchronously.
+    pub fn stop(&self, callback: RingBufferStopCallback) {
+        usb_debug!("{} being stopped", self.name);
+        let mut state = self.state.lock();
+        if *state == RingBufferState::Stopped {
+            usb_debug!("{} is already stopped", self.name);
+            return;
+        }
+        if self.handler.lock().stop() {
+            *state = RingBufferState::Stopping;
+            self.stop_callback.lock().push(callback);
+        } else {
+            *state = RingBufferState::Stopped;
+        }
+    }
+}
+
+impl<T> Drop for RingBufferController<T>
+where
+    T: 'static + TransferDescriptorHandler,
+{
+    fn drop(&mut self) {
+        // Remove self from the event loop.
+        if let Err(e) = self.event_loop.remove_event_for_fd(&self.event) {
+            error!(
+                "cannot remove ring buffer controller from event loop: {}",
+                e
+            );
+        }
+    }
+}
+
+impl<T> EventHandler for RingBufferController<T>
+where
+    T: 'static + TransferDescriptorHandler + Send,
+{
+    fn on_event(&self) -> std::result::Result<(), ()> {
+        // `self.event` triggers ring buffer controller to run, the value read is not important.
+        match self.event.read() {
+            Ok(_) => {}
+            Err(e) => {
+                error!("cannot read from event fd: {}", e);
+                return Err(());
+            }
+        }
+        let mut state = self.state.lock();
+
+        match *state {
+            RingBufferState::Stopped => return Ok(()),
+            RingBufferState::Stopping => {
+                usb_debug!("{}: stopping ring buffer controller", self.name);
+                *state = RingBufferState::Stopped;
+                self.stop_callback.lock().clear();
+                return Ok(());
+            }
+            RingBufferState::Running => {}
+        }
+
+        let transfer_descriptor = match self.lock_ring_buffer().dequeue_transfer_descriptor() {
+            Ok(t) => t,
+            Err(e) => {
+                error!("cannot dequeue transfer descriptor: {}", e);
+                return Err(());
+            }
+        };
+
+        let transfer_descriptor = match transfer_descriptor {
+            Some(t) => t,
+            None => {
+                *state = RingBufferState::Stopped;
+                self.stop_callback.lock().clear();
+                return Ok(());
+            }
+        };
+
+        let event = match self.event.try_clone() {
+            Ok(evt) => evt,
+            Err(e) => {
+                error!("cannot clone event fd: {}", e);
+                return Err(());
+            }
+        };
+        self.handler
+            .lock()
+            .handle_transfer_descriptor(transfer_descriptor, event)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::mem::size_of;
+    use std::sync::mpsc::{channel, Sender};
+
+    struct TestHandler {
+        sender: Sender<i32>,
+    }
+
+    impl TransferDescriptorHandler for TestHandler {
+        fn handle_transfer_descriptor(
+            &self,
+            descriptor: TransferDescriptor,
+            complete_event: EventFd,
+        ) -> std::result::Result<(), ()> {
+            for atrb in descriptor {
+                assert_eq!(atrb.trb.get_trb_type().unwrap(), TrbType::Normal);
+                self.sender.send(atrb.trb.get_parameter() as i32).unwrap();
+            }
+            complete_event.write(1).unwrap();
+            Ok(())
+        }
+    }
+
+    fn setup_mem() -> GuestMemory {
+        let trb_size = size_of::<Trb>() as u64;
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x1000)]).unwrap();
+
+        // Structure of ring buffer:
+        //  0x100  --> 0x200  --> 0x300
+        //  trb 1  |   trb 3  |   trb 5
+        //  trb 2  |   trb 4  |   trb 6
+        //  l trb  -   l trb  -   l trb to 0x100
+        let mut trb = NormalTrb::new();
+        trb.set_trb_type(TrbType::Normal);
+        trb.set_data_buffer(1);
+        trb.set_chain(true);
+        gm.write_obj_at_addr(trb.clone(), GuestAddress(0x100))
+            .unwrap();
+
+        trb.set_data_buffer(2);
+        gm.write_obj_at_addr(trb, GuestAddress(0x100 + trb_size))
+            .unwrap();
+
+        let mut ltrb = LinkTrb::new();
+        ltrb.set_trb_type(TrbType::Link);
+        ltrb.set_ring_segment_pointer(0x200);
+        gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + 2 * trb_size))
+            .unwrap();
+
+        trb.set_data_buffer(3);
+        gm.write_obj_at_addr(trb, GuestAddress(0x200)).unwrap();
+
+        // Chain bit is false.
+        trb.set_data_buffer(4);
+        trb.set_chain(false);
+        gm.write_obj_at_addr(trb, GuestAddress(0x200 + 1 * trb_size))
+            .unwrap();
+
+        ltrb.set_ring_segment_pointer(0x300);
+        gm.write_obj_at_addr(ltrb, GuestAddress(0x200 + 2 * trb_size))
+            .unwrap();
+
+        trb.set_data_buffer(5);
+        trb.set_chain(true);
+        gm.write_obj_at_addr(trb, GuestAddress(0x300)).unwrap();
+
+        // Chain bit is false.
+        trb.set_data_buffer(6);
+        trb.set_chain(false);
+        gm.write_obj_at_addr(trb, GuestAddress(0x300 + 1 * trb_size))
+            .unwrap();
+
+        ltrb.set_ring_segment_pointer(0x100);
+        gm.write_obj_at_addr(ltrb, GuestAddress(0x300 + 2 * trb_size))
+            .unwrap();
+        gm
+    }
+
+    #[test]
+    fn test_ring_buffer_controller() {
+        let (tx, rx) = channel();
+        let mem = setup_mem();
+        let (l, j) = EventLoop::start("test".to_string(), None).unwrap();
+        let l = Arc::new(l);
+        let controller = RingBufferController::new_with_handler(
+            "".to_string(),
+            mem,
+            l.clone(),
+            TestHandler { sender: tx },
+        )
+        .unwrap();
+        controller.set_dequeue_pointer(GuestAddress(0x100));
+        controller.set_consumer_cycle_state(false);
+        controller.start();
+        assert_eq!(rx.recv().unwrap(), 1);
+        assert_eq!(rx.recv().unwrap(), 2);
+        assert_eq!(rx.recv().unwrap(), 3);
+        assert_eq!(rx.recv().unwrap(), 4);
+        assert_eq!(rx.recv().unwrap(), 5);
+        assert_eq!(rx.recv().unwrap(), 6);
+        l.stop();
+        j.join().unwrap();
+    }
+}
diff --git a/devices/src/usb/xhci/ring_buffer_stop_cb.rs b/devices/src/usb/xhci/ring_buffer_stop_cb.rs
new file mode 100644
index 0000000..3eca928
--- /dev/null
+++ b/devices/src/usb/xhci/ring_buffer_stop_cb.rs
@@ -0,0 +1,73 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::utils::FailHandle;
+use std::sync::{Arc, Mutex};
+use sys_util::error;
+
+/// RingBufferStopCallback wraps a callback. The callback will be invoked when last instance of
+/// RingBufferStopCallback and its clones is dropped.
+///
+/// The callback might not be invoked in certain cases. Don't depend this for safety.
+#[derive(Clone)]
+pub struct RingBufferStopCallback {
+    inner: Arc<Mutex<RingBufferStopCallbackInner>>,
+}
+
+impl RingBufferStopCallback {
+    /// Create new callback from closure.
+    pub fn new<C: 'static + FnMut() + Send>(cb: C) -> RingBufferStopCallback {
+        RingBufferStopCallback {
+            inner: Arc::new(Mutex::new(RingBufferStopCallbackInner {
+                callback: Box::new(cb),
+            })),
+        }
+    }
+}
+
+struct RingBufferStopCallbackInner {
+    callback: Box<dyn FnMut() + Send>,
+}
+
+impl Drop for RingBufferStopCallbackInner {
+    fn drop(&mut self) {
+        (self.callback)();
+    }
+}
+
+/// Helper function to wrap up a closure with fail handle. The fail handle will be triggered if the
+/// closure returns an error.
+pub fn fallible_closure<E: std::fmt::Display, C: FnMut() -> Result<(), E> + 'static + Send>(
+    fail_handle: Arc<dyn FailHandle>,
+    mut callback: C,
+) -> impl FnMut() + 'static + Send {
+    move || match callback() {
+        Ok(()) => {}
+        Err(e) => {
+            error!("callback failed {}", e);
+            fail_handle.fail();
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::sync::{Arc, Mutex};
+
+    fn task(_: RingBufferStopCallback) {}
+
+    #[test]
+    fn simple_raii_callback() {
+        let a = Arc::new(Mutex::new(0));
+        let ac = a.clone();
+        let cb = RingBufferStopCallback::new(move || {
+            *ac.lock().unwrap() = 1;
+        });
+        task(cb.clone());
+        task(cb.clone());
+        task(cb);
+        assert_eq!(*a.lock().unwrap(), 1);
+    }
+}
diff --git a/devices/src/usb/xhci/scatter_gather_buffer.rs b/devices/src/usb/xhci/scatter_gather_buffer.rs
new file mode 100644
index 0000000..0150e4f
--- /dev/null
+++ b/devices/src/usb/xhci/scatter_gather_buffer.rs
@@ -0,0 +1,179 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::xhci_abi::{Error as TrbError, NormalTrb, TransferDescriptor, TrbCast, TrbType};
+use bit_field::Error as BitFieldError;
+use std::fmt::{self, Display};
+use sys_util::{GuestAddress, GuestMemory, GuestMemoryError};
+
+#[derive(Debug)]
+pub enum Error {
+    ReadGuestMemory(GuestMemoryError),
+    WriteGuestMemory(GuestMemoryError),
+    UnknownTrbType(BitFieldError),
+    CastTrb(TrbError),
+    BadTrbType(TrbType),
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            ReadGuestMemory(e) => write!(f, "cannot read guest memory: {}", e),
+            WriteGuestMemory(e) => write!(f, "cannot write guest memory: {}", e),
+            UnknownTrbType(e) => write!(f, "unknown trb type: {}", e),
+            CastTrb(e) => write!(f, "cannot cast trb: {}", e),
+            BadTrbType(t) => write!(f, "should not build buffer from trb type: {:?}", t),
+        }
+    }
+}
+
+/// See xHCI spec 3.2.8 for scatter/gather transfer. It's used in bulk/interrupt transfers. See
+/// 3.2.10 for details.
+pub struct ScatterGatherBuffer {
+    mem: GuestMemory,
+    td: TransferDescriptor,
+}
+
+impl ScatterGatherBuffer {
+    /// Create a new buffer from transfer descriptor.
+    pub fn new(mem: GuestMemory, td: TransferDescriptor) -> Result<ScatterGatherBuffer> {
+        for atrb in &td {
+            let trb_type = atrb.trb.get_trb_type().map_err(Error::UnknownTrbType)?;
+            if trb_type != TrbType::Normal
+                && trb_type != TrbType::DataStage
+                && trb_type != TrbType::Isoch
+            {
+                return Err(Error::BadTrbType(trb_type));
+            }
+        }
+        Ok(ScatterGatherBuffer { mem, td })
+    }
+
+    /// Total len of this buffer.
+    pub fn len(&self) -> Result<usize> {
+        let mut total_len = 0usize;
+        for atrb in &self.td {
+            total_len += atrb
+                .trb
+                .cast::<NormalTrb>()
+                .map_err(Error::CastTrb)?
+                .get_trb_transfer_length() as usize;
+        }
+        Ok(total_len)
+    }
+
+    /// Read content to buffer, return number of bytes read.
+    pub fn read(&self, buffer: &mut [u8]) -> Result<usize> {
+        let mut total_size = 0usize;
+        let mut offset = 0;
+        for atrb in &self.td {
+            let normal_trb = atrb.trb.cast::<NormalTrb>().map_err(Error::CastTrb)?;
+            let len = normal_trb.get_trb_transfer_length() as usize;
+            let buffer_len = {
+                if offset == buffer.len() {
+                    return Ok(total_size);
+                }
+                if buffer.len() > offset + len {
+                    len
+                } else {
+                    buffer.len() - offset
+                }
+            };
+            let buffer_end = offset + buffer_len;
+            let cur_buffer = &mut buffer[offset..buffer_end];
+            offset = buffer_end;
+            total_size += self
+                .mem
+                .read_at_addr(cur_buffer, GuestAddress(normal_trb.get_data_buffer()))
+                .map_err(Error::ReadGuestMemory)?;
+        }
+        Ok(total_size)
+    }
+
+    /// Write content from buffer, return number of bytes written.
+    pub fn write(&self, buffer: &[u8]) -> Result<usize> {
+        let mut total_size = 0usize;
+        let mut offset = 0;
+        for atrb in &self.td {
+            let normal_trb = atrb.trb.cast::<NormalTrb>().map_err(Error::CastTrb)?;
+            let len = normal_trb.get_trb_transfer_length() as usize;
+            let buffer_len = {
+                if offset == buffer.len() {
+                    return Ok(total_size);
+                }
+                if buffer.len() > offset + len {
+                    len
+                } else {
+                    buffer.len() - offset
+                }
+            };
+            let buffer_end = offset + buffer_len;
+            let cur_buffer = &buffer[offset..buffer_end];
+            offset = buffer_end;
+            total_size += self
+                .mem
+                .write_at_addr(cur_buffer, GuestAddress(normal_trb.get_data_buffer()))
+                .map_err(Error::WriteGuestMemory)?;
+        }
+        Ok(total_size)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use crate::usb::xhci::xhci_abi::{AddressedTrb, Trb};
+
+    #[test]
+    fn scatter_gather_buffer_test() {
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x1000)]).unwrap();
+        let mut td = TransferDescriptor::new();
+
+        // In this td, we are going to have scatter buffer at 0x100, length 4, 0x200 length 2 and
+        // 0x300 length 1.
+
+        let mut trb = Trb::new();
+        let ntrb = trb.cast_mut::<NormalTrb>().unwrap();
+        ntrb.set_trb_type(TrbType::Normal);
+        ntrb.set_data_buffer(0x100);
+        ntrb.set_trb_transfer_length(4);
+        td.push(AddressedTrb { trb, gpa: 0 });
+
+        let mut trb = Trb::new();
+        let ntrb = trb.cast_mut::<NormalTrb>().unwrap();
+        ntrb.set_trb_type(TrbType::Normal);
+        ntrb.set_data_buffer(0x200);
+        ntrb.set_trb_transfer_length(2);
+        td.push(AddressedTrb { trb, gpa: 0 });
+
+        let mut trb = Trb::new();
+        let ntrb = trb.cast_mut::<NormalTrb>().unwrap();
+        ntrb.set_trb_type(TrbType::Normal);
+        ntrb.set_data_buffer(0x300);
+        ntrb.set_trb_transfer_length(1);
+        td.push(AddressedTrb { trb, gpa: 0 });
+
+        let buffer = ScatterGatherBuffer::new(gm.clone(), td).unwrap();
+
+        assert_eq!(buffer.len().unwrap(), 7);
+        let data_to_write: [u8; 7] = [7, 6, 5, 4, 3, 2, 1];
+        buffer.write(&data_to_write).unwrap();
+
+        let mut d = [0; 4];
+        gm.read_exact_at_addr(&mut d, GuestAddress(0x100)).unwrap();
+        assert_eq!(d, [7, 6, 5, 4]);;
+        gm.read_exact_at_addr(&mut d, GuestAddress(0x200)).unwrap();
+        assert_eq!(d, [3, 2, 0, 0]);;
+        gm.read_exact_at_addr(&mut d, GuestAddress(0x300)).unwrap();
+        assert_eq!(d, [1, 0, 0, 0]);;
+
+        let mut data_read = [0; 7];
+        buffer.read(&mut data_read).unwrap();
+        assert_eq!(data_to_write, data_read);
+    }
+}
diff --git a/devices/src/usb/xhci/transfer_ring_controller.rs b/devices/src/usb/xhci/transfer_ring_controller.rs
new file mode 100644
index 0000000..0b5d3b6
--- /dev/null
+++ b/devices/src/usb/xhci/transfer_ring_controller.rs
@@ -0,0 +1,87 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::usb::xhci::ring_buffer_controller::{
+    Error as RingBufferControllerError, RingBufferController, TransferDescriptorHandler,
+};
+use crate::utils::EventLoop;
+use std::sync::Arc;
+use sync::Mutex;
+use sys_util::{error, EventFd, GuestMemory};
+
+use super::interrupter::Interrupter;
+use super::usb_hub::UsbPort;
+use super::xhci_abi::TransferDescriptor;
+use super::xhci_transfer::XhciTransferManager;
+
+/// Transfer ring controller manages transfer ring.
+pub type TransferRingController = RingBufferController<TransferRingTrbHandler>;
+
+pub type TransferRingControllerError = RingBufferControllerError;
+
+/// TransferRingTrbHandler handles trbs on transfer ring.
+pub struct TransferRingTrbHandler {
+    mem: GuestMemory,
+    port: Arc<UsbPort>,
+    interrupter: Arc<Mutex<Interrupter>>,
+    slot_id: u8,
+    endpoint_id: u8,
+    transfer_manager: XhciTransferManager,
+}
+
+impl TransferDescriptorHandler for TransferRingTrbHandler {
+    fn handle_transfer_descriptor(
+        &self,
+        descriptor: TransferDescriptor,
+        completion_event: EventFd,
+    ) -> Result<(), ()> {
+        let xhci_transfer = self.transfer_manager.create_transfer(
+            self.mem.clone(),
+            self.port.clone(),
+            self.interrupter.clone(),
+            self.slot_id,
+            self.endpoint_id,
+            descriptor,
+            completion_event,
+        );
+        xhci_transfer.send_to_backend_if_valid().map_err(|e| {
+            error!("failed to send transfer to backend: {}", e);
+        })
+    }
+
+    fn stop(&self) -> bool {
+        let backend = self.port.get_backend_device();
+        if backend.is_some() {
+            self.transfer_manager.cancel_all();
+            true
+        } else {
+            false
+        }
+    }
+}
+
+impl TransferRingController {
+    pub fn new(
+        mem: GuestMemory,
+        port: Arc<UsbPort>,
+        event_loop: Arc<EventLoop>,
+        interrupter: Arc<Mutex<Interrupter>>,
+        slot_id: u8,
+        endpoint_id: u8,
+    ) -> Result<Arc<TransferRingController>, TransferRingControllerError> {
+        RingBufferController::new_with_handler(
+            format!("transfer ring slot_{} ep_{}", slot_id, endpoint_id),
+            mem.clone(),
+            event_loop,
+            TransferRingTrbHandler {
+                mem,
+                port,
+                interrupter,
+                slot_id,
+                endpoint_id,
+                transfer_manager: XhciTransferManager::new(),
+            },
+        )
+    }
+}
diff --git a/devices/src/usb/xhci/usb_hub.rs b/devices/src/usb/xhci/usb_hub.rs
new file mode 100644
index 0000000..28c7f19
--- /dev/null
+++ b/devices/src/usb/xhci/usb_hub.rs
@@ -0,0 +1,290 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::interrupter::{Error as InterrupterError, Interrupter};
+use super::xhci_backend_device::{BackendType, XhciBackendDevice};
+use super::xhci_regs::{
+    XhciRegs, MAX_PORTS, PORTSC_CONNECT_STATUS_CHANGE, PORTSC_CURRENT_CONNECT_STATUS,
+    PORTSC_PORT_ENABLED, PORTSC_PORT_ENABLED_DISABLED_CHANGE, USB2_PORTS_END, USB2_PORTS_START,
+    USB3_PORTS_END, USB3_PORTS_START, USB_STS_PORT_CHANGE_DETECT,
+};
+use crate::register_space::Register;
+use std::fmt::{self, Display};
+use std::sync::{Arc, MutexGuard};
+use sync::Mutex;
+
+#[derive(Debug)]
+pub enum Error {
+    AllPortsAttached,
+    AlreadyDetached(u8),
+    Attach {
+        port_id: u8,
+        reason: InterrupterError,
+    },
+    Detach {
+        port_id: u8,
+        reason: InterrupterError,
+    },
+    NoSuchDevice {
+        bus: u8,
+        addr: u8,
+        vid: u16,
+        pid: u16,
+    },
+    NoSuchPort(u8),
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            AllPortsAttached => write!(f, "all suitable ports already attached"),
+            AlreadyDetached(port_id) => write!(f, "device already detached from port {}", port_id),
+            Attach { port_id, reason } => {
+                write!(f, "failed to attach device to port {}: {}", port_id, reason)
+            }
+            Detach { port_id, reason } => write!(
+                f,
+                "failed to detach device from port {}: {}",
+                port_id, reason
+            ),
+            NoSuchDevice {
+                bus,
+                addr,
+                vid,
+                pid,
+            } => write!(
+                f,
+                "device {}:{}:{:04x}:{:04x} is not attached",
+                bus, addr, vid, pid
+            ),
+            NoSuchPort(port_id) => write!(f, "port {} does not exist", port_id),
+        }
+    }
+}
+
+/// A port on usb hub. It could have a device connected to it.
+pub struct UsbPort {
+    ty: BackendType,
+    port_id: u8,
+    portsc: Register<u32>,
+    usbsts: Register<u32>,
+    interrupter: Arc<Mutex<Interrupter>>,
+    backend_device: Mutex<Option<Box<dyn XhciBackendDevice>>>,
+}
+
+impl UsbPort {
+    /// Create a new usb port that has nothing connected to it.
+    pub fn new(
+        ty: BackendType,
+        port_id: u8,
+        portsc: Register<u32>,
+        usbsts: Register<u32>,
+        interrupter: Arc<Mutex<Interrupter>>,
+    ) -> UsbPort {
+        UsbPort {
+            ty,
+            port_id,
+            portsc,
+            usbsts,
+            interrupter,
+            backend_device: Mutex::new(None),
+        }
+    }
+
+    fn port_id(&self) -> u8 {
+        self.port_id
+    }
+
+    /// Detach current connected backend. Returns false when there is no backend connected.
+    pub fn detach(&self) -> Result<()> {
+        let mut locked = self.backend_device.lock();
+        if locked.is_none() {
+            return Err(Error::AlreadyDetached(self.port_id));
+        }
+        usb_debug!("device detached from port {}", self.port_id);
+        *locked = None;
+        self.send_device_disconnected_event()
+            .map_err(|reason| Error::Detach {
+                port_id: self.port_id,
+                reason,
+            })
+    }
+
+    /// Get current connected backend.
+    pub fn get_backend_device(&self) -> MutexGuard<Option<Box<dyn XhciBackendDevice>>> {
+        self.backend_device.lock()
+    }
+
+    fn is_attached(&self) -> bool {
+        self.backend_device.lock().is_some()
+    }
+
+    fn reset(&self) -> std::result::Result<(), InterrupterError> {
+        if self.is_attached() {
+            self.send_device_connected_event()?;
+        }
+        Ok(())
+    }
+
+    fn attach(
+        &self,
+        device: Box<dyn XhciBackendDevice>,
+    ) -> std::result::Result<(), InterrupterError> {
+        usb_debug!("A backend is connected to port {}", self.port_id);
+        let mut locked = self.backend_device.lock();
+        assert!(locked.is_none());
+        *locked = Some(device);
+        self.send_device_connected_event()
+    }
+
+    /// Inform the guest kernel there is device connected to this port. It combines first few steps
+    /// of USB device initialization process in xHCI spec 4.3.
+    pub fn send_device_connected_event(&self) -> std::result::Result<(), InterrupterError> {
+        // xHCI spec 4.3.
+        self.portsc.set_bits(
+            PORTSC_CURRENT_CONNECT_STATUS
+                | PORTSC_PORT_ENABLED
+                | PORTSC_CONNECT_STATUS_CHANGE
+                | PORTSC_PORT_ENABLED_DISABLED_CHANGE,
+        );
+        self.usbsts.set_bits(USB_STS_PORT_CHANGE_DETECT);
+        self.interrupter
+            .lock()
+            .send_port_status_change_trb(self.port_id)
+    }
+
+    /// Inform the guest kernel that device has been detached.
+    pub fn send_device_disconnected_event(&self) -> std::result::Result<(), InterrupterError> {
+        // xHCI spec 4.3.
+        self.portsc
+            .set_bits(PORTSC_CONNECT_STATUS_CHANGE | PORTSC_PORT_ENABLED_DISABLED_CHANGE);
+        self.portsc.clear_bits(PORTSC_CURRENT_CONNECT_STATUS);
+        self.usbsts.set_bits(USB_STS_PORT_CHANGE_DETECT);
+        self.interrupter
+            .lock()
+            .send_port_status_change_trb(self.port_id)
+    }
+}
+
+/// UsbHub is a set of usb ports.
+pub struct UsbHub {
+    ports: Vec<Arc<UsbPort>>,
+}
+
+impl UsbHub {
+    /// Create usb hub with no device attached.
+    pub fn new(regs: &XhciRegs, interrupter: Arc<Mutex<Interrupter>>) -> UsbHub {
+        let mut ports = Vec::new();
+        // Each port should have a portsc register.
+        assert_eq!(MAX_PORTS as usize, regs.portsc.len());
+
+        for i in USB2_PORTS_START..USB2_PORTS_END {
+            ports.push(Arc::new(UsbPort::new(
+                BackendType::Usb2,
+                i + 1,
+                regs.portsc[i as usize].clone(),
+                regs.usbsts.clone(),
+                interrupter.clone(),
+            )));
+        }
+
+        for i in USB3_PORTS_START..USB3_PORTS_END {
+            ports.push(Arc::new(UsbPort::new(
+                BackendType::Usb3,
+                i + 1,
+                regs.portsc[i as usize].clone(),
+                regs.usbsts.clone(),
+                interrupter.clone(),
+            )));
+        }
+        UsbHub { ports }
+    }
+
+    /// Try to detach device of bus, addr, vid, pid
+    pub fn try_detach(&self, bus: u8, addr: u8, vid: u16, pid: u16) -> Result<()> {
+        for port in &self.ports {
+            // This block exists so that we only hold the backend device
+            // lock while checking the address. It needs to be dropped before
+            // calling port.detach(), because that acquires the backend
+            // device lock again.
+            {
+                let backend_device = port.get_backend_device();
+
+                let d = match backend_device.as_ref() {
+                    None => continue,
+                    Some(d) => d,
+                };
+
+                if d.host_bus() != bus
+                    || d.host_address() != addr
+                    || d.get_vid() != vid
+                    || d.get_pid() != pid
+                {
+                    continue;
+                }
+            }
+
+            return port.detach();
+        }
+
+        Err(Error::NoSuchDevice {
+            bus,
+            addr,
+            vid,
+            pid,
+        })
+    }
+
+    /// Reset all ports.
+    pub fn reset(&self) -> Result<()> {
+        usb_debug!("reseting usb hub");
+        for p in &self.ports {
+            p.reset().map_err(|reason| Error::Detach {
+                port_id: p.port_id(),
+                reason,
+            })?;
+        }
+        Ok(())
+    }
+
+    /// Get a specific port of the hub.
+    pub fn get_port(&self, port_id: u8) -> Option<Arc<UsbPort>> {
+        if port_id == 0 || port_id > MAX_PORTS {
+            return None;
+        }
+        let port_index = (port_id - 1) as usize;
+        Some(self.ports.get(port_index)?.clone())
+    }
+
+    /// Connect backend to next empty port.
+    pub fn connect_backend(&self, backend: Box<dyn XhciBackendDevice>) -> Result<u8> {
+        usb_debug!("Trying to connect backend to hub");
+        for port in &self.ports {
+            if port.is_attached() {
+                continue;
+            }
+            if port.ty != backend.get_backend_type() {
+                continue;
+            }
+            let port_id = port.port_id();
+            port.attach(backend)
+                .map_err(|reason| Error::Attach { port_id, reason })?;
+            return Ok(port_id);
+        }
+        Err(Error::AllPortsAttached)
+    }
+
+    /// Disconnect device from port. Returns false if port id is not valid or could not be
+    /// disonnected.
+    pub fn disconnect_port(&self, port_id: u8) -> Result<()> {
+        match self.get_port(port_id) {
+            Some(port) => port.detach(),
+            None => Err(Error::NoSuchPort(port_id)),
+        }
+    }
+}
diff --git a/devices/src/usb/xhci/xhci.rs b/devices/src/usb/xhci/xhci.rs
new file mode 100644
index 0000000..47ebe85
--- /dev/null
+++ b/devices/src/usb/xhci/xhci.rs
@@ -0,0 +1,392 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::command_ring_controller::{CommandRingController, CommandRingControllerError};
+use super::device_slot::{DeviceSlots, Error as DeviceSlotError};
+use super::interrupter::{Error as InterrupterError, Interrupter};
+use super::intr_resample_handler::IntrResampleHandler;
+use super::ring_buffer_stop_cb::RingBufferStopCallback;
+use super::usb_hub::UsbHub;
+use super::xhci_backend_device_provider::XhciBackendDeviceProvider;
+use super::xhci_regs::*;
+use crate::usb::host_backend::host_backend_device_provider::HostBackendDeviceProvider;
+use crate::utils::{Error as UtilsError, EventLoop, FailHandle};
+use std::fmt::{self, Display};
+use std::sync::Arc;
+use sync::Mutex;
+use sys_util::{error, EventFd, GuestAddress, GuestMemory};
+
+#[derive(Debug)]
+pub enum Error {
+    StartEventLoop(UtilsError),
+    GetDeviceSlot(u8),
+    StartResampleHandler,
+    SendInterrupt(InterrupterError),
+    EnableInterrupter(InterrupterError),
+    SetModeration(InterrupterError),
+    SetupEventRing(InterrupterError),
+    SetEventHandlerBusy(InterrupterError),
+    StartProvider,
+    RingDoorbell(DeviceSlotError),
+    CreateCommandRingController(CommandRingControllerError),
+    ResetPort,
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            StartEventLoop(e) => write!(f, "failed to start event loop: {}", e),
+            GetDeviceSlot(i) => write!(f, "failed to get device slot: {}", i),
+            StartResampleHandler => write!(f, "failed to start resample handler"),
+            SendInterrupt(e) => write!(f, "failed to send interrupter: {}", e),
+            EnableInterrupter(e) => write!(f, "failed to enable interrupter: {}", e),
+            SetModeration(e) => write!(f, "failed to set interrupter moderation: {}", e),
+            SetupEventRing(e) => write!(f, "failed to setup event ring: {}", e),
+            SetEventHandlerBusy(e) => write!(f, "failed to set event handler busy: {}", e),
+            StartProvider => write!(f, "failed to start backend provider"),
+            RingDoorbell(e) => write!(f, "failed to ring doorbell: {}", e),
+            CreateCommandRingController(e) => {
+                write!(f, "failed to create command ring controller: {}", e)
+            }
+            ResetPort => write!(f, "failed to reset port"),
+        }
+    }
+}
+
+/// xHCI controller implementation.
+pub struct Xhci {
+    fail_handle: Arc<dyn FailHandle>,
+    regs: XhciRegs,
+    interrupter: Arc<Mutex<Interrupter>>,
+    command_ring_controller: Arc<CommandRingController>,
+    device_slots: DeviceSlots,
+    // resample handler and device provider only lives on EventLoop to handle corresponding events.
+    // By design, event loop only hold weak reference. We need to keep a strong reference here to
+    // keep it alive.
+    #[allow(dead_code)]
+    intr_resample_handler: Arc<IntrResampleHandler>,
+    #[allow(dead_code)]
+    device_provider: HostBackendDeviceProvider,
+}
+
+impl Xhci {
+    /// Create a new xHCI controller.
+    pub fn new(
+        fail_handle: Arc<dyn FailHandle>,
+        mem: GuestMemory,
+        device_provider: HostBackendDeviceProvider,
+        irq_evt: EventFd,
+        irq_resample_evt: EventFd,
+        regs: XhciRegs,
+    ) -> Result<Arc<Self>> {
+        let (event_loop, _join_handle) =
+            EventLoop::start("xhci".to_string(), Some(fail_handle.clone()))
+                .map_err(Error::StartEventLoop)?;
+        let interrupter = Arc::new(Mutex::new(Interrupter::new(mem.clone(), irq_evt, &regs)));
+        let event_loop = Arc::new(event_loop);
+        let intr_resample_handler =
+            IntrResampleHandler::start(&event_loop, interrupter.clone(), irq_resample_evt)
+                .ok_or(Error::StartResampleHandler)?;
+        let hub = Arc::new(UsbHub::new(&regs, interrupter.clone()));
+
+        let mut device_provider = device_provider;
+        device_provider
+            .start(fail_handle.clone(), event_loop.clone(), hub.clone())
+            .map_err(|_| Error::StartProvider)?;
+
+        let device_slots = DeviceSlots::new(
+            fail_handle.clone(),
+            regs.dcbaap.clone(),
+            hub.clone(),
+            interrupter.clone(),
+            event_loop.clone(),
+            mem.clone(),
+        );
+        let command_ring_controller = CommandRingController::new(
+            mem.clone(),
+            event_loop.clone(),
+            device_slots.clone(),
+            interrupter.clone(),
+        )
+        .map_err(Error::CreateCommandRingController)?;
+        let xhci = Arc::new(Xhci {
+            fail_handle,
+            regs,
+            intr_resample_handler,
+            interrupter,
+            command_ring_controller,
+            device_slots,
+            device_provider,
+        });
+        Self::init_reg_callbacks(&xhci);
+        Ok(xhci)
+    }
+
+    fn init_reg_callbacks(xhci: &Arc<Xhci>) {
+        // All the callbacks will hold a weak reference to avoid memory leak. Thos weak upgrade
+        // should never fail.
+        let xhci_weak = Arc::downgrade(xhci);
+        xhci.regs.usbcmd.set_write_cb(move |val: u32| {
+            // All the weak reference upgrade should never fail. xhci hold reference to the
+            // registers, callback won't be invoked if xhci is gone.
+            let xhci = xhci_weak.upgrade().unwrap();
+            let r = xhci.usbcmd_callback(val);
+            xhci.handle_register_callback_result(r, 0)
+        });
+
+        let xhci_weak = Arc::downgrade(xhci);
+        xhci.regs.crcr.set_write_cb(move |val: u64| {
+            let xhci = xhci_weak.upgrade().unwrap();
+            let r = xhci.crcr_callback(val);
+            xhci.handle_register_callback_result(r, 0)
+        });
+
+        for i in 0..xhci.regs.portsc.len() {
+            let xhci_weak = Arc::downgrade(xhci);
+            xhci.regs.portsc[i].set_write_cb(move |val: u32| {
+                let xhci = xhci_weak.upgrade().unwrap();
+                let r = xhci.portsc_callback(i as u32, val);
+                xhci.handle_register_callback_result(r, 0)
+            });
+        }
+
+        for i in 0..xhci.regs.doorbells.len() {
+            let xhci_weak = Arc::downgrade(xhci);
+            xhci.regs.doorbells[i].set_write_cb(move |val: u32| {
+                let xhci = xhci_weak.upgrade().unwrap();
+                let r = xhci.doorbell_callback(i as u32, val);
+                xhci.handle_register_callback_result(r, ());
+                val
+            });
+        }
+
+        let xhci_weak = Arc::downgrade(xhci);
+        xhci.regs.iman.set_write_cb(move |val: u32| {
+            let xhci = xhci_weak.upgrade().unwrap();
+            let r = xhci.iman_callback(val);
+            xhci.handle_register_callback_result(r, ());
+            val
+        });
+
+        let xhci_weak = Arc::downgrade(xhci);
+        xhci.regs.imod.set_write_cb(move |val: u32| {
+            let xhci = xhci_weak.upgrade().unwrap();
+            let r = xhci.imod_callback(val);
+            xhci.handle_register_callback_result(r, ());
+            val
+        });
+
+        let xhci_weak = Arc::downgrade(xhci);
+        xhci.regs.erstsz.set_write_cb(move |val: u32| {
+            let xhci = xhci_weak.upgrade().unwrap();
+            let r = xhci.erstsz_callback(val);
+            xhci.handle_register_callback_result(r, ());
+            val
+        });
+
+        let xhci_weak = Arc::downgrade(xhci);
+        xhci.regs.erstba.set_write_cb(move |val: u64| {
+            let xhci = xhci_weak.upgrade().unwrap();
+            let r = xhci.erstba_callback(val);
+            xhci.handle_register_callback_result(r, ());
+            val
+        });
+
+        let xhci_weak = Arc::downgrade(xhci);
+        xhci.regs.erdp.set_write_cb(move |val: u64| {
+            let xhci = xhci_weak.upgrade().unwrap();
+            let r = xhci.erdp_callback(val);
+            xhci.handle_register_callback_result(r, ());
+            val
+        });
+    }
+
+    fn handle_register_callback_result<T>(&self, r: Result<T>, t: T) -> T {
+        match r {
+            Ok(v) => v,
+            Err(e) => {
+                error!("xhci controller failed: {}", e);
+                self.fail_handle.fail();
+                t
+            }
+        }
+    }
+
+    // Callback for usbcmd register write.
+    fn usbcmd_callback(&self, value: u32) -> Result<u32> {
+        if (value & USB_CMD_RESET) > 0 {
+            usb_debug!("xhci_controller: reset controller");
+            self.reset()?;
+            return Ok(value & (!USB_CMD_RESET));
+        }
+
+        if (value & USB_CMD_RUNSTOP) > 0 {
+            usb_debug!("xhci_controller: clear halt bits");
+            self.regs.usbsts.clear_bits(USB_STS_HALTED);
+        } else {
+            usb_debug!("xhci_controller: halt device");
+            self.halt()?;
+            self.regs.crcr.clear_bits(CRCR_COMMAND_RING_RUNNING);
+        }
+
+        // Enable interrupter if needed.
+        let enabled = (value & USB_CMD_INTERRUPTER_ENABLE) > 0
+            && (self.regs.iman.get_value() & IMAN_INTERRUPT_ENABLE) > 0;
+        usb_debug!("xhci_controller: interrupter enable?: {}", enabled);
+        self.interrupter
+            .lock()
+            .set_enabled(enabled)
+            .map_err(Error::EnableInterrupter)?;
+        Ok(value)
+    }
+
+    // Callback for crcr register write.
+    fn crcr_callback(&self, value: u64) -> Result<u64> {
+        usb_debug!("xhci_controller: write to crcr {:x}", value);
+        let value = if (self.regs.crcr.get_value() & CRCR_COMMAND_RING_RUNNING) == 0 {
+            self.command_ring_controller
+                .set_dequeue_pointer(GuestAddress(value & CRCR_COMMAND_RING_POINTER));
+            self.command_ring_controller
+                .set_consumer_cycle_state((value & CRCR_RING_CYCLE_STATE) > 0);
+            value
+        } else {
+            error!("Write to crcr while command ring is running");
+            self.regs.crcr.get_value()
+        };
+        Ok(value)
+    }
+
+    // Callback for portsc register write.
+    fn portsc_callback(&self, index: u32, value: u32) -> Result<u32> {
+        let mut value = value;
+        usb_debug!(
+            "xhci_controller: write to portsc index {} value {:x}",
+            index,
+            value
+        );
+        let port_id = (index + 1) as u8;
+        // xHCI spec 4.19.5. Note: we might want to change this logic if we support USB 3.0.
+        if (value & PORTSC_PORT_RESET) > 0 || (value & PORTSC_WARM_PORT_RESET) > 0 {
+            self.device_slots
+                .reset_port(port_id)
+                .map_err(|_| Error::ResetPort)?;
+            value &= !PORTSC_PORT_LINK_STATE_MASK;
+            value &= !PORTSC_PORT_RESET;
+            value |= PORTSC_PORT_ENABLED;
+            value |= PORTSC_PORT_RESET_CHANGE;
+            self.interrupter
+                .lock()
+                .send_port_status_change_trb(port_id)
+                .map_err(Error::SendInterrupt)?;
+        }
+        Ok(value)
+    }
+
+    // Callback for doorbell register write.
+    fn doorbell_callback(&self, index: u32, value: u32) -> Result<()> {
+        usb_debug!(
+            "xhci_controller: write to doorbell index {} value {:x}",
+            index,
+            value
+        );
+        let target = (value & DOORBELL_TARGET) as u8;
+        let stream_id: u16 = (value >> DOORBELL_STREAM_ID_OFFSET) as u16;
+        if (self.regs.usbcmd.get_value() & USB_CMD_RUNSTOP) > 0 {
+            // First doorbell is for command ring.
+            if index == 0 {
+                if target != 0 || stream_id != 0 {
+                    return Ok(());
+                }
+                usb_debug!("doorbell to command ring");
+                self.regs.crcr.set_bits(CRCR_COMMAND_RING_RUNNING);
+                self.command_ring_controller.start();
+            } else {
+                usb_debug!("doorbell to device slot");
+                self.device_slots
+                    .slot(index as u8)
+                    .ok_or(Error::GetDeviceSlot(index as u8))?
+                    .ring_doorbell(target, stream_id)
+                    .map_err(Error::RingDoorbell)?;
+            }
+        }
+        Ok(())
+    }
+
+    // Callback for iman register write.
+    fn iman_callback(&self, value: u32) -> Result<()> {
+        usb_debug!("xhci_controller: write to iman {:x}", value);
+        let enabled = ((value & IMAN_INTERRUPT_ENABLE) > 0)
+            && ((self.regs.usbcmd.get_value() & USB_CMD_INTERRUPTER_ENABLE) > 0);
+        self.interrupter
+            .lock()
+            .set_enabled(enabled)
+            .map_err(Error::EnableInterrupter)
+    }
+
+    // Callback for imod register write.
+    fn imod_callback(&self, value: u32) -> Result<()> {
+        usb_debug!("xhci_controller: write to imod {:x}", value);
+        self.interrupter
+            .lock()
+            .set_moderation(
+                (value & IMOD_INTERRUPT_MODERATION_INTERVAL) as u16,
+                (value >> IMOD_INTERRUPT_MODERATION_COUNTER_OFFSET) as u16,
+            )
+            .map_err(Error::SetModeration)
+    }
+
+    // Callback for erstsz register write.
+    fn erstsz_callback(&self, value: u32) -> Result<()> {
+        usb_debug!("xhci_controller: write to erstz {:x}", value);
+        self.interrupter
+            .lock()
+            .set_event_ring_seg_table_size((value & ERSTSZ_SEGMENT_TABLE_SIZE) as u16)
+            .map_err(Error::SetupEventRing)
+    }
+
+    // Callback for erstba register write.
+    fn erstba_callback(&self, value: u64) -> Result<()> {
+        usb_debug!("xhci_controller: write to erstba {:x}", value);
+        self.interrupter
+            .lock()
+            .set_event_ring_seg_table_base_addr(GuestAddress(
+                value & ERSTBA_SEGMENT_TABLE_BASE_ADDRESS,
+            ))
+            .map_err(Error::SetupEventRing)
+    }
+
+    // Callback for erdp register write.
+    fn erdp_callback(&self, value: u64) -> Result<()> {
+        usb_debug!("xhci_controller: write to erdp {:x}", value);
+        let mut interrupter = self.interrupter.lock();
+        interrupter
+            .set_event_ring_dequeue_pointer(GuestAddress(value & ERDP_EVENT_RING_DEQUEUE_POINTER))
+            .map_err(Error::SetupEventRing)?;
+        interrupter
+            .set_event_handler_busy((value & ERDP_EVENT_HANDLER_BUSY) > 0)
+            .map_err(Error::SetEventHandlerBusy)
+    }
+
+    fn reset(&self) -> Result<()> {
+        self.regs.usbsts.set_bits(USB_STS_CONTROLLER_NOT_READY);
+        let usbsts = self.regs.usbsts.clone();
+        self.device_slots.stop_all_and_reset(move || {
+            usbsts.clear_bits(USB_STS_CONTROLLER_NOT_READY);
+        });
+        Ok(())
+    }
+
+    fn halt(&self) -> Result<()> {
+        let usbsts = self.regs.usbsts.clone();
+        self.device_slots
+            .stop_all(RingBufferStopCallback::new(move || {
+                usbsts.set_bits(USB_STS_HALTED);
+            }));
+        Ok(())
+    }
+}
diff --git a/devices/src/usb/xhci/xhci_abi.rs b/devices/src/usb/xhci/xhci_abi.rs
new file mode 100644
index 0000000..5a8748e
--- /dev/null
+++ b/devices/src/usb/xhci/xhci_abi.rs
@@ -0,0 +1,929 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use bit_field::Error as BitFieldError;
+use bit_field::*;
+use data_model::DataInit;
+use std::fmt::{self, Display};
+use sys_util::GuestAddress;
+
+use std;
+
+#[derive(Debug)]
+pub enum Error {
+    UnknownTrbType(BitFieldError),
+    CannotCastTrb,
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            UnknownTrbType(e) => write!(f, "we got an unknown trb type value: {}", e),
+            CannotCastTrb => write!(f, "cannot cast trb from raw memory"),
+        }
+    }
+}
+
+// Fixed size of all TRB types.
+const TRB_SIZE: usize = 16;
+
+// Size of segment table.
+const SEGMENT_TABLE_SIZE: usize = 16;
+
+/// All kinds of trb.
+#[bitfield]
+#[bits = 6]
+#[derive(PartialEq, Debug, Clone, Copy)]
+pub enum TrbType {
+    Reserved = 0,
+    Normal = 1,
+    SetupStage = 2,
+    DataStage = 3,
+    StatusStage = 4,
+    Isoch = 5,
+    Link = 6,
+    EventData = 7,
+    Noop = 8,
+    EnableSlotCommand = 9,
+    DisableSlotCommand = 10,
+    AddressDeviceCommand = 11,
+    ConfigureEndpointCommand = 12,
+    EvaluateContextCommand = 13,
+    ResetEndpointCommand = 14,
+    StopEndpointCommand = 15,
+    SetTRDequeuePointerCommand = 16,
+    ResetDeviceCommand = 17,
+    NoopCommand = 23,
+    TransferEvent = 32,
+    CommandCompletionEvent = 33,
+    PortStatusChangeEvent = 34,
+}
+
+/// Completion code of trb types.
+#[bitfield]
+#[bits = 8]
+#[derive(PartialEq, Debug)]
+pub enum TrbCompletionCode {
+    Success = 1,
+    TransactionError = 4,
+    TrbError = 5,
+    NoSlotsAvailableError = 9,
+    SlotNotEnabledError = 11,
+    ShortPacket = 13,
+    ContextStateError = 19,
+}
+
+/// State of device slot.
+#[bitfield]
+#[bits = 5]
+#[derive(PartialEq, Debug)]
+pub enum DeviceSlotState {
+    // The same value (0) is used for both the enabled and disabled states. See
+    // xhci spec table 60.
+    DisabledOrEnabled = 0,
+    Default = 1,
+    Addressed = 2,
+    Configured = 3,
+}
+
+/// State of endpoint.
+#[bitfield]
+#[bits = 3]
+#[derive(PartialEq, Debug)]
+pub enum EndpointState {
+    Disabled = 0,
+    Running = 1,
+}
+
+#[bitfield]
+#[bits = 60]
+#[derive(PartialEq, Debug)]
+pub struct DequeuePtr(u64);
+
+impl DequeuePtr {
+    pub fn new(addr: GuestAddress) -> Self {
+        DequeuePtr(addr.0 >> 4)
+    }
+
+    // Get the guest physical address.
+    pub fn get_gpa(&self) -> GuestAddress {
+        GuestAddress(self.0 << 4)
+    }
+}
+
+// Generic TRB struct containing only fields common to all types.
+#[bitfield]
+#[derive(Clone, Copy, PartialEq)]
+pub struct Trb {
+    parameter: B64,
+    status: B32,
+    cycle: bool,
+    flags: B9,
+    trb_type: TrbType,
+    control: B16,
+}
+
+impl Trb {
+    fn fmt_helper(&self, f: &mut fmt::Formatter) -> Result<fmt::Result> {
+        match self.get_trb_type().map_err(Error::UnknownTrbType)? {
+            TrbType::Reserved => Ok(write!(f, "reserved trb type")),
+            TrbType::Normal => {
+                let t = self.cast::<NormalTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::SetupStage => {
+                let t = self.cast::<SetupStageTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::DataStage => {
+                let t = self.cast::<DataStageTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::StatusStage => {
+                let t = self.cast::<StatusStageTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::Isoch => {
+                let t = self.cast::<IsochTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::Link => {
+                let t = self.cast::<LinkTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::EventData => {
+                let t = self.cast::<EventDataTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::Noop => {
+                let t = self.cast::<NoopTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::EnableSlotCommand => Ok(write!(f, "trb: enable slot command {:?}", self)),
+            TrbType::DisableSlotCommand => {
+                let t = self.cast::<DisableSlotCommandTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::AddressDeviceCommand => {
+                let t = self.cast::<AddressDeviceCommandTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::ConfigureEndpointCommand => {
+                let t = self.cast::<ConfigureEndpointCommandTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::EvaluateContextCommand => {
+                let t = self.cast::<EvaluateContextCommandTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::ResetEndpointCommand => {
+                let t = self.cast::<ResetEndpointCommandTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::StopEndpointCommand => {
+                let t = self.cast::<StopEndpointCommandTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::SetTRDequeuePointerCommand => {
+                let t = self.cast::<SetTRDequeuePointerCommandTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::ResetDeviceCommand => {
+                let t = self.cast::<ResetDeviceCommandTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::NoopCommand => Ok(write!(f, "trb: noop command {:?}", self)),
+            TrbType::TransferEvent => {
+                let t = self.cast::<TransferEventTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::CommandCompletionEvent => {
+                let t = self.cast::<CommandCompletionEventTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+            TrbType::PortStatusChangeEvent => {
+                let t = self.cast::<PortStatusChangeEventTrb>()?;
+                Ok(write!(f, "trb: {:?}", t))
+            }
+        }
+    }
+}
+
+impl Display for Trb {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self.fmt_helper(f) {
+            Ok(f) => f,
+            Err(e) => write!(f, "fail to format trb {}", e),
+        }
+    }
+}
+
+impl Trb {
+    /// Get chain bit.
+    pub fn get_chain_bit(&self) -> Result<bool> {
+        Ok(match self.get_trb_type() {
+            Ok(TrbType::Normal) => self.cast::<NormalTrb>()?.get_chain(),
+            Ok(TrbType::DataStage) => self.cast::<DataStageTrb>()?.get_chain(),
+            Ok(TrbType::StatusStage) => self.cast::<StatusStageTrb>()?.get_chain(),
+            Ok(TrbType::Isoch) => self.cast::<IsochTrb>()?.get_chain(),
+            Ok(TrbType::Noop) => self.cast::<NoopTrb>()?.get_chain(),
+            Ok(TrbType::Link) => self.cast::<LinkTrb>()?.get_chain(),
+            Ok(TrbType::EventData) => self.cast::<EventDataTrb>()?.get_chain(),
+            _ => false,
+        })
+    }
+
+    /// Get interrupt target.
+    pub fn interrupter_target(&self) -> u8 {
+        const STATUS_INTERRUPTER_TARGET_OFFSET: u8 = 22;
+        (self.get_status() >> STATUS_INTERRUPTER_TARGET_OFFSET) as u8
+    }
+
+    /// Only some of trb types could appear in transfer ring.
+    pub fn can_be_in_transfer_ring(&self) -> Result<bool> {
+        match self.get_trb_type().map_err(Error::UnknownTrbType)? {
+            TrbType::Normal
+            | TrbType::SetupStage
+            | TrbType::DataStage
+            | TrbType::StatusStage
+            | TrbType::Isoch
+            | TrbType::Link
+            | TrbType::EventData
+            | TrbType::Noop => Ok(true),
+            _ => Ok(false),
+        }
+    }
+
+    /// Length of this transfer.
+    pub fn transfer_length(&self) -> Result<u32> {
+        const STATUS_TRANSFER_LENGTH_MASK: u32 = 0x1ffff;
+        match self.get_trb_type().map_err(Error::UnknownTrbType)? {
+            TrbType::Normal | TrbType::SetupStage | TrbType::DataStage | TrbType::Isoch => {
+                Ok(self.get_status() & STATUS_TRANSFER_LENGTH_MASK)
+            }
+            _ => Ok(0),
+        }
+    }
+
+    /// Returns true if interrupt is required on completion.
+    pub fn interrupt_on_completion(&self) -> bool {
+        const FLAGS_INTERRUPT_ON_COMPLETION_MASK: u16 = 0x10;
+        (self.get_flags() & FLAGS_INTERRUPT_ON_COMPLETION_MASK) > 0
+    }
+
+    /// Returns true if interrupt is required on transfer of short packet.
+    pub fn interrupt_on_short_packet(&self) -> bool {
+        const FLAGS_INTERRUPT_ON_SHORT_PACKET: u16 = 0x2;
+        (self.get_flags() & FLAGS_INTERRUPT_ON_SHORT_PACKET) > 0
+    }
+
+    /// Returns true if this trb is immediate data.
+    pub fn immediate_data(&self) -> Result<bool> {
+        const FLAGS_IMMEDIATE_DATA_MASK: u16 = 0x20;
+        match self.get_trb_type().map_err(Error::UnknownTrbType)? {
+            TrbType::Normal | TrbType::SetupStage | TrbType::DataStage | TrbType::Isoch => {
+                Ok((self.get_flags() & FLAGS_IMMEDIATE_DATA_MASK) != 0)
+            }
+            _ => Ok(false),
+        }
+    }
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct NormalTrb {
+    data_buffer: B64,
+    trb_transfer_length: B17,
+    td_size: B5,
+    interrupter_target: B10,
+    cycle: bool,
+    evaluate_next_trb: B1,
+    interrupt_on_short_packet: B1,
+    no_snoop: B1,
+    chain: bool,
+    interrupt_on_completion: B1,
+    immediate_data: B1,
+    reserved: B2,
+    block_event_interrupt: B1,
+    trb_type: TrbType,
+    reserved1: B16,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct SetupStageTrb {
+    request_type: B8,
+    request: B8,
+    value: B16,
+    index: B16,
+    length: B16,
+    trb_transfer_length: B17,
+    reserved0: B5,
+    interrupter_target: B10,
+    cycle: bool,
+    reserved1: B4,
+    interrupt_on_completion: B1,
+    immediate_data: B1,
+    reserved2: B3,
+    trb_type: TrbType,
+    transfer_type: B2,
+    reserved3: B14,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct DataStageTrb {
+    data_buffer_pointer: B64,
+    trb_transfer_length: B17,
+    td_size: B5,
+    interrupter_target: B10,
+    cycle: bool,
+    evaluate_next_trb: B1,
+    interrupt_on_short_packet: B1,
+    no_snoop: B1,
+    chain: bool,
+    interrupt_on_completion: B1,
+    immediate_data: B1,
+    reserved0: B3,
+    trb_type: TrbType,
+    direction: B1,
+    reserved1: B15,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct StatusStageTrb {
+    reserved0: B64,
+    reserved1: B22,
+    interrupter_target: B10,
+    cycle: bool,
+    evaluate_next_trb: B1,
+    reserved2: B2,
+    chain: bool,
+    interrupt_on_completion: B1,
+    reserved3: B4,
+    trb_type: TrbType,
+    direction: B1,
+    reserved4: B15,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct IsochTrb {
+    data_buffer_pointer: B64,
+    trb_transfer_length: B17,
+    td_size: B5,
+    interrupter_target: B10,
+    cycle: bool,
+    evaulate_nex_trb: B1,
+    interrupt_on_short_packet: B1,
+    no_snoop: B1,
+    chain: bool,
+    interrupt_on_completion: B1,
+    immediate_data: B1,
+    transfer_burst_count: B2,
+    block_event_interrupt: B1,
+    trb_type: TrbType,
+    tlbpc: B4,
+    frame_id: B11,
+    sia: B1,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct LinkTrb {
+    ring_segment_pointer: B64,
+    reserved0: B22,
+    interrupter_target: B10,
+    cycle: bool,
+    toggle_cycle: bool,
+    reserved1: B2,
+    chain: bool,
+    interrupt_on_completion: bool,
+    reserved2: B4,
+    trb_type: TrbType,
+    reserved3: B16,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct EventDataTrb {
+    event_data: B64,
+    reserved0: B22,
+    interrupter_target: B10,
+    cycle: bool,
+    evaluate_next_trb: B1,
+    reserved1: B2,
+    chain: bool,
+    interrupt_on_completion: B1,
+    reserved2: B3,
+    block_event_interrupt: B1,
+    trb_type: TrbType,
+    reserved3: B16,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct NoopTrb {
+    reserved0: B64,
+    reserved1: B22,
+    interrupter_target: B10,
+    cycle: bool,
+    evaluate_next_trb: B1,
+    reserved2: B2,
+    chain: bool,
+    interrupt_on_completion: B1,
+    reserved3: B4,
+    trb_type: TrbType,
+    reserved4: B16,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct DisableSlotCommandTrb {
+    reserved0: B32,
+    reserved1: B32,
+    reserved2: B32,
+    cycle: bool,
+    reserved3: B9,
+    trb_type: TrbType,
+    reserved4: B8,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct AddressDeviceCommandTrb {
+    input_context_pointer: B64,
+    reserved: B32,
+    cycle: bool,
+    reserved2: B8,
+    block_set_address_request: bool,
+    trb_type: TrbType,
+    reserved3: B8,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct ConfigureEndpointCommandTrb {
+    input_context_pointer: B64,
+    reserved0: B32,
+    cycle: bool,
+    reserved1: B8,
+    deconfigure: bool,
+    trb_type: TrbType,
+    reserved2: B8,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct EvaluateContextCommandTrb {
+    input_context_pointer: B64,
+    reserved0: B32,
+    cycle: bool,
+    reserved1: B9,
+    trb_type: TrbType,
+    reserved2: B8,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct ResetEndpointCommandTrb {
+    reserved0: B32,
+    reserved1: B32,
+    reserved2: B32,
+    cycle: bool,
+    reserved3: B8,
+    transfer_state_preserve: B1,
+    trb_type: TrbType,
+    endpoint_id: B5,
+    reserved4: B3,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct StopEndpointCommandTrb {
+    reserved0: B32,
+    reserved1: B32,
+    reserved2: B32,
+    cycle: bool,
+    reserved3: B9,
+    trb_type: TrbType,
+    endpoint_id: B5,
+    reserved4: B2,
+    suspend: B1,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct SetTRDequeuePointerCommandTrb {
+    dequeue_cycle_state: bool,
+    stream_context_type: B3,
+    dequeue_ptr: DequeuePtr,
+    reserved0: B16,
+    stream_id: B16,
+    cycle: bool,
+    reserved1: B9,
+    trb_type: TrbType,
+    endpoint_id: B5,
+    reserved3: B2,
+    suspend: B1,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct ResetDeviceCommandTrb {
+    reserved0: B32,
+    reserved1: B32,
+    reserved2: B32,
+    cycle: bool,
+    reserved3: B9,
+    trb_type: TrbType,
+    reserved4: B8,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct TransferEventTrb {
+    trb_pointer: B64,
+    trb_transfer_length: B24,
+    completion_code: TrbCompletionCode,
+    cycle: bool,
+    reserved0: B1,
+    event_data: B1,
+    reserved1: B7,
+    trb_type: TrbType,
+    endpoint_id: B5,
+    reserved2: B3,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct CommandCompletionEventTrb {
+    trb_pointer: B64,
+    command_completion_parameter: B24,
+    completion_code: TrbCompletionCode,
+    cycle: bool,
+    reserved: B9,
+    trb_type: TrbType,
+    vf_id: B8,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct PortStatusChangeEventTrb {
+    reserved0: B24,
+    port_id: B8,
+    reserved1: B32,
+    reserved2: B24,
+    completion_code: TrbCompletionCode,
+    cycle: bool,
+    reserved3: B9,
+    trb_type: TrbType,
+    reserved4: B16,
+}
+
+/// Associate real type of trb.
+pub trait TypedTrb {
+    const TY: TrbType;
+}
+
+impl TypedTrb for Trb {
+    const TY: TrbType = TrbType::Reserved;
+}
+
+impl TypedTrb for NormalTrb {
+    const TY: TrbType = TrbType::Normal;
+}
+
+impl TypedTrb for SetupStageTrb {
+    const TY: TrbType = TrbType::SetupStage;
+}
+
+impl TypedTrb for DataStageTrb {
+    const TY: TrbType = TrbType::DataStage;
+}
+
+impl TypedTrb for StatusStageTrb {
+    const TY: TrbType = TrbType::StatusStage;
+}
+
+impl TypedTrb for IsochTrb {
+    const TY: TrbType = TrbType::Isoch;
+}
+
+impl TypedTrb for LinkTrb {
+    const TY: TrbType = TrbType::Link;
+}
+
+impl TypedTrb for EventDataTrb {
+    const TY: TrbType = TrbType::EventData;
+}
+
+impl TypedTrb for NoopTrb {
+    const TY: TrbType = TrbType::Noop;
+}
+
+impl TypedTrb for DisableSlotCommandTrb {
+    const TY: TrbType = TrbType::DisableSlotCommand;
+}
+
+impl TypedTrb for AddressDeviceCommandTrb {
+    const TY: TrbType = TrbType::AddressDeviceCommand;
+}
+
+impl TypedTrb for ConfigureEndpointCommandTrb {
+    const TY: TrbType = TrbType::ConfigureEndpointCommand;
+}
+
+impl TypedTrb for EvaluateContextCommandTrb {
+    const TY: TrbType = TrbType::EvaluateContextCommand;
+}
+
+impl TypedTrb for ResetEndpointCommandTrb {
+    const TY: TrbType = TrbType::ResetEndpointCommand;
+}
+
+impl TypedTrb for StopEndpointCommandTrb {
+    const TY: TrbType = TrbType::StopEndpointCommand;
+}
+
+impl TypedTrb for SetTRDequeuePointerCommandTrb {
+    const TY: TrbType = TrbType::SetTRDequeuePointerCommand;
+}
+
+impl TypedTrb for ResetDeviceCommandTrb {
+    const TY: TrbType = TrbType::ResetDeviceCommand;
+}
+
+impl TypedTrb for TransferEventTrb {
+    const TY: TrbType = TrbType::TransferEvent;
+}
+
+impl TypedTrb for CommandCompletionEventTrb {
+    const TY: TrbType = TrbType::CommandCompletionEvent;
+}
+
+impl TypedTrb for PortStatusChangeEventTrb {
+    const TY: TrbType = TrbType::PortStatusChangeEvent;
+}
+
+/// All trb structs have the same size. One trb could be safely casted to another, though the
+/// values might be invalid.
+pub unsafe trait TrbCast: DataInit + TypedTrb {
+    fn cast<T: TrbCast>(&self) -> Result<&T> {
+        T::from_slice(self.as_slice()).ok_or(Error::CannotCastTrb)
+    }
+
+    fn cast_mut<T: TrbCast>(&mut self) -> Result<&mut T> {
+        T::from_mut_slice(self.as_mut_slice()).ok_or(Error::CannotCastTrb)
+    }
+
+    fn checked_cast<T: TrbCast>(&self) -> Result<&T> {
+        if Trb::from_slice(self.as_slice())
+            .ok_or(Error::CannotCastTrb)?
+            .get_trb_type()
+            .map_err(Error::UnknownTrbType)?
+            != T::TY
+        {
+            return Err(Error::CannotCastTrb);
+        }
+        T::from_slice(self.as_slice()).ok_or(Error::CannotCastTrb)
+    }
+
+    fn checked_mut_cast<T: TrbCast>(&mut self) -> Result<&mut T> {
+        if Trb::from_slice(self.as_slice())
+            .ok_or(Error::CannotCastTrb)?
+            .get_trb_type()
+            .map_err(Error::UnknownTrbType)?
+            != T::TY
+        {
+            return Err(Error::CannotCastTrb);
+        }
+        T::from_mut_slice(self.as_mut_slice()).ok_or(Error::CannotCastTrb)
+    }
+}
+
+unsafe impl DataInit for Trb {}
+unsafe impl DataInit for NormalTrb {}
+unsafe impl DataInit for SetupStageTrb {}
+unsafe impl DataInit for DataStageTrb {}
+unsafe impl DataInit for StatusStageTrb {}
+unsafe impl DataInit for IsochTrb {}
+unsafe impl DataInit for LinkTrb {}
+unsafe impl DataInit for EventDataTrb {}
+unsafe impl DataInit for NoopTrb {}
+unsafe impl DataInit for DisableSlotCommandTrb {}
+unsafe impl DataInit for AddressDeviceCommandTrb {}
+unsafe impl DataInit for ConfigureEndpointCommandTrb {}
+unsafe impl DataInit for EvaluateContextCommandTrb {}
+unsafe impl DataInit for ResetEndpointCommandTrb {}
+unsafe impl DataInit for StopEndpointCommandTrb {}
+unsafe impl DataInit for SetTRDequeuePointerCommandTrb {}
+unsafe impl DataInit for ResetDeviceCommandTrb {}
+unsafe impl DataInit for TransferEventTrb {}
+unsafe impl DataInit for CommandCompletionEventTrb {}
+unsafe impl DataInit for PortStatusChangeEventTrb {}
+unsafe impl DataInit for EventRingSegmentTableEntry {}
+unsafe impl DataInit for InputControlContext {}
+unsafe impl DataInit for SlotContext {}
+unsafe impl DataInit for EndpointContext {}
+
+unsafe impl DataInit for DeviceContext {}
+unsafe impl DataInit for AddressedTrb {}
+
+unsafe impl TrbCast for Trb {}
+unsafe impl TrbCast for NormalTrb {}
+unsafe impl TrbCast for SetupStageTrb {}
+unsafe impl TrbCast for DataStageTrb {}
+unsafe impl TrbCast for StatusStageTrb {}
+unsafe impl TrbCast for IsochTrb {}
+unsafe impl TrbCast for LinkTrb {}
+unsafe impl TrbCast for EventDataTrb {}
+unsafe impl TrbCast for NoopTrb {}
+unsafe impl TrbCast for DisableSlotCommandTrb {}
+unsafe impl TrbCast for AddressDeviceCommandTrb {}
+unsafe impl TrbCast for ConfigureEndpointCommandTrb {}
+unsafe impl TrbCast for EvaluateContextCommandTrb {}
+unsafe impl TrbCast for ResetEndpointCommandTrb {}
+unsafe impl TrbCast for StopEndpointCommandTrb {}
+unsafe impl TrbCast for SetTRDequeuePointerCommandTrb {}
+unsafe impl TrbCast for ResetDeviceCommandTrb {}
+unsafe impl TrbCast for TransferEventTrb {}
+unsafe impl TrbCast for CommandCompletionEventTrb {}
+unsafe impl TrbCast for PortStatusChangeEventTrb {}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct EventRingSegmentTableEntry {
+    ring_segment_base_address: B64,
+    ring_segment_size: B16,
+    reserved2: B48,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct InputControlContext {
+    // Xhci spec 6.2.5.1.
+    drop_context_flags: B32,
+    add_context_flags: B32,
+    reserved0: B32,
+    reserved1: B32,
+    reserved2: B32,
+    reserved3: B32,
+    reserved4: B32,
+    configuration_value: B8,
+    interface_number: B8,
+    alternate_setting: B8,
+    reserved5: B8,
+}
+
+impl InputControlContext {
+    /// Get drop context flag.
+    pub fn drop_context_flag(&self, idx: u8) -> bool {
+        (self.get_drop_context_flags() & (1 << idx)) != 0
+    }
+
+    /// Get add context flag.
+    pub fn add_context_flag(&self, idx: u8) -> bool {
+        (self.get_add_context_flags() & (1 << idx)) != 0
+    }
+}
+
+// Size of device context entries (SlotContext and EndpointContext).
+pub const DEVICE_CONTEXT_ENTRY_SIZE: usize = 32usize;
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct SlotContext {
+    route_string: B20,
+    speed: B4,
+    reserved1: B1,
+    mtt: B1,
+    hub: B1,
+    context_entries: B5,
+    max_exit_latency: B16,
+    root_hub_port_number: B8,
+    num_ports: B8,
+    tt_hub_slot_id: B8,
+    tt_port_number: B8,
+    tt_think_time: B2,
+    reserved2: B4,
+    interrupter_target: B10,
+    usb_device_address: B8,
+    reserved3: B19,
+    slot_state: DeviceSlotState,
+    reserved4: B32,
+    reserved5: B32,
+    reserved6: B32,
+    reserved7: B32,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct EndpointContext {
+    endpoint_state: EndpointState,
+    reserved1: B5,
+    mult: B2,
+    max_primary_streams: B5,
+    linear_stream_array: B1,
+    interval: B8,
+    max_esit_payload_hi: B8,
+    reserved2: B1,
+    error_count: B2,
+    endpoint_type: B3,
+    reserved3: B1,
+    host_initiate_disable: B1,
+    max_burst_size: B8,
+    max_packet_size: B16,
+    dequeue_cycle_state: bool,
+    reserved4: B3,
+    tr_dequeue_pointer: DequeuePtr,
+    average_trb_length: B16,
+    max_esit_payload_lo: B16,
+    reserved5: B32,
+    reserved6: B32,
+    reserved7: B32,
+}
+
+/// Device context.
+#[derive(Clone, Copy, Debug)]
+pub struct DeviceContext {
+    pub slot_context: SlotContext,
+    pub endpoint_context: [EndpointContext; 31],
+}
+
+/// POD struct associates a TRB with its address in guest memory.  This is
+/// useful because transfer and command completion event TRBs must contain
+/// pointers to the original TRB that generated the event.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct AddressedTrb {
+    pub trb: Trb,
+    pub gpa: u64,
+}
+
+pub type TransferDescriptor = Vec<AddressedTrb>;
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn check_struct_sizes() {
+        assert_eq!(std::mem::size_of::<Trb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<NormalTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<SetupStageTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<DataStageTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<StatusStageTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<IsochTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<LinkTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<EventDataTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<NoopTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<DisableSlotCommandTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<AddressDeviceCommandTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<ConfigureEndpointCommandTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<EvaluateContextCommandTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<ResetEndpointCommandTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<StopEndpointCommandTrb>(), TRB_SIZE);
+        assert_eq!(
+            std::mem::size_of::<SetTRDequeuePointerCommandTrb>(),
+            TRB_SIZE
+        );
+        assert_eq!(std::mem::size_of::<ResetDeviceCommandTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<TransferEventTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<CommandCompletionEventTrb>(), TRB_SIZE);
+        assert_eq!(std::mem::size_of::<PortStatusChangeEventTrb>(), TRB_SIZE);
+
+        assert_eq!(
+            std::mem::size_of::<EventRingSegmentTableEntry>(),
+            SEGMENT_TABLE_SIZE
+        );
+        assert_eq!(std::mem::size_of::<InputControlContext>(), 32);
+        assert_eq!(
+            std::mem::size_of::<SlotContext>(),
+            DEVICE_CONTEXT_ENTRY_SIZE
+        );
+        assert_eq!(
+            std::mem::size_of::<EndpointContext>(),
+            DEVICE_CONTEXT_ENTRY_SIZE
+        );
+        assert_eq!(
+            std::mem::size_of::<DeviceContext>(),
+            32 * DEVICE_CONTEXT_ENTRY_SIZE
+        );
+    }
+}
diff --git a/devices/src/usb/xhci/xhci_backend_device.rs b/devices/src/usb/xhci/xhci_backend_device.rs
new file mode 100644
index 0000000..e104cdc
--- /dev/null
+++ b/devices/src/usb/xhci/xhci_backend_device.rs
@@ -0,0 +1,35 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::xhci_transfer::XhciTransfer;
+
+/// Address of this usb device, as in Set Address standard usb device request.
+pub type UsbDeviceAddress = u32;
+
+/// The type USB device provided by the backend device.
+#[derive(PartialEq, Eq)]
+pub enum BackendType {
+    Usb2,
+    Usb3,
+}
+
+/// Xhci backend device is a virtual device connected to xHCI controller. It handles xhci transfers.
+pub trait XhciBackendDevice: Send {
+    /// Returns the type of USB device provided by this device.
+    fn get_backend_type(&self) -> BackendType;
+    /// Returns host bus number of this device.
+    fn host_bus(&self) -> u8;
+    /// Returns host address of this device.
+    fn host_address(&self) -> u8;
+    /// Get vendor id of this device.
+    fn get_vid(&self) -> u16;
+    /// Get product id of this device.
+    fn get_pid(&self) -> u16;
+    /// Submit a xhci transfer to backend.
+    fn submit_transfer(&mut self, transfer: XhciTransfer) -> std::result::Result<(), ()>;
+    /// Set address of this backend.
+    fn set_address(&mut self, address: UsbDeviceAddress);
+    /// Reset the backend device.
+    fn reset(&mut self) -> std::result::Result<(), ()>;
+}
diff --git a/devices/src/usb/xhci/xhci_backend_device_provider.rs b/devices/src/usb/xhci/xhci_backend_device_provider.rs
new file mode 100644
index 0000000..c014d77
--- /dev/null
+++ b/devices/src/usb/xhci/xhci_backend_device_provider.rs
@@ -0,0 +1,22 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::usb_hub::UsbHub;
+use crate::utils::{EventLoop, FailHandle};
+use std::os::unix::io::RawFd;
+use std::sync::Arc;
+
+/// Xhci backend provider will run on an EventLoop and connect new devices to usb ports.
+pub trait XhciBackendDeviceProvider: Send {
+    /// Start the provider on EventLoop.
+    fn start(
+        &mut self,
+        fail_handle: Arc<dyn FailHandle>,
+        event_loop: Arc<EventLoop>,
+        hub: Arc<UsbHub>,
+    ) -> std::result::Result<(), ()>;
+
+    /// Keep fds that should be kept open.
+    fn keep_fds(&self) -> Vec<RawFd>;
+}
diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs
new file mode 100644
index 0000000..76e1d4a
--- /dev/null
+++ b/devices/src/usb/xhci/xhci_controller.rs
@@ -0,0 +1,283 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::pci::{
+    PciBarConfiguration, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType,
+    PciInterruptPin, PciProgrammingInterface, PciSerialBusSubClass,
+};
+use crate::register_space::{Register, RegisterSpace};
+use crate::usb::host_backend::host_backend_device_provider::HostBackendDeviceProvider;
+use crate::usb::xhci::xhci::Xhci;
+use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
+use crate::usb::xhci::xhci_regs::{init_xhci_mmio_space_and_regs, XhciRegs};
+use crate::utils::FailHandle;
+use resources::{Alloc, SystemAllocator};
+use std::mem;
+use std::os::unix::io::RawFd;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::Arc;
+use sys_util::{error, EventFd, GuestMemory};
+
+const XHCI_BAR0_SIZE: u64 = 0x10000;
+
+#[derive(Clone, Copy)]
+enum UsbControllerProgrammingInterface {
+    Usb3HostController = 0x30,
+}
+
+impl PciProgrammingInterface for UsbControllerProgrammingInterface {
+    fn get_register_value(&self) -> u8 {
+        *self as u8
+    }
+}
+
+/// Use this handle to fail xhci controller.
+pub struct XhciFailHandle {
+    usbcmd: Register<u32>,
+    usbsts: Register<u32>,
+    xhci_failed: AtomicBool,
+}
+
+impl XhciFailHandle {
+    pub fn new(regs: &XhciRegs) -> XhciFailHandle {
+        XhciFailHandle {
+            usbcmd: regs.usbcmd.clone(),
+            usbsts: regs.usbsts.clone(),
+            xhci_failed: AtomicBool::new(false),
+        }
+    }
+}
+
+impl FailHandle for XhciFailHandle {
+    /// Fail this controller. Will set related registers and flip failed bool.
+    fn fail(&self) {
+        // set run/stop to stop.
+        const USBCMD_STOPPED: u32 = 0;
+        // Set host system error bit.
+        const USBSTS_HSE: u32 = 1 << 2;
+        self.usbcmd.set_value(USBCMD_STOPPED);
+        self.usbsts.set_value(USBSTS_HSE);
+
+        self.xhci_failed.store(true, Ordering::SeqCst);
+        error!("xhci controller stopped working");
+    }
+
+    /// Returns true if xhci is already failed.
+    fn failed(&self) -> bool {
+        self.xhci_failed.load(Ordering::SeqCst)
+    }
+}
+
+// Xhci controller should be created with backend device provider. Then irq should be assigned
+// before initialized. We are not making `failed` as a state here to optimize performance. Cause we
+// need to set failed in other threads.
+enum XhciControllerState {
+    Unknown,
+    Created {
+        device_provider: HostBackendDeviceProvider,
+    },
+    IrqAssigned {
+        device_provider: HostBackendDeviceProvider,
+        irq_evt: EventFd,
+        irq_resample_evt: EventFd,
+    },
+    Initialized {
+        mmio: RegisterSpace,
+        // Xhci init could fail.
+        #[allow(dead_code)]
+        xhci: Option<Arc<Xhci>>,
+        fail_handle: Arc<dyn FailHandle>,
+    },
+}
+
+/// xHCI PCI interface implementation.
+pub struct XhciController {
+    config_regs: PciConfiguration,
+    pci_bus_dev: Option<(u8, u8)>,
+    mem: GuestMemory,
+    bar0: u64, // bar0 in config_regs will be changed by guest. Not sure why.
+    state: XhciControllerState,
+}
+
+impl XhciController {
+    /// Create new xhci controller.
+    pub fn new(mem: GuestMemory, usb_provider: HostBackendDeviceProvider) -> Self {
+        let config_regs = PciConfiguration::new(
+            0x01b73, // fresco logic, (google = 0x1ae0)
+            0x1000,  // fresco logic pdk. This chip has broken msi. See kernel xhci-pci.c
+            PciClassCode::SerialBusController,
+            &PciSerialBusSubClass::USB,
+            Some(&UsbControllerProgrammingInterface::Usb3HostController),
+            PciHeaderType::Device,
+            0,
+            0,
+        );
+        XhciController {
+            config_regs,
+            pci_bus_dev: None,
+            mem,
+            bar0: 0,
+            state: XhciControllerState::Created {
+                device_provider: usb_provider,
+            },
+        }
+    }
+
+    /// Init xhci controller when it's forked.
+    pub fn init_when_forked(&mut self) {
+        match mem::replace(&mut self.state, XhciControllerState::Unknown) {
+            XhciControllerState::IrqAssigned {
+                device_provider,
+                irq_evt,
+                irq_resample_evt,
+            } => {
+                let (mmio, regs) = init_xhci_mmio_space_and_regs();
+                let fail_handle: Arc<dyn FailHandle> = Arc::new(XhciFailHandle::new(&regs));
+                let xhci = match Xhci::new(
+                    fail_handle.clone(),
+                    self.mem.clone(),
+                    device_provider,
+                    irq_evt,
+                    irq_resample_evt,
+                    regs,
+                ) {
+                    Ok(xhci) => Some(xhci),
+                    Err(_) => {
+                        error!("fail to init xhci");
+                        fail_handle.fail();
+                        return;
+                    }
+                };
+
+                self.state = XhciControllerState::Initialized {
+                    mmio,
+                    xhci,
+                    fail_handle,
+                }
+            }
+            _ => {
+                error!("xhci controller is in a wrong state");
+                return;
+            }
+        }
+    }
+}
+
+impl PciDevice for XhciController {
+    fn debug_label(&self) -> String {
+        "xhci controller".to_owned()
+    }
+
+    fn assign_bus_dev(&mut self, bus: u8, device: u8) {
+        self.pci_bus_dev = Some((bus, device));
+    }
+
+    fn keep_fds(&self) -> Vec<RawFd> {
+        match &self.state {
+            XhciControllerState::Created { device_provider } => device_provider.keep_fds(),
+            _ => {
+                error!("xhci controller is in a wrong state");
+                vec![]
+            }
+        }
+    }
+
+    fn assign_irq(
+        &mut self,
+        irq_evt: EventFd,
+        irq_resample_evt: EventFd,
+        irq_num: u32,
+        irq_pin: PciInterruptPin,
+    ) {
+        match mem::replace(&mut self.state, XhciControllerState::Unknown) {
+            XhciControllerState::Created { device_provider } => {
+                self.config_regs.set_irq(irq_num as u8, irq_pin);
+                self.state = XhciControllerState::IrqAssigned {
+                    device_provider,
+                    irq_evt,
+                    irq_resample_evt,
+                }
+            }
+            _ => {
+                error!("xhci controller is in a wrong state");
+                return;
+            }
+        }
+    }
+
+    fn allocate_io_bars(
+        &mut self,
+        resources: &mut SystemAllocator,
+    ) -> std::result::Result<Vec<(u64, u64)>, PciDeviceError> {
+        let (bus, dev) = self
+            .pci_bus_dev
+            .expect("assign_bus_dev must be called prior to allocate_io_bars");
+        // xHCI spec 5.2.1.
+        let bar0_addr = resources
+            .mmio_allocator()
+            .allocate(
+                XHCI_BAR0_SIZE,
+                Alloc::PciBar { bus, dev, bar: 0 },
+                "xhci_bar0".to_string(),
+            )
+            .map_err(|e| PciDeviceError::IoAllocationFailed(XHCI_BAR0_SIZE, e))?;
+        let bar0_config = PciBarConfiguration::default()
+            .set_register_index(0)
+            .set_address(bar0_addr)
+            .set_size(XHCI_BAR0_SIZE);
+        self.config_regs
+            .add_pci_bar(&bar0_config)
+            .map_err(|e| PciDeviceError::IoRegistrationFailed(bar0_addr, e))?;
+        self.bar0 = bar0_addr;
+        Ok(vec![(bar0_addr, XHCI_BAR0_SIZE)])
+    }
+
+    fn config_registers(&self) -> &PciConfiguration {
+        &self.config_regs
+    }
+
+    fn config_registers_mut(&mut self) -> &mut PciConfiguration {
+        &mut self.config_regs
+    }
+
+    fn read_bar(&mut self, addr: u64, data: &mut [u8]) {
+        let bar0 = self.bar0;
+        if addr < bar0 || addr > bar0 + XHCI_BAR0_SIZE {
+            return;
+        }
+        match &self.state {
+            XhciControllerState::Initialized { mmio, .. } => {
+                // Read bar would still work even if it's already failed.
+                mmio.read(addr - bar0, data);
+            }
+            _ => {
+                error!("xhci controller is in a wrong state");
+                return;
+            }
+        }
+    }
+
+    fn write_bar(&mut self, addr: u64, data: &[u8]) {
+        let bar0 = self.bar0;
+        if addr < bar0 || addr > bar0 + XHCI_BAR0_SIZE {
+            return;
+        }
+        match &self.state {
+            XhciControllerState::Initialized {
+                mmio, fail_handle, ..
+            } => {
+                if !fail_handle.failed() {
+                    mmio.write(addr - bar0, data);
+                }
+            }
+            _ => {
+                error!("xhci controller is in a wrong state");
+                return;
+            }
+        }
+    }
+    fn on_device_sandboxed(&mut self) {
+        self.init_when_forked();
+    }
+}
diff --git a/devices/src/usb/xhci/xhci_regs.rs b/devices/src/usb/xhci/xhci_regs.rs
new file mode 100644
index 0000000..810c44e
--- /dev/null
+++ b/devices/src/usb/xhci/xhci_regs.rs
@@ -0,0 +1,532 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::register_space::{Register, RegisterSpace};
+
+/// Max interrupter number.
+pub const MAX_INTERRUPTER: u8 = 1;
+/// For port configuration, see register HCSPARAMS1, spcap1.3 and spcap2.3.
+pub const MAX_SLOTS: u8 = 16;
+
+/// Usb 2 ports start from port number 0.
+pub const USB2_PORTS_START: u8 = 0;
+/// Last usb 2 ports is 7.
+pub const USB2_PORTS_END: u8 = 8;
+/// Usb 3 ports start from port number 8.
+pub const USB3_PORTS_START: u8 = 8;
+/// Last usb 3 port is 15.
+pub const USB3_PORTS_END: u8 = 16;
+
+/// Max port number. Review the following before changing this:
+///     HCSPARAMS1, portsc, spcap1.3 and spcap2.3.
+pub const MAX_PORTS: u8 = USB3_PORTS_END;
+
+/// Cap register length.
+pub const XHCI_CAPLENGTH: u8 = 0x20;
+/// Offset for doorbell register.
+pub const XHCI_DBOFF: u32 = 0x00002000;
+/// Offset for RTs.
+pub const XHCI_RTSOFF: u32 = 0x00003000;
+
+/// Bitmask for the usbcmd register, see spec 5.4.1.
+pub const USB_CMD_RUNSTOP: u32 = 1u32 << 0;
+/// Bitmask for the usbcmd register, see spec 5.4.1.
+pub const USB_CMD_RESET: u32 = 1u32 << 1;
+/// Bitmask for the usbcmd register, see spec 5.4.1.
+pub const USB_CMD_INTERRUPTER_ENABLE: u32 = 1u32 << 2;
+
+/// Bitmask for the usbsts register, see spec 5.4.2.
+pub const USB_STS_HALTED: u32 = 1u32 << 0;
+/// Bitmask for the usbsts register, see spec 5.4.2.
+pub const USB_STS_EVENT_INTERRUPT: u32 = 1u32 << 3;
+/// Bitmask for the usbsts register, see spec 5.4.2.
+pub const USB_STS_PORT_CHANGE_DETECT: u32 = 1u32 << 4;
+/// Bitmask for the usbsts register, see spec 5.4.2.
+pub const USB_STS_CONTROLLER_NOT_READY: u32 = 1u32 << 11;
+/// Bitmask for the usbsts register, see spec 5.4.2.
+pub const USB_STS_SET_TO_CLEAR_MASK: u32 = 0x0000041C;
+
+/// Bitmask for the crcr register, see spec 5.4.5.
+pub const CRCR_RING_CYCLE_STATE: u64 = 1u64 << 0;
+/// Bitmask for the crcr register, see spec 5.4.5.
+pub const CRCR_COMMAND_STOP: u64 = 1u64 << 1;
+/// Bitmask for the crcr register, see spec 5.4.5.
+pub const CRCR_COMMAND_ABORT: u64 = 1u64 << 2;
+/// Bitmask for the crcr register, see spec 5.4.5.
+pub const CRCR_COMMAND_RING_RUNNING: u64 = 1u64 << 3;
+/// Bitmask for the crcr register, see spec 5.4.5.
+pub const CRCR_COMMAND_RING_POINTER: u64 = 0xFFFFFFFFFFFFFFC0;
+
+/// Bitmask for portsc register, see spec 5.4.8.
+pub const PORTSC_CURRENT_CONNECT_STATUS: u32 = 1u32 << 0;
+/// Bitmask for portsc register, see spec 5.4.8.
+pub const PORTSC_PORT_ENABLED: u32 = 1u32 << 1;
+/// Bitmask for portsc register, see spec 5.4.8.
+pub const PORTSC_PORT_RESET: u32 = 1u32 << 4;
+/// Bitmask for portsc register, see spec 5.4.8.
+pub const PORTSC_PORT_LINK_STATE_MASK: u32 = 0x000001E0;
+/// Bitmask for portsc register, see spec 5.4.8.
+pub const PORTSC_PORT_POWER: u32 = 1u32 << 9;
+/// Bitmask for portsc register, see spec 5.4.8.
+pub const PORTSC_CONNECT_STATUS_CHANGE: u32 = 1u32 << 17;
+/// Bitmask for portsc register, see spec 5.4.8.
+pub const PORTSC_PORT_ENABLED_DISABLED_CHANGE: u32 = 1u32 << 18;
+/// Bitmask for portsc register, see spec 5.4.8.
+pub const PORTSC_PORT_RESET_CHANGE: u32 = 1u32 << 21;
+/// Bitmask for portsc register, see spec 5.4.8.
+pub const PORTSC_WARM_PORT_RESET: u32 = 1u32 << 31;
+/// Bitmask for portsc register, see spec 5.4.8.
+pub const PORTSC_SET_TO_CLEAR_MASK: u32 = 0x00FE0002;
+
+/// Bitmask for iman registers, see spec 5.5.2.1.
+pub const IMAN_INTERRUPT_PENDING: u32 = 1u32 << 0;
+/// Bitmask for iman registers, see spec 5.5.2.1.
+pub const IMAN_INTERRUPT_ENABLE: u32 = 1u32 << 1;
+/// Bitmask for iman registers, see spec 5.5.2.1.
+pub const IMAN_SET_TO_CLEAR_MASK: u32 = 0x00000001;
+
+/// Bitmask for imod registers, see spec 5.5.2.2.
+pub const IMOD_INTERRUPT_MODERATION_INTERVAL: u32 = 0xFFFF;
+/// Bitmask for imod registers, see spec 5.5.2.2.
+pub const IMOD_INTERRUPT_MODERATION_COUNTER_OFFSET: u8 = 16;
+
+/// Bitmask for erstsz registers, see 5.5.2.3.
+pub const ERSTSZ_SEGMENT_TABLE_SIZE: u32 = 0xFFFF;
+
+/// Bitmask for erstba registers, see 5.5.2.3.
+pub const ERSTBA_SEGMENT_TABLE_BASE_ADDRESS: u64 = 0xFFFFFFFFFFFFFFC0;
+
+/// Bitmask for erdp registers, see 5.5.2.3.
+pub const ERDP_EVENT_HANDLER_BUSY: u64 = 1u64 << 3;
+/// Bitmask for erdp registers, see 5.5.2.3.
+pub const ERDP_EVENT_RING_DEQUEUE_POINTER: u64 = 0xFFFFFFFFFFFFFFF0;
+/// Bitmask for erdp registers, see 5.5.2.3.
+pub const ERDP_SET_TO_CLEAR_MASK: u64 = 0x0000000000000008;
+
+/// Bitmask for doorbell registers.
+pub const DOORBELL_TARGET: u32 = 0xFF;
+/// Offset of stream id.
+pub const DOORBELL_STREAM_ID_OFFSET: u32 = 16;
+
+/// Bitmask for structural parameter registers.
+pub const HCSPARAMS1_MAX_INTERRUPTERS_MASK: u32 = 0x7FF00;
+/// Offset of max interrupters.
+pub const HCSPARAMS1_MAX_INTERRUPTERS_OFFSET: u32 = 8;
+/// Mask to get max slots.
+pub const HCSPARAMS1_MAX_SLOTS_MASK: u32 = 0xFF;
+
+/// Bitmask for extended capabilities registers.
+pub const SPCAP_PORT_COUNT_MASK: u32 = 0xFF00;
+/// Offset of port count.
+pub const SPCAP_PORT_COUNT_OFFSET: u32 = 8;
+
+/// Helper function for validating slot_id.
+pub fn valid_slot_id(slot_id: u8) -> bool {
+    // slot id count from 1.
+    slot_id > 0 && slot_id <= MAX_SLOTS
+}
+
+/// XhciRegs hold all xhci registers.
+pub struct XhciRegs {
+    pub usbcmd: Register<u32>,
+    pub usbsts: Register<u32>,
+    pub dnctrl: Register<u32>,
+    pub crcr: Register<u64>,
+    pub dcbaap: Register<u64>,
+    pub config: Register<u64>,
+    pub portsc: Vec<Register<u32>>,
+    pub doorbells: Vec<Register<u32>>,
+    pub iman: Register<u32>,
+    pub imod: Register<u32>,
+    pub erstsz: Register<u32>,
+    pub erstba: Register<u64>,
+    pub erdp: Register<u64>,
+}
+
+/// This function returns mmio space definition for xhci. See Xhci spec chapter 5
+/// for details.
+pub fn init_xhci_mmio_space_and_regs() -> (RegisterSpace, XhciRegs) {
+    let mut mmio = RegisterSpace::new();
+
+    /* Host Controller Capability Registers */
+    mmio.add_register(
+        // CAPLENGTH
+        static_register!(
+        ty: u8,
+        offset: 0x00,
+        value: XHCI_CAPLENGTH, // Operation register start at offset 0x20
+        ),
+    );
+    mmio.add_register(
+        // HCIVERSION
+        static_register!(
+        ty: u16,
+        offset: 0x02,
+        value: 0x0110,// Revision 1.1
+        ),
+    );
+    mmio.add_register(
+        // HCSPARAMS1
+        static_register!(
+        ty: u32,
+        offset: 0x04,
+        value: 0x10000110, // max_slots = 16, max_interrupters = 1, max_ports = 16
+        ),
+    );
+
+    mmio.add_register(
+        // HCSPARAMS2
+        static_register!(
+        ty: u32,
+        offset: 0x08,
+        // Maximum number of event ring segment table entries = 32k
+        // No scratchpad buffers.
+        value: 0xf0,
+        ),
+    );
+
+    mmio.add_register(
+        // HCSPARAM3
+        static_register!(
+        ty: u32,
+        offset: 0x0c,
+
+        // Exit latencies for U1 (standby with fast exit) and U2 (standby with
+        // slower exit) power states. We use the max values:
+        // - U1 to U0: < 10 us
+        // - U2 to U1: < 2047 us
+        value: 0x07FF000A,
+        ),
+    );
+
+    mmio.add_register(
+        // HCCPARAMS1
+        static_register!(
+        ty: u32,
+        offset: 0x10,
+        // Supports 64 bit addressing
+        // Max primary stream array size = 0 (streams not supported).
+        // Extended capabilities pointer = 0xC000 offset from base.
+        value: 0x30000501,
+        ),
+    );
+    mmio.add_register(
+        // DBOFF
+        static_register!(
+        ty: u32,
+        offset: 0x14,
+        value: XHCI_DBOFF, // Doorbell array offset 0x2000 from base.
+        ),
+    );
+
+    mmio.add_register(
+        // RTSOFF
+        static_register!(
+        ty: u32,
+        offset: 0x18,
+        value: XHCI_RTSOFF, // Runtime registers offset 0x3000 from base.
+        ),
+    );
+
+    mmio.add_register(
+        // HCCPARAMS2
+        static_register!(
+        ty: u32,
+        offset: 0x1c,
+        value: 0,
+        ),
+    );
+    /* End of Host Controller Capability Registers */
+
+    /* Host Controller Operational Registers */
+    let usbcmd = register!(
+        name: "usbcmd",
+        ty: u32,
+        offset: 0x20,
+        reset_value: 0,
+        guest_writeable_mask: 0x00002F0F,
+        guest_write_1_to_clear_mask: 0,
+    );
+    mmio.add_register(usbcmd.clone());
+
+    let usbsts = register!(
+        name: "usbsts",
+        ty: u32,
+        offset: 0x24,
+        reset_value: 0x00000001,
+        guest_writeable_mask: 0x0000041C,
+        guest_write_1_to_clear_mask: 0x0000041C,
+    );
+    mmio.add_register(usbsts.clone());
+
+    mmio.add_register(
+        //  Pagesize
+        static_register!(
+        ty: u32,
+        offset: 0x28,
+        value: 0x00000001,
+        ),
+    );
+
+    let dnctrl = register!(
+        name: "dnctrl",
+        ty: u32,
+        offset: 0x34,
+        reset_value: 0,
+        guest_writeable_mask: 0x0000FFFF,
+        guest_write_1_to_clear_mask: 0,
+    );
+    mmio.add_register(dnctrl.clone());
+
+    let crcr = register!(
+        name: "crcr",
+        ty: u64,
+        offset: 0x38,
+        reset_value: 9,
+        guest_writeable_mask: 0xFFFFFFFFFFFFFFC7,
+        guest_write_1_to_clear_mask: 0,
+    );
+    mmio.add_register(crcr.clone());
+
+    let dcbaap = register!(
+        name: "dcbaap",
+        ty: u64,
+        offset: 0x50,
+        reset_value: 0x0,
+        guest_writeable_mask: 0xFFFFFFFFFFFFFFC0,
+        guest_write_1_to_clear_mask: 0,
+    );
+    mmio.add_register(dcbaap.clone());
+
+    let config = register!(
+        name: "config",
+        ty: u64,
+        offset: 0x58,
+        reset_value: 0,
+        guest_writeable_mask: 0x0000003F,
+        guest_write_1_to_clear_mask: 0,
+    );
+    mmio.add_register(config.clone());
+
+    let portsc = register_array!(
+        name: "portsc",
+        ty: u32,
+        cnt: MAX_PORTS,
+        base_offset: 0x420,
+        stride: 16,
+        reset_value: 0x000002A0,
+        guest_writeable_mask: 0x8EFFC3F2,
+        guest_write_1_to_clear_mask: 0x00FE0002,);
+    mmio.add_register_array(&portsc);
+
+    // Portpmsc.
+    mmio.add_register_array(&register_array!(
+            name: "portpmsc",
+            ty: u32,
+            cnt: MAX_PORTS,
+            base_offset: 0x424,
+            stride: 16,
+            reset_value: 0,
+            guest_writeable_mask: 0x0001FFFF,
+            guest_write_1_to_clear_mask: 0,));
+
+    // Portli
+    mmio.add_register_array(&register_array!(
+            name: "portli",
+            ty: u32,
+            cnt: MAX_PORTS,
+            base_offset: 0x428,
+            stride: 16,
+            reset_value: 0,
+            guest_writeable_mask: 0,
+            guest_write_1_to_clear_mask: 0,));
+
+    // Porthlpmc
+    mmio.add_register_array(&register_array!(
+            name: "porthlpmc",
+            ty: u32,
+            cnt: MAX_PORTS,
+            base_offset: 0x42c,
+            stride: 16,
+            reset_value: 0,
+            guest_writeable_mask: 0x00003FFF,
+            guest_write_1_to_clear_mask: 0,));
+
+    let doorbells = register_array!(
+        name: "doorbell",
+        ty: u32,
+        cnt: MAX_SLOTS + 1, //  Must be equal to max_slots + 1
+        base_offset: 0x2000,
+        stride: 4,
+        reset_value: 0,
+        guest_writeable_mask: 0xFFFF00FF,
+        guest_write_1_to_clear_mask: 0,);
+    mmio.add_register_array(&doorbells);
+
+    /*Runtime Registers */
+
+    mmio.add_register(
+        // mfindex
+        static_register!(
+        ty: u32,
+        offset: 0x3000,
+        value: 0, // 4 ports starting at port 5
+        ),
+    );
+
+    /* Reg Array for interrupters */
+    // Although the following should be register arrays, we only have one interrupter.
+    let iman = register!(
+            name: "iman",
+            ty: u32,
+            offset: 0x3020,
+            reset_value: 0,
+            guest_writeable_mask: 0x00000003,
+            guest_write_1_to_clear_mask: 0x00000001,);
+    mmio.add_register(iman.clone());
+
+    let imod = register!(
+            name: "imod",
+            ty: u32,
+            offset: 0x3024,
+            reset_value: 0x00000FA0,
+            guest_writeable_mask: 0xFFFFFFFF,
+            guest_write_1_to_clear_mask: 0,);
+    mmio.add_register(imod.clone());
+
+    let erstsz = register!(
+        name: "erstsz",
+        ty: u32,
+        offset: 0x3028,
+        reset_value: 0,
+        guest_writeable_mask: 0x0000FFFF,
+        guest_write_1_to_clear_mask: 0,);
+    mmio.add_register(erstsz.clone());
+
+    let erstba = register!(
+        name: "erstba",
+        ty: u64,
+        offset: 0x3030,
+        reset_value: 0,
+        guest_writeable_mask: 0xFFFFFFFFFFFFFFC0,
+        guest_write_1_to_clear_mask: 0,);
+    mmio.add_register(erstba.clone());
+
+    let erdp = register!(
+        name: "erdp",
+        ty: u64,
+        offset: 0x3038,
+        reset_value: 0,
+        guest_writeable_mask: 0xFFFFFFFFFFFFFFFF,
+        guest_write_1_to_clear_mask: 0x0000000000000008,);
+    mmio.add_register(erdp.clone());
+
+    /* End of Runtime Registers */
+
+    let xhci_regs = XhciRegs {
+        usbcmd,
+        usbsts,
+        dnctrl,
+        crcr,
+        dcbaap,
+        config,
+        portsc,
+        doorbells,
+        iman,
+        imod,
+        erstsz,
+        erstba,
+        erdp,
+    };
+
+    /* End of Host Controller Operational Registers */
+
+    /* Extended Capability Registers */
+
+    // Extended capability registers. Base offset defined by hccparams1.
+    // Each set of 4 registers represents a "Supported Protocol" extended
+    // capability.  The first capability indicates that ports 1-8 are USB 2.0. There is no USB 3.0
+    // port for now. See xHCI spec 7.1 & 7.2 for more details.
+    mmio.add_register(
+        // spcap 1.1
+        static_register!(
+        ty: u32,
+        offset: 0xc000,
+        // "Supported Protocol" capability.
+        // Next capability starts after 0x40 dwords.
+        // USB 2.0. Revision 2.0.
+        value: 0x02004002,
+        ),
+    );
+    mmio.add_register(
+        // spcap 1.2
+        static_register!(
+        ty: u32,
+        offset: 0xc004,
+        value: 0x20425355, // Name string = "USB "
+        ),
+    );
+    mmio.add_register(
+        // spcap 1.3
+        static_register!(
+        ty: u32,
+        offset: 0xc008,
+        value: 0x00000801, // 8 ports starting at port 1. See USB2_PORTS_START and USB2_PORTS_END.
+        ),
+    );
+
+    mmio.add_register(
+        // spcap 1.4
+        static_register!(
+        ty: u32,
+        offset: 0xc00c,
+        // The specification says that this shall be set to 0.
+        // Section 7.2.2.1.4.
+        value: 0,
+        ),
+    );
+
+    mmio.add_register(
+        // spcap 2.1
+        static_register!(
+        ty: u32,
+        offset: 0xc100,
+        // "Supported Protocol" capability.
+        // Not next capability.
+        // USB 3.0. Revision 2.0.
+        value: 0x03000002,
+        ),
+    );
+    mmio.add_register(
+        // spcap 2.2
+        static_register!(
+        ty: u32,
+        offset: 0xc104,
+        value: 0x20425355, // Name string = "USB "
+        ),
+    );
+    mmio.add_register(
+        // spcap 2.3
+        static_register!(
+        ty: u32,
+        offset: 0xc108,
+        value: 0x00000809, // 8 ports starting at port 9. See USB3_PORTS_START and USB3_PORTS_END.
+        ),
+    );
+
+    mmio.add_register(
+        // spcap 2.4
+        static_register!(
+        ty: u32,
+        offset: 0xc10c,
+        // The specification says that this shall be set to 0.
+        // Section 7.2.2.1.4.
+        value: 0,
+        ),
+    );
+
+    /* End of Host Controller Operational Registers */
+
+    (mmio, xhci_regs)
+}
diff --git a/devices/src/usb/xhci/xhci_transfer.rs b/devices/src/usb/xhci/xhci_transfer.rs
new file mode 100644
index 0000000..e166c1a
--- /dev/null
+++ b/devices/src/usb/xhci/xhci_transfer.rs
@@ -0,0 +1,444 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::interrupter::{Error as InterrupterError, Interrupter};
+use super::scatter_gather_buffer::{Error as BufferError, ScatterGatherBuffer};
+use super::usb_hub::{Error as HubError, UsbPort};
+use super::xhci_abi::{
+    AddressedTrb, Error as TrbError, EventDataTrb, SetupStageTrb, TransferDescriptor, TrbCast,
+    TrbCompletionCode, TrbType,
+};
+use super::xhci_regs::MAX_INTERRUPTER;
+use bit_field::Error as BitFieldError;
+use std::cmp::min;
+use std::fmt::{self, Display};
+use std::mem;
+use std::sync::{Arc, Weak};
+use sync::Mutex;
+use sys_util::{error, Error as SysError, EventFd, GuestMemory};
+use usb_util::types::UsbRequestSetup;
+use usb_util::usb_transfer::TransferStatus;
+
+#[derive(Debug)]
+pub enum Error {
+    TrbType(BitFieldError),
+    CastTrb(TrbError),
+    TransferLength(TrbError),
+    BadTrbType(TrbType),
+    WriteCompletionEvent(SysError),
+    CreateBuffer(BufferError),
+    DetachPort(HubError),
+    SendInterrupt(InterrupterError),
+    SubmitTransfer,
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            TrbType(e) => write!(f, "cannot get trb type: {}", e),
+            CastTrb(e) => write!(f, "cannot cast trb: {}", e),
+            TransferLength(e) => write!(f, "cannot get transfer length: {}", e),
+            BadTrbType(t) => write!(f, "unexpected trb type: {:?}", t),
+            WriteCompletionEvent(e) => write!(f, "cannot write completion event: {}", e),
+            CreateBuffer(e) => write!(f, "cannot create transfer buffer: {}", e),
+            DetachPort(e) => write!(f, "cannot detach from port: {}", e),
+            SendInterrupt(e) => write!(f, "cannot send interrupter: {}", e),
+            SubmitTransfer => write!(f, "failed to submit transfer to backend"),
+        }
+    }
+}
+
+/// Type of usb endpoints.
+#[derive(PartialEq, Clone, Copy, Debug)]
+pub enum TransferDirection {
+    In,
+    Out,
+    Control,
+}
+
+/// Current state of xhci transfer.
+pub enum XhciTransferState {
+    Created,
+    /// When transfer is submitted, it will contain a transfer callback, which should be invoked
+    /// when the transfer is cancelled.
+    Submitted {
+        cancel_callback: Box<dyn FnMut() + Send>,
+    },
+    Cancelling,
+    Cancelled,
+    Completed,
+}
+
+impl XhciTransferState {
+    /// Try to cancel this transfer, if it's possible.
+    pub fn try_cancel(&mut self) {
+        match mem::replace(self, XhciTransferState::Created) {
+            XhciTransferState::Submitted {
+                mut cancel_callback,
+            } => {
+                *self = XhciTransferState::Cancelling;
+                cancel_callback();
+            }
+            XhciTransferState::Cancelling => {
+                error!("Another cancellation is already issued.");
+            }
+            _ => {
+                *self = XhciTransferState::Cancelled;
+            }
+        }
+    }
+}
+
+/// Type of a transfer received handled by transfer ring.
+pub enum XhciTransferType {
+    // Normal means bulk transfer or interrupt transfer, depending on endpoint type.
+    // See spec 4.11.2.1.
+    Normal(ScatterGatherBuffer),
+    // See usb spec for setup stage, data stage and status stage,
+    // see xHCI spec 4.11.2.2 for corresponding trbs.
+    SetupStage(UsbRequestSetup),
+    DataStage(ScatterGatherBuffer),
+    StatusStage,
+    // See xHCI spec 4.11.2.3.
+    Isochronous(ScatterGatherBuffer),
+    // See xHCI spec 6.4.1.4.
+    Noop,
+}
+
+impl XhciTransferType {
+    /// Analyze transfer descriptor and return transfer type.
+    pub fn new(mem: GuestMemory, td: TransferDescriptor) -> Result<XhciTransferType> {
+        // We can figure out transfer type from the first trb.
+        // See transfer descriptor description in xhci spec for more details.
+        match td[0].trb.get_trb_type().map_err(Error::TrbType)? {
+            TrbType::Normal => {
+                let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
+                Ok(XhciTransferType::Normal(buffer))
+            }
+            TrbType::SetupStage => {
+                let trb = td[0].trb.cast::<SetupStageTrb>().map_err(Error::CastTrb)?;
+                Ok(XhciTransferType::SetupStage(UsbRequestSetup::new(
+                    trb.get_request_type(),
+                    trb.get_request(),
+                    trb.get_value(),
+                    trb.get_index(),
+                    trb.get_length(),
+                )))
+            }
+            TrbType::DataStage => {
+                let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
+                Ok(XhciTransferType::DataStage(buffer))
+            }
+            TrbType::StatusStage => Ok(XhciTransferType::StatusStage),
+            TrbType::Isoch => {
+                let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
+                Ok(XhciTransferType::Isochronous(buffer))
+            }
+            TrbType::Noop => Ok(XhciTransferType::Noop),
+            t => Err(Error::BadTrbType(t)),
+        }
+    }
+}
+
+/// Xhci Transfer manager holds reference to all ongoing transfers. Can cancel them all if
+/// needed.
+#[derive(Clone)]
+pub struct XhciTransferManager {
+    transfers: Arc<Mutex<Vec<Weak<Mutex<XhciTransferState>>>>>,
+}
+
+impl XhciTransferManager {
+    /// Create a new manager.
+    pub fn new() -> XhciTransferManager {
+        XhciTransferManager {
+            transfers: Arc::new(Mutex::new(Vec::new())),
+        }
+    }
+
+    /// Build a new XhciTransfer. Endpoint id is the id in xHCI device slot.
+    pub fn create_transfer(
+        &self,
+        mem: GuestMemory,
+        port: Arc<UsbPort>,
+        interrupter: Arc<Mutex<Interrupter>>,
+        slot_id: u8,
+        endpoint_id: u8,
+        transfer_trbs: TransferDescriptor,
+        completion_event: EventFd,
+    ) -> XhciTransfer {
+        assert!(!transfer_trbs.is_empty());
+        let transfer_dir = {
+            if endpoint_id == 0 {
+                TransferDirection::Control
+            } else if (endpoint_id % 2) == 0 {
+                TransferDirection::Out
+            } else {
+                TransferDirection::In
+            }
+        };
+        let t = XhciTransfer {
+            manager: self.clone(),
+            state: Arc::new(Mutex::new(XhciTransferState::Created)),
+            mem,
+            port,
+            interrupter,
+            transfer_completion_event: completion_event,
+            slot_id,
+            endpoint_id,
+            transfer_dir,
+            transfer_trbs,
+        };
+        self.transfers.lock().push(Arc::downgrade(&t.state));
+        t
+    }
+
+    /// Cancel all current transfers.
+    pub fn cancel_all(&self) {
+        self.transfers.lock().iter().for_each(|t| {
+            let state = match t.upgrade() {
+                Some(state) => state,
+                None => {
+                    error!("transfer is already cancelled or finished");
+                    return;
+                }
+            };
+            state.lock().try_cancel();
+        });
+    }
+
+    fn remove_transfer(&self, t: &Arc<Mutex<XhciTransferState>>) {
+        let mut transfers = self.transfers.lock();
+        match transfers.iter().position(|wt| match wt.upgrade() {
+            Some(wt) => Arc::ptr_eq(&wt, t),
+            None => false,
+        }) {
+            None => error!("attempted to remove unknow transfer"),
+            Some(i) => {
+                transfers.swap_remove(i);
+            }
+        }
+    }
+}
+
+/// Xhci transfer denotes a transfer initiated by guest os driver. It will be submitted to a
+/// XhciBackendDevice.
+pub struct XhciTransfer {
+    manager: XhciTransferManager,
+    state: Arc<Mutex<XhciTransferState>>,
+    mem: GuestMemory,
+    port: Arc<UsbPort>,
+    interrupter: Arc<Mutex<Interrupter>>,
+    slot_id: u8,
+    // id of endpoint in device slot.
+    endpoint_id: u8,
+    transfer_dir: TransferDirection,
+    transfer_trbs: TransferDescriptor,
+    transfer_completion_event: EventFd,
+}
+
+impl Drop for XhciTransfer {
+    fn drop(&mut self) {
+        self.manager.remove_transfer(&self.state);
+    }
+}
+
+impl fmt::Debug for XhciTransfer {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            f,
+            "xhci_transfer slot id: {}, endpoint id {}, transfer_dir {:?}, transfer_trbs {:?}",
+            self.slot_id, self.endpoint_id, self.transfer_dir, self.transfer_trbs
+        )
+    }
+}
+
+impl XhciTransfer {
+    /// Get state of this transfer.
+    pub fn state(&self) -> &Arc<Mutex<XhciTransferState>> {
+        &self.state
+    }
+
+    /// Get transfer type.
+    pub fn get_transfer_type(&self) -> Result<XhciTransferType> {
+        XhciTransferType::new(self.mem.clone(), self.transfer_trbs.clone())
+    }
+
+    /// Get endpoint number.
+    pub fn get_endpoint_number(&self) -> u8 {
+        // See spec 4.5.1 for dci.
+        self.endpoint_id / 2
+    }
+
+    /// get transfer direction.
+    pub fn get_transfer_dir(&self) -> TransferDirection {
+        self.transfer_dir
+    }
+
+    /// This functions should be invoked when transfer is completed (or failed).
+    pub fn on_transfer_complete(
+        &self,
+        status: &TransferStatus,
+        bytes_transferred: u32,
+    ) -> Result<()> {
+        match status {
+            TransferStatus::NoDevice => {
+                usb_debug!("device disconnected, detaching from port");
+                // If the device is gone, we don't need to send transfer completion event, cause we
+                // are going to destroy everything related to this device anyway.
+                self.port.detach().map_err(Error::DetachPort)?;
+                return Ok(());
+            }
+            TransferStatus::Cancelled => {
+                // TODO(jkwang) According to the spec, we should send a stopped event here. But
+                // kernel driver does not do anything meaningful when it sees a stopped event.
+                return self
+                    .transfer_completion_event
+                    .write(1)
+                    .map_err(Error::WriteCompletionEvent);
+            }
+            TransferStatus::Completed => {
+                self.transfer_completion_event
+                    .write(1)
+                    .map_err(Error::WriteCompletionEvent)?;
+            }
+            _ => {
+                // Transfer failed, we are not handling this correctly yet. Guest kernel might see
+                // short packets for in transfer and might think control transfer is successful. It
+                // will eventually find out device is in a wrong state.
+                self.transfer_completion_event
+                    .write(1)
+                    .map_err(Error::WriteCompletionEvent)?;
+            }
+        }
+
+        let mut edtla: u32 = 0;
+        // As noted in xHCI spec 4.11.3.1
+        // Transfer Event TRB only occurs under the following conditions:
+        //   1. If the Interrupt On Completion flag is set.
+        //   2. When a short transfer occurs during the execution of a Transfer TRB and the
+        //      Interrupt-on-Short Packet flag is set.
+        //   3. If an error occurs during the execution of a Transfer TRB.
+        // Errors are handled above, so just check for the two flags.
+        for atrb in &self.transfer_trbs {
+            edtla += atrb.trb.transfer_length().map_err(Error::TransferLength)?;
+            if atrb.trb.interrupt_on_completion()
+                || (atrb.trb.interrupt_on_short_packet() && edtla > bytes_transferred)
+            {
+                // For details about event data trb and EDTLA, see spec 4.11.5.2.
+                if atrb.trb.get_trb_type().map_err(Error::TrbType)? == TrbType::EventData {
+                    let tlength = min(edtla, bytes_transferred);
+                    self.interrupter
+                        .lock()
+                        .send_transfer_event_trb(
+                            TrbCompletionCode::Success,
+                            atrb.trb
+                                .cast::<EventDataTrb>()
+                                .map_err(Error::CastTrb)?
+                                .get_event_data(),
+                            tlength,
+                            true,
+                            self.slot_id,
+                            self.endpoint_id,
+                        )
+                        .map_err(Error::SendInterrupt)?;
+                } else {
+                    // For Short Transfer details, see xHCI spec 4.10.1.1.
+                    if edtla > bytes_transferred {
+                        usb_debug!("on transfer complete short packet");
+                        let residual_transfer_length = edtla - bytes_transferred;
+                        self.interrupter
+                            .lock()
+                            .send_transfer_event_trb(
+                                TrbCompletionCode::ShortPacket,
+                                atrb.gpa,
+                                residual_transfer_length,
+                                true,
+                                self.slot_id,
+                                self.endpoint_id,
+                            )
+                            .map_err(Error::SendInterrupt)?;
+                    } else {
+                        usb_debug!("on transfer complete success");
+                        self.interrupter
+                            .lock()
+                            .send_transfer_event_trb(
+                                TrbCompletionCode::Success,
+                                atrb.gpa,
+                                0, // transfer length
+                                true,
+                                self.slot_id,
+                                self.endpoint_id,
+                            )
+                            .map_err(Error::SendInterrupt)?;
+                    }
+                }
+            }
+        }
+        Ok(())
+    }
+
+    /// Send this transfer to backend if it's a valid transfer.
+    pub fn send_to_backend_if_valid(self) -> Result<()> {
+        if self.validate_transfer()? {
+            // Backend should invoke on transfer complete when transfer is completed.
+            let port = self.port.clone();
+            let mut backend = port.get_backend_device();
+            match &mut *backend {
+                Some(backend) => backend
+                    .submit_transfer(self)
+                    .map_err(|_| Error::SubmitTransfer)?,
+                None => {
+                    error!("backend is already disconnected");
+                    self.transfer_completion_event
+                        .write(1)
+                        .map_err(Error::WriteCompletionEvent)?;
+                }
+            }
+        } else {
+            error!("invalid td on transfer ring");
+            self.transfer_completion_event
+                .write(1)
+                .map_err(Error::WriteCompletionEvent)?;
+        }
+        Ok(())
+    }
+
+    // Check each trb in the transfer descriptor for invalid or out of bounds
+    // parameters. Returns true iff the transfer descriptor is valid.
+    fn validate_transfer(&self) -> Result<bool> {
+        let mut valid = true;
+        for atrb in &self.transfer_trbs {
+            if !trb_is_valid(&atrb) {
+                self.interrupter
+                    .lock()
+                    .send_transfer_event_trb(
+                        TrbCompletionCode::TrbError,
+                        atrb.gpa,
+                        0,
+                        false,
+                        self.slot_id,
+                        self.endpoint_id,
+                    )
+                    .map_err(Error::SendInterrupt)?;
+                valid = false;
+            }
+        }
+        Ok(valid)
+    }
+}
+
+fn trb_is_valid(atrb: &AddressedTrb) -> bool {
+    let can_be_in_transfer_ring = match atrb.trb.can_be_in_transfer_ring() {
+        Ok(v) => v,
+        Err(e) => {
+            error!("unknown error {:?}", e);
+            return false;
+        }
+    };
+    can_be_in_transfer_ring && (atrb.trb.interrupter_target() < MAX_INTERRUPTER)
+}
diff --git a/devices/src/utils/async_job_queue.rs b/devices/src/utils/async_job_queue.rs
new file mode 100644
index 0000000..76ae8c7
--- /dev/null
+++ b/devices/src/utils/async_job_queue.rs
@@ -0,0 +1,59 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::{Error, Result};
+use super::{EventHandler, EventLoop};
+use std::mem;
+use std::sync::Arc;
+use sync::Mutex;
+use sys_util::{error, EventFd, WatchingEvents};
+
+/// Async Job Queue can schedule async jobs.
+pub struct AsyncJobQueue {
+    jobs: Mutex<Vec<Box<dyn FnMut() + Send>>>,
+    evt: EventFd,
+}
+
+impl AsyncJobQueue {
+    /// Init job queue on event loop.
+    pub fn init(event_loop: &EventLoop) -> Result<Arc<AsyncJobQueue>> {
+        let evt = EventFd::new().map_err(Error::CreateEventFd)?;
+        let queue = Arc::new(AsyncJobQueue {
+            jobs: Mutex::new(Vec::new()),
+            evt,
+        });
+        let handler: Arc<dyn EventHandler> = queue.clone();
+        event_loop.add_event(
+            &queue.evt,
+            WatchingEvents::empty().set_read(),
+            Arc::downgrade(&handler),
+        )?;
+        Ok(queue)
+    }
+
+    /// Queue a new job. It will be invoked on event loop.
+    pub fn queue_job<T: Fn() + 'static + Send>(&self, cb: T) -> Result<()> {
+        self.jobs.lock().push(Box::new(cb));
+        self.evt.write(1).map_err(Error::WriteEventFd)
+    }
+}
+
+impl EventHandler for AsyncJobQueue {
+    fn on_event(&self) -> std::result::Result<(), ()> {
+        // We want to read out the event, but the value is not important.
+        match self.evt.read() {
+            Ok(_) => {}
+            Err(e) => {
+                error!("read event fd failed {}", e);
+                return Err(());
+            }
+        }
+
+        let jobs = mem::replace(&mut *self.jobs.lock(), Vec::new());
+        for mut cb in jobs {
+            cb();
+        }
+        Ok(())
+    }
+}
diff --git a/devices/src/utils/error.rs b/devices/src/utils/error.rs
new file mode 100644
index 0000000..024d3f7
--- /dev/null
+++ b/devices/src/utils/error.rs
@@ -0,0 +1,37 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fmt::{self, Display};
+use sys_util::Error as SysError;
+
+#[derive(Debug)]
+pub enum Error {
+    EventLoopAlreadyFailed,
+    CreateEventFd(SysError),
+    ReadEventFd(SysError),
+    WriteEventFd(SysError),
+    CreatePollContext(SysError),
+    PollContextAddFd(SysError),
+    PollContextDeleteFd(SysError),
+    StartThread(std::io::Error),
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            EventLoopAlreadyFailed => write!(f, "event loop already failed due to previous errors"),
+            CreateEventFd(e) => write!(f, "failed to create event fd: {}", e),
+            ReadEventFd(e) => write!(f, "failed to read event fd: {}", e),
+            WriteEventFd(e) => write!(f, "failed to write event fd: {}", e),
+            CreatePollContext(e) => write!(f, "failed to create poll context: {}", e),
+            PollContextAddFd(e) => write!(f, "failed to add fd to poll context: {}", e),
+            PollContextDeleteFd(e) => write!(f, "failed to delete fd from poll context: {}", e),
+            StartThread(e) => write!(f, "failed to start thread: {}", e),
+        }
+    }
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
diff --git a/devices/src/utils/event_loop.rs b/devices/src/utils/event_loop.rs
new file mode 100644
index 0000000..405c543
--- /dev/null
+++ b/devices/src/utils/event_loop.rs
@@ -0,0 +1,252 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::error::{Error, Result};
+use std::collections::BTreeMap;
+use std::mem::drop;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::sync::{Arc, Weak};
+use std::thread;
+use sync::Mutex;
+use sys_util::{error, warn, EpollContext, EpollEvents, EventFd, PollToken, WatchingEvents};
+
+/// A fail handle will do the clean up when we cannot recover from some error.
+pub trait FailHandle: Send + Sync {
+    /// Fail the code.
+    fn fail(&self);
+    /// Returns true if already failed.
+    fn failed(&self) -> bool;
+}
+
+impl FailHandle for Option<Arc<dyn FailHandle>> {
+    fn fail(&self) {
+        match self {
+            Some(handle) => handle.fail(),
+            None => error!("event loop trying to fail without a fail handle"),
+        }
+    }
+
+    fn failed(&self) -> bool {
+        match self {
+            Some(handle) => handle.failed(),
+            None => false,
+        }
+    }
+}
+
+/// Fd is a wrapper of RawFd. It implements AsRawFd trait and PollToken trait for RawFd.
+/// It does not own the fd, thus won't close the fd when dropped.
+struct Fd(pub RawFd);
+impl AsRawFd for Fd {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0
+    }
+}
+
+impl PollToken for Fd {
+    fn as_raw_token(&self) -> u64 {
+        self.0 as u64
+    }
+
+    fn from_raw_token(data: u64) -> Self {
+        Fd(data as RawFd)
+    }
+}
+
+/// EpollEventLoop is an event loop blocked on a set of fds. When a monitered events is triggered,
+/// event loop will invoke the mapped handler.
+pub struct EventLoop {
+    fail_handle: Option<Arc<dyn FailHandle>>,
+    poll_ctx: Arc<EpollContext<Fd>>,
+    handlers: Arc<Mutex<BTreeMap<RawFd, Weak<dyn EventHandler>>>>,
+    stop_evt: EventFd,
+}
+
+/// Interface for event handler.
+pub trait EventHandler: Send + Sync {
+    fn on_event(&self) -> std::result::Result<(), ()>;
+}
+
+impl EventLoop {
+    /// Start an event loop. An optional fail handle could be passed to the event loop.
+    pub fn start(
+        name: String,
+        fail_handle: Option<Arc<dyn FailHandle>>,
+    ) -> Result<(EventLoop, thread::JoinHandle<()>)> {
+        let (self_stop_evt, stop_evt) = EventFd::new()
+            .and_then(|e| Ok((e.try_clone()?, e)))
+            .map_err(Error::CreateEventFd)?;
+
+        let fd_callbacks: Arc<Mutex<BTreeMap<RawFd, Weak<dyn EventHandler>>>> =
+            Arc::new(Mutex::new(BTreeMap::new()));
+        let poll_ctx: EpollContext<Fd> = EpollContext::new()
+            .and_then(|pc| pc.add(&stop_evt, Fd(stop_evt.as_raw_fd())).and(Ok(pc)))
+            .map_err(Error::CreatePollContext)?;
+
+        let poll_ctx = Arc::new(poll_ctx);
+        let event_loop = EventLoop {
+            fail_handle: fail_handle.clone(),
+            poll_ctx: poll_ctx.clone(),
+            handlers: fd_callbacks.clone(),
+            stop_evt: self_stop_evt,
+        };
+
+        let handle = thread::Builder::new()
+            .name(name)
+            .spawn(move || {
+                let event_loop = EpollEvents::new();
+                loop {
+                    if fail_handle.failed() {
+                        error!("xhci controller already failed, stopping event ring");
+                        return;
+                    }
+                    let events = match poll_ctx.wait(&event_loop) {
+                        Ok(events) => events,
+                        Err(e) => {
+                            error!("cannot poll {:?}", e);
+                            fail_handle.fail();
+                            return;
+                        }
+                    };
+                    for event in &events {
+                        if event.token().as_raw_fd() == stop_evt.as_raw_fd() {
+                            return;
+                        } else {
+                            let fd = event.token().as_raw_fd();
+                            let mut locked = fd_callbacks.lock();
+                            let weak_handler = match locked.get(&fd) {
+                                Some(cb) => cb.clone(),
+                                None => {
+                                    warn!("callback for fd {} already removed", fd);
+                                    continue;
+                                }
+                            };
+                            match weak_handler.upgrade() {
+                                Some(handler) => {
+                                    // Drop lock before triggering the event.
+                                    drop(locked);
+                                    match handler.on_event() {
+                                        Ok(()) => {}
+                                        Err(_) => {
+                                            error!("event loop stopping due to handle event error");
+                                            fail_handle.fail();
+                                            return;
+                                        }
+                                    };
+                                }
+                                // If the handler is already gone, we remove the fd.
+                                None => {
+                                    let _ = poll_ctx.delete(&Fd(fd));
+                                    if locked.remove(&fd).is_none() {
+                                        error!("fail to remove handler for file descriptor {}", fd);
+                                    }
+                                }
+                            };
+                        }
+                    }
+                }
+            })
+            .map_err(Error::StartThread)?;
+
+        Ok((event_loop, handle))
+    }
+
+    /// Add a new event to event loop. The event handler will be invoked when `event` happens on
+    /// `fd`.
+    ///
+    /// If the same `fd` is added multiple times, the old handler will be replaced.
+    /// EventLoop will not keep `handler` alive, if handler is dropped when `event` is triggered,
+    /// the event will be removed.
+    pub fn add_event(
+        &self,
+        fd: &dyn AsRawFd,
+        events: WatchingEvents,
+        handler: Weak<dyn EventHandler>,
+    ) -> Result<()> {
+        if self.fail_handle.failed() {
+            return Err(Error::EventLoopAlreadyFailed);
+        }
+        self.handlers.lock().insert(fd.as_raw_fd(), handler);
+        // This might fail due to epoll syscall. Check epoll_ctl(2).
+        self.poll_ctx
+            .add_fd_with_events(fd, events, Fd(fd.as_raw_fd()))
+            .map_err(Error::PollContextAddFd)
+    }
+
+    /// Removes event for this `fd`. This function returns false if it fails.
+    ///
+    /// EventLoop does not guarantee all events for `fd` is handled.
+    pub fn remove_event_for_fd(&self, fd: &dyn AsRawFd) -> Result<()> {
+        if self.fail_handle.failed() {
+            return Err(Error::EventLoopAlreadyFailed);
+        }
+        // This might fail due to epoll syscall. Check epoll_ctl(2).
+        self.poll_ctx
+            .delete(fd)
+            .map_err(Error::PollContextDeleteFd)?;
+        self.handlers.lock().remove(&fd.as_raw_fd());
+        Ok(())
+    }
+
+    /// Stops this event loop asynchronously. Previous events might not be handled.
+    pub fn stop(&self) {
+        match self.stop_evt.write(1) {
+            Ok(_) => {}
+            Err(_) => {
+                error!("fail to send event loop stop event, it might already stopped");
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::sync::{Arc, Condvar, Mutex};
+    use sys_util::EventFd;
+
+    struct EventLoopTestHandler {
+        val: Mutex<u8>,
+        cvar: Condvar,
+        evt: EventFd,
+    }
+
+    impl EventHandler for EventLoopTestHandler {
+        fn on_event(&self) -> std::result::Result<(), ()> {
+            self.evt.read().unwrap();
+            *self.val.lock().unwrap() += 1;
+            self.cvar.notify_one();
+            Ok(())
+        }
+    }
+
+    #[test]
+    fn event_loop_test() {
+        let (l, j) = EventLoop::start("test".to_string(), None).unwrap();
+        let (self_evt, evt) = match EventFd::new().and_then(|e| Ok((e.try_clone()?, e))) {
+            Ok(v) => v,
+            Err(e) => {
+                error!("failed creating EventFd pair: {:?}", e);
+                return;
+            }
+        };
+        let h = Arc::new(EventLoopTestHandler {
+            val: Mutex::new(0),
+            cvar: Condvar::new(),
+            evt,
+        });
+        let t: Arc<EventHandler> = h.clone();
+        l.add_event(
+            &h.evt,
+            WatchingEvents::empty().set_read(),
+            Arc::downgrade(&t),
+        )
+        .unwrap();
+        self_evt.write(1).unwrap();
+        let _ = h.cvar.wait(h.val.lock().unwrap()).unwrap();
+        l.stop();
+        j.join().unwrap();
+        assert_eq!(*(h.val.lock().unwrap()), 1);
+    }
+}
diff --git a/devices/src/utils/mod.rs b/devices/src/utils/mod.rs
new file mode 100644
index 0000000..6f35025
--- /dev/null
+++ b/devices/src/utils/mod.rs
@@ -0,0 +1,11 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+mod async_job_queue;
+mod error;
+mod event_loop;
+
+pub use self::async_job_queue::*;
+pub use self::error::*;
+pub use self::event_loop::*;
diff --git a/devices/src/virtio/balloon.rs b/devices/src/virtio/balloon.rs
new file mode 100644
index 0000000..451421b
--- /dev/null
+++ b/devices/src/virtio/balloon.rs
@@ -0,0 +1,362 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std;
+use std::cmp;
+use std::fmt::{self, Display};
+use std::io::Write;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+use std::thread;
+
+use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
+use msg_socket::MsgReceiver;
+use sys_util::{
+    self, error, info, warn, EventFd, GuestAddress, GuestMemory, PollContext, PollToken,
+};
+use vm_control::{BalloonControlCommand, BalloonControlResponseSocket};
+
+use super::{
+    DescriptorChain, Queue, VirtioDevice, INTERRUPT_STATUS_CONFIG_CHANGED,
+    INTERRUPT_STATUS_USED_RING, TYPE_BALLOON, VIRTIO_F_VERSION_1,
+};
+
+#[derive(Debug)]
+pub enum BalloonError {
+    /// Request to adjust memory size can't provide the number of pages requested.
+    NotEnoughPages,
+    /// Failure wriitng the config notification event.
+    WritingConfigEvent(sys_util::Error),
+}
+pub type Result<T> = std::result::Result<T, BalloonError>;
+
+impl Display for BalloonError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::BalloonError::*;
+
+        match self {
+            NotEnoughPages => write!(f, "not enough pages"),
+            WritingConfigEvent(e) => write!(f, "failed to write config event: {}", e),
+        }
+    }
+}
+
+// Balloon has three virt IO queues: Inflate, Deflate, and Stats.
+// Stats is currently not used.
+const QUEUE_SIZE: u16 = 128;
+const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE, QUEUE_SIZE];
+
+const VIRTIO_BALLOON_PFN_SHIFT: u32 = 12;
+
+// The feature bitmap for virtio balloon
+const VIRTIO_BALLOON_F_MUST_TELL_HOST: u32 = 0; // Tell before reclaiming pages
+const VIRTIO_BALLOON_F_DEFLATE_ON_OOM: u32 = 2; // Deflate balloon on OOM
+
+// BalloonConfig is modified by the worker and read from the device thread.
+#[derive(Default)]
+struct BalloonConfig {
+    num_pages: AtomicUsize,
+    actual_pages: AtomicUsize,
+}
+
+struct Worker {
+    mem: GuestMemory,
+    inflate_queue: Queue,
+    deflate_queue: Queue,
+    interrupt_status: Arc<AtomicUsize>,
+    interrupt_evt: EventFd,
+    interrupt_resample_evt: EventFd,
+    config: Arc<BalloonConfig>,
+    command_socket: BalloonControlResponseSocket,
+}
+
+fn valid_inflate_desc(desc: &DescriptorChain) -> bool {
+    !desc.is_write_only() && desc.len % 4 == 0
+}
+
+impl Worker {
+    fn process_inflate_deflate(&mut self, inflate: bool) -> bool {
+        let queue = if inflate {
+            &mut self.inflate_queue
+        } else {
+            &mut self.deflate_queue
+        };
+
+        let mut needs_interrupt = false;
+        while let Some(avail_desc) = queue.pop(&self.mem) {
+            if inflate && valid_inflate_desc(&avail_desc) {
+                let num_addrs = avail_desc.len / 4;
+                for i in 0..num_addrs as usize {
+                    let addr = match avail_desc.addr.checked_add((i * 4) as u64) {
+                        Some(a) => a,
+                        None => break,
+                    };
+                    let guest_input: u32 = match self.mem.read_obj_from_addr(addr) {
+                        Ok(a) => a,
+                        Err(_) => continue,
+                    };
+                    let guest_address =
+                        GuestAddress((guest_input as u64) << VIRTIO_BALLOON_PFN_SHIFT);
+
+                    if self
+                        .mem
+                        .remove_range(guest_address, 1 << VIRTIO_BALLOON_PFN_SHIFT)
+                        .is_err()
+                    {
+                        warn!("Marking pages unused failed; addr={}", guest_address);
+                        continue;
+                    }
+                }
+            }
+
+            queue.add_used(&self.mem, avail_desc.index, 0);
+            needs_interrupt = true;
+        }
+
+        needs_interrupt
+    }
+
+    fn signal_used_queue(&self) {
+        self.interrupt_status
+            .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
+        self.interrupt_evt.write(1).unwrap();
+    }
+
+    fn signal_config_changed(&self) {
+        self.interrupt_status
+            .fetch_or(INTERRUPT_STATUS_CONFIG_CHANGED as usize, Ordering::SeqCst);
+        self.interrupt_evt.write(1).unwrap();
+    }
+
+    fn run(&mut self, mut queue_evts: Vec<EventFd>, kill_evt: EventFd) {
+        #[derive(PartialEq, PollToken)]
+        enum Token {
+            Inflate,
+            Deflate,
+            CommandSocket,
+            InterruptResample,
+            Kill,
+        }
+
+        let inflate_queue_evt = queue_evts.remove(0);
+        let deflate_queue_evt = queue_evts.remove(0);
+
+        let poll_ctx: PollContext<Token> = match PollContext::new()
+            .and_then(|pc| pc.add(&inflate_queue_evt, Token::Inflate).and(Ok(pc)))
+            .and_then(|pc| pc.add(&deflate_queue_evt, Token::Deflate).and(Ok(pc)))
+            .and_then(|pc| {
+                pc.add(&self.command_socket, Token::CommandSocket)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| {
+                pc.add(&self.interrupt_resample_evt, Token::InterruptResample)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc)))
+        {
+            Ok(pc) => pc,
+            Err(e) => {
+                error!("failed creating PollContext: {}", e);
+                return;
+            }
+        };
+
+        'poll: loop {
+            let events = match poll_ctx.wait() {
+                Ok(v) => v,
+                Err(e) => {
+                    error!("failed polling for events: {}", e);
+                    break;
+                }
+            };
+
+            let mut needs_interrupt = false;
+            for event in events.iter_readable() {
+                match event.token() {
+                    Token::Inflate => {
+                        if let Err(e) = inflate_queue_evt.read() {
+                            error!("failed reading inflate queue EventFd: {}", e);
+                            break 'poll;
+                        }
+                        needs_interrupt |= self.process_inflate_deflate(true);
+                    }
+                    Token::Deflate => {
+                        if let Err(e) = deflate_queue_evt.read() {
+                            error!("failed reading deflate queue EventFd: {}", e);
+                            break 'poll;
+                        }
+                        needs_interrupt |= self.process_inflate_deflate(false);
+                    }
+                    Token::CommandSocket => {
+                        if let Ok(req) = self.command_socket.recv() {
+                            match req {
+                                BalloonControlCommand::Adjust { num_bytes } => {
+                                    let num_pages =
+                                        (num_bytes >> VIRTIO_BALLOON_PFN_SHIFT) as usize;
+                                    info!("ballon config changed to consume {} pages", num_pages);
+
+                                    self.config.num_pages.store(num_pages, Ordering::Relaxed);
+                                    self.signal_config_changed();
+                                }
+                            };
+                        }
+                    }
+                    Token::InterruptResample => {
+                        let _ = self.interrupt_resample_evt.read();
+                        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
+                            self.interrupt_evt.write(1).unwrap();
+                        }
+                    }
+                    Token::Kill => break 'poll,
+                }
+            }
+            for event in events.iter_hungup() {
+                if event.token() == Token::CommandSocket && !event.readable() {
+                    // If this call fails, the command socket was already removed from the
+                    // PollContext.
+                    let _ = poll_ctx.delete(&self.command_socket);
+                }
+            }
+            if needs_interrupt {
+                self.signal_used_queue();
+            }
+        }
+    }
+}
+
+/// Virtio device for memory balloon inflation/deflation.
+pub struct Balloon {
+    command_socket: Option<BalloonControlResponseSocket>,
+    config: Arc<BalloonConfig>,
+    features: u64,
+    kill_evt: Option<EventFd>,
+}
+
+impl Balloon {
+    /// Create a new virtio balloon device.
+    pub fn new(command_socket: BalloonControlResponseSocket) -> Result<Balloon> {
+        Ok(Balloon {
+            command_socket: Some(command_socket),
+            config: Arc::new(BalloonConfig {
+                num_pages: AtomicUsize::new(0),
+                actual_pages: AtomicUsize::new(0),
+            }),
+            kill_evt: None,
+            // TODO(dgreid) - Add stats queue feature.
+            features: 1 << VIRTIO_BALLOON_F_MUST_TELL_HOST | 1 << VIRTIO_BALLOON_F_DEFLATE_ON_OOM,
+        })
+    }
+}
+
+impl Drop for Balloon {
+    fn drop(&mut self) {
+        if let Some(kill_evt) = self.kill_evt.take() {
+            // Ignore the result because there is nothing we can do with a failure.
+            let _ = kill_evt.write(1);
+        }
+    }
+}
+
+impl VirtioDevice for Balloon {
+    fn keep_fds(&self) -> Vec<RawFd> {
+        vec![self.command_socket.as_ref().unwrap().as_raw_fd()]
+    }
+
+    fn device_type(&self) -> u32 {
+        TYPE_BALLOON
+    }
+
+    fn queue_max_sizes(&self) -> &[u16] {
+        QUEUE_SIZES
+    }
+
+    fn read_config(&self, offset: u64, mut data: &mut [u8]) {
+        if offset >= 8 {
+            return;
+        }
+        let num_pages = self.config.num_pages.load(Ordering::Relaxed) as u32;
+        let actual_pages = self.config.actual_pages.load(Ordering::Relaxed) as u32;
+        let mut config = [0u8; 8];
+        // These writes can't fail as they fit in the declared array so unwrap is fine.
+        (&mut config[0..])
+            .write_u32::<LittleEndian>(num_pages)
+            .unwrap();
+        (&mut config[4..])
+            .write_u32::<LittleEndian>(actual_pages)
+            .unwrap();
+        if let Some(end) = offset.checked_add(data.len() as u64) {
+            // This write can't fail, offset and end are checked against the length of config.
+            data.write_all(&config[offset as usize..cmp::min(end, 8) as usize])
+                .unwrap();
+        }
+    }
+
+    fn write_config(&mut self, offset: u64, mut data: &[u8]) {
+        // Only allow writing to `actual` pages from the guest.
+        if offset != 4 || data.len() != 4 {
+            return;
+        }
+        // This read can't fail as it fits in the declared array so unwrap is fine.
+        let new_actual: u32 = data.read_u32::<LittleEndian>().unwrap();
+        self.config
+            .actual_pages
+            .store(new_actual as usize, Ordering::Relaxed);
+    }
+
+    fn features(&self) -> u64 {
+        1 << VIRTIO_BALLOON_F_MUST_TELL_HOST
+            | 1 << VIRTIO_BALLOON_F_DEFLATE_ON_OOM
+            | 1 << VIRTIO_F_VERSION_1
+    }
+
+    fn ack_features(&mut self, value: u64) {
+        self.features &= value;
+    }
+
+    fn activate(
+        &mut self,
+        mem: GuestMemory,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        status: Arc<AtomicUsize>,
+        mut queues: Vec<Queue>,
+        queue_evts: Vec<EventFd>,
+    ) {
+        if queues.len() != QUEUE_SIZES.len() || queue_evts.len() != QUEUE_SIZES.len() {
+            return;
+        }
+
+        let (self_kill_evt, kill_evt) = match EventFd::new().and_then(|e| Ok((e.try_clone()?, e))) {
+            Ok(v) => v,
+            Err(e) => {
+                error!("failed to create kill EventFd pair: {}", e);
+                return;
+            }
+        };
+        self.kill_evt = Some(self_kill_evt);
+
+        let config = self.config.clone();
+        let command_socket = self.command_socket.take().unwrap();
+        let worker_result = thread::Builder::new()
+            .name("virtio_balloon".to_string())
+            .spawn(move || {
+                let mut worker = Worker {
+                    mem,
+                    inflate_queue: queues.remove(0),
+                    deflate_queue: queues.remove(0),
+                    interrupt_status: status,
+                    interrupt_evt,
+                    interrupt_resample_evt,
+                    command_socket,
+                    config,
+                };
+                worker.run(queue_evts, kill_evt);
+            });
+        if let Err(e) = worker_result {
+            error!("failed to spawn virtio_balloon worker: {}", e);
+            return;
+        }
+    }
+}
diff --git a/devices/src/virtio/block.rs b/devices/src/virtio/block.rs
new file mode 100644
index 0000000..59cc51a
--- /dev/null
+++ b/devices/src/virtio/block.rs
@@ -0,0 +1,1169 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::cmp;
+use std::fmt::{self, Display};
+use std::io::{self, Seek, SeekFrom, Write};
+use std::mem::{size_of, size_of_val};
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::result;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+use std::thread;
+use std::time::Duration;
+use std::u32;
+
+use sync::Mutex;
+use sys_util::Error as SysError;
+use sys_util::Result as SysResult;
+use sys_util::{
+    error, info, warn, EventFd, FileReadWriteVolatile, FileSetLen, FileSync, GuestAddress,
+    GuestMemory, GuestMemoryError, PollContext, PollToken, PunchHole, TimerFd, WriteZeroes,
+};
+
+use data_model::{DataInit, Le16, Le32, Le64, VolatileMemory, VolatileMemoryError};
+use msg_socket::{MsgReceiver, MsgSender};
+use vm_control::{DiskControlCommand, DiskControlResponseSocket, DiskControlResult};
+
+use super::{
+    DescriptorChain, Queue, VirtioDevice, INTERRUPT_STATUS_CONFIG_CHANGED,
+    INTERRUPT_STATUS_USED_RING, TYPE_BLOCK, VIRTIO_F_VERSION_1,
+};
+
+const QUEUE_SIZE: u16 = 256;
+const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE];
+const SECTOR_SHIFT: u8 = 9;
+const SECTOR_SIZE: u64 = 0x01 << SECTOR_SHIFT;
+const MAX_DISCARD_SECTORS: u32 = u32::MAX;
+const MAX_WRITE_ZEROES_SECTORS: u32 = u32::MAX;
+// Hard-coded to 64 KiB (in 512-byte sectors) for now,
+// but this should probably be based on cluster size for qcow.
+const DISCARD_SECTOR_ALIGNMENT: u32 = 128;
+
+const VIRTIO_BLK_T_IN: u32 = 0;
+const VIRTIO_BLK_T_OUT: u32 = 1;
+const VIRTIO_BLK_T_FLUSH: u32 = 4;
+const VIRTIO_BLK_T_DISCARD: u32 = 11;
+const VIRTIO_BLK_T_WRITE_ZEROES: u32 = 13;
+
+const VIRTIO_BLK_S_OK: u8 = 0;
+const VIRTIO_BLK_S_IOERR: u8 = 1;
+const VIRTIO_BLK_S_UNSUPP: u8 = 2;
+
+const VIRTIO_BLK_F_RO: u32 = 5;
+const VIRTIO_BLK_F_BLK_SIZE: u32 = 6;
+const VIRTIO_BLK_F_FLUSH: u32 = 9;
+const VIRTIO_BLK_F_DISCARD: u32 = 13;
+const VIRTIO_BLK_F_WRITE_ZEROES: u32 = 14;
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+struct virtio_blk_geometry {
+    cylinders: Le16,
+    heads: u8,
+    sectors: u8,
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_blk_geometry {}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+struct virtio_blk_topology {
+    physical_block_exp: u8,
+    alignment_offset: u8,
+    min_io_size: Le16,
+    opt_io_size: Le32,
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_blk_topology {}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+struct virtio_blk_config {
+    capacity: Le64,
+    size_max: Le32,
+    seg_max: Le32,
+    geometry: virtio_blk_geometry,
+    blk_size: Le32,
+    topology: virtio_blk_topology,
+    writeback: u8,
+    unused0: [u8; 3],
+    max_discard_sectors: Le32,
+    max_discard_seg: Le32,
+    discard_sector_alignment: Le32,
+    max_write_zeroes_sectors: Le32,
+    max_write_zeroes_seg: Le32,
+    write_zeroes_may_unmap: u8,
+    unused1: [u8; 3],
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_blk_config {}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+struct virtio_blk_discard_write_zeroes {
+    sector: Le64,
+    num_sectors: Le32,
+    flags: Le32,
+}
+
+const VIRTIO_BLK_DISCARD_WRITE_ZEROES_FLAG_UNMAP: u32 = 1 << 0;
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_blk_discard_write_zeroes {}
+
+pub trait DiskFile:
+    FileSetLen + FileSync + FileReadWriteVolatile + PunchHole + Seek + WriteZeroes
+{
+}
+impl<D: FileSetLen + FileSync + PunchHole + FileReadWriteVolatile + Seek + WriteZeroes> DiskFile
+    for D
+{
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+enum RequestType {
+    In,
+    Out,
+    Flush,
+    Discard,
+    WriteZeroes,
+    Unsupported(u32),
+}
+
+impl Display for RequestType {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::RequestType::*;
+
+        match self {
+            In => write!(f, "in"),
+            Out => write!(f, "out"),
+            Flush => write!(f, "flush"),
+            Discard => write!(f, "discard"),
+            WriteZeroes => write!(f, "write zeroes"),
+            Unsupported(n) => write!(f, "unsupported({})", n),
+        }
+    }
+}
+
+#[derive(Debug)]
+enum ParseError {
+    /// Guest gave us bad memory addresses
+    GuestMemory(GuestMemoryError),
+    /// Guest gave us offsets that would have overflowed a usize.
+    CheckedOffset(GuestAddress, u64),
+    /// Guest gave us a write only descriptor that protocol says to read from.
+    UnexpectedWriteOnlyDescriptor,
+    /// Guest gave us a read only descriptor that protocol says to write to.
+    UnexpectedReadOnlyDescriptor,
+    /// Guest gave us too few descriptors in a descriptor chain.
+    DescriptorChainTooShort,
+    /// Guest gave us a descriptor that was too short to use.
+    DescriptorLengthTooSmall,
+}
+
+impl Display for ParseError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::ParseError::*;
+
+        match self {
+            GuestMemory(e) => write!(f, "bad guest memory address: {}", e),
+            CheckedOffset(addr, offset) => write!(f, "{}+{} would overflow a usize", addr, offset),
+            UnexpectedWriteOnlyDescriptor => write!(f, "unexpected write-only descriptor"),
+            UnexpectedReadOnlyDescriptor => write!(f, "unexpected read-only descriptor"),
+            DescriptorChainTooShort => write!(f, "descriptor chain too short"),
+            DescriptorLengthTooSmall => write!(f, "descriptor length too small"),
+        }
+    }
+}
+
+fn request_type(
+    mem: &GuestMemory,
+    desc_addr: GuestAddress,
+) -> result::Result<RequestType, ParseError> {
+    let type_ = mem
+        .read_obj_from_addr(desc_addr)
+        .map_err(ParseError::GuestMemory)?;
+    match type_ {
+        VIRTIO_BLK_T_IN => Ok(RequestType::In),
+        VIRTIO_BLK_T_OUT => Ok(RequestType::Out),
+        VIRTIO_BLK_T_FLUSH => Ok(RequestType::Flush),
+        VIRTIO_BLK_T_DISCARD => Ok(RequestType::Discard),
+        VIRTIO_BLK_T_WRITE_ZEROES => Ok(RequestType::WriteZeroes),
+        t => Ok(RequestType::Unsupported(t)),
+    }
+}
+
+fn sector(mem: &GuestMemory, desc_addr: GuestAddress) -> result::Result<u64, ParseError> {
+    const SECTOR_OFFSET: u64 = 8;
+    let addr = match mem.checked_offset(desc_addr, SECTOR_OFFSET) {
+        Some(v) => v,
+        None => return Err(ParseError::CheckedOffset(desc_addr, SECTOR_OFFSET)),
+    };
+
+    mem.read_obj_from_addr(addr)
+        .map_err(ParseError::GuestMemory)
+}
+
+fn discard_write_zeroes_segment(
+    mem: &GuestMemory,
+    seg_addr: GuestAddress,
+) -> result::Result<virtio_blk_discard_write_zeroes, ParseError> {
+    mem.read_obj_from_addr(seg_addr)
+        .map_err(ParseError::GuestMemory)
+}
+
+#[derive(Debug)]
+enum ExecuteError {
+    /// Error arming the flush timer.
+    Flush(io::Error),
+    ReadVolatile {
+        addr: GuestAddress,
+        length: u32,
+        sector: u64,
+        volatile_memory_error: VolatileMemoryError,
+    },
+    ReadIo {
+        addr: GuestAddress,
+        length: u32,
+        sector: u64,
+        io_error: io::Error,
+    },
+    Seek {
+        ioerr: io::Error,
+        sector: u64,
+    },
+    TimerFd(SysError),
+    WriteVolatile {
+        addr: GuestAddress,
+        length: u32,
+        sector: u64,
+        volatile_memory_error: VolatileMemoryError,
+    },
+    WriteIo {
+        addr: GuestAddress,
+        length: u32,
+        sector: u64,
+        io_error: io::Error,
+    },
+    DiscardWriteZeroes {
+        ioerr: Option<io::Error>,
+        sector: u64,
+        num_sectors: u32,
+        flags: u32,
+    },
+    ReadOnly {
+        request_type: RequestType,
+    },
+    OutOfRange,
+    Unsupported(u32),
+}
+
+impl Display for ExecuteError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::ExecuteError::*;
+
+        match self {
+            Flush(e) => write!(f, "failed to flush: {}", e),
+            ReadVolatile {
+                addr,
+                length,
+                sector,
+                volatile_memory_error,
+            } => write!(
+                f,
+                "memory error reading {} bytes from sector {} to address {}: {}",
+                length, sector, addr, volatile_memory_error,
+            ),
+            ReadIo {
+                addr,
+                length,
+                sector,
+                io_error,
+            } => write!(
+                f,
+                "io error reading {} bytes from sector {} to address {}: {}",
+                length, sector, addr, io_error,
+            ),
+            Seek { ioerr, sector } => write!(f, "failed to seek to sector {}: {}", sector, ioerr),
+            TimerFd(e) => write!(f, "{}", e),
+            WriteVolatile {
+                addr,
+                length,
+                sector,
+                volatile_memory_error,
+            } => write!(
+                f,
+                "memory error writing {} bytes from address {} to sector {}: {}",
+                length, addr, sector, volatile_memory_error,
+            ),
+            WriteIo {
+                addr,
+                length,
+                sector,
+                io_error,
+            } => write!(
+                f,
+                "io error writing {} bytes from address {} to sector {}: {}",
+                length, addr, sector, io_error,
+            ),
+            DiscardWriteZeroes {
+                ioerr: Some(ioerr),
+                sector,
+                num_sectors,
+                flags,
+            } => write!(
+                f,
+                "failed to perform discard or write zeroes; sector={} num_sectors={} flags={}; {}",
+                sector, num_sectors, flags, ioerr,
+            ),
+            DiscardWriteZeroes {
+                ioerr: None,
+                sector,
+                num_sectors,
+                flags,
+            } => write!(
+                f,
+                "failed to perform discard or write zeroes; sector={} num_sectors={} flags={}",
+                sector, num_sectors, flags,
+            ),
+            ReadOnly { request_type } => write!(f, "read only; request_type={}", request_type),
+            OutOfRange => write!(f, "out of range"),
+            Unsupported(n) => write!(f, "unsupported ({})", n),
+        }
+    }
+}
+
+impl ExecuteError {
+    fn status(&self) -> u8 {
+        match self {
+            ExecuteError::Flush(_) => VIRTIO_BLK_S_IOERR,
+            ExecuteError::ReadIo { .. } => VIRTIO_BLK_S_IOERR,
+            ExecuteError::ReadVolatile { .. } => VIRTIO_BLK_S_IOERR,
+            ExecuteError::Seek { .. } => VIRTIO_BLK_S_IOERR,
+            ExecuteError::TimerFd(_) => VIRTIO_BLK_S_IOERR,
+            ExecuteError::WriteIo { .. } => VIRTIO_BLK_S_IOERR,
+            ExecuteError::WriteVolatile { .. } => VIRTIO_BLK_S_IOERR,
+            ExecuteError::DiscardWriteZeroes { .. } => VIRTIO_BLK_S_IOERR,
+            ExecuteError::ReadOnly { .. } => VIRTIO_BLK_S_IOERR,
+            ExecuteError::OutOfRange { .. } => VIRTIO_BLK_S_IOERR,
+            ExecuteError::Unsupported(_) => VIRTIO_BLK_S_UNSUPP,
+        }
+    }
+}
+
+struct Request {
+    request_type: RequestType,
+    sector: u64,
+    data_addr: GuestAddress,
+    data_len: u32,
+    status_addr: GuestAddress,
+    discard_write_zeroes_seg: Option<virtio_blk_discard_write_zeroes>,
+}
+
+impl Request {
+    fn parse(
+        avail_desc: &DescriptorChain,
+        mem: &GuestMemory,
+    ) -> result::Result<Request, ParseError> {
+        // The head contains the request type which MUST be readable.
+        if avail_desc.is_write_only() {
+            return Err(ParseError::UnexpectedWriteOnlyDescriptor);
+        }
+
+        let req_type = request_type(&mem, avail_desc.addr)?;
+        if req_type == RequestType::Flush {
+            Request::parse_flush(avail_desc, mem)
+        } else if req_type == RequestType::Discard || req_type == RequestType::WriteZeroes {
+            Request::parse_discard_write_zeroes(avail_desc, mem, req_type)
+        } else {
+            Request::parse_read_write(avail_desc, mem, req_type)
+        }
+    }
+
+    fn parse_flush(
+        avail_desc: &DescriptorChain,
+        mem: &GuestMemory,
+    ) -> result::Result<Request, ParseError> {
+        let sector = sector(&mem, avail_desc.addr)?;
+        let status_desc = avail_desc
+            .next_descriptor()
+            .ok_or(ParseError::DescriptorChainTooShort)?;
+
+        // The status MUST always be writable
+        if !status_desc.is_write_only() {
+            return Err(ParseError::UnexpectedReadOnlyDescriptor);
+        }
+
+        if status_desc.len < 1 {
+            return Err(ParseError::DescriptorLengthTooSmall);
+        }
+
+        Ok(Request {
+            request_type: RequestType::Flush,
+            sector,
+            data_addr: GuestAddress(0),
+            data_len: 0,
+            status_addr: status_desc.addr,
+            discard_write_zeroes_seg: None,
+        })
+    }
+
+    fn parse_discard_write_zeroes(
+        avail_desc: &DescriptorChain,
+        mem: &GuestMemory,
+        req_type: RequestType,
+    ) -> result::Result<Request, ParseError> {
+        let seg_desc = avail_desc
+            .next_descriptor()
+            .ok_or(ParseError::DescriptorChainTooShort)?;
+        let status_desc = seg_desc
+            .next_descriptor()
+            .ok_or(ParseError::DescriptorChainTooShort)?;
+
+        if seg_desc.is_write_only() {
+            return Err(ParseError::UnexpectedWriteOnlyDescriptor);
+        }
+
+        // For simplicity, we currently only support a single segment
+        // for discard and write zeroes commands.  This allows the
+        // request to be represented as a single Request object.
+        if seg_desc.len < size_of::<virtio_blk_discard_write_zeroes>() as u32 {
+            return Err(ParseError::DescriptorLengthTooSmall);
+        }
+
+        let seg = discard_write_zeroes_segment(&mem, seg_desc.addr)?;
+
+        // The status MUST always be writable
+        if !status_desc.is_write_only() {
+            return Err(ParseError::UnexpectedReadOnlyDescriptor);
+        }
+
+        if status_desc.len < 1 {
+            return Err(ParseError::DescriptorLengthTooSmall);
+        }
+
+        Ok(Request {
+            request_type: req_type,
+            sector: 0,
+            data_addr: GuestAddress(0),
+            data_len: 0,
+            status_addr: status_desc.addr,
+            discard_write_zeroes_seg: Some(seg),
+        })
+    }
+
+    fn parse_read_write(
+        avail_desc: &DescriptorChain,
+        mem: &GuestMemory,
+        req_type: RequestType,
+    ) -> result::Result<Request, ParseError> {
+        let sector = sector(&mem, avail_desc.addr)?;
+        let data_desc = avail_desc
+            .next_descriptor()
+            .ok_or(ParseError::DescriptorChainTooShort)?;
+        let status_desc = data_desc
+            .next_descriptor()
+            .ok_or(ParseError::DescriptorChainTooShort)?;
+
+        if data_desc.is_write_only() && req_type == RequestType::Out {
+            return Err(ParseError::UnexpectedWriteOnlyDescriptor);
+        }
+
+        if !data_desc.is_write_only() && req_type == RequestType::In {
+            return Err(ParseError::UnexpectedReadOnlyDescriptor);
+        }
+
+        // The status MUST always be writable
+        if !status_desc.is_write_only() {
+            return Err(ParseError::UnexpectedReadOnlyDescriptor);
+        }
+
+        if status_desc.len < 1 {
+            return Err(ParseError::DescriptorLengthTooSmall);
+        }
+
+        Ok(Request {
+            request_type: req_type,
+            sector,
+            data_addr: data_desc.addr,
+            data_len: data_desc.len,
+            status_addr: status_desc.addr,
+            discard_write_zeroes_seg: None,
+        })
+    }
+
+    fn execute<T: DiskFile>(
+        &self,
+        read_only: bool,
+        disk: &mut T,
+        disk_size: u64,
+        flush_timer: &mut TimerFd,
+        flush_timer_armed: &mut bool,
+        mem: &GuestMemory,
+    ) -> result::Result<u32, ExecuteError> {
+        // Delay after a write when the file is auto-flushed.
+        let flush_delay = Duration::from_secs(60);
+
+        if read_only && self.request_type != RequestType::In {
+            return Err(ExecuteError::ReadOnly {
+                request_type: self.request_type,
+            });
+        }
+
+        /// Check that a request accesses only data within the disk's current size.
+        /// All parameters are in units of bytes.
+        fn check_range(
+            io_start: u64,
+            io_length: u64,
+            disk_size: u64,
+        ) -> result::Result<(), ExecuteError> {
+            let io_end = io_start
+                .checked_add(io_length)
+                .ok_or(ExecuteError::OutOfRange)?;
+            if io_end > disk_size {
+                Err(ExecuteError::OutOfRange)
+            } else {
+                Ok(())
+            }
+        }
+
+        match self.request_type {
+            RequestType::In => {
+                let offset = self
+                    .sector
+                    .checked_shl(u32::from(SECTOR_SHIFT))
+                    .ok_or(ExecuteError::OutOfRange)?;
+                check_range(offset, u64::from(self.data_len), disk_size)?;
+                disk.seek(SeekFrom::Start(offset))
+                    .map_err(|e| ExecuteError::Seek {
+                        ioerr: e,
+                        sector: self.sector,
+                    })?;
+                let mem_slice = mem
+                    .get_slice(self.data_addr.0, self.data_len as u64)
+                    .map_err(|volatile_memory_error| ExecuteError::ReadVolatile {
+                        addr: self.data_addr,
+                        length: self.data_len,
+                        sector: self.sector,
+                        volatile_memory_error,
+                    })?;
+                disk.read_exact_volatile(mem_slice)
+                    .map_err(|io_error| ExecuteError::ReadIo {
+                        addr: self.data_addr,
+                        length: self.data_len,
+                        sector: self.sector,
+                        io_error,
+                    })?;
+                return Ok(self.data_len);
+            }
+            RequestType::Out => {
+                let offset = self
+                    .sector
+                    .checked_shl(u32::from(SECTOR_SHIFT))
+                    .ok_or(ExecuteError::OutOfRange)?;
+                check_range(offset, u64::from(self.data_len), disk_size)?;
+                disk.seek(SeekFrom::Start(offset))
+                    .map_err(|e| ExecuteError::Seek {
+                        ioerr: e,
+                        sector: self.sector,
+                    })?;
+                let mem_slice = mem
+                    .get_slice(self.data_addr.0, self.data_len as u64)
+                    .map_err(|volatile_memory_error| ExecuteError::WriteVolatile {
+                        addr: self.data_addr,
+                        length: self.data_len,
+                        sector: self.sector,
+                        volatile_memory_error,
+                    })?;
+                disk.write_all_volatile(mem_slice)
+                    .map_err(|io_error| ExecuteError::WriteIo {
+                        addr: self.data_addr,
+                        length: self.data_len,
+                        sector: self.sector,
+                        io_error,
+                    })?;
+                if !*flush_timer_armed {
+                    flush_timer
+                        .reset(flush_delay, None)
+                        .map_err(ExecuteError::TimerFd)?;
+                    *flush_timer_armed = true;
+                }
+            }
+            RequestType::Discard | RequestType::WriteZeroes => {
+                if let Some(seg) = self.discard_write_zeroes_seg {
+                    let sector = seg.sector.to_native();
+                    let num_sectors = seg.num_sectors.to_native();
+                    let flags = seg.flags.to_native();
+
+                    let valid_flags = if self.request_type == RequestType::WriteZeroes {
+                        VIRTIO_BLK_DISCARD_WRITE_ZEROES_FLAG_UNMAP
+                    } else {
+                        0
+                    };
+
+                    if (flags & !valid_flags) != 0 {
+                        return Err(ExecuteError::DiscardWriteZeroes {
+                            ioerr: None,
+                            sector,
+                            num_sectors,
+                            flags,
+                        });
+                    }
+
+                    let offset = sector
+                        .checked_shl(u32::from(SECTOR_SHIFT))
+                        .ok_or(ExecuteError::OutOfRange)?;
+                    let length = u64::from(num_sectors)
+                        .checked_shl(u32::from(SECTOR_SHIFT))
+                        .ok_or(ExecuteError::OutOfRange)?;
+                    check_range(offset, length, disk_size)?;
+
+                    if self.request_type == RequestType::Discard {
+                        // Since Discard is just a hint and some filesystems may not implement
+                        // FALLOC_FL_PUNCH_HOLE, ignore punch_hole errors.
+                        let _ = disk.punch_hole(offset, length);
+                    } else {
+                        disk.seek(SeekFrom::Start(offset))
+                            .map_err(|e| ExecuteError::Seek { ioerr: e, sector })?;
+                        disk.write_zeroes(length as usize).map_err(|e| {
+                            ExecuteError::DiscardWriteZeroes {
+                                ioerr: Some(e),
+                                sector,
+                                num_sectors,
+                                flags,
+                            }
+                        })?;
+                    }
+                }
+            }
+            RequestType::Flush => {
+                disk.fsync().map_err(ExecuteError::Flush)?;
+                flush_timer.clear().map_err(ExecuteError::TimerFd)?;
+                *flush_timer_armed = false;
+            }
+            RequestType::Unsupported(t) => return Err(ExecuteError::Unsupported(t)),
+        };
+        Ok(0)
+    }
+}
+
+struct Worker<T: DiskFile> {
+    queues: Vec<Queue>,
+    mem: GuestMemory,
+    disk_image: T,
+    disk_size: Arc<Mutex<u64>>,
+    read_only: bool,
+    interrupt_status: Arc<AtomicUsize>,
+    interrupt_evt: EventFd,
+    interrupt_resample_evt: EventFd,
+}
+
+impl<T: DiskFile> Worker<T> {
+    fn process_queue(
+        &mut self,
+        queue_index: usize,
+        flush_timer: &mut TimerFd,
+        flush_timer_armed: &mut bool,
+    ) -> bool {
+        let queue = &mut self.queues[queue_index];
+
+        let disk_size = self.disk_size.lock();
+
+        let mut needs_interrupt = false;
+        while let Some(avail_desc) = queue.pop(&self.mem) {
+            let len;
+            match Request::parse(&avail_desc, &self.mem) {
+                Ok(request) => {
+                    let status = match request.execute(
+                        self.read_only,
+                        &mut self.disk_image,
+                        *disk_size,
+                        flush_timer,
+                        flush_timer_armed,
+                        &self.mem,
+                    ) {
+                        Ok(l) => {
+                            len = l;
+                            VIRTIO_BLK_S_OK
+                        }
+                        Err(e) => {
+                            error!("failed executing disk request: {}", e);
+                            len = 1; // 1 byte for the status
+                            e.status()
+                        }
+                    };
+                    // We use unwrap because the request parsing process already checked that the
+                    // status_addr was valid.
+                    self.mem
+                        .write_obj_at_addr(status, request.status_addr)
+                        .unwrap();
+                }
+                Err(e) => {
+                    error!("failed processing available descriptor chain: {}", e);
+                    len = 0;
+                }
+            }
+
+            queue.add_used(&self.mem, avail_desc.index, len);
+            needs_interrupt = true;
+        }
+
+        needs_interrupt
+    }
+
+    fn resize(&mut self, new_size: u64) -> DiskControlResult {
+        if self.read_only {
+            error!("Attempted to resize read-only block device");
+            return DiskControlResult::Err(SysError::new(libc::EROFS));
+        }
+
+        info!("Resizing block device to {} bytes", new_size);
+
+        if let Err(e) = self.disk_image.set_len(new_size) {
+            error!("Resizing disk failed! {}", e);
+            return DiskControlResult::Err(SysError::new(libc::EIO));
+        }
+
+        if let Ok(new_disk_size) = self.disk_image.seek(SeekFrom::End(0)) {
+            let mut disk_size = self.disk_size.lock();
+            *disk_size = new_disk_size;
+        }
+        DiskControlResult::Ok
+    }
+
+    fn signal_used_queue(&self) {
+        self.interrupt_status
+            .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
+        self.interrupt_evt.write(1).unwrap();
+    }
+
+    fn signal_config_changed(&self) {
+        self.interrupt_status
+            .fetch_or(INTERRUPT_STATUS_CONFIG_CHANGED as usize, Ordering::SeqCst);
+        self.interrupt_evt.write(1).unwrap();
+    }
+
+    fn run(
+        &mut self,
+        queue_evt: EventFd,
+        kill_evt: EventFd,
+        control_socket: DiskControlResponseSocket,
+    ) {
+        #[derive(PollToken)]
+        enum Token {
+            FlushTimer,
+            QueueAvailable,
+            ControlRequest,
+            InterruptResample,
+            Kill,
+        }
+
+        let mut flush_timer = match TimerFd::new() {
+            Ok(t) => t,
+            Err(e) => {
+                error!("Failed to create the flush timer: {}", e);
+                return;
+            }
+        };
+        let mut flush_timer_armed = false;
+
+        let poll_ctx: PollContext<Token> = match PollContext::new()
+            .and_then(|pc| pc.add(&flush_timer, Token::FlushTimer).and(Ok(pc)))
+            .and_then(|pc| pc.add(&queue_evt, Token::QueueAvailable).and(Ok(pc)))
+            .and_then(|pc| pc.add(&control_socket, Token::ControlRequest).and(Ok(pc)))
+            .and_then(|pc| {
+                pc.add(&self.interrupt_resample_evt, Token::InterruptResample)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc)))
+        {
+            Ok(pc) => pc,
+            Err(e) => {
+                error!("failed creating PollContext: {}", e);
+                return;
+            }
+        };
+
+        'poll: loop {
+            let events = match poll_ctx.wait() {
+                Ok(v) => v,
+                Err(e) => {
+                    error!("failed polling for events: {}", e);
+                    break;
+                }
+            };
+
+            let mut needs_interrupt = false;
+            let mut needs_config_interrupt = false;
+            for event in events.iter_readable() {
+                match event.token() {
+                    Token::FlushTimer => {
+                        if let Err(e) = self.disk_image.fsync() {
+                            error!("Failed to flush the disk: {}", e);
+                            break 'poll;
+                        }
+                        if let Err(e) = flush_timer.wait() {
+                            error!("Failed to clear flush timer: {}", e);
+                            break 'poll;
+                        }
+                    }
+                    Token::QueueAvailable => {
+                        if let Err(e) = queue_evt.read() {
+                            error!("failed reading queue EventFd: {}", e);
+                            break 'poll;
+                        }
+                        needs_interrupt |=
+                            self.process_queue(0, &mut flush_timer, &mut flush_timer_armed);
+                    }
+                    Token::ControlRequest => {
+                        let req = match control_socket.recv() {
+                            Ok(req) => req,
+                            Err(e) => {
+                                error!("control socket failed recv: {}", e);
+                                break 'poll;
+                            }
+                        };
+
+                        let resp = match req {
+                            DiskControlCommand::Resize { new_size } => {
+                                needs_config_interrupt = true;
+                                self.resize(new_size)
+                            }
+                        };
+
+                        if let Err(e) = control_socket.send(&resp) {
+                            error!("control socket failed send: {}", e);
+                            break 'poll;
+                        }
+                    }
+                    Token::InterruptResample => {
+                        let _ = self.interrupt_resample_evt.read();
+                        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
+                            self.interrupt_evt.write(1).unwrap();
+                        }
+                    }
+                    Token::Kill => break 'poll,
+                }
+            }
+            if needs_interrupt {
+                self.signal_used_queue();
+            }
+            if needs_config_interrupt {
+                self.signal_config_changed();
+            }
+        }
+    }
+}
+
+/// Virtio device for exposing block level read/write operations on a host file.
+pub struct Block<T: DiskFile> {
+    kill_evt: Option<EventFd>,
+    disk_image: Option<T>,
+    disk_size: Arc<Mutex<u64>>,
+    avail_features: u64,
+    read_only: bool,
+    control_socket: Option<DiskControlResponseSocket>,
+}
+
+fn build_config_space(disk_size: u64) -> virtio_blk_config {
+    virtio_blk_config {
+        // If the image is not a multiple of the sector size, the tail bits are not exposed.
+        capacity: Le64::from(disk_size >> SECTOR_SHIFT),
+        blk_size: Le32::from(SECTOR_SIZE as u32),
+        max_discard_sectors: Le32::from(MAX_DISCARD_SECTORS),
+        discard_sector_alignment: Le32::from(DISCARD_SECTOR_ALIGNMENT),
+        max_write_zeroes_sectors: Le32::from(MAX_WRITE_ZEROES_SECTORS),
+        write_zeroes_may_unmap: 1,
+        // Limit number of segments to 1 - see parse_discard_write_zeroes()
+        max_discard_seg: Le32::from(1),
+        max_write_zeroes_seg: Le32::from(1),
+        ..Default::default()
+    }
+}
+
+impl<T: DiskFile> Block<T> {
+    /// Create a new virtio block device that operates on the given file.
+    ///
+    /// The given file must be seekable and sizable.
+    pub fn new(
+        mut disk_image: T,
+        read_only: bool,
+        control_socket: Option<DiskControlResponseSocket>,
+    ) -> SysResult<Block<T>> {
+        let disk_size = disk_image.seek(SeekFrom::End(0))? as u64;
+        if disk_size % SECTOR_SIZE != 0 {
+            warn!(
+                "Disk size {} is not a multiple of sector size {}; \
+                 the remainder will not be visible to the guest.",
+                disk_size, SECTOR_SIZE
+            );
+        }
+
+        let mut avail_features: u64 = 1 << VIRTIO_BLK_F_FLUSH;
+        if read_only {
+            avail_features |= 1 << VIRTIO_BLK_F_RO;
+        } else {
+            avail_features |= 1 << VIRTIO_BLK_F_DISCARD;
+            avail_features |= 1 << VIRTIO_BLK_F_WRITE_ZEROES;
+        }
+        avail_features |= 1 << VIRTIO_F_VERSION_1;
+        avail_features |= 1 << VIRTIO_BLK_F_BLK_SIZE;
+
+        Ok(Block {
+            kill_evt: None,
+            disk_image: Some(disk_image),
+            disk_size: Arc::new(Mutex::new(disk_size)),
+            avail_features,
+            read_only,
+            control_socket,
+        })
+    }
+}
+
+impl<T: DiskFile> Drop for Block<T> {
+    fn drop(&mut self) {
+        if let Some(kill_evt) = self.kill_evt.take() {
+            // Ignore the result because there is nothing we can do about it.
+            let _ = kill_evt.write(1);
+        }
+    }
+}
+
+impl<T: 'static + AsRawFd + DiskFile + Send> VirtioDevice for Block<T> {
+    fn keep_fds(&self) -> Vec<RawFd> {
+        let mut keep_fds = Vec::new();
+
+        if let Some(disk_image) = &self.disk_image {
+            keep_fds.push(disk_image.as_raw_fd());
+        }
+
+        if let Some(control_socket) = &self.control_socket {
+            keep_fds.push(control_socket.as_raw_fd());
+        }
+
+        keep_fds
+    }
+
+    fn features(&self) -> u64 {
+        self.avail_features
+    }
+
+    fn device_type(&self) -> u32 {
+        TYPE_BLOCK
+    }
+
+    fn queue_max_sizes(&self) -> &[u16] {
+        QUEUE_SIZES
+    }
+
+    fn read_config(&self, offset: u64, mut data: &mut [u8]) {
+        let config_space = {
+            let disk_size = self.disk_size.lock();
+            build_config_space(*disk_size)
+        };
+        let config_len = size_of_val(&config_space) as u64;
+        if offset >= config_len {
+            return;
+        }
+
+        if let Some(end) = offset.checked_add(data.len() as u64) {
+            let offset = offset as usize;
+            let end = cmp::min(end, config_len) as usize;
+            // This write can't fail, offset and end are checked against config_len.
+            data.write_all(&config_space.as_slice()[offset..end])
+                .unwrap();
+        }
+    }
+
+    fn activate(
+        &mut self,
+        mem: GuestMemory,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        status: Arc<AtomicUsize>,
+        queues: Vec<Queue>,
+        mut queue_evts: Vec<EventFd>,
+    ) {
+        if queues.len() != 1 || queue_evts.len() != 1 {
+            return;
+        }
+
+        let (self_kill_evt, kill_evt) = match EventFd::new().and_then(|e| Ok((e.try_clone()?, e))) {
+            Ok(v) => v,
+            Err(e) => {
+                error!("failed creating kill EventFd pair: {}", e);
+                return;
+            }
+        };
+        self.kill_evt = Some(self_kill_evt);
+
+        let read_only = self.read_only;
+        let disk_size = self.disk_size.clone();
+        if let Some(disk_image) = self.disk_image.take() {
+            if let Some(control_socket) = self.control_socket.take() {
+                let worker_result =
+                    thread::Builder::new()
+                        .name("virtio_blk".to_string())
+                        .spawn(move || {
+                            let mut worker = Worker {
+                                queues,
+                                mem,
+                                disk_image,
+                                disk_size,
+                                read_only,
+                                interrupt_status: status,
+                                interrupt_evt,
+                                interrupt_resample_evt,
+                            };
+                            worker.run(queue_evts.remove(0), kill_evt, control_socket);
+                        });
+
+                if let Err(e) = worker_result {
+                    error!("failed to spawn virtio_blk worker: {}", e);
+                    return;
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::fs::{File, OpenOptions};
+    use std::path::PathBuf;
+    use sys_util::TempDir;
+
+    use super::*;
+
+    #[test]
+    fn read_size() {
+        let tempdir = TempDir::new("/tmp/block_read_test").unwrap();
+        let mut path = PathBuf::from(tempdir.as_path().unwrap());
+        path.push("disk_image");
+        let f = File::create(&path).unwrap();
+        f.set_len(0x1000).unwrap();
+
+        let b = Block::new(f, true, None).unwrap();
+        let mut num_sectors = [0u8; 4];
+        b.read_config(0, &mut num_sectors);
+        // size is 0x1000, so num_sectors is 8 (4096/512).
+        assert_eq!([0x08, 0x00, 0x00, 0x00], num_sectors);
+        let mut msw_sectors = [0u8; 4];
+        b.read_config(4, &mut msw_sectors);
+        // size is 0x1000, so msw_sectors is 0.
+        assert_eq!([0x00, 0x00, 0x00, 0x00], msw_sectors);
+    }
+
+    #[test]
+    fn read_features() {
+        let tempdir = TempDir::new("/tmp/block_read_test").unwrap();
+        let mut path = PathBuf::from(tempdir.as_path().unwrap());
+        path.push("disk_image");
+
+        // read-write block device
+        {
+            let f = File::create(&path).unwrap();
+            let b = Block::new(f, false, None).unwrap();
+            // writable device should set VIRTIO_BLK_F_FLUSH + VIRTIO_BLK_F_DISCARD
+            // + VIRTIO_BLK_F_WRITE_ZEROES + VIRTIO_F_VERSION_1 + VIRTIO_BLK_F_BLK_SIZE
+            assert_eq!(0x100006240, b.features());
+        }
+
+        // read-only block device
+        {
+            let f = File::create(&path).unwrap();
+            let b = Block::new(f, true, None).unwrap();
+            // read-only device should set VIRTIO_BLK_F_FLUSH and VIRTIO_BLK_F_RO
+            // + VIRTIO_F_VERSION_1 + VIRTIO_BLK_F_BLK_SIZE
+            assert_eq!(0x100000260, b.features());
+        }
+    }
+
+    #[test]
+    fn read_last_sector() {
+        let tempdir = TempDir::new("/tmp/block_read_test").unwrap();
+        let mut path = PathBuf::from(tempdir.as_path().unwrap());
+        path.push("disk_image");
+        let mut f = OpenOptions::new()
+            .read(true)
+            .write(true)
+            .create(true)
+            .open(&path)
+            .unwrap();
+        let disk_size = 0x1000;
+        f.set_len(disk_size).unwrap();
+
+        let mem = GuestMemory::new(&[(GuestAddress(0u64), 4 * 1024 * 1024)])
+            .expect("Creating guest memory failed.");
+
+        let req = Request {
+            request_type: RequestType::In,
+            sector: 7, // Disk is 8 sectors long, so this is the last valid sector.
+            data_addr: GuestAddress(0x1000),
+            data_len: 512, // Read 1 sector of data.
+            status_addr: GuestAddress(0),
+            discard_write_zeroes_seg: None,
+        };
+
+        let mut flush_timer = TimerFd::new().expect("failed to create flush_timer");
+        let mut flush_timer_armed = false;
+
+        assert_eq!(
+            512,
+            req.execute(
+                false,
+                &mut f,
+                disk_size,
+                &mut flush_timer,
+                &mut flush_timer_armed,
+                &mem
+            )
+            .expect("execute failed"),
+        );
+    }
+
+    #[test]
+    fn read_beyond_last_sector() {
+        let tempdir = TempDir::new("/tmp/block_read_test").unwrap();
+        let mut path = PathBuf::from(tempdir.as_path().unwrap());
+        path.push("disk_image");
+        let mut f = OpenOptions::new()
+            .read(true)
+            .write(true)
+            .create(true)
+            .open(&path)
+            .unwrap();
+        let disk_size = 0x1000;
+        f.set_len(disk_size).unwrap();
+
+        let mem = GuestMemory::new(&[(GuestAddress(0u64), 4 * 1024 * 1024)])
+            .expect("Creating guest memory failed.");
+
+        let req = Request {
+            request_type: RequestType::In,
+            sector: 7, // Disk is 8 sectors long, so this is the last valid sector.
+            data_addr: GuestAddress(0x1000),
+            data_len: 512 * 2, // Read 2 sectors of data (overlap the end of the disk).
+            status_addr: GuestAddress(0),
+            discard_write_zeroes_seg: None,
+        };
+
+        let mut flush_timer = TimerFd::new().expect("failed to create flush_timer");
+        let mut flush_timer_armed = false;
+
+        req.execute(
+            false,
+            &mut f,
+            disk_size,
+            &mut flush_timer,
+            &mut flush_timer_armed,
+            &mem,
+        )
+        .expect_err("execute was supposed to fail");
+    }
+}
diff --git a/devices/src/virtio/gpu/backend.rs b/devices/src/virtio/gpu/backend.rs
new file mode 100644
index 0000000..e441541
--- /dev/null
+++ b/devices/src/virtio/gpu/backend.rs
@@ -0,0 +1,1020 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Implementation for the transport agnostic virtio-gpu protocol, including display and rendering.
+
+use std::cell::RefCell;
+use std::collections::btree_map::Entry;
+use std::collections::BTreeMap as Map;
+use std::os::unix::io::AsRawFd;
+use std::rc::Rc;
+use std::usize;
+
+use data_model::*;
+
+use msg_socket::{MsgReceiver, MsgSender};
+use sys_util::{error, warn, GuestAddress, GuestMemory};
+
+use gpu_buffer::{Buffer, Device, Flags, Format};
+use gpu_display::*;
+use gpu_renderer::{
+    format_fourcc as renderer_fourcc, Box3, Context as RendererContext, Image as RendererImage,
+    Renderer, Resource as GpuRendererResource, ResourceCreateArgs, VIRGL_RES_BIND_SCANOUT,
+};
+
+use super::protocol::{
+    GpuResponse, GpuResponsePlaneInfo, VIRTIO_GPU_CAPSET_VIRGL, VIRTIO_GPU_CAPSET_VIRGL2,
+};
+use crate::virtio::resource_bridge::*;
+use vm_control::VmMemoryControlRequestSocket;
+
+const DEFAULT_WIDTH: u32 = 1280;
+const DEFAULT_HEIGHT: u32 = 1024;
+
+/// Trait for virtio-gpu resources allocated by the guest.
+trait VirglResource {
+    /// The width in pixels of this resource.
+    fn width(&self) -> u32;
+
+    /// The height in pixels of this resource.
+    fn height(&self) -> u32;
+
+    /// Associates the backing for this resource with the given guest memory.
+    fn attach_guest_backing(&mut self, mem: &GuestMemory, vecs: Vec<(GuestAddress, usize)>);
+
+    /// Removes associated memory for this resource previously made with `attach_guest_backing`.
+    fn detach_guest_backing(&mut self);
+
+    /// Returns the GPU `Buffer` for this resource, if it has one.
+    fn buffer(&self) -> Option<&Buffer> {
+        None
+    }
+
+    /// Returns the renderer's concrete `GpuRendererResource` for this resource, if it has one.
+    fn gpu_renderer_resource(&mut self) -> Option<&mut GpuRendererResource> {
+        None
+    }
+
+    /// Returns an import ID for this resource onto the given display, if successful.
+    fn import_to_display(&mut self, _display: &Rc<RefCell<GpuDisplay>>) -> Option<u32> {
+        None
+    }
+
+    /// Copies the given rectangle of pixels from guest memory, using the backing specified from a
+    /// call to `attach_guest_backing`.
+    fn write_from_guest_memory(
+        &mut self,
+        x: u32,
+        y: u32,
+        width: u32,
+        height: u32,
+        src_offset: u64,
+        mem: &GuestMemory,
+    );
+
+    /// Reads from the given rectangle of pixels in the resource to the `dst` slice of memory.
+    fn read_to_volatile(&mut self, x: u32, y: u32, width: u32, height: u32, dst: VolatileSlice);
+}
+
+impl VirglResource for GpuRendererResource {
+    fn width(&self) -> u32 {
+        match self.get_info() {
+            Ok(info) => info.width,
+            Err(_) => 0,
+        }
+    }
+    fn height(&self) -> u32 {
+        match self.get_info() {
+            Ok(info) => info.height,
+            Err(_) => 0,
+        }
+    }
+
+    fn attach_guest_backing(&mut self, mem: &GuestMemory, vecs: Vec<(GuestAddress, usize)>) {
+        if let Err(e) = self.attach_backing(&vecs[..], mem) {
+            error!("failed to attach backing to resource: {}", e);
+        }
+    }
+
+    fn detach_guest_backing(&mut self) {
+        self.detach_backing();
+    }
+
+    fn gpu_renderer_resource(&mut self) -> Option<&mut GpuRendererResource> {
+        Some(self)
+    }
+
+    fn write_from_guest_memory(
+        &mut self,
+        x: u32,
+        y: u32,
+        width: u32,
+        height: u32,
+        src_offset: u64,
+        _mem: &GuestMemory,
+    ) {
+        let res = self.transfer_write(
+            None,
+            0,
+            0,
+            0,
+            Box3 {
+                x,
+                y,
+                z: 0,
+                w: width,
+                h: height,
+                d: 0,
+            },
+            src_offset,
+        );
+        if let Err(e) = res {
+            error!(
+                "failed to write to resource (x={} y={} w={} h={}, src_offset={}): {}",
+                x, y, width, height, src_offset, e
+            );
+        }
+    }
+
+    fn read_to_volatile(&mut self, x: u32, y: u32, width: u32, height: u32, dst: VolatileSlice) {
+        let res = GpuRendererResource::read_to_volatile(
+            self,
+            None,
+            0,
+            0,
+            0,
+            Box3 {
+                x,
+                y,
+                z: 0,
+                w: width,
+                h: height,
+                d: 0,
+            },
+            0,
+            dst,
+        );
+        if let Err(e) = res {
+            error!("failed to read from resource: {}", e);
+        }
+    }
+}
+
+/// A buffer backed with a `gpu_buffer::Buffer`.
+struct BackedBuffer {
+    display_import: Option<(Rc<RefCell<GpuDisplay>>, u32)>,
+    backing: Vec<(GuestAddress, usize)>,
+    buffer: Buffer,
+    gpu_renderer_resource: Option<GpuRendererResource>,
+    _image: Option<RendererImage>,
+}
+
+impl BackedBuffer {
+    fn new_renderer_registered(
+        buffer: Buffer,
+        gpu_renderer_resource: GpuRendererResource,
+        image: RendererImage,
+    ) -> BackedBuffer {
+        BackedBuffer {
+            display_import: None,
+            backing: Vec::new(),
+            buffer,
+            gpu_renderer_resource: Some(gpu_renderer_resource),
+            _image: Some(image),
+        }
+    }
+}
+
+impl From<Buffer> for BackedBuffer {
+    fn from(buffer: Buffer) -> BackedBuffer {
+        BackedBuffer {
+            display_import: None,
+            backing: Vec::new(),
+            buffer,
+            gpu_renderer_resource: None,
+            _image: None,
+        }
+    }
+}
+
+impl VirglResource for BackedBuffer {
+    fn width(&self) -> u32 {
+        self.buffer.width()
+    }
+
+    fn height(&self) -> u32 {
+        self.buffer.height()
+    }
+
+    fn attach_guest_backing(&mut self, mem: &GuestMemory, vecs: Vec<(GuestAddress, usize)>) {
+        self.backing = vecs.clone();
+        if let Some(resource) = &mut self.gpu_renderer_resource {
+            if let Err(e) = resource.attach_backing(&vecs[..], mem) {
+                error!("failed to attach backing to BackBuffer resource: {}", e);
+            }
+        }
+    }
+
+    fn detach_guest_backing(&mut self) {
+        if let Some(resource) = &mut self.gpu_renderer_resource {
+            resource.detach_backing();
+        }
+        self.backing.clear();
+    }
+
+    fn gpu_renderer_resource(&mut self) -> Option<&mut GpuRendererResource> {
+        self.gpu_renderer_resource.as_mut()
+    }
+
+    fn buffer(&self) -> Option<&Buffer> {
+        Some(&self.buffer)
+    }
+
+    fn import_to_display(&mut self, display: &Rc<RefCell<GpuDisplay>>) -> Option<u32> {
+        if let Some((self_display, import)) = &self.display_import {
+            if Rc::ptr_eq(self_display, display) {
+                return Some(*import);
+            }
+        }
+        let dmabuf = match self.buffer.export_plane_fd(0) {
+            Ok(dmabuf) => dmabuf,
+            Err(e) => {
+                error!("failed to get dmabuf for scanout: {}", e);
+                return None;
+            }
+        };
+
+        match display.borrow_mut().import_dmabuf(
+            dmabuf.as_raw_fd(),
+            0, /* offset */
+            self.buffer.stride(),
+            self.buffer.format_modifier(),
+            self.buffer.width(),
+            self.buffer.height(),
+            self.buffer.format().into(),
+        ) {
+            Ok(import_id) => {
+                self.display_import = Some((display.clone(), import_id));
+                Some(import_id)
+            }
+            Err(e) => {
+                error!("failed to import dmabuf for display: {}", e);
+                None
+            }
+        }
+    }
+
+    fn write_from_guest_memory(
+        &mut self,
+        x: u32,
+        y: u32,
+        width: u32,
+        height: u32,
+        src_offset: u64,
+        mem: &GuestMemory,
+    ) {
+        if src_offset >= usize::MAX as u64 {
+            error!(
+                "failed to write to resource with given offset: {}",
+                src_offset
+            );
+            return;
+        }
+        let res = self.buffer.write_from_sg(
+            x,
+            y,
+            width,
+            height,
+            0, // plane
+            src_offset as usize,
+            self.backing
+                .iter()
+                .map(|&(addr, len)| mem.get_slice(addr.offset(), len as u64).unwrap_or_default()),
+        );
+        if let Err(e) = res {
+            error!("failed to write to resource from guest memory: {}", e)
+        }
+    }
+
+    fn read_to_volatile(&mut self, x: u32, y: u32, width: u32, height: u32, dst: VolatileSlice) {
+        if let Err(e) = self.buffer.read_to_volatile(x, y, width, height, 0, dst) {
+            error!("failed to copy resource: {}", e);
+        }
+    }
+}
+
+/// The virtio-gpu backend state tracker.
+///
+/// Commands from the virtio-gpu protocol can be submitted here using the methods, and they will be
+/// realized on the hardware. Most methods return a `GpuResponse` that indicate the success,
+/// failure, or requested data for the given command.
+pub struct Backend {
+    display: Rc<RefCell<GpuDisplay>>,
+    device: Device,
+    renderer: Renderer,
+    resources: Map<u32, Box<dyn VirglResource>>,
+    contexts: Map<u32, RendererContext>,
+    #[allow(dead_code)]
+    gpu_device_socket: VmMemoryControlRequestSocket,
+    scanout_surface: Option<u32>,
+    cursor_surface: Option<u32>,
+    scanout_resource: u32,
+    cursor_resource: u32,
+}
+
+impl Backend {
+    /// Creates a new backend for virtio-gpu that realizes all commands using the given `device` for
+    /// allocating buffers, `display` for showing the results, and `renderer` for submitting
+    /// rendering commands.
+    pub fn new(
+        device: Device,
+        display: GpuDisplay,
+        renderer: Renderer,
+        gpu_device_socket: VmMemoryControlRequestSocket,
+    ) -> Backend {
+        Backend {
+            display: Rc::new(RefCell::new(display)),
+            device,
+            renderer,
+            gpu_device_socket,
+            resources: Default::default(),
+            contexts: Default::default(),
+            scanout_surface: None,
+            cursor_surface: None,
+            scanout_resource: 0,
+            cursor_resource: 0,
+        }
+    }
+
+    /// Gets a reference to the display passed into `new`.
+    pub fn display(&self) -> &Rc<RefCell<GpuDisplay>> {
+        &self.display
+    }
+
+    /// Processes the internal `display` events and returns `true` if the main display was closed.
+    pub fn process_display(&mut self) -> bool {
+        let mut display = self.display.borrow_mut();
+        display.dispatch_events();
+        self.scanout_surface
+            .map(|s| display.close_requested(s))
+            .unwrap_or(false)
+    }
+
+    pub fn process_resource_bridge(&self, resource_bridge: &ResourceResponseSocket) {
+        let request = match resource_bridge.recv() {
+            Ok(msg) => msg,
+            Err(e) => {
+                error!("error receiving resource bridge request: {}", e);
+                return;
+            }
+        };
+
+        let response = match request {
+            ResourceRequest::GetResource { id } => self
+                .resources
+                .get(&id)
+                .and_then(|resource| resource.buffer())
+                .and_then(|buffer| buffer.export_plane_fd(0).ok())
+                .map(ResourceResponse::Resource)
+                .unwrap_or(ResourceResponse::Invalid),
+        };
+
+        if let Err(e) = resource_bridge.send(&response) {
+            error!("error sending resource bridge request: {}", e);
+        }
+    }
+
+    /// Gets the list of supported display resolutions as a slice of `(width, height)` tuples.
+    pub fn display_info(&self) -> &[(u32, u32)] {
+        &[(DEFAULT_WIDTH, DEFAULT_HEIGHT)]
+    }
+
+    /// Creates a 2D resource with the given properties and associated it with the given id.
+    pub fn create_resource_2d(
+        &mut self,
+        id: u32,
+        width: u32,
+        height: u32,
+        fourcc: u32,
+    ) -> GpuResponse {
+        if id == 0 {
+            return GpuResponse::ErrInvalidResourceId;
+        }
+        match self.resources.entry(id) {
+            Entry::Vacant(slot) => {
+                let res = self.device.create_buffer(
+                    width,
+                    height,
+                    Format::from(fourcc),
+                    Flags::empty().use_scanout(true).use_linear(true),
+                );
+                match res {
+                    Ok(res) => {
+                        slot.insert(Box::from(BackedBuffer::from(res)));
+                        GpuResponse::OkNoData
+                    }
+                    Err(_) => {
+                        error!("failed to create renderer resource {}", fourcc);
+                        GpuResponse::ErrUnspec
+                    }
+                }
+            }
+            Entry::Occupied(_) => GpuResponse::ErrInvalidResourceId,
+        }
+    }
+
+    /// Removes the guest's reference count for the given resource id.
+    pub fn unref_resource(&mut self, id: u32) -> GpuResponse {
+        match self.resources.remove(&id) {
+            Some(_) => GpuResponse::OkNoData,
+            None => GpuResponse::ErrInvalidResourceId,
+        }
+    }
+
+    /// Sets the given resource id as the source of scanout to the display.
+    pub fn set_scanout(&mut self, id: u32) -> GpuResponse {
+        let mut display = self.display.borrow_mut();
+        if id == 0 {
+            if let Some(surface) = self.scanout_surface.take() {
+                display.release_surface(surface);
+            }
+            self.scanout_resource = 0;
+            if let Some(surface) = self.cursor_surface.take() {
+                display.release_surface(surface);
+            }
+            self.cursor_resource = 0;
+            GpuResponse::OkNoData
+        } else if self.resources.get_mut(&id).is_some() {
+            self.scanout_resource = id;
+
+            if self.scanout_surface.is_none() {
+                match display.create_surface(None, DEFAULT_WIDTH, DEFAULT_HEIGHT) {
+                    Ok(surface) => self.scanout_surface = Some(surface),
+                    Err(e) => error!("failed to create display surface: {}", e),
+                }
+            }
+            GpuResponse::OkNoData
+        } else {
+            GpuResponse::ErrInvalidResourceId
+        }
+    }
+
+    fn flush_resource_to_surface(
+        &mut self,
+        resource_id: u32,
+        surface_id: u32,
+        x: u32,
+        y: u32,
+        width: u32,
+        height: u32,
+    ) -> GpuResponse {
+        let resource = match self.resources.get_mut(&resource_id) {
+            Some(r) => r,
+            None => return GpuResponse::ErrInvalidResourceId,
+        };
+
+        if let Some(import_id) = resource.import_to_display(&self.display) {
+            self.display.borrow_mut().flip_to(surface_id, import_id);
+            return GpuResponse::OkNoData;
+        }
+
+        // Import failed, fall back to a copy.
+        let display = self.display.borrow_mut();
+        // Prevent overwriting a buffer that is currently being used by the compositor.
+        if display.next_buffer_in_use(surface_id) {
+            return GpuResponse::OkNoData;
+        }
+        let fb = match display.framebuffer_memory(surface_id) {
+            Some(fb) => fb,
+            None => {
+                error!("failed to access framebuffer for surface {}", surface_id);
+                return GpuResponse::ErrUnspec;
+            }
+        };
+
+        resource.read_to_volatile(x, y, width, height, fb);
+        display.flip(surface_id);
+
+        GpuResponse::OkNoData
+    }
+
+    /// Flushes the given rectangle of pixels of the given resource to the display.
+    pub fn flush_resource(
+        &mut self,
+        id: u32,
+        x: u32,
+        y: u32,
+        width: u32,
+        height: u32,
+    ) -> GpuResponse {
+        if id == 0 {
+            return GpuResponse::OkNoData;
+        }
+
+        let mut response = GpuResponse::OkNoData;
+
+        if id == self.scanout_resource {
+            if let Some(surface_id) = self.scanout_surface {
+                response = self.flush_resource_to_surface(id, surface_id, x, y, width, height);
+            }
+        }
+
+        if response != GpuResponse::OkNoData {
+            return response;
+        }
+
+        if id == self.cursor_resource {
+            if let Some(surface_id) = self.cursor_surface {
+                response = self.flush_resource_to_surface(id, surface_id, x, y, width, height);
+            }
+        }
+
+        response
+    }
+
+    /// Copes the given rectangle of pixels of the given resource's backing memory to the host side
+    /// resource.
+    pub fn transfer_to_resource_2d(
+        &mut self,
+        id: u32,
+        x: u32,
+        y: u32,
+        width: u32,
+        height: u32,
+        src_offset: u64,
+        mem: &GuestMemory,
+    ) -> GpuResponse {
+        match self.resources.get_mut(&id) {
+            Some(res) => {
+                res.write_from_guest_memory(x, y, width, height, src_offset, mem);
+                GpuResponse::OkNoData
+            }
+            None => GpuResponse::ErrInvalidResourceId,
+        }
+    }
+
+    /// Attaches backing memory to the given resource, represented by a `Vec` of `(address, size)`
+    /// tuples in the guest's physical address space.
+    pub fn attach_backing(
+        &mut self,
+        id: u32,
+        mem: &GuestMemory,
+        vecs: Vec<(GuestAddress, usize)>,
+    ) -> GpuResponse {
+        match self.resources.get_mut(&id) {
+            Some(resource) => {
+                resource.attach_guest_backing(mem, vecs);
+                GpuResponse::OkNoData
+            }
+            None => GpuResponse::ErrInvalidResourceId,
+        }
+    }
+
+    /// Detaches any backing memory from the given resource, if there is any.
+    pub fn detach_backing(&mut self, id: u32) -> GpuResponse {
+        match self.resources.get_mut(&id) {
+            Some(resource) => {
+                resource.detach_guest_backing();
+                GpuResponse::OkNoData
+            }
+            None => GpuResponse::ErrInvalidResourceId,
+        }
+    }
+
+    /// Updates the cursor's memory to the given id, and sets its position to the given coordinates.
+    pub fn update_cursor(&mut self, id: u32, x: u32, y: u32) -> GpuResponse {
+        if id == 0 {
+            if let Some(surface) = self.cursor_surface.take() {
+                self.display.borrow_mut().release_surface(surface);
+            }
+            self.cursor_resource = 0;
+            GpuResponse::OkNoData
+        } else if let Some(resource) = self.resources.get_mut(&id) {
+            self.cursor_resource = id;
+            if self.cursor_surface.is_none() {
+                match self.display.borrow_mut().create_surface(
+                    self.scanout_surface,
+                    resource.width(),
+                    resource.height(),
+                ) {
+                    Ok(surface) => self.cursor_surface = Some(surface),
+                    Err(e) => {
+                        error!("failed to create cursor surface: {}", e);
+                        return GpuResponse::ErrUnspec;
+                    }
+                }
+            }
+
+            let cursor_surface = self.cursor_surface.unwrap();
+            self.display.borrow_mut().set_position(cursor_surface, x, y);
+
+            // Gets the resource's pixels into the display by importing the buffer.
+            if let Some(import_id) = resource.import_to_display(&self.display) {
+                self.display.borrow_mut().flip_to(cursor_surface, import_id);
+                return GpuResponse::OkNoData;
+            }
+
+            // Importing failed, so try copying the pixels into the surface's slower shared memory
+            // framebuffer.
+            if let Some(buffer) = resource.buffer() {
+                if let Some(fb) = self.display.borrow_mut().framebuffer_memory(cursor_surface) {
+                    if let Err(e) =
+                        buffer.read_to_volatile(0, 0, buffer.width(), buffer.height(), 0, fb)
+                    {
+                        error!("failed to copy resource to cursor: {}", e);
+                        return GpuResponse::ErrInvalidParameter;
+                    }
+                }
+                self.display.borrow_mut().flip(cursor_surface);
+            }
+            GpuResponse::OkNoData
+        } else {
+            GpuResponse::ErrInvalidResourceId
+        }
+    }
+
+    /// Moves the cursor's position to the given coordinates.
+    pub fn move_cursor(&mut self, x: u32, y: u32) -> GpuResponse {
+        if let Some(cursor_surface) = self.cursor_surface {
+            if let Some(scanout_surface) = self.scanout_surface {
+                let display = self.display.borrow_mut();
+                display.set_position(cursor_surface, x, y);
+                display.commit(scanout_surface);
+            }
+        }
+        GpuResponse::OkNoData
+    }
+
+    /// Gets the renderer's capset information associated with `index`.
+    pub fn get_capset_info(&self, index: u32) -> GpuResponse {
+        let id = match index {
+            0 => VIRTIO_GPU_CAPSET_VIRGL,
+            1 => VIRTIO_GPU_CAPSET_VIRGL2,
+            _ => return GpuResponse::ErrInvalidParameter,
+        };
+        let (version, size) = self.renderer.get_cap_set_info(id);
+        GpuResponse::OkCapsetInfo { id, version, size }
+    }
+
+    /// Gets the capset of `version` associated with `id`.
+    pub fn get_capset(&self, id: u32, version: u32) -> GpuResponse {
+        GpuResponse::OkCapset(self.renderer.get_cap_set(id, version))
+    }
+
+    /// Creates a fresh renderer context with the given `id`.
+    pub fn create_renderer_context(&mut self, id: u32) -> GpuResponse {
+        if id == 0 {
+            return GpuResponse::ErrInvalidContextId;
+        }
+        match self.contexts.entry(id) {
+            Entry::Occupied(_) => GpuResponse::ErrInvalidContextId,
+            Entry::Vacant(slot) => match self.renderer.create_context(id) {
+                Ok(ctx) => {
+                    slot.insert(ctx);
+                    GpuResponse::OkNoData
+                }
+                Err(e) => {
+                    error!("failed to create renderer ctx: {}", e);
+                    GpuResponse::ErrUnspec
+                }
+            },
+        }
+    }
+
+    /// Destorys the renderer context associated with `id`.
+    pub fn destroy_renderer_context(&mut self, id: u32) -> GpuResponse {
+        match self.contexts.remove(&id) {
+            Some(_) => GpuResponse::OkNoData,
+            None => GpuResponse::ErrInvalidContextId,
+        }
+    }
+
+    /// Attaches the indicated resource to the given context.
+    pub fn context_attach_resource(&mut self, ctx_id: u32, res_id: u32) -> GpuResponse {
+        match (
+            self.contexts.get_mut(&ctx_id),
+            self.resources
+                .get_mut(&res_id)
+                .and_then(|res| res.gpu_renderer_resource()),
+        ) {
+            (Some(ctx), Some(res)) => {
+                ctx.attach(res);
+                GpuResponse::OkNoData
+            }
+            (None, _) => GpuResponse::ErrInvalidContextId,
+            (_, None) => GpuResponse::ErrInvalidResourceId,
+        }
+    }
+
+    /// detaches the indicated resource to the given context.
+    pub fn context_detach_resource(&mut self, ctx_id: u32, res_id: u32) -> GpuResponse {
+        match (
+            self.contexts.get_mut(&ctx_id),
+            self.resources
+                .get_mut(&res_id)
+                .and_then(|res| res.gpu_renderer_resource()),
+        ) {
+            (Some(ctx), Some(res)) => {
+                ctx.detach(res);
+                GpuResponse::OkNoData
+            }
+            (None, _) => GpuResponse::ErrInvalidContextId,
+            (_, None) => GpuResponse::ErrInvalidResourceId,
+        }
+    }
+
+    pub fn allocate_using_minigbm(args: ResourceCreateArgs) -> bool {
+        args.bind & VIRGL_RES_BIND_SCANOUT != 0
+            && args.depth == 1
+            && args.array_size == 1
+            && args.last_level == 0
+            && args.nr_samples == 0
+    }
+
+    /// Creates a 3D resource with the given properties and associated it with the given id.
+    pub fn resource_create_3d(
+        &mut self,
+        id: u32,
+        target: u32,
+        format: u32,
+        bind: u32,
+        width: u32,
+        height: u32,
+        depth: u32,
+        array_size: u32,
+        last_level: u32,
+        nr_samples: u32,
+        flags: u32,
+    ) -> GpuResponse {
+        if id == 0 {
+            return GpuResponse::ErrInvalidResourceId;
+        }
+
+        let create_args = ResourceCreateArgs {
+            handle: id,
+            target,
+            format,
+            bind,
+            width,
+            height,
+            depth,
+            array_size,
+            last_level,
+            nr_samples,
+            flags,
+        };
+
+        match self.resources.entry(id) {
+            Entry::Occupied(_) => GpuResponse::ErrInvalidResourceId,
+            Entry::Vacant(slot) => {
+                if Backend::allocate_using_minigbm(create_args) {
+                    match renderer_fourcc(create_args.format) {
+                        Some(fourcc) => {
+                            let buffer = match self.device.create_buffer(
+                                width,
+                                height,
+                                Format::from(fourcc),
+                                Flags::empty().use_scanout(true).use_rendering(true),
+                            ) {
+                                Ok(buffer) => buffer,
+                                Err(_) => {
+                                    // Attempt to allocate the buffer without scanout flag.
+                                    match self.device.create_buffer(
+                                        width,
+                                        height,
+                                        Format::from(fourcc),
+                                        Flags::empty().use_rendering(true),
+                                    ) {
+                                        Ok(buffer) => buffer,
+                                        Err(e) => {
+                                            error!(
+                                                "failed to create buffer for 3d resource {}: {}",
+                                                format, e
+                                            );
+                                            return GpuResponse::ErrUnspec;
+                                        }
+                                    }
+                                }
+                            };
+
+                            let dma_buf_fd = match buffer.export_plane_fd(0) {
+                                Ok(dma_buf_fd) => dma_buf_fd,
+                                Err(e) => {
+                                    error!("failed to export plane fd: {}", e);
+                                    return GpuResponse::ErrUnspec;
+                                }
+                            };
+
+                            let image = match self.renderer.image_from_dmabuf(
+                                fourcc,
+                                width,
+                                height,
+                                dma_buf_fd.as_raw_fd(),
+                                buffer.plane_offset(0),
+                                buffer.plane_stride(0),
+                            ) {
+                                Ok(image) => image,
+                                Err(e) => {
+                                    error!("failed to create egl image: {}", e);
+                                    return GpuResponse::ErrUnspec;
+                                }
+                            };
+
+                            let res = self.renderer.import_resource(create_args, &image);
+                            match res {
+                                Ok(res) => {
+                                    let format_modifier = buffer.format_modifier();
+                                    let mut plane_info = Vec::with_capacity(buffer.num_planes());
+                                    for plane_index in 0..buffer.num_planes() {
+                                        plane_info.push(GpuResponsePlaneInfo {
+                                            stride: buffer.plane_stride(plane_index),
+                                            offset: buffer.plane_offset(plane_index),
+                                        });
+                                    }
+                                    let backed =
+                                        BackedBuffer::new_renderer_registered(buffer, res, image);
+                                    slot.insert(Box::new(backed));
+                                    GpuResponse::OkResourcePlaneInfo {
+                                        format_modifier,
+                                        plane_info,
+                                    }
+                                }
+                                Err(e) => {
+                                    error!("failed to import renderer resource: {}", e);
+                                    GpuResponse::ErrUnspec
+                                }
+                            }
+                        }
+                        None => {
+                            warn!(
+                                "failed to get fourcc for minigbm 3d resource {}, falling back",
+                                format
+                            );
+                            let res = self.renderer.create_resource(create_args);
+                            match res {
+                                Ok(res) => {
+                                    slot.insert(Box::new(res));
+                                    GpuResponse::OkNoData
+                                }
+                                Err(e) => {
+                                    error!("failed to create renderer resource: {}", e);
+                                    GpuResponse::ErrUnspec
+                                }
+                            }
+                        }
+                    }
+                } else {
+                    let res = self.renderer.create_resource(create_args);
+                    match res {
+                        Ok(res) => {
+                            slot.insert(Box::new(res));
+                            GpuResponse::OkNoData
+                        }
+                        Err(e) => {
+                            error!("failed to create renderer resource: {}", e);
+                            GpuResponse::ErrUnspec
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /// Copes the given 3D rectangle of pixels of the given resource's backing memory to the host
+    /// side resource.
+    pub fn transfer_to_resource_3d(
+        &mut self,
+        ctx_id: u32,
+        res_id: u32,
+        x: u32,
+        y: u32,
+        z: u32,
+        width: u32,
+        height: u32,
+        depth: u32,
+        level: u32,
+        stride: u32,
+        layer_stride: u32,
+        offset: u64,
+    ) -> GpuResponse {
+        let ctx = match ctx_id {
+            0 => None,
+            id => match self.contexts.get(&id) {
+                None => return GpuResponse::ErrInvalidContextId,
+                ctx => ctx,
+            },
+        };
+        match self.resources.get_mut(&res_id) {
+            Some(res) => match res.gpu_renderer_resource() {
+                Some(res) => {
+                    let transfer_box = Box3 {
+                        x,
+                        y,
+                        z,
+                        w: width,
+                        h: height,
+                        d: depth,
+                    };
+                    let res =
+                        res.transfer_write(ctx, level, stride, layer_stride, transfer_box, offset);
+                    match res {
+                        Ok(_) => GpuResponse::OkNoData,
+                        Err(e) => {
+                            error!("failed to transfer to host: {}", e);
+                            GpuResponse::ErrUnspec
+                        }
+                    }
+                }
+                None => GpuResponse::ErrInvalidResourceId,
+            },
+            None => GpuResponse::ErrInvalidResourceId,
+        }
+    }
+
+    /// Copes the given rectangle of pixels from the resource to the given resource's backing
+    /// memory.
+    pub fn transfer_from_resource_3d(
+        &mut self,
+        ctx_id: u32,
+        res_id: u32,
+        x: u32,
+        y: u32,
+        z: u32,
+        width: u32,
+        height: u32,
+        depth: u32,
+        level: u32,
+        stride: u32,
+        layer_stride: u32,
+        offset: u64,
+    ) -> GpuResponse {
+        let ctx = match ctx_id {
+            0 => None,
+            id => match self.contexts.get(&id) {
+                None => return GpuResponse::ErrInvalidContextId,
+                ctx => ctx,
+            },
+        };
+        match self.resources.get_mut(&res_id) {
+            Some(res) => match res.gpu_renderer_resource() {
+                Some(res) => {
+                    let transfer_box = Box3 {
+                        x,
+                        y,
+                        z,
+                        w: width,
+                        h: height,
+                        d: depth,
+                    };
+                    let res =
+                        res.transfer_read(ctx, level, stride, layer_stride, transfer_box, offset);
+                    match res {
+                        Ok(_) => GpuResponse::OkNoData,
+                        Err(e) => {
+                            error!("failed to transfer from host: {}", e);
+                            GpuResponse::ErrUnspec
+                        }
+                    }
+                }
+                None => GpuResponse::ErrInvalidResourceId,
+            },
+            None => GpuResponse::ErrInvalidResourceId,
+        }
+    }
+
+    /// Submits a command buffer to the given rendering context.
+    pub fn submit_command(&mut self, ctx_id: u32, commands: &mut [u8]) -> GpuResponse {
+        match self.contexts.get_mut(&ctx_id) {
+            Some(ctx) => match ctx.submit(&mut commands[..]) {
+                Ok(_) => GpuResponse::OkNoData,
+                Err(e) => {
+                    error!("failed to submit command buffer: {}", e);
+                    GpuResponse::ErrUnspec
+                }
+            },
+            None => GpuResponse::ErrInvalidContextId,
+        }
+    }
+
+    pub fn create_fence(&mut self, ctx_id: u32, fence_id: u32) -> GpuResponse {
+        // There is a mismatch of ordering that is intentional.
+        // This create_fence matches the other functions in Backend, yet
+        // the renderer matches the virgl interface.
+        match self.renderer.create_fence(fence_id, ctx_id) {
+            Ok(_) => GpuResponse::OkNoData,
+            Err(e) => {
+                error!("failed to create fence: {}", e);
+                GpuResponse::ErrUnspec
+            }
+        }
+    }
+
+    pub fn fence_poll(&mut self) -> u32 {
+        self.renderer.poll()
+    }
+
+    pub fn force_ctx_0(&mut self) {
+        self.renderer.force_ctx_0();
+    }
+}
diff --git a/devices/src/virtio/gpu/mod.rs b/devices/src/virtio/gpu/mod.rs
new file mode 100644
index 0000000..cc42ace
--- /dev/null
+++ b/devices/src/virtio/gpu/mod.rs
@@ -0,0 +1,833 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+mod backend;
+mod protocol;
+
+use std::cell::RefCell;
+use std::collections::VecDeque;
+use std::i64;
+use std::mem::size_of;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::path::{Path, PathBuf};
+use std::rc::Rc;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+use std::thread;
+use std::time::Duration;
+
+use data_model::*;
+
+use sys_util::{
+    debug, error, warn, Error, EventFd, GuestAddress, GuestMemory, PollContext, PollToken,
+};
+
+use gpu_buffer::Device;
+use gpu_display::*;
+use gpu_renderer::{format_fourcc, Renderer};
+
+use super::{
+    resource_bridge::*, AvailIter, Queue, VirtioDevice, INTERRUPT_STATUS_USED_RING, TYPE_GPU,
+    VIRTIO_F_VERSION_1,
+};
+
+use self::backend::Backend;
+use self::protocol::*;
+use crate::pci::{PciBarConfiguration, PciBarPrefetchable, PciBarRegionType};
+
+use vm_control::VmMemoryControlRequestSocket;
+
+// First queue is for virtio gpu commands. Second queue is for cursor commands, which we expect
+// there to be fewer of.
+const QUEUE_SIZES: &[u16] = &[256, 16];
+const FENCE_POLL_MS: u64 = 1;
+
+struct QueueDescriptor {
+    index: u16,
+    addr: GuestAddress,
+    len: u32,
+    data: Option<(GuestAddress, u32)>,
+    ret: Option<(GuestAddress, u32)>,
+}
+
+struct ReturnDescriptor {
+    index: u16,
+    len: u32,
+}
+
+struct FenceDescriptor {
+    fence_id: u32,
+    len: u32,
+    desc: QueueDescriptor,
+}
+
+struct Frontend {
+    ctrl_descriptors: VecDeque<QueueDescriptor>,
+    cursor_descriptors: VecDeque<QueueDescriptor>,
+    return_ctrl_descriptors: VecDeque<ReturnDescriptor>,
+    return_cursor_descriptors: VecDeque<ReturnDescriptor>,
+    fence_descriptors: Vec<FenceDescriptor>,
+    backend: Backend,
+}
+
+impl Frontend {
+    fn new(backend: Backend) -> Frontend {
+        Frontend {
+            ctrl_descriptors: Default::default(),
+            cursor_descriptors: Default::default(),
+            return_ctrl_descriptors: Default::default(),
+            return_cursor_descriptors: Default::default(),
+            fence_descriptors: Default::default(),
+            backend,
+        }
+    }
+
+    fn display(&self) -> &Rc<RefCell<GpuDisplay>> {
+        self.backend.display()
+    }
+
+    fn process_display(&mut self) -> bool {
+        self.backend.process_display()
+    }
+
+    fn process_resource_bridge(&self, resource_bridge: &ResourceResponseSocket) {
+        self.backend.process_resource_bridge(resource_bridge);
+    }
+
+    fn process_gpu_command(
+        &mut self,
+        mem: &GuestMemory,
+        cmd: GpuCommand,
+        data: Option<VolatileSlice>,
+    ) -> GpuResponse {
+        self.backend.force_ctx_0();
+
+        match cmd {
+            GpuCommand::GetDisplayInfo(_) => {
+                GpuResponse::OkDisplayInfo(self.backend.display_info().to_vec())
+            }
+            GpuCommand::ResourceCreate2d(info) => {
+                let format = info.format.to_native();
+                match format_fourcc(format) {
+                    Some(fourcc) => self.backend.create_resource_2d(
+                        info.resource_id.to_native(),
+                        info.width.to_native(),
+                        info.height.to_native(),
+                        fourcc,
+                    ),
+                    None => {
+                        warn!(
+                            "failed to create resource with unrecognized pipe format {}",
+                            format
+                        );
+                        GpuResponse::ErrInvalidParameter
+                    }
+                }
+            }
+            GpuCommand::ResourceUnref(info) => {
+                self.backend.unref_resource(info.resource_id.to_native())
+            }
+            GpuCommand::SetScanout(info) => self.backend.set_scanout(info.resource_id.to_native()),
+            GpuCommand::ResourceFlush(info) => self.backend.flush_resource(
+                info.resource_id.to_native(),
+                info.r.x.to_native(),
+                info.r.y.to_native(),
+                info.r.width.to_native(),
+                info.r.height.to_native(),
+            ),
+            GpuCommand::TransferToHost2d(info) => self.backend.transfer_to_resource_2d(
+                info.resource_id.to_native(),
+                info.r.x.to_native(),
+                info.r.y.to_native(),
+                info.r.width.to_native(),
+                info.r.height.to_native(),
+                info.offset.to_native(),
+                mem,
+            ),
+            GpuCommand::ResourceAttachBacking(info) if data.is_some() => {
+                let data = data.unwrap();
+                let entry_count = info.nr_entries.to_native() as usize;
+                let mut iovecs = Vec::with_capacity(entry_count);
+                for i in 0..entry_count {
+                    if let Ok(entry_ref) =
+                        data.get_ref((i * size_of::<virtio_gpu_mem_entry>()) as u64)
+                    {
+                        let entry: virtio_gpu_mem_entry = entry_ref.load();
+                        let addr = GuestAddress(entry.addr.to_native());
+                        let len = entry.length.to_native() as usize;
+                        iovecs.push((addr, len))
+                    } else {
+                        return GpuResponse::ErrUnspec;
+                    }
+                }
+                self.backend
+                    .attach_backing(info.resource_id.to_native(), mem, iovecs)
+            }
+            GpuCommand::ResourceDetachBacking(info) => {
+                self.backend.detach_backing(info.resource_id.to_native())
+            }
+            GpuCommand::UpdateCursor(info) => self.backend.update_cursor(
+                info.resource_id.to_native(),
+                info.pos.x.into(),
+                info.pos.y.into(),
+            ),
+            GpuCommand::MoveCursor(info) => self
+                .backend
+                .move_cursor(info.pos.x.into(), info.pos.y.into()),
+            GpuCommand::GetCapsetInfo(info) => {
+                self.backend.get_capset_info(info.capset_index.to_native())
+            }
+            GpuCommand::GetCapset(info) => self
+                .backend
+                .get_capset(info.capset_id.to_native(), info.capset_version.to_native()),
+            GpuCommand::CtxCreate(info) => self
+                .backend
+                .create_renderer_context(info.hdr.ctx_id.to_native()),
+            GpuCommand::CtxDestroy(info) => self
+                .backend
+                .destroy_renderer_context(info.hdr.ctx_id.to_native()),
+            GpuCommand::CtxAttachResource(info) => self
+                .backend
+                .context_attach_resource(info.hdr.ctx_id.to_native(), info.resource_id.to_native()),
+            GpuCommand::CtxDetachResource(info) => self
+                .backend
+                .context_detach_resource(info.hdr.ctx_id.to_native(), info.resource_id.to_native()),
+            GpuCommand::ResourceCreate3d(info) => {
+                let id = info.resource_id.to_native();
+                let target = info.target.to_native();
+                let format = info.format.to_native();
+                let bind = info.bind.to_native();
+                let width = info.width.to_native();
+                let height = info.height.to_native();
+                let depth = info.depth.to_native();
+                let array_size = info.array_size.to_native();
+                let last_level = info.last_level.to_native();
+                let nr_samples = info.nr_samples.to_native();
+                let flags = info.flags.to_native();
+                self.backend.resource_create_3d(
+                    id, target, format, bind, width, height, depth, array_size, last_level,
+                    nr_samples, flags,
+                )
+            }
+            GpuCommand::TransferToHost3d(info) => {
+                let ctx_id = info.hdr.ctx_id.to_native();
+                let res_id = info.resource_id.to_native();
+                let x = info.box_.x.to_native();
+                let y = info.box_.y.to_native();
+                let z = info.box_.z.to_native();
+                let width = info.box_.w.to_native();
+                let height = info.box_.h.to_native();
+                let depth = info.box_.d.to_native();
+                let level = info.level.to_native();
+                let stride = info.stride.to_native();
+                let layer_stride = info.layer_stride.to_native();
+                let offset = info.offset.to_native();
+                self.backend.transfer_to_resource_3d(
+                    ctx_id,
+                    res_id,
+                    x,
+                    y,
+                    z,
+                    width,
+                    height,
+                    depth,
+                    level,
+                    stride,
+                    layer_stride,
+                    offset,
+                )
+            }
+            GpuCommand::TransferFromHost3d(info) => {
+                let ctx_id = info.hdr.ctx_id.to_native();
+                let res_id = info.resource_id.to_native();
+                let x = info.box_.x.to_native();
+                let y = info.box_.y.to_native();
+                let z = info.box_.z.to_native();
+                let width = info.box_.w.to_native();
+                let height = info.box_.h.to_native();
+                let depth = info.box_.d.to_native();
+                let level = info.level.to_native();
+                let stride = info.stride.to_native();
+                let layer_stride = info.layer_stride.to_native();
+                let offset = info.offset.to_native();
+                self.backend.transfer_from_resource_3d(
+                    ctx_id,
+                    res_id,
+                    x,
+                    y,
+                    z,
+                    width,
+                    height,
+                    depth,
+                    level,
+                    stride,
+                    layer_stride,
+                    offset,
+                )
+            }
+            GpuCommand::CmdSubmit3d(info) => {
+                if data.is_some() {
+                    let data = data.unwrap(); // guarded by this match arm
+                    let cmd_size = info.size.to_native() as usize;
+                    match data.get_slice(0, cmd_size as u64) {
+                        Ok(cmd_slice) => {
+                            let mut cmd_buf = vec![0; cmd_size];
+                            cmd_slice.copy_to(&mut cmd_buf[..]);
+                            self.backend
+                                .submit_command(info.hdr.ctx_id.to_native(), &mut cmd_buf[..])
+                        }
+                        Err(_) => GpuResponse::ErrInvalidParameter,
+                    }
+                } else {
+                    // Silently accept empty command buffers to allow for
+                    // benchmarking.
+                    GpuResponse::OkNoData
+                }
+            }
+            _ => {
+                error!("unhandled command {:?}", cmd);
+                GpuResponse::ErrUnspec
+            }
+        }
+    }
+
+    fn take_descriptors(
+        mem: &GuestMemory,
+        desc_iter: AvailIter,
+        descriptors: &mut VecDeque<QueueDescriptor>,
+        return_descriptors: &mut VecDeque<ReturnDescriptor>,
+    ) {
+        for desc in desc_iter {
+            if desc.len as usize >= size_of::<virtio_gpu_ctrl_hdr>() && !desc.is_write_only() {
+                let mut q_desc = QueueDescriptor {
+                    index: desc.index,
+                    addr: desc.addr,
+                    len: desc.len,
+                    data: None,
+                    ret: None,
+                };
+                if let Some(extra_desc) = desc.next_descriptor() {
+                    if extra_desc.is_write_only() {
+                        q_desc.ret = Some((extra_desc.addr, extra_desc.len));
+                    } else {
+                        q_desc.data = Some((extra_desc.addr, extra_desc.len));
+                    }
+                    if let Some(extra_desc) = extra_desc.next_descriptor() {
+                        if extra_desc.is_write_only() && q_desc.ret.is_none() {
+                            q_desc.ret = Some((extra_desc.addr, extra_desc.len));
+                        }
+                    }
+                }
+                descriptors.push_back(q_desc);
+            } else {
+                let likely_type = mem.read_obj_from_addr(desc.addr).unwrap_or(Le32::from(0));
+                debug!(
+                    "ctrl queue bad descriptor index = {} len = {} write = {} type = {}",
+                    desc.index,
+                    desc.len,
+                    desc.is_write_only(),
+                    virtio_gpu_cmd_str(likely_type.to_native())
+                );
+                return_descriptors.push_back(ReturnDescriptor {
+                    index: desc.index,
+                    len: 0,
+                });
+            }
+        }
+    }
+
+    fn take_ctrl_descriptors(&mut self, mem: &GuestMemory, desc_iter: AvailIter) {
+        Frontend::take_descriptors(
+            mem,
+            desc_iter,
+            &mut self.ctrl_descriptors,
+            &mut self.return_ctrl_descriptors,
+        );
+    }
+
+    fn take_cursor_descriptors(&mut self, mem: &GuestMemory, desc_iter: AvailIter) {
+        Frontend::take_descriptors(
+            mem,
+            desc_iter,
+            &mut self.cursor_descriptors,
+            &mut self.return_cursor_descriptors,
+        );
+    }
+
+    fn process_descriptor(
+        &mut self,
+        mem: &GuestMemory,
+        desc: QueueDescriptor,
+    ) -> Option<ReturnDescriptor> {
+        let mut resp = GpuResponse::ErrUnspec;
+        let mut gpu_cmd = None;
+        let mut len = 0;
+        if let Ok(desc_mem) = mem.get_slice(desc.addr.offset(), desc.len as u64) {
+            match GpuCommand::decode(desc_mem) {
+                Ok(cmd) => {
+                    match desc.data {
+                        Some(data_desc) => {
+                            match mem.get_slice(data_desc.0.offset(), data_desc.1 as u64) {
+                                Ok(data_mem) => {
+                                    resp = self.process_gpu_command(mem, cmd, Some(data_mem))
+                                }
+                                Err(e) => debug!("ctrl queue invalid data descriptor: {}", e),
+                            }
+                        }
+                        None => resp = self.process_gpu_command(mem, cmd, None),
+                    }
+                    gpu_cmd = Some(cmd);
+                }
+                Err(e) => debug!("ctrl queue decode error: {}", e),
+            }
+        }
+        if resp.is_err() {
+            debug!("{:?} -> {:?}", gpu_cmd, resp);
+        }
+        if let Some(ret_desc) = desc.ret {
+            if let Ok(ret_desc_mem) = mem.get_slice(ret_desc.0.offset(), ret_desc.1 as u64) {
+                let mut fence_id = 0;
+                let mut ctx_id = 0;
+                let mut flags = 0;
+                if let Some(cmd) = gpu_cmd {
+                    let ctrl_hdr = cmd.ctrl_hdr();
+                    if ctrl_hdr.flags.to_native() & VIRTIO_GPU_FLAG_FENCE != 0 {
+                        fence_id = ctrl_hdr.fence_id.to_native();
+                        ctx_id = ctrl_hdr.ctx_id.to_native();
+                        flags = VIRTIO_GPU_FLAG_FENCE;
+
+                        let fence_resp = self.backend.create_fence(ctx_id, fence_id as u32);
+                        if fence_resp.is_err() {
+                            warn!("create_fence {} -> {:?}", fence_id, fence_resp);
+                            resp = fence_resp;
+                        }
+                    }
+                }
+
+                // Prepare the response now, even if it is going to wait until
+                // fence is complete.
+                match resp.encode(flags, fence_id, ctx_id, ret_desc_mem) {
+                    Ok(l) => len = l,
+                    Err(e) => debug!("ctrl queue response encode error: {}", e),
+                }
+
+                if flags & VIRTIO_GPU_FLAG_FENCE != 0 {
+                    self.fence_descriptors.push(FenceDescriptor {
+                        fence_id: fence_id as u32,
+                        len,
+                        desc,
+                    });
+
+                    return None;
+                }
+
+                // No fence, respond now.
+            }
+        }
+        Some(ReturnDescriptor {
+            index: desc.index,
+            len,
+        })
+    }
+
+    fn process_ctrl(&mut self, mem: &GuestMemory) -> Option<ReturnDescriptor> {
+        self.return_ctrl_descriptors.pop_front().or_else(|| {
+            self.ctrl_descriptors
+                .pop_front()
+                .and_then(|desc| self.process_descriptor(mem, desc))
+        })
+    }
+
+    fn process_cursor(&mut self, mem: &GuestMemory) -> Option<ReturnDescriptor> {
+        self.return_cursor_descriptors.pop_front().or_else(|| {
+            self.cursor_descriptors
+                .pop_front()
+                .and_then(|desc| self.process_descriptor(mem, desc))
+        })
+    }
+
+    fn fence_poll(&mut self) {
+        let fence_id = self.backend.fence_poll();
+        let return_descs = &mut self.return_ctrl_descriptors;
+        self.fence_descriptors.retain(|f_desc| {
+            if f_desc.fence_id > fence_id {
+                true
+            } else {
+                return_descs.push_back(ReturnDescriptor {
+                    index: f_desc.desc.index,
+                    len: f_desc.len,
+                });
+                false
+            }
+        })
+    }
+}
+
+struct Worker {
+    exit_evt: EventFd,
+    mem: GuestMemory,
+    interrupt_evt: EventFd,
+    interrupt_resample_evt: EventFd,
+    interrupt_status: Arc<AtomicUsize>,
+    ctrl_queue: Queue,
+    ctrl_evt: EventFd,
+    cursor_queue: Queue,
+    cursor_evt: EventFd,
+    resource_bridge: Option<ResourceResponseSocket>,
+    kill_evt: EventFd,
+    state: Frontend,
+}
+
+impl Worker {
+    fn signal_used_queue(&self) {
+        self.interrupt_status
+            .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
+        let _ = self.interrupt_evt.write(1);
+    }
+
+    fn run(&mut self) {
+        #[derive(PollToken)]
+        enum Token {
+            CtrlQueue,
+            CursorQueue,
+            Display,
+            ResourceBridge,
+            InterruptResample,
+            Kill,
+        }
+
+        let poll_ctx: PollContext<Token> = match PollContext::new()
+            .and_then(|pc| pc.add(&self.ctrl_evt, Token::CtrlQueue).and(Ok(pc)))
+            .and_then(|pc| pc.add(&self.cursor_evt, Token::CursorQueue).and(Ok(pc)))
+            .and_then(|pc| {
+                pc.add(&*self.state.display().borrow(), Token::Display)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| {
+                pc.add(&self.interrupt_resample_evt, Token::InterruptResample)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| pc.add(&self.kill_evt, Token::Kill).and(Ok(pc)))
+        {
+            Ok(pc) => pc,
+            Err(e) => {
+                error!("failed creating PollContext: {}", e);
+                return;
+            }
+        };
+
+        if let Some(resource_bridge) = &self.resource_bridge {
+            if let Err(e) = poll_ctx.add(resource_bridge, Token::ResourceBridge) {
+                error!("failed to add resource bridge to PollContext: {}", e);
+            }
+        }
+
+        'poll: loop {
+            // If there are outstanding fences, wake up early to poll them.
+            let duration = if !self.state.fence_descriptors.is_empty() {
+                Duration::from_millis(FENCE_POLL_MS)
+            } else {
+                Duration::new(i64::MAX as u64, 0)
+            };
+
+            let events = match poll_ctx.wait_timeout(duration) {
+                Ok(v) => v,
+                Err(e) => {
+                    error!("failed polling for events: {}", e);
+                    break;
+                }
+            };
+            let mut signal_used = false;
+            let mut process_resource_bridge = false;
+            for event in events.iter_readable() {
+                match event.token() {
+                    Token::CtrlQueue => {
+                        let _ = self.ctrl_evt.read();
+                        self.state
+                            .take_ctrl_descriptors(&self.mem, self.ctrl_queue.iter(&self.mem));
+                    }
+                    Token::CursorQueue => {
+                        let _ = self.cursor_evt.read();
+                        self.state
+                            .take_cursor_descriptors(&self.mem, self.cursor_queue.iter(&self.mem));
+                    }
+                    Token::Display => {
+                        let close_requested = self.state.process_display();
+                        if close_requested {
+                            let _ = self.exit_evt.write(1);
+                        }
+                    }
+                    Token::ResourceBridge => process_resource_bridge = true,
+                    Token::InterruptResample => {
+                        let _ = self.interrupt_resample_evt.read();
+                        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
+                            self.interrupt_evt.write(1).unwrap();
+                        }
+                    }
+                    Token::Kill => {
+                        break 'poll;
+                    }
+                }
+            }
+
+            // All cursor commands go first because they have higher priority.
+            while let Some(desc) = self.state.process_cursor(&self.mem) {
+                self.cursor_queue.add_used(&self.mem, desc.index, desc.len);
+                signal_used = true;
+            }
+
+            self.state.fence_poll();
+
+            while let Some(desc) = self.state.process_ctrl(&self.mem) {
+                self.ctrl_queue.add_used(&self.mem, desc.index, desc.len);
+                signal_used = true;
+            }
+
+            // Process the entire control queue before the resource bridge in case a resource is
+            // created or destroyed by the control queue. Processing the resource bridge first may
+            // lead to a race condition.
+            if process_resource_bridge {
+                if let Some(resource_bridge) = &self.resource_bridge {
+                    self.state.process_resource_bridge(resource_bridge);
+                }
+            }
+
+            if signal_used {
+                self.signal_used_queue();
+            }
+        }
+    }
+}
+
+pub struct Gpu {
+    config_event: bool,
+    exit_evt: EventFd,
+    gpu_device_socket: Option<VmMemoryControlRequestSocket>,
+    resource_bridge: Option<ResourceResponseSocket>,
+    kill_evt: Option<EventFd>,
+    wayland_socket_path: PathBuf,
+}
+
+impl Gpu {
+    pub fn new<P: AsRef<Path>>(
+        exit_evt: EventFd,
+        gpu_device_socket: Option<VmMemoryControlRequestSocket>,
+        resource_bridge: Option<ResourceResponseSocket>,
+        wayland_socket_path: P,
+    ) -> Gpu {
+        Gpu {
+            config_event: false,
+            exit_evt,
+            gpu_device_socket,
+            resource_bridge,
+            kill_evt: None,
+            wayland_socket_path: wayland_socket_path.as_ref().to_path_buf(),
+        }
+    }
+
+    fn get_config(&self) -> virtio_gpu_config {
+        let mut events_read = 0;
+        if self.config_event {
+            events_read |= VIRTIO_GPU_EVENT_DISPLAY;
+        }
+        virtio_gpu_config {
+            events_read: Le32::from(events_read),
+            events_clear: Le32::from(0),
+            num_scanouts: Le32::from(1),
+            num_capsets: Le32::from(2),
+        }
+    }
+}
+
+impl Drop for Gpu {
+    fn drop(&mut self) {
+        if let Some(kill_evt) = self.kill_evt.take() {
+            // Ignore the result because there is nothing we can do about it.
+            let _ = kill_evt.write(1);
+        }
+    }
+}
+
+impl VirtioDevice for Gpu {
+    fn keep_fds(&self) -> Vec<RawFd> {
+        let mut keep_fds = Vec::new();
+        // TODO(davidriley): Remove once virgl has another path to include
+        // debugging logs.
+        if cfg!(debug_assertions) {
+            keep_fds.push(libc::STDOUT_FILENO);
+            keep_fds.push(libc::STDERR_FILENO);
+        }
+
+        if let Some(ref gpu_device_socket) = self.gpu_device_socket {
+            keep_fds.push(gpu_device_socket.as_raw_fd());
+        }
+
+        keep_fds.push(self.exit_evt.as_raw_fd());
+        if let Some(resource_bridge) = &self.resource_bridge {
+            keep_fds.push(resource_bridge.as_raw_fd());
+        }
+        keep_fds
+    }
+
+    fn device_type(&self) -> u32 {
+        TYPE_GPU
+    }
+
+    fn queue_max_sizes(&self) -> &[u16] {
+        QUEUE_SIZES
+    }
+
+    fn features(&self) -> u64 {
+        1 << VIRTIO_GPU_F_VIRGL | 1 << VIRTIO_F_VERSION_1
+    }
+
+    fn ack_features(&mut self, value: u64) {
+        let _ = value;
+    }
+
+    fn read_config(&self, offset: u64, data: &mut [u8]) {
+        let offset = offset as usize;
+        let len = data.len();
+        let cfg = self.get_config();
+        let cfg_slice = cfg.as_slice();
+        if offset + len <= cfg_slice.len() {
+            data.copy_from_slice(&cfg_slice[offset..offset + len]);
+        }
+    }
+
+    fn write_config(&mut self, offset: u64, data: &[u8]) {
+        let offset = offset as usize;
+        let len = data.len();
+        let mut cfg = self.get_config();
+        let cfg_slice = cfg.as_mut_slice();
+        if offset + len <= cfg_slice.len() {
+            cfg_slice[offset..offset + len].copy_from_slice(data);
+        }
+        if (cfg.events_clear.to_native() & VIRTIO_GPU_EVENT_DISPLAY) != 0 {
+            self.config_event = false;
+        }
+    }
+
+    fn activate(
+        &mut self,
+        mem: GuestMemory,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        interrupt_status: Arc<AtomicUsize>,
+        mut queues: Vec<Queue>,
+        mut queue_evts: Vec<EventFd>,
+    ) {
+        if queues.len() != QUEUE_SIZES.len() || queue_evts.len() != QUEUE_SIZES.len() {
+            return;
+        }
+
+        let exit_evt = match self.exit_evt.try_clone() {
+            Ok(e) => e,
+            Err(e) => {
+                error!("error cloning exit eventfd: {}", e);
+                return;
+            }
+        };
+
+        let (self_kill_evt, kill_evt) = match EventFd::new().and_then(|e| Ok((e.try_clone()?, e))) {
+            Ok(v) => v,
+            Err(e) => {
+                error!("error creating kill EventFd pair: {}", e);
+                return;
+            }
+        };
+        self.kill_evt = Some(self_kill_evt);
+
+        let resource_bridge = self.resource_bridge.take();
+
+        let ctrl_queue = queues.remove(0);
+        let ctrl_evt = queue_evts.remove(0);
+        let cursor_queue = queues.remove(0);
+        let cursor_evt = queue_evts.remove(0);
+        let socket_path = self.wayland_socket_path.clone();
+        if let Some(gpu_device_socket) = self.gpu_device_socket.take() {
+            let worker_result =
+                thread::Builder::new()
+                    .name("virtio_gpu".to_string())
+                    .spawn(move || {
+                        const UNDESIRED_CARDS: &[&str] = &["vgem", "pvr"];
+                        let drm_card = match gpu_buffer::rendernode::open_device(UNDESIRED_CARDS) {
+                            Ok(f) => f,
+                            Err(()) => {
+                                error!("failed to open card");
+                                return;
+                            }
+                        };
+
+                        let device = match Device::new(drm_card) {
+                            Ok(d) => d,
+                            Err(()) => {
+                                error!("failed to open device");
+                                return;
+                            }
+                        };
+
+                        let display = match GpuDisplay::new(socket_path) {
+                            Ok(c) => c,
+                            Err(e) => {
+                                error!("failed to open display: {}", e);
+                                return;
+                            }
+                        };
+
+                        if cfg!(debug_assertions) {
+                            let ret =
+                                unsafe { libc::dup2(libc::STDOUT_FILENO, libc::STDERR_FILENO) };
+                            if ret == -1 {
+                                warn!("unable to dup2 stdout to stderr: {}", Error::last());
+                            }
+                        }
+
+                        let renderer = match Renderer::init() {
+                            Ok(r) => r,
+                            Err(e) => {
+                                error!("failed to initialize gpu renderer: {}", e);
+                                return;
+                            }
+                        };
+
+                        Worker {
+                            exit_evt,
+                            mem,
+                            interrupt_evt,
+                            interrupt_resample_evt,
+                            interrupt_status,
+                            ctrl_queue,
+                            ctrl_evt,
+                            cursor_queue,
+                            cursor_evt,
+                            resource_bridge,
+                            kill_evt,
+                            state: Frontend::new(Backend::new(
+                                device,
+                                display,
+                                renderer,
+                                gpu_device_socket,
+                            )),
+                        }
+                        .run()
+                    });
+
+            if let Err(e) = worker_result {
+                error!("failed to spawn virtio_gpu worker: {}", e);
+                return;
+            }
+        }
+    }
+
+    // Require 1 BAR for mapping 3D buffers
+    fn get_device_bars(&self) -> Vec<PciBarConfiguration> {
+        vec![PciBarConfiguration::new(
+            4,
+            1 << 33,
+            PciBarRegionType::Memory64BitRegion,
+            PciBarPrefetchable::NotPrefetchable,
+        )]
+    }
+}
diff --git a/devices/src/virtio/gpu/protocol.rs b/devices/src/virtio/gpu/protocol.rs
new file mode 100644
index 0000000..008283b
--- /dev/null
+++ b/devices/src/virtio/gpu/protocol.rs
@@ -0,0 +1,798 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+
+use std::cmp::min;
+use std::fmt::{self, Display};
+use std::marker::PhantomData;
+use std::mem::{size_of, size_of_val};
+use std::str::from_utf8;
+
+use data_model::{DataInit, Le32, Le64, VolatileMemory, VolatileMemoryError, VolatileSlice};
+
+pub const VIRTIO_GPU_F_VIRGL: u32 = 0;
+
+pub const VIRTIO_GPU_UNDEFINED: u32 = 0x0;
+
+/* 2d commands */
+pub const VIRTIO_GPU_CMD_GET_DISPLAY_INFO: u32 = 0x100;
+pub const VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: u32 = 0x101;
+pub const VIRTIO_GPU_CMD_RESOURCE_UNREF: u32 = 0x102;
+pub const VIRTIO_GPU_CMD_SET_SCANOUT: u32 = 0x103;
+pub const VIRTIO_GPU_CMD_RESOURCE_FLUSH: u32 = 0x104;
+pub const VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: u32 = 0x105;
+pub const VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING: u32 = 0x106;
+pub const VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING: u32 = 0x107;
+pub const VIRTIO_GPU_CMD_GET_CAPSET_INFO: u32 = 0x108;
+pub const VIRTIO_GPU_CMD_GET_CAPSET: u32 = 0x109;
+
+/* 3d commands */
+pub const VIRTIO_GPU_CMD_CTX_CREATE: u32 = 0x200;
+pub const VIRTIO_GPU_CMD_CTX_DESTROY: u32 = 0x201;
+pub const VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE: u32 = 0x202;
+pub const VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE: u32 = 0x203;
+pub const VIRTIO_GPU_CMD_RESOURCE_CREATE_3D: u32 = 0x204;
+pub const VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D: u32 = 0x205;
+pub const VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D: u32 = 0x206;
+pub const VIRTIO_GPU_CMD_SUBMIT_3D: u32 = 0x207;
+
+/* cursor commands */
+pub const VIRTIO_GPU_CMD_UPDATE_CURSOR: u32 = 0x300;
+pub const VIRTIO_GPU_CMD_MOVE_CURSOR: u32 = 0x301;
+
+/* success responses */
+pub const VIRTIO_GPU_RESP_OK_NODATA: u32 = 0x1100;
+pub const VIRTIO_GPU_RESP_OK_DISPLAY_INFO: u32 = 0x1101;
+pub const VIRTIO_GPU_RESP_OK_CAPSET_INFO: u32 = 0x1102;
+pub const VIRTIO_GPU_RESP_OK_CAPSET: u32 = 0x1103;
+pub const VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO: u32 = 0x1104;
+
+/* error responses */
+pub const VIRTIO_GPU_RESP_ERR_UNSPEC: u32 = 0x1200;
+pub const VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY: u32 = 0x1201;
+pub const VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID: u32 = 0x1202;
+pub const VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID: u32 = 0x1203;
+pub const VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID: u32 = 0x1204;
+pub const VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER: u32 = 0x1205;
+
+pub fn virtio_gpu_cmd_str(cmd: u32) -> &'static str {
+    match cmd {
+        VIRTIO_GPU_CMD_GET_DISPLAY_INFO => "VIRTIO_GPU_CMD_GET_DISPLAY_INFO",
+        VIRTIO_GPU_CMD_RESOURCE_CREATE_2D => "VIRTIO_GPU_CMD_RESOURCE_CREATE_2D",
+        VIRTIO_GPU_CMD_RESOURCE_UNREF => "VIRTIO_GPU_CMD_RESOURCE_UNREF",
+        VIRTIO_GPU_CMD_SET_SCANOUT => "VIRTIO_GPU_CMD_SET_SCANOUT",
+        VIRTIO_GPU_CMD_RESOURCE_FLUSH => "VIRTIO_GPU_CMD_RESOURCE_FLUSH",
+        VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D => "VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D",
+        VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING => "VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING",
+        VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING => "VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING",
+        VIRTIO_GPU_CMD_GET_CAPSET_INFO => "VIRTIO_GPU_CMD_GET_CAPSET_INFO",
+        VIRTIO_GPU_CMD_GET_CAPSET => "VIRTIO_GPU_CMD_GET_CAPSET",
+        VIRTIO_GPU_CMD_CTX_CREATE => "VIRTIO_GPU_CMD_CTX_CREATE",
+        VIRTIO_GPU_CMD_CTX_DESTROY => "VIRTIO_GPU_CMD_CTX_DESTROY",
+        VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE => "VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE",
+        VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE => "VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE",
+        VIRTIO_GPU_CMD_RESOURCE_CREATE_3D => "VIRTIO_GPU_CMD_RESOURCE_CREATE_3D",
+        VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D => "VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D",
+        VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D => "VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D",
+        VIRTIO_GPU_CMD_SUBMIT_3D => "VIRTIO_GPU_CMD_SUBMIT_3D",
+        VIRTIO_GPU_CMD_UPDATE_CURSOR => "VIRTIO_GPU_CMD_UPDATE_CURSOR",
+        VIRTIO_GPU_CMD_MOVE_CURSOR => "VIRTIO_GPU_CMD_MOVE_CURSOR",
+        VIRTIO_GPU_RESP_OK_NODATA => "VIRTIO_GPU_RESP_OK_NODATA",
+        VIRTIO_GPU_RESP_OK_DISPLAY_INFO => "VIRTIO_GPU_RESP_OK_DISPLAY_INFO",
+        VIRTIO_GPU_RESP_OK_CAPSET_INFO => "VIRTIO_GPU_RESP_OK_CAPSET_INFO",
+        VIRTIO_GPU_RESP_OK_CAPSET => "VIRTIO_GPU_RESP_OK_CAPSET",
+        VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO => "VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO",
+        VIRTIO_GPU_RESP_ERR_UNSPEC => "VIRTIO_GPU_RESP_ERR_UNSPEC",
+        VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY => "VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY",
+        VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID => "VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID",
+        VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID => "VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID",
+        VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID => "VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID",
+        VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER => "VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER",
+        _ => "UNKNOWN",
+    }
+}
+
+pub const VIRTIO_GPU_FLAG_FENCE: u32 = (1 << 0);
+
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_ctrl_hdr {
+    pub type_: Le32,
+    pub flags: Le32,
+    pub fence_id: Le64,
+    pub ctx_id: Le32,
+    pub padding: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_ctrl_hdr {}
+
+/* data passed in the cursor vq */
+
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_cursor_pos {
+    pub scanout_id: Le32,
+    pub x: Le32,
+    pub y: Le32,
+    pub padding: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_cursor_pos {}
+
+/* VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_CMD_MOVE_CURSOR */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_update_cursor {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub pos: virtio_gpu_cursor_pos, /* update & move */
+    pub resource_id: Le32,          /* update only */
+    pub hot_x: Le32,                /* update only */
+    pub hot_y: Le32,                /* update only */
+    pub padding: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_update_cursor {}
+
+/* data passed in the control vq, 2d related */
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+pub struct virtio_gpu_rect {
+    pub x: Le32,
+    pub y: Le32,
+    pub width: Le32,
+    pub height: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_rect {}
+
+/* VIRTIO_GPU_CMD_RESOURCE_UNREF */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_resource_unref {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub resource_id: Le32,
+    pub padding: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_resource_unref {}
+
+/* VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: create a 2d resource with a format */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_resource_create_2d {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub resource_id: Le32,
+    pub format: Le32,
+    pub width: Le32,
+    pub height: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_resource_create_2d {}
+
+/* VIRTIO_GPU_CMD_SET_SCANOUT */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_set_scanout {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub r: virtio_gpu_rect,
+    pub scanout_id: Le32,
+    pub resource_id: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_set_scanout {}
+
+/* VIRTIO_GPU_CMD_RESOURCE_FLUSH */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_resource_flush {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub r: virtio_gpu_rect,
+    pub resource_id: Le32,
+    pub padding: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_resource_flush {}
+
+/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: simple transfer to_host */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_transfer_to_host_2d {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub r: virtio_gpu_rect,
+    pub offset: Le64,
+    pub resource_id: Le32,
+    pub padding: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_transfer_to_host_2d {}
+
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_mem_entry {
+    pub addr: Le64,
+    pub length: Le32,
+    pub padding: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_mem_entry {}
+
+/* VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_resource_attach_backing {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub resource_id: Le32,
+    pub nr_entries: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_resource_attach_backing {}
+
+/* VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_resource_detach_backing {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub resource_id: Le32,
+    pub padding: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_resource_detach_backing {}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+pub struct virtio_gpu_display_one {
+    pub r: virtio_gpu_rect,
+    pub enabled: Le32,
+    pub flags: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_display_one {}
+
+/* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */
+const VIRTIO_GPU_MAX_SCANOUTS: usize = 16;
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_resp_display_info {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub pmodes: [virtio_gpu_display_one; VIRTIO_GPU_MAX_SCANOUTS],
+}
+
+unsafe impl DataInit for virtio_gpu_resp_display_info {}
+
+/* data passed in the control vq, 3d related */
+
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_box {
+    pub x: Le32,
+    pub y: Le32,
+    pub z: Le32,
+    pub w: Le32,
+    pub h: Le32,
+    pub d: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_box {}
+
+/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_transfer_host_3d {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub box_: virtio_gpu_box,
+    pub offset: Le64,
+    pub resource_id: Le32,
+    pub level: Le32,
+    pub stride: Le32,
+    pub layer_stride: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_transfer_host_3d {}
+
+/* VIRTIO_GPU_CMD_RESOURCE_CREATE_3D */
+pub const VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP: u32 = (1 << 0);
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_resource_create_3d {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub resource_id: Le32,
+    pub target: Le32,
+    pub format: Le32,
+    pub bind: Le32,
+    pub width: Le32,
+    pub height: Le32,
+    pub depth: Le32,
+    pub array_size: Le32,
+    pub last_level: Le32,
+    pub nr_samples: Le32,
+    pub flags: Le32,
+    pub padding: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_resource_create_3d {}
+
+/* VIRTIO_GPU_CMD_CTX_CREATE */
+#[derive(Copy)]
+#[repr(C)]
+pub struct virtio_gpu_ctx_create {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub nlen: Le32,
+    pub padding: Le32,
+    pub debug_name: [u8; 64],
+}
+
+unsafe impl DataInit for virtio_gpu_ctx_create {}
+
+impl Clone for virtio_gpu_ctx_create {
+    fn clone(&self) -> virtio_gpu_ctx_create {
+        *self
+    }
+}
+
+impl fmt::Debug for virtio_gpu_ctx_create {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let debug_name = from_utf8(&self.debug_name[..min(64, self.nlen.to_native() as usize)])
+            .unwrap_or("<invalid>");
+        f.debug_struct("virtio_gpu_ctx_create")
+            .field("hdr", &self.hdr)
+            .field("debug_name", &debug_name)
+            .finish()
+    }
+}
+
+/* VIRTIO_GPU_CMD_CTX_DESTROY */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_ctx_destroy {
+    pub hdr: virtio_gpu_ctrl_hdr,
+}
+
+unsafe impl DataInit for virtio_gpu_ctx_destroy {}
+
+/* VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_ctx_resource {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub resource_id: Le32,
+    pub padding: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_ctx_resource {}
+
+/* VIRTIO_GPU_CMD_SUBMIT_3D */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_cmd_submit {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub size: Le32,
+    pub padding: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_cmd_submit {}
+
+pub const VIRTIO_GPU_CAPSET_VIRGL: u32 = 1;
+pub const VIRTIO_GPU_CAPSET_VIRGL2: u32 = 2;
+
+/* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_get_capset_info {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub capset_index: Le32,
+    pub padding: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_get_capset_info {}
+
+/* VIRTIO_GPU_RESP_OK_CAPSET_INFO */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_resp_capset_info {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub capset_id: Le32,
+    pub capset_max_version: Le32,
+    pub capset_max_size: Le32,
+    pub padding: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_resp_capset_info {}
+
+/* VIRTIO_GPU_CMD_GET_CAPSET */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_get_capset {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub capset_id: Le32,
+    pub capset_version: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_get_capset {}
+
+/* VIRTIO_GPU_RESP_OK_CAPSET */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_resp_capset {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub capset_data: PhantomData<[u8]>,
+}
+
+unsafe impl DataInit for virtio_gpu_resp_capset {}
+
+/* VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO */
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_resp_resource_plane_info {
+    pub hdr: virtio_gpu_ctrl_hdr,
+    pub count: Le32,
+    pub padding: Le32,
+    pub format_modifier: Le64,
+    pub strides: [Le32; 4],
+    pub offsets: [Le32; 4],
+}
+
+unsafe impl DataInit for virtio_gpu_resp_resource_plane_info {}
+
+const PLANE_INFO_MAX_COUNT: usize = 4;
+
+pub const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0;
+
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct virtio_gpu_config {
+    pub events_read: Le32,
+    pub events_clear: Le32,
+    pub num_scanouts: Le32,
+    pub num_capsets: Le32,
+}
+
+unsafe impl DataInit for virtio_gpu_config {}
+
+/* simple formats for fbcon/X use */
+pub const VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM: u32 = 1;
+pub const VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM: u32 = 2;
+pub const VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM: u32 = 3;
+pub const VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM: u32 = 4;
+pub const VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM: u32 = 67;
+pub const VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM: u32 = 68;
+pub const VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM: u32 = 121;
+pub const VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM: u32 = 134;
+
+/// A virtio gpu command and associated metadata specific to each command.
+#[derive(Copy, Clone)]
+pub enum GpuCommand {
+    GetDisplayInfo(virtio_gpu_ctrl_hdr),
+    ResourceCreate2d(virtio_gpu_resource_create_2d),
+    ResourceUnref(virtio_gpu_resource_unref),
+    SetScanout(virtio_gpu_set_scanout),
+    ResourceFlush(virtio_gpu_resource_flush),
+    TransferToHost2d(virtio_gpu_transfer_to_host_2d),
+    ResourceAttachBacking(virtio_gpu_resource_attach_backing),
+    ResourceDetachBacking(virtio_gpu_resource_detach_backing),
+    GetCapsetInfo(virtio_gpu_get_capset_info),
+    GetCapset(virtio_gpu_get_capset),
+    CtxCreate(virtio_gpu_ctx_create),
+    CtxDestroy(virtio_gpu_ctx_destroy),
+    CtxAttachResource(virtio_gpu_ctx_resource),
+    CtxDetachResource(virtio_gpu_ctx_resource),
+    ResourceCreate3d(virtio_gpu_resource_create_3d),
+    TransferToHost3d(virtio_gpu_transfer_host_3d),
+    TransferFromHost3d(virtio_gpu_transfer_host_3d),
+    CmdSubmit3d(virtio_gpu_cmd_submit),
+    UpdateCursor(virtio_gpu_update_cursor),
+    MoveCursor(virtio_gpu_update_cursor),
+}
+
+/// An error indicating something went wrong decoding a `GpuCommand`. These correspond to
+/// `VIRTIO_GPU_CMD_*`.
+#[derive(Debug)]
+pub enum GpuCommandDecodeError {
+    /// The command referenced an inaccessible area of memory.
+    Memory(VolatileMemoryError),
+    /// The type of the command was invalid.
+    InvalidType(u32),
+}
+
+impl Display for GpuCommandDecodeError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::GpuCommandDecodeError::*;
+
+        match self {
+            Memory(e) => write!(
+                f,
+                "command referenced an inaccessible area of memory: {}",
+                e,
+            ),
+            InvalidType(n) => write!(f, "invalid command type ({})", n),
+        }
+    }
+}
+
+impl From<VolatileMemoryError> for GpuCommandDecodeError {
+    fn from(e: VolatileMemoryError) -> GpuCommandDecodeError {
+        GpuCommandDecodeError::Memory(e)
+    }
+}
+
+impl fmt::Debug for GpuCommand {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::GpuCommand::*;
+        match self {
+            GetDisplayInfo(_info) => f.debug_struct("GetDisplayInfo").finish(),
+            ResourceCreate2d(_info) => f.debug_struct("ResourceCreate2d").finish(),
+            ResourceUnref(_info) => f.debug_struct("ResourceUnref").finish(),
+            SetScanout(_info) => f.debug_struct("SetScanout").finish(),
+            ResourceFlush(_info) => f.debug_struct("ResourceFlush").finish(),
+            TransferToHost2d(_info) => f.debug_struct("TransferToHost2d").finish(),
+            ResourceAttachBacking(_info) => f.debug_struct("ResourceAttachBacking").finish(),
+            ResourceDetachBacking(_info) => f.debug_struct("ResourceDetachBacking").finish(),
+            GetCapsetInfo(_info) => f.debug_struct("GetCapsetInfo").finish(),
+            GetCapset(_info) => f.debug_struct("GetCapset").finish(),
+            CtxCreate(_info) => f.debug_struct("CtxCreate").finish(),
+            CtxDestroy(_info) => f.debug_struct("CtxDestroy").finish(),
+            CtxAttachResource(_info) => f.debug_struct("CtxAttachResource").finish(),
+            CtxDetachResource(_info) => f.debug_struct("CtxDetachResource").finish(),
+            ResourceCreate3d(_info) => f.debug_struct("ResourceCreate3d").finish(),
+            TransferToHost3d(_info) => f.debug_struct("TransferToHost3d").finish(),
+            TransferFromHost3d(_info) => f.debug_struct("TransferFromHost3d").finish(),
+            CmdSubmit3d(_info) => f.debug_struct("CmdSubmit3d").finish(),
+            UpdateCursor(_info) => f.debug_struct("UpdateCursor").finish(),
+            MoveCursor(_info) => f.debug_struct("MoveCursor").finish(),
+        }
+    }
+}
+
+impl GpuCommand {
+    /// Decodes a command from the given chunk of memory.
+    pub fn decode(cmd: VolatileSlice) -> Result<GpuCommand, GpuCommandDecodeError> {
+        use self::GpuCommand::*;
+        let hdr: virtio_gpu_ctrl_hdr = cmd.get_ref(0)?.load();
+        Ok(match hdr.type_.into() {
+            VIRTIO_GPU_CMD_GET_DISPLAY_INFO => GetDisplayInfo(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_RESOURCE_CREATE_2D => ResourceCreate2d(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_RESOURCE_UNREF => ResourceUnref(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_SET_SCANOUT => SetScanout(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_RESOURCE_FLUSH => ResourceFlush(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D => TransferToHost2d(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING => ResourceAttachBacking(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING => ResourceDetachBacking(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_GET_CAPSET_INFO => GetCapsetInfo(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_GET_CAPSET => GetCapset(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_CTX_CREATE => CtxCreate(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_CTX_DESTROY => CtxDestroy(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE => CtxAttachResource(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE => CtxDetachResource(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_RESOURCE_CREATE_3D => ResourceCreate3d(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D => TransferToHost3d(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D => TransferFromHost3d(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_SUBMIT_3D => CmdSubmit3d(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_UPDATE_CURSOR => UpdateCursor(cmd.get_ref(0)?.load()),
+            VIRTIO_GPU_CMD_MOVE_CURSOR => MoveCursor(cmd.get_ref(0)?.load()),
+            _ => return Err(GpuCommandDecodeError::InvalidType(hdr.type_.into())),
+        })
+    }
+
+    /// Gets the generic `virtio_gpu_ctrl_hdr` from this command.
+    pub fn ctrl_hdr(&self) -> &virtio_gpu_ctrl_hdr {
+        use self::GpuCommand::*;
+        match self {
+            GetDisplayInfo(info) => info,
+            ResourceCreate2d(info) => &info.hdr,
+            ResourceUnref(info) => &info.hdr,
+            SetScanout(info) => &info.hdr,
+            ResourceFlush(info) => &info.hdr,
+            TransferToHost2d(info) => &info.hdr,
+            ResourceAttachBacking(info) => &info.hdr,
+            ResourceDetachBacking(info) => &info.hdr,
+            GetCapsetInfo(info) => &info.hdr,
+            GetCapset(info) => &info.hdr,
+            CtxCreate(info) => &info.hdr,
+            CtxDestroy(info) => &info.hdr,
+            CtxAttachResource(info) => &info.hdr,
+            CtxDetachResource(info) => &info.hdr,
+            ResourceCreate3d(info) => &info.hdr,
+            TransferToHost3d(info) => &info.hdr,
+            TransferFromHost3d(info) => &info.hdr,
+            CmdSubmit3d(info) => &info.hdr,
+            UpdateCursor(info) => &info.hdr,
+            MoveCursor(info) => &info.hdr,
+        }
+    }
+}
+
+#[derive(Debug, PartialEq)]
+pub struct GpuResponsePlaneInfo {
+    pub stride: u32,
+    pub offset: u32,
+}
+
+/// A response to a `GpuCommand`. These correspond to `VIRTIO_GPU_RESP_*`.
+#[derive(Debug, PartialEq)]
+pub enum GpuResponse {
+    OkNoData,
+    OkDisplayInfo(Vec<(u32, u32)>),
+    OkCapsetInfo {
+        id: u32,
+        version: u32,
+        size: u32,
+    },
+    OkCapset(Vec<u8>),
+    OkResourcePlaneInfo {
+        format_modifier: u64,
+        plane_info: Vec<GpuResponsePlaneInfo>,
+    },
+    ErrUnspec,
+    ErrOutOfMemory,
+    ErrInvalidScanoutId,
+    ErrInvalidResourceId,
+    ErrInvalidContextId,
+    ErrInvalidParameter,
+}
+
+/// An error indicating something went wrong decoding a `GpuCommand`.
+#[derive(Debug)]
+pub enum GpuResponseEncodeError {
+    /// The response was encoded to an inaccessible area of memory.
+    Memory(VolatileMemoryError),
+    /// More displays than are valid were in a `OkDisplayInfo`.
+    TooManyDisplays(usize),
+    /// More planes than are valid were in a `OkResourcePlaneInfo`.
+    TooManyPlanes(usize),
+}
+
+impl Display for GpuResponseEncodeError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::GpuResponseEncodeError::*;
+
+        match self {
+            Memory(e) => write!(
+                f,
+                "response was encoded to an inaccessible area of memory: {}",
+                e,
+            ),
+            TooManyDisplays(n) => write!(f, "{} is more displays than are valid", n),
+            TooManyPlanes(n) => write!(f, "{} is more planes than are valid", n),
+        }
+    }
+}
+
+impl From<VolatileMemoryError> for GpuResponseEncodeError {
+    fn from(e: VolatileMemoryError) -> GpuResponseEncodeError {
+        GpuResponseEncodeError::Memory(e)
+    }
+}
+
+impl GpuResponse {
+    /// Encodes a this `GpuResponse` into `resp` and the given set of metadata.
+    pub fn encode(
+        &self,
+        flags: u32,
+        fence_id: u64,
+        ctx_id: u32,
+        resp: VolatileSlice,
+    ) -> Result<u32, GpuResponseEncodeError> {
+        let hdr = virtio_gpu_ctrl_hdr {
+            type_: Le32::from(self.get_type()),
+            flags: Le32::from(flags),
+            fence_id: Le64::from(fence_id),
+            ctx_id: Le32::from(ctx_id),
+            padding: Le32::from(0),
+        };
+        let len = match *self {
+            GpuResponse::OkDisplayInfo(ref info) => {
+                if info.len() > VIRTIO_GPU_MAX_SCANOUTS {
+                    return Err(GpuResponseEncodeError::TooManyDisplays(info.len()));
+                }
+                let mut disp_info = virtio_gpu_resp_display_info {
+                    hdr,
+                    pmodes: Default::default(),
+                };
+                for (disp_mode, &(width, height)) in disp_info.pmodes.iter_mut().zip(info) {
+                    disp_mode.r.width = Le32::from(width);
+                    disp_mode.r.height = Le32::from(height);
+                    disp_mode.enabled = Le32::from(1);
+                }
+                resp.get_ref(0)?.store(disp_info);
+                size_of_val(&disp_info)
+            }
+            GpuResponse::OkCapsetInfo { id, version, size } => {
+                resp.get_ref(0)?.store(virtio_gpu_resp_capset_info {
+                    hdr,
+                    capset_id: Le32::from(id),
+                    capset_max_version: Le32::from(version),
+                    capset_max_size: Le32::from(size),
+                    padding: Le32::from(0),
+                });
+                size_of::<virtio_gpu_resp_capset_info>()
+            }
+            GpuResponse::OkCapset(ref data) => {
+                resp.get_ref(0)?.store(hdr);
+                let resp_data_slice =
+                    resp.get_slice(size_of_val(&hdr) as u64, data.len() as u64)?;
+                resp_data_slice.copy_from(data);
+                size_of_val(&hdr) + data.len()
+            }
+            GpuResponse::OkResourcePlaneInfo {
+                format_modifier,
+                ref plane_info,
+            } => {
+                if plane_info.len() > PLANE_INFO_MAX_COUNT {
+                    return Err(GpuResponseEncodeError::TooManyPlanes(plane_info.len()));
+                }
+                let mut strides = [Le32::default(); PLANE_INFO_MAX_COUNT];
+                let mut offsets = [Le32::default(); PLANE_INFO_MAX_COUNT];
+                for (plane_index, plane) in plane_info.iter().enumerate() {
+                    strides[plane_index] = plane.stride.into();
+                    offsets[plane_index] = plane.offset.into();
+                }
+                let plane_info = virtio_gpu_resp_resource_plane_info {
+                    hdr,
+                    count: Le32::from(plane_info.len() as u32),
+                    padding: 0.into(),
+                    format_modifier: format_modifier.into(),
+                    strides,
+                    offsets,
+                };
+                match resp.get_ref(0) {
+                    Ok(resp_ref) => {
+                        resp_ref.store(plane_info);
+                        size_of_val(&plane_info)
+                    }
+                    _ => {
+                        // In case there is too little room in the response slice to store the
+                        // entire virtio_gpu_resp_resource_plane_info, convert response to a regular
+                        // VIRTIO_GPU_RESP_OK_NODATA and attempt to return that.
+                        resp.get_ref(0)?.store(virtio_gpu_ctrl_hdr {
+                            type_: Le32::from(VIRTIO_GPU_RESP_OK_NODATA),
+                            ..hdr
+                        });
+                        size_of_val(&hdr)
+                    }
+                }
+            }
+            _ => {
+                resp.get_ref(0)?.store(hdr);
+                size_of_val(&hdr)
+            }
+        };
+        Ok(len as u32)
+    }
+
+    /// Gets the `VIRTIO_GPU_*` enum value that corresponds to this variant.
+    pub fn get_type(&self) -> u32 {
+        match self {
+            GpuResponse::OkNoData => VIRTIO_GPU_RESP_OK_NODATA,
+            GpuResponse::OkDisplayInfo(_) => VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
+            GpuResponse::OkCapsetInfo { .. } => VIRTIO_GPU_RESP_OK_CAPSET_INFO,
+            GpuResponse::OkCapset(_) => VIRTIO_GPU_RESP_OK_CAPSET,
+            GpuResponse::OkResourcePlaneInfo { .. } => VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO,
+            GpuResponse::ErrUnspec => VIRTIO_GPU_RESP_ERR_UNSPEC,
+            GpuResponse::ErrOutOfMemory => VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY,
+            GpuResponse::ErrInvalidScanoutId => VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID,
+            GpuResponse::ErrInvalidResourceId => VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID,
+            GpuResponse::ErrInvalidContextId => VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID,
+            GpuResponse::ErrInvalidParameter => VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
+        }
+    }
+
+    /// Returns true if this response indicates success.
+    pub fn is_ok(&self) -> bool {
+        match self {
+            GpuResponse::OkNoData => true,
+            GpuResponse::OkDisplayInfo(_) => true,
+            GpuResponse::OkCapsetInfo { .. } => true,
+            GpuResponse::OkCapset(_) => true,
+            GpuResponse::OkResourcePlaneInfo { .. } => true,
+            _ => false,
+        }
+    }
+
+    /// Returns true if this response indicates an error.
+    pub fn is_err(&self) -> bool {
+        !self.is_ok()
+    }
+}
diff --git a/devices/src/virtio/input/constants.rs b/devices/src/virtio/input/constants.rs
new file mode 100644
index 0000000..6cc3574
--- /dev/null
+++ b/devices/src/virtio/input/constants.rs
@@ -0,0 +1,738 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Should match linux/input-event-codes.h
+pub const INPUT_PROP_POINTER: u16 = 0x00;
+pub const INPUT_PROP_DIRECT: u16 = 0x01;
+pub const INPUT_PROP_BUTTONPAD: u16 = 0x02;
+pub const INPUT_PROP_SEMI_MT: u16 = 0x03;
+pub const INPUT_PROP_TOPBUTTONPAD: u16 = 0x04;
+pub const INPUT_PROP_POINTING_STICK: u16 = 0x05;
+pub const INPUT_PROP_ACCELEROMETER: u16 = 0x06;
+
+pub const INPUT_PROP_MAX: u16 = 0x1f;
+pub const INPUT_PROP_CNT: u16 = (INPUT_PROP_MAX + 1);
+
+pub const EV_SYN: u16 = 0x00;
+pub const EV_KEY: u16 = 0x01;
+pub const EV_REL: u16 = 0x02;
+pub const EV_ABS: u16 = 0x03;
+pub const EV_MSC: u16 = 0x04;
+pub const EV_SW: u16 = 0x05;
+pub const EV_LED: u16 = 0x11;
+pub const EV_SND: u16 = 0x12;
+pub const EV_REP: u16 = 0x14;
+pub const EV_FF: u16 = 0x15;
+pub const EV_PWR: u16 = 0x16;
+pub const EV_FF_STATUS: u16 = 0x17;
+pub const EV_MAX: u16 = 0x1f;
+pub const EV_CNT: u16 = EV_MAX + 1;
+
+pub const SYN_REPORT: u16 = 0;
+pub const SYN_CONFIG: u16 = 1;
+pub const SYN_MT_REPORT: u16 = 2;
+pub const SYN_DROPPED: u16 = 3;
+
+pub const KEY_RESERVED: u16 = 0;
+pub const KEY_ESC: u16 = 1;
+pub const KEY_1: u16 = 2;
+pub const KEY_2: u16 = 3;
+pub const KEY_3: u16 = 4;
+pub const KEY_4: u16 = 5;
+pub const KEY_5: u16 = 6;
+pub const KEY_6: u16 = 7;
+pub const KEY_7: u16 = 8;
+pub const KEY_8: u16 = 9;
+pub const KEY_9: u16 = 10;
+pub const KEY_0: u16 = 11;
+pub const KEY_MINUS: u16 = 12;
+pub const KEY_EQUAL: u16 = 13;
+pub const KEY_BACKSPACE: u16 = 14;
+pub const KEY_TAB: u16 = 15;
+pub const KEY_Q: u16 = 16;
+pub const KEY_W: u16 = 17;
+pub const KEY_E: u16 = 18;
+pub const KEY_R: u16 = 19;
+pub const KEY_T: u16 = 20;
+pub const KEY_Y: u16 = 21;
+pub const KEY_U: u16 = 22;
+pub const KEY_I: u16 = 23;
+pub const KEY_O: u16 = 24;
+pub const KEY_P: u16 = 25;
+pub const KEY_LEFTBRACE: u16 = 26;
+pub const KEY_RIGHTBRACE: u16 = 27;
+pub const KEY_ENTER: u16 = 28;
+pub const KEY_LEFTCTRL: u16 = 29;
+pub const KEY_A: u16 = 30;
+pub const KEY_S: u16 = 31;
+pub const KEY_D: u16 = 32;
+pub const KEY_F: u16 = 33;
+pub const KEY_G: u16 = 34;
+pub const KEY_H: u16 = 35;
+pub const KEY_J: u16 = 36;
+pub const KEY_K: u16 = 37;
+pub const KEY_L: u16 = 38;
+pub const KEY_SEMICOLON: u16 = 39;
+pub const KEY_APOSTROPHE: u16 = 40;
+pub const KEY_GRAVE: u16 = 41;
+pub const KEY_LEFTSHIFT: u16 = 42;
+pub const KEY_BACKSLASH: u16 = 43;
+pub const KEY_Z: u16 = 44;
+pub const KEY_X: u16 = 45;
+pub const KEY_C: u16 = 46;
+pub const KEY_V: u16 = 47;
+pub const KEY_B: u16 = 48;
+pub const KEY_N: u16 = 49;
+pub const KEY_M: u16 = 50;
+pub const KEY_COMMA: u16 = 51;
+pub const KEY_DOT: u16 = 52;
+pub const KEY_SLASH: u16 = 53;
+pub const KEY_RIGHTSHIFT: u16 = 54;
+pub const KEY_KPASTERISK: u16 = 55;
+pub const KEY_LEFTALT: u16 = 56;
+pub const KEY_SPACE: u16 = 57;
+pub const KEY_CAPSLOCK: u16 = 58;
+pub const KEY_F1: u16 = 59;
+pub const KEY_F2: u16 = 60;
+pub const KEY_F3: u16 = 61;
+pub const KEY_F4: u16 = 62;
+pub const KEY_F5: u16 = 63;
+pub const KEY_F6: u16 = 64;
+pub const KEY_F7: u16 = 65;
+pub const KEY_F8: u16 = 66;
+pub const KEY_F9: u16 = 67;
+pub const KEY_F10: u16 = 68;
+pub const KEY_NUMLOCK: u16 = 69;
+pub const KEY_SCROLLLOCK: u16 = 70;
+pub const KEY_KP7: u16 = 71;
+pub const KEY_KP8: u16 = 72;
+pub const KEY_KP9: u16 = 73;
+pub const KEY_KPMINUS: u16 = 74;
+pub const KEY_KP4: u16 = 75;
+pub const KEY_KP5: u16 = 76;
+pub const KEY_KP6: u16 = 77;
+pub const KEY_KPPLUS: u16 = 78;
+pub const KEY_KP1: u16 = 79;
+pub const KEY_KP2: u16 = 80;
+pub const KEY_KP3: u16 = 81;
+pub const KEY_KP0: u16 = 82;
+pub const KEY_KPDOT: u16 = 83;
+
+pub const KEY_ZENKAKUHANKAKU: u16 = 85;
+pub const KEY_102ND: u16 = 86;
+pub const KEY_F11: u16 = 87;
+pub const KEY_F12: u16 = 88;
+pub const KEY_RO: u16 = 89;
+pub const KEY_KATAKANA: u16 = 90;
+pub const KEY_HIRAGANA: u16 = 91;
+pub const KEY_HENKAN: u16 = 92;
+pub const KEY_KATAKANAHIRAGANA: u16 = 93;
+pub const KEY_MUHENKAN: u16 = 94;
+pub const KEY_KPJPCOMMA: u16 = 95;
+pub const KEY_KPENTER: u16 = 96;
+pub const KEY_RIGHTCTRL: u16 = 97;
+pub const KEY_KPSLASH: u16 = 98;
+pub const KEY_SYSRQ: u16 = 99;
+pub const KEY_RIGHTALT: u16 = 100;
+pub const KEY_LINEFEED: u16 = 101;
+pub const KEY_HOME: u16 = 102;
+pub const KEY_UP: u16 = 103;
+pub const KEY_PAGEUP: u16 = 104;
+pub const KEY_LEFT: u16 = 105;
+pub const KEY_RIGHT: u16 = 106;
+pub const KEY_END: u16 = 107;
+pub const KEY_DOWN: u16 = 108;
+pub const KEY_PAGEDOWN: u16 = 109;
+pub const KEY_INSERT: u16 = 110;
+pub const KEY_DELETE: u16 = 111;
+pub const KEY_MACRO: u16 = 112;
+pub const KEY_MUTE: u16 = 113;
+pub const KEY_VOLUMEDOWN: u16 = 114;
+pub const KEY_VOLUMEUP: u16 = 115;
+pub const KEY_POWER: u16 = 116;
+pub const KEY_KPEQUAL: u16 = 117;
+pub const KEY_KPPLUSMINUS: u16 = 118;
+pub const KEY_PAUSE: u16 = 119;
+pub const KEY_SCALE: u16 = 120;
+
+pub const KEY_KPCOMMA: u16 = 121;
+pub const KEY_HANGEUL: u16 = 122;
+pub const KEY_HANGUEL: u16 = KEY_HANGEUL;
+pub const KEY_HANJA: u16 = 123;
+pub const KEY_YEN: u16 = 124;
+pub const KEY_LEFTMETA: u16 = 125;
+pub const KEY_RIGHTMETA: u16 = 126;
+pub const KEY_COMPOSE: u16 = 127;
+
+pub const KEY_STOP: u16 = 128;
+pub const KEY_AGAIN: u16 = 129;
+pub const KEY_PROPS: u16 = 130;
+pub const KEY_UNDO: u16 = 131;
+pub const KEY_FRONT: u16 = 132;
+pub const KEY_COPY: u16 = 133;
+pub const KEY_OPEN: u16 = 134;
+pub const KEY_PASTE: u16 = 135;
+pub const KEY_FIND: u16 = 136;
+pub const KEY_CUT: u16 = 137;
+pub const KEY_HELP: u16 = 138;
+pub const KEY_MENU: u16 = 139;
+pub const KEY_CALC: u16 = 140;
+pub const KEY_SETUP: u16 = 141;
+pub const KEY_SLEEP: u16 = 142;
+pub const KEY_WAKEUP: u16 = 143;
+pub const KEY_FILE: u16 = 144;
+pub const KEY_SENDFILE: u16 = 145;
+pub const KEY_DELETEFILE: u16 = 146;
+pub const KEY_XFER: u16 = 147;
+pub const KEY_PROG1: u16 = 148;
+pub const KEY_PROG2: u16 = 149;
+pub const KEY_WWW: u16 = 150;
+pub const KEY_MSDOS: u16 = 151;
+pub const KEY_COFFEE: u16 = 152;
+pub const KEY_SCREENLOCK: u16 = KEY_COFFEE;
+pub const KEY_ROTATE_DISPLAY: u16 = 153;
+pub const KEY_DIRECTION: u16 = KEY_ROTATE_DISPLAY;
+pub const KEY_CYCLEWINDOWS: u16 = 154;
+pub const KEY_MAIL: u16 = 155;
+pub const KEY_BOOKMARKS: u16 = 156;
+pub const KEY_COMPUTER: u16 = 157;
+pub const KEY_BACK: u16 = 158;
+pub const KEY_FORWARD: u16 = 159;
+pub const KEY_CLOSECD: u16 = 160;
+pub const KEY_EJECTCD: u16 = 161;
+pub const KEY_EJECTCLOSECD: u16 = 162;
+pub const KEY_NEXTSONG: u16 = 163;
+pub const KEY_PLAYPAUSE: u16 = 164;
+pub const KEY_PREVIOUSSONG: u16 = 165;
+pub const KEY_STOPCD: u16 = 166;
+pub const KEY_RECORD: u16 = 167;
+pub const KEY_REWIND: u16 = 168;
+pub const KEY_PHONE: u16 = 169;
+pub const KEY_ISO: u16 = 170;
+pub const KEY_CONFIG: u16 = 171;
+pub const KEY_HOMEPAGE: u16 = 172;
+pub const KEY_REFRESH: u16 = 173;
+pub const KEY_EXIT: u16 = 174;
+pub const KEY_MOVE: u16 = 175;
+pub const KEY_EDIT: u16 = 176;
+pub const KEY_SCROLLUP: u16 = 177;
+pub const KEY_SCROLLDOWN: u16 = 178;
+pub const KEY_KPLEFTPAREN: u16 = 179;
+pub const KEY_KPRIGHTPAREN: u16 = 180;
+pub const KEY_NEW: u16 = 181;
+pub const KEY_REDO: u16 = 182;
+
+pub const KEY_F13: u16 = 183;
+pub const KEY_F14: u16 = 184;
+pub const KEY_F15: u16 = 185;
+pub const KEY_F16: u16 = 186;
+pub const KEY_F17: u16 = 187;
+pub const KEY_F18: u16 = 188;
+pub const KEY_F19: u16 = 189;
+pub const KEY_F20: u16 = 190;
+pub const KEY_F21: u16 = 191;
+pub const KEY_F22: u16 = 192;
+pub const KEY_F23: u16 = 193;
+pub const KEY_F24: u16 = 194;
+
+pub const KEY_PLAYCD: u16 = 200;
+pub const KEY_PAUSECD: u16 = 201;
+pub const KEY_PROG3: u16 = 202;
+pub const KEY_PROG4: u16 = 203;
+pub const KEY_DASHBOARD: u16 = 204;
+pub const KEY_SUSPEND: u16 = 205;
+pub const KEY_CLOSE: u16 = 206;
+pub const KEY_PLAY: u16 = 207;
+pub const KEY_FASTFORWARD: u16 = 208;
+pub const KEY_BASSBOOST: u16 = 209;
+pub const KEY_PRINT: u16 = 210;
+pub const KEY_HP: u16 = 211;
+pub const KEY_CAMERA: u16 = 212;
+pub const KEY_SOUND: u16 = 213;
+pub const KEY_QUESTION: u16 = 214;
+pub const KEY_EMAIL: u16 = 215;
+pub const KEY_CHAT: u16 = 216;
+pub const KEY_SEARCH: u16 = 217;
+pub const KEY_CONNECT: u16 = 218;
+pub const KEY_FINANCE: u16 = 219;
+pub const KEY_SPORT: u16 = 220;
+pub const KEY_SHOP: u16 = 221;
+pub const KEY_ALTERASE: u16 = 222;
+pub const KEY_CANCEL: u16 = 223;
+pub const KEY_BRIGHTNESSDOWN: u16 = 224;
+pub const KEY_BRIGHTNESSUP: u16 = 225;
+pub const KEY_MEDIA: u16 = 226;
+
+pub const KEY_SWITCHVIDEOMODE: u16 = 227;
+pub const KEY_KBDILLUMTOGGLE: u16 = 228;
+pub const KEY_KBDILLUMDOWN: u16 = 229;
+pub const KEY_KBDILLUMUP: u16 = 230;
+
+pub const KEY_SEND: u16 = 231;
+pub const KEY_REPLY: u16 = 232;
+pub const KEY_FORWARDMAIL: u16 = 233;
+pub const KEY_SAVE: u16 = 234;
+pub const KEY_DOCUMENTS: u16 = 235;
+
+pub const KEY_BATTERY: u16 = 236;
+
+pub const KEY_BLUETOOTH: u16 = 237;
+pub const KEY_WLAN: u16 = 238;
+pub const KEY_UWB: u16 = 239;
+
+pub const KEY_UNKNOWN: u16 = 240;
+
+pub const KEY_VIDEO_NEXT: u16 = 241;
+pub const KEY_VIDEO_PREV: u16 = 242;
+pub const KEY_BRIGHTNESS_CYCLE: u16 = 243;
+pub const KEY_BRIGHTNESS_AUTO: u16 = 244;
+pub const KEY_BRIGHTNESS_ZERO: u16 = KEY_BRIGHTNESS_AUTO;
+pub const KEY_DISPLAY_OFF: u16 = 245;
+
+pub const KEY_WWAN: u16 = 246;
+pub const KEY_WIMAX: u16 = KEY_WWAN;
+pub const KEY_RFKILL: u16 = 247;
+
+pub const KEY_MICMUTE: u16 = 248;
+
+pub const BTN_MISC: u16 = 0x100;
+pub const BTN_0: u16 = 0x100;
+pub const BTN_1: u16 = 0x101;
+pub const BTN_2: u16 = 0x102;
+pub const BTN_3: u16 = 0x103;
+pub const BTN_4: u16 = 0x104;
+pub const BTN_5: u16 = 0x105;
+pub const BTN_6: u16 = 0x106;
+pub const BTN_7: u16 = 0x107;
+pub const BTN_8: u16 = 0x108;
+pub const BTN_9: u16 = 0x109;
+
+pub const BTN_MOUSE: u16 = 0x110;
+pub const BTN_LEFT: u16 = 0x110;
+pub const BTN_RIGHT: u16 = 0x111;
+pub const BTN_MIDDLE: u16 = 0x112;
+pub const BTN_SIDE: u16 = 0x113;
+pub const BTN_EXTRA: u16 = 0x114;
+pub const BTN_FORWARD: u16 = 0x115;
+pub const BTN_BACK: u16 = 0x116;
+pub const BTN_TASK: u16 = 0x117;
+
+pub const BTN_JOYSTICK: u16 = 0x120;
+pub const BTN_TRIGGER: u16 = 0x120;
+pub const BTN_THUMB: u16 = 0x121;
+pub const BTN_THUMB2: u16 = 0x122;
+pub const BTN_TOP: u16 = 0x123;
+pub const BTN_TOP2: u16 = 0x124;
+pub const BTN_PINKIE: u16 = 0x125;
+pub const BTN_BASE: u16 = 0x126;
+pub const BTN_BASE2: u16 = 0x127;
+pub const BTN_BASE3: u16 = 0x128;
+pub const BTN_BASE4: u16 = 0x129;
+pub const BTN_BASE5: u16 = 0x12a;
+pub const BTN_BASE6: u16 = 0x12b;
+pub const BTN_DEAD: u16 = 0x12f;
+
+pub const BTN_GAMEPAD: u16 = 0x130;
+pub const BTN_SOUTH: u16 = 0x130;
+pub const BTN_A: u16 = BTN_SOUTH;
+pub const BTN_EAST: u16 = 0x131;
+pub const BTN_B: u16 = BTN_EAST;
+pub const BTN_C: u16 = 0x132;
+pub const BTN_NORTH: u16 = 0x133;
+pub const BTN_X: u16 = BTN_NORTH;
+pub const BTN_WEST: u16 = 0x134;
+pub const BTN_Y: u16 = BTN_WEST;
+pub const BTN_Z: u16 = 0x135;
+pub const BTN_TL: u16 = 0x136;
+pub const BTN_TR: u16 = 0x137;
+pub const BTN_TL2: u16 = 0x138;
+pub const BTN_TR2: u16 = 0x139;
+pub const BTN_SELECT: u16 = 0x13a;
+pub const BTN_START: u16 = 0x13b;
+pub const BTN_MODE: u16 = 0x13c;
+pub const BTN_THUMBL: u16 = 0x13d;
+pub const BTN_THUMBR: u16 = 0x13e;
+
+pub const BTN_DIGI: u16 = 0x140;
+pub const BTN_TOOL_PEN: u16 = 0x140;
+pub const BTN_TOOL_RUBBER: u16 = 0x141;
+pub const BTN_TOOL_BRUSH: u16 = 0x142;
+pub const BTN_TOOL_PENCIL: u16 = 0x143;
+pub const BTN_TOOL_AIRBRUSH: u16 = 0x144;
+pub const BTN_TOOL_FINGER: u16 = 0x145;
+pub const BTN_TOOL_MOUSE: u16 = 0x146;
+pub const BTN_TOOL_LENS: u16 = 0x147;
+pub const BTN_TOOL_QUINTTAP: u16 = 0x148;
+pub const BTN_STYLUS3: u16 = 0x149;
+pub const BTN_TOUCH: u16 = 0x14a;
+pub const BTN_STYLUS: u16 = 0x14b;
+pub const BTN_STYLUS2: u16 = 0x14c;
+pub const BTN_TOOL_DOUBLETAP: u16 = 0x14d;
+pub const BTN_TOOL_TRIPLETAP: u16 = 0x14e;
+pub const BTN_TOOL_QUADTAP: u16 = 0x14f;
+
+pub const BTN_WHEEL: u16 = 0x150;
+pub const BTN_GEAR_DOWN: u16 = 0x150;
+pub const BTN_GEAR_UP: u16 = 0x151;
+
+pub const KEY_OK: u16 = 0x160;
+pub const KEY_SELECT: u16 = 0x161;
+pub const KEY_GOTO: u16 = 0x162;
+pub const KEY_CLEAR: u16 = 0x163;
+pub const KEY_POWER2: u16 = 0x164;
+pub const KEY_OPTION: u16 = 0x165;
+pub const KEY_INFO: u16 = 0x166;
+pub const KEY_TIME: u16 = 0x167;
+pub const KEY_VENDOR: u16 = 0x168;
+pub const KEY_ARCHIVE: u16 = 0x169;
+pub const KEY_PROGRAM: u16 = 0x16a;
+pub const KEY_CHANNEL: u16 = 0x16b;
+pub const KEY_FAVORITES: u16 = 0x16c;
+pub const KEY_EPG: u16 = 0x16d;
+pub const KEY_PVR: u16 = 0x16e;
+pub const KEY_MHP: u16 = 0x16f;
+pub const KEY_LANGUAGE: u16 = 0x170;
+pub const KEY_TITLE: u16 = 0x171;
+pub const KEY_SUBTITLE: u16 = 0x172;
+pub const KEY_ANGLE: u16 = 0x173;
+pub const KEY_ZOOM: u16 = 0x174;
+pub const KEY_MODE: u16 = 0x175;
+pub const KEY_KEYBOARD: u16 = 0x176;
+pub const KEY_SCREEN: u16 = 0x177;
+pub const KEY_PC: u16 = 0x178;
+pub const KEY_TV: u16 = 0x179;
+pub const KEY_TV2: u16 = 0x17a;
+pub const KEY_VCR: u16 = 0x17b;
+pub const KEY_VCR2: u16 = 0x17c;
+pub const KEY_SAT: u16 = 0x17d;
+pub const KEY_SAT2: u16 = 0x17e;
+pub const KEY_CD: u16 = 0x17f;
+pub const KEY_TAPE: u16 = 0x180;
+pub const KEY_RADIO: u16 = 0x181;
+pub const KEY_TUNER: u16 = 0x182;
+pub const KEY_PLAYER: u16 = 0x183;
+pub const KEY_TEXT: u16 = 0x184;
+pub const KEY_DVD: u16 = 0x185;
+pub const KEY_AUX: u16 = 0x186;
+pub const KEY_MP3: u16 = 0x187;
+pub const KEY_AUDIO: u16 = 0x188;
+pub const KEY_VIDEO: u16 = 0x189;
+pub const KEY_DIRECTORY: u16 = 0x18a;
+pub const KEY_LIST: u16 = 0x18b;
+pub const KEY_MEMO: u16 = 0x18c;
+pub const KEY_CALENDAR: u16 = 0x18d;
+pub const KEY_RED: u16 = 0x18e;
+pub const KEY_GREEN: u16 = 0x18f;
+pub const KEY_YELLOW: u16 = 0x190;
+pub const KEY_BLUE: u16 = 0x191;
+pub const KEY_CHANNELUP: u16 = 0x192;
+pub const KEY_CHANNELDOWN: u16 = 0x193;
+pub const KEY_FIRST: u16 = 0x194;
+pub const KEY_LAST: u16 = 0x195;
+pub const KEY_AB: u16 = 0x196;
+pub const KEY_NEXT: u16 = 0x197;
+pub const KEY_RESTART: u16 = 0x198;
+pub const KEY_SLOW: u16 = 0x199;
+pub const KEY_SHUFFLE: u16 = 0x19a;
+pub const KEY_BREAK: u16 = 0x19b;
+pub const KEY_PREVIOUS: u16 = 0x19c;
+pub const KEY_DIGITS: u16 = 0x19d;
+pub const KEY_TEEN: u16 = 0x19e;
+pub const KEY_TWEN: u16 = 0x19f;
+pub const KEY_VIDEOPHONE: u16 = 0x1a0;
+pub const KEY_GAMES: u16 = 0x1a1;
+pub const KEY_ZOOMIN: u16 = 0x1a2;
+pub const KEY_ZOOMOUT: u16 = 0x1a3;
+pub const KEY_ZOOMRESET: u16 = 0x1a4;
+pub const KEY_WORDPROCESSOR: u16 = 0x1a5;
+pub const KEY_EDITOR: u16 = 0x1a6;
+pub const KEY_SPREADSHEET: u16 = 0x1a7;
+pub const KEY_GRAPHICSEDITOR: u16 = 0x1a8;
+pub const KEY_PRESENTATION: u16 = 0x1a9;
+pub const KEY_DATABASE: u16 = 0x1aa;
+pub const KEY_NEWS: u16 = 0x1ab;
+pub const KEY_VOICEMAIL: u16 = 0x1ac;
+pub const KEY_ADDRESSBOOK: u16 = 0x1ad;
+pub const KEY_MESSENGER: u16 = 0x1ae;
+pub const KEY_DISPLAYTOGGLE: u16 = 0x1af;
+pub const KEY_BRIGHTNESS_TOGGLE: u16 = KEY_DISPLAYTOGGLE;
+pub const KEY_SPELLCHECK: u16 = 0x1b0;
+pub const KEY_LOGOFF: u16 = 0x1b1;
+
+pub const KEY_DOLLAR: u16 = 0x1b2;
+pub const KEY_EURO: u16 = 0x1b3;
+
+pub const KEY_FRAMEBACK: u16 = 0x1b4;
+pub const KEY_FRAMEFORWARD: u16 = 0x1b5;
+pub const KEY_CONTEXT_MENU: u16 = 0x1b6;
+pub const KEY_MEDIA_REPEAT: u16 = 0x1b7;
+pub const KEY_10CHANNELSUP: u16 = 0x1b8;
+pub const KEY_10CHANNELSDOWN: u16 = 0x1b9;
+pub const KEY_IMAGES: u16 = 0x1ba;
+
+pub const KEY_DEL_EOL: u16 = 0x1c0;
+pub const KEY_DEL_EOS: u16 = 0x1c1;
+pub const KEY_INS_LINE: u16 = 0x1c2;
+pub const KEY_DEL_LINE: u16 = 0x1c3;
+
+pub const KEY_FN: u16 = 0x1d0;
+pub const KEY_FN_ESC: u16 = 0x1d1;
+pub const KEY_FN_F1: u16 = 0x1d2;
+pub const KEY_FN_F2: u16 = 0x1d3;
+pub const KEY_FN_F3: u16 = 0x1d4;
+pub const KEY_FN_F4: u16 = 0x1d5;
+pub const KEY_FN_F5: u16 = 0x1d6;
+pub const KEY_FN_F6: u16 = 0x1d7;
+pub const KEY_FN_F7: u16 = 0x1d8;
+pub const KEY_FN_F8: u16 = 0x1d9;
+pub const KEY_FN_F9: u16 = 0x1da;
+pub const KEY_FN_F10: u16 = 0x1db;
+pub const KEY_FN_F11: u16 = 0x1dc;
+pub const KEY_FN_F12: u16 = 0x1dd;
+pub const KEY_FN_1: u16 = 0x1de;
+pub const KEY_FN_2: u16 = 0x1df;
+pub const KEY_FN_D: u16 = 0x1e0;
+pub const KEY_FN_E: u16 = 0x1e1;
+pub const KEY_FN_F: u16 = 0x1e2;
+pub const KEY_FN_S: u16 = 0x1e3;
+pub const KEY_FN_B: u16 = 0x1e4;
+
+pub const KEY_BRL_DOT1: u16 = 0x1f1;
+pub const KEY_BRL_DOT2: u16 = 0x1f2;
+pub const KEY_BRL_DOT3: u16 = 0x1f3;
+pub const KEY_BRL_DOT4: u16 = 0x1f4;
+pub const KEY_BRL_DOT5: u16 = 0x1f5;
+pub const KEY_BRL_DOT6: u16 = 0x1f6;
+pub const KEY_BRL_DOT7: u16 = 0x1f7;
+pub const KEY_BRL_DOT8: u16 = 0x1f8;
+pub const KEY_BRL_DOT9: u16 = 0x1f9;
+pub const KEY_BRL_DOT10: u16 = 0x1fa;
+
+pub const KEY_NUMERIC_0: u16 = 0x200;
+pub const KEY_NUMERIC_1: u16 = 0x201;
+pub const KEY_NUMERIC_2: u16 = 0x202;
+pub const KEY_NUMERIC_3: u16 = 0x203;
+pub const KEY_NUMERIC_4: u16 = 0x204;
+pub const KEY_NUMERIC_5: u16 = 0x205;
+pub const KEY_NUMERIC_6: u16 = 0x206;
+pub const KEY_NUMERIC_7: u16 = 0x207;
+pub const KEY_NUMERIC_8: u16 = 0x208;
+pub const KEY_NUMERIC_9: u16 = 0x209;
+pub const KEY_NUMERIC_STAR: u16 = 0x20a;
+pub const KEY_NUMERIC_POUND: u16 = 0x20b;
+pub const KEY_NUMERIC_A: u16 = 0x20c;
+pub const KEY_NUMERIC_B: u16 = 0x20d;
+pub const KEY_NUMERIC_C: u16 = 0x20e;
+pub const KEY_NUMERIC_D: u16 = 0x20f;
+
+pub const KEY_CAMERA_FOCUS: u16 = 0x210;
+pub const KEY_WPS_BUTTON: u16 = 0x211;
+
+pub const KEY_TOUCHPAD_TOGGLE: u16 = 0x212;
+pub const KEY_TOUCHPAD_ON: u16 = 0x213;
+pub const KEY_TOUCHPAD_OFF: u16 = 0x214;
+
+pub const KEY_CAMERA_ZOOMIN: u16 = 0x215;
+pub const KEY_CAMERA_ZOOMOUT: u16 = 0x216;
+pub const KEY_CAMERA_UP: u16 = 0x217;
+pub const KEY_CAMERA_DOWN: u16 = 0x218;
+pub const KEY_CAMERA_LEFT: u16 = 0x219;
+pub const KEY_CAMERA_RIGHT: u16 = 0x21a;
+
+pub const KEY_ATTENDANT_ON: u16 = 0x21b;
+pub const KEY_ATTENDANT_OFF: u16 = 0x21c;
+pub const KEY_ATTENDANT_TOGGLE: u16 = 0x21d;
+pub const KEY_LIGHTS_TOGGLE: u16 = 0x21e;
+
+pub const BTN_DPAD_UP: u16 = 0x220;
+pub const BTN_DPAD_DOWN: u16 = 0x221;
+pub const BTN_DPAD_LEFT: u16 = 0x222;
+pub const BTN_DPAD_RIGHT: u16 = 0x223;
+
+pub const KEY_ALS_TOGGLE: u16 = 0x230;
+pub const KEY_ROTATE_LOCK_TOGGLE: u16 = 0x231;
+
+pub const KEY_BUTTONCONFIG: u16 = 0x240;
+pub const KEY_TASKMANAGER: u16 = 0x241;
+pub const KEY_JOURNAL: u16 = 0x242;
+pub const KEY_CONTROLPANEL: u16 = 0x243;
+pub const KEY_APPSELECT: u16 = 0x244;
+pub const KEY_SCREENSAVER: u16 = 0x245;
+pub const KEY_VOICECOMMAND: u16 = 0x246;
+pub const KEY_ASSISTANT: u16 = 0x247;
+
+pub const KEY_BRIGHTNESS_MIN: u16 = 0x250;
+pub const KEY_BRIGHTNESS_MAX: u16 = 0x251;
+
+pub const KEY_KBDINPUTASSIST_PREV: u16 = 0x260;
+pub const KEY_KBDINPUTASSIST_NEXT: u16 = 0x261;
+pub const KEY_KBDINPUTASSIST_PREVGROUP: u16 = 0x262;
+pub const KEY_KBDINPUTASSIST_NEXTGROUP: u16 = 0x263;
+pub const KEY_KBDINPUTASSIST_ACCEPT: u16 = 0x264;
+pub const KEY_KBDINPUTASSIST_CANCEL: u16 = 0x265;
+
+pub const KEY_RIGHT_UP: u16 = 0x266;
+pub const KEY_RIGHT_DOWN: u16 = 0x267;
+pub const KEY_LEFT_UP: u16 = 0x268;
+pub const KEY_LEFT_DOWN: u16 = 0x269;
+
+pub const KEY_ROOT_MENU: u16 = 0x26a;
+
+pub const KEY_MEDIA_TOP_MENU: u16 = 0x26b;
+pub const KEY_NUMERIC_11: u16 = 0x26c;
+pub const KEY_NUMERIC_12: u16 = 0x26d;
+pub const KEY_AUDIO_DESC: u16 = 0x26e;
+pub const KEY_3D_MODE: u16 = 0x26f;
+pub const KEY_NEXT_FAVORITE: u16 = 0x270;
+pub const KEY_STOP_RECORD: u16 = 0x271;
+pub const KEY_PAUSE_RECORD: u16 = 0x272;
+pub const KEY_VOD: u16 = 0x273;
+pub const KEY_UNMUTE: u16 = 0x274;
+pub const KEY_FASTREVERSE: u16 = 0x275;
+pub const KEY_SLOWREVERSE: u16 = 0x276;
+pub const KEY_DATA: u16 = 0x277;
+pub const KEY_ONSCREEN_KEYBOARD: u16 = 0x278;
+
+pub const BTN_TRIGGER_HAPPY: u16 = 0x2c0;
+pub const BTN_TRIGGER_HAPPY1: u16 = 0x2c0;
+pub const BTN_TRIGGER_HAPPY2: u16 = 0x2c1;
+pub const BTN_TRIGGER_HAPPY3: u16 = 0x2c2;
+pub const BTN_TRIGGER_HAPPY4: u16 = 0x2c3;
+pub const BTN_TRIGGER_HAPPY5: u16 = 0x2c4;
+pub const BTN_TRIGGER_HAPPY6: u16 = 0x2c5;
+pub const BTN_TRIGGER_HAPPY7: u16 = 0x2c6;
+pub const BTN_TRIGGER_HAPPY8: u16 = 0x2c7;
+pub const BTN_TRIGGER_HAPPY9: u16 = 0x2c8;
+pub const BTN_TRIGGER_HAPPY10: u16 = 0x2c9;
+pub const BTN_TRIGGER_HAPPY11: u16 = 0x2ca;
+pub const BTN_TRIGGER_HAPPY12: u16 = 0x2cb;
+pub const BTN_TRIGGER_HAPPY13: u16 = 0x2cc;
+pub const BTN_TRIGGER_HAPPY14: u16 = 0x2cd;
+pub const BTN_TRIGGER_HAPPY15: u16 = 0x2ce;
+pub const BTN_TRIGGER_HAPPY16: u16 = 0x2cf;
+pub const BTN_TRIGGER_HAPPY17: u16 = 0x2d0;
+pub const BTN_TRIGGER_HAPPY18: u16 = 0x2d1;
+pub const BTN_TRIGGER_HAPPY19: u16 = 0x2d2;
+pub const BTN_TRIGGER_HAPPY20: u16 = 0x2d3;
+pub const BTN_TRIGGER_HAPPY21: u16 = 0x2d4;
+pub const BTN_TRIGGER_HAPPY22: u16 = 0x2d5;
+pub const BTN_TRIGGER_HAPPY23: u16 = 0x2d6;
+pub const BTN_TRIGGER_HAPPY24: u16 = 0x2d7;
+pub const BTN_TRIGGER_HAPPY25: u16 = 0x2d8;
+pub const BTN_TRIGGER_HAPPY26: u16 = 0x2d9;
+pub const BTN_TRIGGER_HAPPY27: u16 = 0x2da;
+pub const BTN_TRIGGER_HAPPY28: u16 = 0x2db;
+pub const BTN_TRIGGER_HAPPY29: u16 = 0x2dc;
+pub const BTN_TRIGGER_HAPPY30: u16 = 0x2dd;
+pub const BTN_TRIGGER_HAPPY31: u16 = 0x2de;
+pub const BTN_TRIGGER_HAPPY32: u16 = 0x2df;
+pub const BTN_TRIGGER_HAPPY33: u16 = 0x2e0;
+pub const BTN_TRIGGER_HAPPY34: u16 = 0x2e1;
+pub const BTN_TRIGGER_HAPPY35: u16 = 0x2e2;
+pub const BTN_TRIGGER_HAPPY36: u16 = 0x2e3;
+pub const BTN_TRIGGER_HAPPY37: u16 = 0x2e4;
+pub const BTN_TRIGGER_HAPPY38: u16 = 0x2e5;
+pub const BTN_TRIGGER_HAPPY39: u16 = 0x2e6;
+pub const BTN_TRIGGER_HAPPY40: u16 = 0x2e7;
+
+pub const KEY_MIN_INTERESTING: u16 = KEY_MUTE;
+pub const KEY_MAX: u16 = 0x2ff;
+pub const KEY_CNT: u16 = (KEY_MAX + 1);
+
+pub const REL_X: u16 = 0x00;
+pub const REL_Y: u16 = 0x01;
+pub const REL_Z: u16 = 0x02;
+pub const REL_RX: u16 = 0x03;
+pub const REL_RY: u16 = 0x04;
+pub const REL_RZ: u16 = 0x05;
+pub const REL_HWHEEL: u16 = 0x06;
+pub const REL_DIAL: u16 = 0x07;
+pub const REL_WHEEL: u16 = 0x08;
+pub const REL_MISC: u16 = 0x09;
+pub const REL_MAX: u16 = 0x0f;
+pub const REL_CNT: u16 = (REL_MAX + 1);
+
+pub const ABS_X: u16 = 0x00;
+pub const ABS_Y: u16 = 0x01;
+pub const ABS_Z: u16 = 0x02;
+pub const ABS_RX: u16 = 0x03;
+pub const ABS_RY: u16 = 0x04;
+pub const ABS_RZ: u16 = 0x05;
+pub const ABS_THROTTLE: u16 = 0x06;
+pub const ABS_RUDDER: u16 = 0x07;
+pub const ABS_WHEEL: u16 = 0x08;
+pub const ABS_GAS: u16 = 0x09;
+pub const ABS_BRAKE: u16 = 0x0a;
+pub const ABS_HAT0X: u16 = 0x10;
+pub const ABS_HAT0Y: u16 = 0x11;
+pub const ABS_HAT1X: u16 = 0x12;
+pub const ABS_HAT1Y: u16 = 0x13;
+pub const ABS_HAT2X: u16 = 0x14;
+pub const ABS_HAT2Y: u16 = 0x15;
+pub const ABS_HAT3X: u16 = 0x16;
+pub const ABS_HAT3Y: u16 = 0x17;
+pub const ABS_PRESSURE: u16 = 0x18;
+pub const ABS_DISTANCE: u16 = 0x19;
+pub const ABS_TILT_X: u16 = 0x1a;
+pub const ABS_TILT_Y: u16 = 0x1b;
+pub const ABS_TOOL_WIDTH: u16 = 0x1c;
+
+pub const ABS_VOLUME: u16 = 0x20;
+
+pub const ABS_MISC: u16 = 0x28;
+
+pub const ABS_MT_SLOT: u16 = 0x2f;
+pub const ABS_MT_TOUCH_MAJOR: u16 = 0x30;
+pub const ABS_MT_TOUCH_MINOR: u16 = 0x31;
+pub const ABS_MT_WIDTH_MAJOR: u16 = 0x32;
+pub const ABS_MT_WIDTH_MINOR: u16 = 0x33;
+pub const ABS_MT_ORIENTATION: u16 = 0x34;
+pub const ABS_MT_POSITION_X: u16 = 0x35;
+pub const ABS_MT_POSITION_Y: u16 = 0x36;
+pub const ABS_MT_TOOL_TYPE: u16 = 0x37;
+pub const ABS_MT_BLOB_ID: u16 = 0x38;
+pub const ABS_MT_TRACKING_ID: u16 = 0x39;
+pub const ABS_MT_PRESSURE: u16 = 0x3a;
+pub const ABS_MT_DISTANCE: u16 = 0x3b;
+pub const ABS_MT_TOOL_X: u16 = 0x3c;
+pub const ABS_MT_TOOL_Y: u16 = 0x3d;
+
+pub const ABS_MAX: u16 = 0x3f;
+pub const ABS_CNT: u16 = (ABS_MAX + 1);
+
+pub const MSC_SERIAL: u16 = 0x00;
+pub const MSC_PULSELED: u16 = 0x01;
+pub const MSC_GESTURE: u16 = 0x02;
+pub const MSC_RAW: u16 = 0x03;
+pub const MSC_SCAN: u16 = 0x04;
+pub const MSC_TIMESTAMP: u16 = 0x05;
+pub const MSC_MAX: u16 = 0x07;
+pub const MSC_CNT: u16 = (MSC_MAX + 1);
+
+pub const LED_NUML: u16 = 0x00;
+pub const LED_CAPSL: u16 = 0x01;
+pub const LED_SCROLLL: u16 = 0x02;
+pub const LED_COMPOSE: u16 = 0x03;
+pub const LED_KANA: u16 = 0x04;
+pub const LED_SLEEP: u16 = 0x05;
+pub const LED_SUSPEND: u16 = 0x06;
+pub const LED_MUTE: u16 = 0x07;
+pub const LED_MISC: u16 = 0x08;
+pub const LED_MAIL: u16 = 0x09;
+pub const LED_CHARGING: u16 = 0x0a;
+pub const LED_MAX: u16 = 0x0f;
+pub const LED_CNT: u16 = (LED_MAX + 1);
+
+pub const REP_DELAY: u16 = 0x00;
+pub const REP_PERIOD: u16 = 0x01;
+pub const REP_MAX: u16 = 0x01;
+pub const REP_CNT: u16 = (REP_MAX + 1);
+
+// Should match linux/virtio_input.h
+pub const VIRTIO_INPUT_CFG_ID_NAME: u8 = 0x01;
+pub const VIRTIO_INPUT_CFG_ID_SERIAL: u8 = 0x02;
+pub const VIRTIO_INPUT_CFG_PROP_BITS: u8 = 0x10;
+pub const VIRTIO_INPUT_CFG_EV_BITS: u8 = 0x11;
+pub const VIRTIO_INPUT_CFG_ABS_INFO: u8 = 0x12;
+pub const VIRTIO_INPUT_CFG_ID_DEVIDS: u8 = 0x03;
diff --git a/devices/src/virtio/input/defaults.rs b/devices/src/virtio/input/defaults.rs
new file mode 100644
index 0000000..4bf1ba2
--- /dev/null
+++ b/devices/src/virtio/input/defaults.rs
@@ -0,0 +1,229 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::collections::BTreeMap;
+
+use super::constants::*;
+use super::virtio_input_absinfo;
+use super::virtio_input_bitmap;
+use super::virtio_input_device_ids;
+use super::VirtioInputConfig;
+
+/// Instantiates a VirtioInputConfig object with the default configuration for a trackpad. It
+/// supports touch, left button and right button events, as well as X and Y axis.
+pub fn new_trackpad_config(width: u32, height: u32) -> VirtioInputConfig {
+    VirtioInputConfig::new(
+        virtio_input_device_ids::new(0, 0, 0, 0),
+        b"Crosvm Virtio Trackpad".to_vec(),
+        b"virtio-trackpad".to_vec(),
+        virtio_input_bitmap::new([0u8; 128]),
+        default_trackpad_events(),
+        default_trackpad_absinfo(width, height),
+    )
+}
+
+/// Instantiates a VirtioInputConfig object with the default configuration for a mouse.
+/// It supports left, right and middle buttons, as wel as X, Y and wheel relative axes.
+pub fn new_mouse_config() -> VirtioInputConfig {
+    VirtioInputConfig::new(
+        virtio_input_device_ids::new(0, 0, 0, 0),
+        b"Crosvm Virtio Mouse".to_vec(),
+        b"virtio-mouse".to_vec(),
+        virtio_input_bitmap::new([0u8; 128]),
+        default_mouse_events(),
+        BTreeMap::new(),
+    )
+}
+
+/// Instantiates a VirtioInputConfig object with the default configuration for a keyboard.
+/// It supports the same keys as a en-us keyboard and the CAPSLOCK, NUMLOCK and SCROLLLOCK leds.
+pub fn new_keyboard_config() -> VirtioInputConfig {
+    VirtioInputConfig::new(
+        virtio_input_device_ids::new(0, 0, 0, 0),
+        b"Crosvm Virtio Keyboard".to_vec(),
+        b"virtio-keyboard".to_vec(),
+        virtio_input_bitmap::new([0u8; 128]),
+        default_keyboard_events(),
+        BTreeMap::new(),
+    )
+}
+
+/// Instantiates a VirtioInputConfig object with the default configuration for a touchscreen (no
+/// multitouch support).
+pub fn new_single_touch_config(width: u32, height: u32) -> VirtioInputConfig {
+    VirtioInputConfig::new(
+        virtio_input_device_ids::new(0, 0, 0, 0),
+        b"Crosvm Virtio Touchscreen".to_vec(),
+        b"virtio-touchscreen".to_vec(),
+        virtio_input_bitmap::from_bits(&[INPUT_PROP_DIRECT]),
+        default_touchscreen_events(),
+        default_touchscreen_absinfo(width, height),
+    )
+}
+
+fn default_touchscreen_absinfo(width: u32, height: u32) -> BTreeMap<u16, virtio_input_absinfo> {
+    let mut absinfo: BTreeMap<u16, virtio_input_absinfo> = BTreeMap::new();
+    absinfo.insert(ABS_X, virtio_input_absinfo::new(0, width, 0, 0));
+    absinfo.insert(ABS_Y, virtio_input_absinfo::new(0, height, 0, 0));
+    absinfo
+}
+
+fn default_touchscreen_events() -> BTreeMap<u16, virtio_input_bitmap> {
+    let mut supported_events: BTreeMap<u16, virtio_input_bitmap> = BTreeMap::new();
+    supported_events.insert(EV_KEY, virtio_input_bitmap::from_bits(&[BTN_TOUCH]));
+    supported_events.insert(EV_ABS, virtio_input_bitmap::from_bits(&[ABS_X, ABS_Y]));
+    supported_events
+}
+
+fn default_trackpad_absinfo(width: u32, height: u32) -> BTreeMap<u16, virtio_input_absinfo> {
+    let mut absinfo: BTreeMap<u16, virtio_input_absinfo> = BTreeMap::new();
+    absinfo.insert(ABS_X, virtio_input_absinfo::new(0, width, 0, 0));
+    absinfo.insert(ABS_Y, virtio_input_absinfo::new(0, height, 0, 0));
+    absinfo
+}
+
+fn default_trackpad_events() -> BTreeMap<u16, virtio_input_bitmap> {
+    let mut supported_events: BTreeMap<u16, virtio_input_bitmap> = BTreeMap::new();
+    supported_events.insert(
+        EV_KEY,
+        virtio_input_bitmap::from_bits(&[BTN_TOOL_FINGER, BTN_TOUCH, BTN_LEFT, BTN_RIGHT]),
+    );
+    supported_events.insert(EV_ABS, virtio_input_bitmap::from_bits(&[ABS_X, ABS_Y]));
+    supported_events
+}
+
+fn default_mouse_events() -> BTreeMap<u16, virtio_input_bitmap> {
+    let mut supported_events: BTreeMap<u16, virtio_input_bitmap> = BTreeMap::new();
+    supported_events.insert(
+        EV_KEY,
+        virtio_input_bitmap::from_bits(&[BTN_LEFT, BTN_RIGHT, BTN_MIDDLE]),
+    );
+    supported_events.insert(
+        EV_REL,
+        virtio_input_bitmap::from_bits(&[REL_X, REL_Y, REL_WHEEL]),
+    );
+    supported_events
+}
+
+fn default_keyboard_events() -> BTreeMap<u16, virtio_input_bitmap> {
+    let mut supported_events: BTreeMap<u16, virtio_input_bitmap> = BTreeMap::new();
+    supported_events.insert(
+        EV_KEY,
+        virtio_input_bitmap::from_bits(&[
+            KEY_ESC,
+            KEY_1,
+            KEY_2,
+            KEY_3,
+            KEY_4,
+            KEY_5,
+            KEY_6,
+            KEY_7,
+            KEY_8,
+            KEY_9,
+            KEY_0,
+            KEY_MINUS,
+            KEY_EQUAL,
+            KEY_BACKSPACE,
+            KEY_TAB,
+            KEY_Q,
+            KEY_W,
+            KEY_E,
+            KEY_R,
+            KEY_T,
+            KEY_Y,
+            KEY_U,
+            KEY_I,
+            KEY_O,
+            KEY_P,
+            KEY_LEFTBRACE,
+            KEY_RIGHTBRACE,
+            KEY_ENTER,
+            KEY_LEFTCTRL,
+            KEY_A,
+            KEY_S,
+            KEY_D,
+            KEY_F,
+            KEY_G,
+            KEY_H,
+            KEY_J,
+            KEY_K,
+            KEY_L,
+            KEY_SEMICOLON,
+            KEY_APOSTROPHE,
+            KEY_GRAVE,
+            KEY_LEFTSHIFT,
+            KEY_BACKSLASH,
+            KEY_Z,
+            KEY_X,
+            KEY_C,
+            KEY_V,
+            KEY_B,
+            KEY_N,
+            KEY_M,
+            KEY_COMMA,
+            KEY_DOT,
+            KEY_SLASH,
+            KEY_RIGHTSHIFT,
+            KEY_KPASTERISK,
+            KEY_LEFTALT,
+            KEY_SPACE,
+            KEY_CAPSLOCK,
+            KEY_F1,
+            KEY_F2,
+            KEY_F3,
+            KEY_F4,
+            KEY_F5,
+            KEY_F6,
+            KEY_F7,
+            KEY_F8,
+            KEY_F9,
+            KEY_F10,
+            KEY_NUMLOCK,
+            KEY_SCROLLLOCK,
+            KEY_KP7,
+            KEY_KP8,
+            KEY_KP9,
+            KEY_KPMINUS,
+            KEY_KP4,
+            KEY_KP5,
+            KEY_KP6,
+            KEY_KPPLUS,
+            KEY_KP1,
+            KEY_KP2,
+            KEY_KP3,
+            KEY_KP0,
+            KEY_KPDOT,
+            KEY_F11,
+            KEY_F12,
+            KEY_KPENTER,
+            KEY_RIGHTCTRL,
+            KEY_KPSLASH,
+            KEY_SYSRQ,
+            KEY_RIGHTALT,
+            KEY_HOME,
+            KEY_UP,
+            KEY_PAGEUP,
+            KEY_LEFT,
+            KEY_RIGHT,
+            KEY_END,
+            KEY_DOWN,
+            KEY_PAGEDOWN,
+            KEY_INSERT,
+            KEY_DELETE,
+            KEY_PAUSE,
+            KEY_MENU,
+            KEY_PRINT,
+            KEY_POWER,
+        ]),
+    );
+    supported_events.insert(
+        EV_REP,
+        virtio_input_bitmap::from_bits(&[REP_DELAY, REP_PERIOD]),
+    );
+    supported_events.insert(
+        EV_LED,
+        virtio_input_bitmap::from_bits(&[LED_CAPSL, LED_NUML, LED_SCROLLL]),
+    );
+    supported_events
+}
diff --git a/devices/src/virtio/input/evdev.rs b/devices/src/virtio/input/evdev.rs
new file mode 100644
index 0000000..6301dfa
--- /dev/null
+++ b/devices/src/virtio/input/evdev.rs
@@ -0,0 +1,257 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::os::unix::io::AsRawFd;
+
+use data_model::Le32;
+use sys_util::{ioctl_ior_nr, ioctl_iow_nr, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref};
+
+use super::constants::*;
+use super::virtio_input_absinfo;
+use super::virtio_input_bitmap;
+use super::virtio_input_device_ids;
+use super::InputError;
+use super::Result;
+
+use std::collections::BTreeMap;
+use std::os::raw::c_uint;
+use std::ptr::null;
+
+const EVDEV: c_uint = 69;
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct evdev_buffer {
+    buffer: [std::os::raw::c_uchar; 128],
+}
+
+impl evdev_buffer {
+    fn new() -> evdev_buffer {
+        evdev_buffer {
+            buffer: [0 as std::os::raw::c_uchar; 128],
+        }
+    }
+
+    fn get(&self, bit: usize) -> bool {
+        let idx = bit / 8;
+        let inner_bit = bit % 8;
+        self.buffer
+            .get(idx)
+            .map_or(false, |val| val & (1u8 << inner_bit) != 0)
+    }
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct evdev_id {
+    bustype: u16,
+    vendor: u16,
+    product: u16,
+    version: u16,
+}
+
+impl evdev_id {
+    fn new() -> evdev_id {
+        evdev_id {
+            bustype: 0,
+            vendor: 0,
+            product: 0,
+            version: 0,
+        }
+    }
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct evdev_abs_info {
+    // These should technically by signed ints, but Le32 is only compatible with u32 and we only
+    // forward the bytes but don't care about its actual values.
+    value: u32,
+    minimum: u32,
+    maximum: u32,
+    fuzz: u32,
+    flat: u32,
+    resolution: u32,
+}
+
+impl evdev_abs_info {
+    fn new() -> evdev_abs_info {
+        evdev_abs_info {
+            value: 0,
+            minimum: 0,
+            maximum: 0,
+            fuzz: 0,
+            flat: 0,
+            resolution: 0,
+        }
+    }
+}
+
+impl From<evdev_abs_info> for virtio_input_absinfo {
+    fn from(other: evdev_abs_info) -> Self {
+        virtio_input_absinfo {
+            min: Le32::from(other.minimum),
+            max: Le32::from(other.maximum),
+            fuzz: Le32::from(other.fuzz),
+            flat: Le32::from(other.flat),
+        }
+    }
+}
+
+ioctl_ior_nr!(EVIOCGID, EVDEV, 0x02, evdev_id);
+ioctl_ior_nr!(EVIOCGNAME, EVDEV, 0x06, evdev_buffer);
+ioctl_ior_nr!(EVIOCGUNIQ, EVDEV, 0x08, evdev_buffer);
+ioctl_ior_nr!(EVIOCGPROP, EVDEV, 0x09, evdev_buffer);
+ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, evdev_buffer, evt);
+ioctl_ior_nr!(EVIOCGABS, EVDEV, 0x40 + abs, evdev_abs_info, abs);
+ioctl_iow_nr!(EVIOCGRAB, EVDEV, 0x90, u32);
+
+fn errno() -> sys_util::Error {
+    sys_util::Error::last()
+}
+
+/// Gets id information from an event device (see EVIOCGID ioctl for details).
+pub fn device_ids<T: AsRawFd>(fd: &T) -> Result<virtio_input_device_ids> {
+    let mut dev_id = evdev_id::new();
+    let len = unsafe {
+        // Safe because the kernel won't write more than size of evdev_id and we check the return
+        // value
+        ioctl_with_mut_ref(fd, EVIOCGID(), &mut dev_id)
+    };
+    if len < 0 {
+        return Err(InputError::EvdevIdError(errno()));
+    }
+    Ok(virtio_input_device_ids::new(
+        dev_id.bustype,
+        dev_id.vendor,
+        dev_id.product,
+        dev_id.version,
+    ))
+}
+
+/// Gets the name of an event device (see EVIOCGNAME ioctl for details).
+pub fn name<T: AsRawFd>(fd: &T) -> Result<Vec<u8>> {
+    let mut name = evdev_buffer::new();
+    let len = unsafe {
+        // Safe because the kernel won't write more than size of evdev_buffer and we check the
+        // return value
+        ioctl_with_mut_ref(fd, EVIOCGNAME(), &mut name)
+    };
+    if len < 0 {
+        return Err(InputError::EvdevNameError(errno()));
+    }
+    Ok(name.buffer[0..len as usize].to_vec())
+}
+
+/// Gets the unique (serial) name of an event device (see EVIOCGUNIQ ioctl for details).
+pub fn serial_name<T: AsRawFd>(fd: &T) -> Result<Vec<u8>> {
+    let mut uniq = evdev_buffer::new();
+    let len = unsafe {
+        // Safe because the kernel won't write more than size of evdev_buffer and we check the
+        // return value
+        ioctl_with_mut_ref(fd, EVIOCGUNIQ(), &mut uniq)
+    };
+    if len < 0 {
+        return Err(InputError::EvdevSerialError(errno()));
+    }
+    Ok(uniq.buffer[0..len as usize].to_vec())
+}
+
+/// Gets the properties of an event device (see EVIOCGPROP ioctl for details).
+pub fn properties<T: AsRawFd>(fd: &T) -> Result<virtio_input_bitmap> {
+    let mut props = evdev_buffer::new();
+    let len = unsafe {
+        // Safe because the kernel won't write more than size of evdev_buffer and we check the
+        // return value
+        ioctl_with_mut_ref(fd, EVIOCGPROP(), &mut props)
+    };
+    if len < 0 {
+        return Err(InputError::EvdevPropertiesError(errno()));
+    }
+    Ok(virtio_input_bitmap::new(props.buffer))
+}
+
+/// Gets the event types supported by an event device as well as the event codes supported for each
+/// type (see EVIOCGBIT ioctl for details).
+pub fn supported_events<T: AsRawFd>(fd: &T) -> Result<BTreeMap<u16, virtio_input_bitmap>> {
+    let mut evts: BTreeMap<u16, virtio_input_bitmap> = BTreeMap::new();
+
+    let mut evt_types = evdev_buffer::new();
+    let len = unsafe {
+        // Safe because the kernel won't write more than size of evdev_buffer and we check the
+        // return value
+        ioctl_with_mut_ref(fd, EVIOCGBIT(0), &mut evt_types)
+    };
+    if len < 0 {
+        return Err(InputError::EvdevEventTypesError(errno()));
+    }
+
+    // no need to ask for zero (EV_SYN) since it's always supported and treated as a special case
+    for ev in 1..EV_MAX {
+        if ev == EV_REP || !evt_types.get(ev as usize) {
+            // Event type not supported, skip it.
+            continue;
+        }
+        // Create a new zero-filled buffer every time to avoid carry-overs.
+        let mut evt_codes = evdev_buffer::new();
+        let len = unsafe {
+            // Safe because the kernel won't write more than size of evdev_buffer and we check the
+            // return value
+            ioctl_with_mut_ref(fd, EVIOCGBIT(ev as c_uint), &mut evt_codes)
+        };
+        if len < 0 {
+            return Err(InputError::EvdevEventTypesError(errno()));
+        }
+        evts.insert(ev, virtio_input_bitmap::new(evt_codes.buffer));
+    }
+    Ok(evts)
+}
+
+/// Gets the absolute axes of an event device (see EVIOCGABS ioctl for details).
+pub fn abs_info<T: AsRawFd>(fd: &T) -> BTreeMap<u16, virtio_input_absinfo> {
+    let mut ret: BTreeMap<u16, virtio_input_absinfo> = BTreeMap::new();
+
+    for abs in 0..ABS_MAX {
+        // Create a new one, zero-ed out every time to avoid carry-overs.
+        let mut abs_info = evdev_abs_info::new();
+        let len = unsafe {
+            // Safe because the kernel won't write more than size of evdev_buffer and we check the
+            // return value
+            ioctl_with_mut_ref(fd, EVIOCGABS(abs as c_uint), &mut abs_info)
+        };
+        if len > 0 {
+            ret.insert(abs, virtio_input_absinfo::from(abs_info));
+        }
+    }
+    ret
+}
+
+/// Grabs an event device (see EVIOCGGRAB ioctl for details). After this function succeeds the given
+/// fd has exclusive access to the device, effectively making it unusable for any other process in
+/// the host.
+pub fn grab_evdev<T: AsRawFd>(fd: &mut T) -> Result<()> {
+    let val: u32 = 1;
+    let ret = unsafe {
+        // Safe because the kernel only read the value of the ptr and we check the return value
+        ioctl_with_ref(fd, EVIOCGRAB(), &val)
+    };
+    if ret == 0 {
+        Ok(())
+    } else {
+        Err(InputError::EvdevGrabError(errno()))
+    }
+}
+
+pub fn ungrab_evdev<T: AsRawFd>(fd: &mut T) -> Result<()> {
+    let ret = unsafe {
+        // Safe because the kernel only reads the value of the ptr (doesn't dereference) and
+        // we check the return value
+        ioctl_with_ptr(fd, EVIOCGRAB(), null::<u32>())
+    };
+    if ret == 0 {
+        Ok(())
+    } else {
+        Err(InputError::EvdevGrabError(errno()))
+    }
+}
diff --git a/devices/src/virtio/input/event_source.rs b/devices/src/virtio/input/event_source.rs
new file mode 100644
index 0000000..a92dc83
--- /dev/null
+++ b/devices/src/virtio/input/event_source.rs
@@ -0,0 +1,519 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use super::constants::*;
+use super::evdev::{grab_evdev, ungrab_evdev};
+use super::virtio_input_event;
+use super::InputError;
+use super::Result;
+use data_model::DataInit;
+use std::collections::VecDeque;
+use std::io::Read;
+use std::io::Write;
+use std::mem::size_of;
+use std::os::unix::io::{AsRawFd, RawFd};
+use sys_util::{error, warn};
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+pub struct input_event {
+    timestamp_fields: [u64; 2],
+    pub type_: u16,
+    pub code: u16,
+    pub value: u32,
+}
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for input_event {}
+
+impl input_event {
+    const EVENT_SIZE: usize = size_of::<input_event>();
+
+    fn from_virtio_input_event(other: &virtio_input_event) -> input_event {
+        input_event {
+            timestamp_fields: [0, 0],
+            type_: other.type_.into(),
+            code: other.code.into(),
+            value: other.value.into(),
+        }
+    }
+}
+
+/// Encapsulates a socket or device node into an abstract event source, providing a common
+/// interface.
+/// It supports read and write operations to provide and accept events just like an event device
+/// node would, except that it handles virtio_input_event instead of input_event structures.
+/// It's necessary to call receive_events() before events are available for read.
+pub trait EventSource: Read + Write + AsRawFd {
+    /// Perform any necessary initialization before receiving and sending events from/to the source.
+    fn init(&mut self) -> Result<()> {
+        Ok(())
+    }
+    /// Perform any necessary cleanup when the device will no longer be used.
+    fn finalize(&mut self) -> Result<()> {
+        Ok(())
+    }
+
+    /// Receive events from the source, filters them and stores them in a queue for future
+    /// consumption by reading from this object. Returns the number of new non filtered events
+    /// received. This function may block waiting for events to be available.
+    fn receive_events(&mut self) -> Result<usize>;
+    /// Returns the number of received events that have not been filtered or consumed yet.
+    fn available_events_count(&self) -> usize;
+}
+
+// Try to read 16 events at a time to match what the linux guest driver does.
+const READ_BUFFER_SIZE: usize = 16 * size_of::<input_event>();
+
+// The read buffer needs to be aligned to the alignment of input_event, which is aligned as u64
+#[repr(align(8))]
+pub struct ReadBuffer {
+    buffer: [u8; READ_BUFFER_SIZE],
+}
+
+/// Encapsulates implementation details common to all kinds of event sources.
+pub struct EventSourceImpl<T> {
+    source: T,
+    queue: VecDeque<virtio_input_event>,
+    read_buffer: ReadBuffer,
+    // The read index accounts for incomplete events read previously.
+    read_idx: usize,
+}
+
+// Reads input events from the source.
+// Events are originally read as input_event structs and converted to virtio_input_event internally.
+impl<T: Read> EventSourceImpl<T> {
+    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+        let mut bytes = 0usize;
+        for evt_slice in buf.chunks_exact_mut(virtio_input_event::EVENT_SIZE) {
+            match self.queue.pop_front() {
+                None => {
+                    break;
+                }
+                Some(evt) => {
+                    evt_slice.copy_from_slice(evt.as_slice());
+                    bytes += evt_slice.len();
+                }
+            }
+        }
+        Ok(bytes)
+    }
+}
+
+// Writes input events to the source.
+// Events come as virtio_input_event structs and are converted to input_event internally.
+impl<T: Write> EventSourceImpl<T> {
+    fn write<F: Fn(&virtio_input_event) -> bool>(
+        &mut self,
+        buf: &[u8],
+        event_filter: F,
+    ) -> std::io::Result<usize> {
+        for evt_slice in buf.chunks_exact(virtio_input_event::EVENT_SIZE) {
+            // Don't use from_slice() here, the buffer is not guaranteed to be properly aligned.
+            let mut vio_evt = virtio_input_event::new(0, 0, 0);
+            vio_evt.as_mut_slice().copy_from_slice(evt_slice);
+            if !event_filter(&vio_evt) {
+                continue;
+            }
+            let evt = input_event::from_virtio_input_event(&vio_evt);
+            self.source.write_all(evt.as_slice())?;
+        }
+
+        let len = buf.len() - buf.len() % virtio_input_event::EVENT_SIZE;
+        Ok(len)
+    }
+
+    fn flush(&mut self) -> std::io::Result<()> {
+        self.source.flush()
+    }
+}
+
+impl<T: AsRawFd> EventSourceImpl<T> {
+    fn as_raw_fd(&self) -> RawFd {
+        self.source.as_raw_fd()
+    }
+}
+
+impl<T> EventSourceImpl<T>
+where
+    T: Read + Write,
+{
+    // Receive events from the source and store them in a queue, unless they should be filtered out.
+    fn receive_events<F: Fn(&input_event) -> bool>(&mut self, event_filter: F) -> Result<usize> {
+        let read = self
+            .source
+            .read(&mut self.read_buffer.buffer[self.read_idx..])
+            .map_err(InputError::EventsReadError)?;
+        let buff_size = read + self.read_idx;
+
+        for evt_slice in self.read_buffer.buffer[..buff_size].chunks_exact(input_event::EVENT_SIZE)
+        {
+            let input_evt = match input_event::from_slice(evt_slice) {
+                Some(x) => x,
+                None => {
+                    // This shouldn't happen because all slices (even the last one) are guaranteed
+                    // to have the correct size and be properly aligned.
+                    error!(
+                        "Failed converting a slice of sice {} to input_event",
+                        evt_slice.len()
+                    );
+                    // Skipping the event here effectively means no events will be received, because
+                    // if from_slice fails once it will fail always.
+                    continue;
+                }
+            };
+            if !event_filter(&input_evt) {
+                continue;
+            }
+            let vio_evt = virtio_input_event::from_input_event(input_evt);
+            self.queue.push_back(vio_evt);
+        }
+
+        let remainder = buff_size % input_event::EVENT_SIZE;
+        // If there is an incomplete event at the end of the buffer, it needs to be moved to the
+        // beginning and the next read operation must write right after it.
+        if remainder != 0 {
+            warn!("read incomplete event from source");
+            // The copy should only happen if there is at least one complete event in the buffer,
+            // otherwise source and destination would be the same.
+            if buff_size != remainder {
+                let (des, src) = self.read_buffer.buffer.split_at_mut(buff_size - remainder);
+                des[..remainder].copy_from_slice(src);
+            }
+        }
+        self.read_idx = remainder;
+
+        let received_events = buff_size / input_event::EVENT_SIZE;
+
+        Ok(received_events)
+    }
+
+    fn available_events(&self) -> usize {
+        self.queue.len()
+    }
+
+    fn new(source: T) -> EventSourceImpl<T> {
+        EventSourceImpl {
+            source,
+            queue: VecDeque::new(),
+            read_buffer: ReadBuffer {
+                buffer: [0u8; READ_BUFFER_SIZE],
+            },
+            read_idx: 0,
+        }
+    }
+}
+
+/// Encapsulates a (unix) socket as an event source.
+pub struct SocketEventSource<T> {
+    evt_source_impl: EventSourceImpl<T>,
+}
+
+impl<T> SocketEventSource<T>
+where
+    T: Read + Write + AsRawFd,
+{
+    pub fn new(source: T) -> SocketEventSource<T> {
+        SocketEventSource {
+            evt_source_impl: EventSourceImpl::new(source),
+        }
+    }
+}
+
+impl<T: Read> Read for SocketEventSource<T> {
+    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+        self.evt_source_impl.read(buf)
+    }
+}
+
+impl<T> Write for SocketEventSource<T>
+where
+    T: Read + Write + AsRawFd,
+{
+    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+        self.evt_source_impl.write(buf, |_evt| true)
+    }
+
+    fn flush(&mut self) -> std::io::Result<()> {
+        self.evt_source_impl.flush()
+    }
+}
+
+impl<T: AsRawFd> AsRawFd for SocketEventSource<T> {
+    fn as_raw_fd(&self) -> RawFd {
+        self.evt_source_impl.as_raw_fd()
+    }
+}
+
+impl<T> EventSource for SocketEventSource<T>
+where
+    T: Read + Write + AsRawFd,
+{
+    fn init(&mut self) -> Result<()> {
+        Ok(())
+    }
+
+    fn finalize(&mut self) -> Result<()> {
+        ungrab_evdev(self)
+    }
+
+    fn receive_events(&mut self) -> Result<usize> {
+        self.evt_source_impl.receive_events(|_evt| true)
+    }
+
+    fn available_events_count(&self) -> usize {
+        self.evt_source_impl.available_events()
+    }
+}
+
+/// Encapsulates an event device node as an event source
+pub struct EvdevEventSource<T> {
+    evt_source_impl: EventSourceImpl<T>,
+}
+
+impl<T> EvdevEventSource<T>
+where
+    T: Read + Write + AsRawFd,
+{
+    pub fn new(source: T) -> EvdevEventSource<T> {
+        EvdevEventSource {
+            evt_source_impl: EventSourceImpl::new(source),
+        }
+    }
+}
+
+impl<T: Read> Read for EvdevEventSource<T> {
+    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+        self.evt_source_impl.read(buf)
+    }
+}
+
+impl<T> Write for EvdevEventSource<T>
+where
+    T: Read + Write + AsRawFd,
+{
+    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+        self.evt_source_impl.write(buf, |evt| {
+            // Miscellaneous events produced by the device are sent back to it by the kernel input
+            // subsystem, but because these events are handled by the host kernel as well as the
+            // guest the device would get them twice. Which would prompt the device to send the
+            // event to the guest again entering an infinite loop.
+            evt.type_ != EV_MSC
+        })
+    }
+
+    fn flush(&mut self) -> std::io::Result<()> {
+        self.evt_source_impl.flush()
+    }
+}
+
+impl<T: AsRawFd> AsRawFd for EvdevEventSource<T> {
+    fn as_raw_fd(&self) -> RawFd {
+        self.evt_source_impl.as_raw_fd()
+    }
+}
+
+impl<T> EventSource for EvdevEventSource<T>
+where
+    T: Read + Write + AsRawFd,
+{
+    fn init(&mut self) -> Result<()> {
+        grab_evdev(self)
+    }
+
+    fn finalize(&mut self) -> Result<()> {
+        ungrab_evdev(self)
+    }
+
+    fn receive_events(&mut self) -> Result<usize> {
+        self.evt_source_impl.receive_events(|_evt| true)
+    }
+
+    fn available_events_count(&self) -> usize {
+        self.evt_source_impl.available_events()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::virtio::input::event_source::input_event;
+    use crate::virtio::input::event_source::EventSourceImpl;
+    use crate::virtio::input::virtio_input_event;
+    use data_model::{DataInit, Le16, Le32};
+    use std::cmp::min;
+    use std::io::Read;
+    use std::io::Write;
+    use std::mem::size_of;
+
+    struct SourceMock {
+        events: Vec<u8>,
+    }
+
+    impl SourceMock {
+        fn new(evts: &Vec<input_event>) -> SourceMock {
+            let mut events: Vec<u8> = vec![];
+            for evt in evts {
+                for byte in evt.as_slice() {
+                    events.push(byte.clone());
+                }
+            }
+            SourceMock { events }
+        }
+    }
+
+    impl Read for SourceMock {
+        fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
+            let copy_size = min(buf.len(), self.events.len());
+            buf[..copy_size].copy_from_slice(&self.events[..copy_size]);
+            Ok(copy_size)
+        }
+    }
+    impl Write for SourceMock {
+        fn write(&mut self, buf: &[u8]) -> std::result::Result<usize, std::io::Error> {
+            Ok(buf.len())
+        }
+
+        fn flush(&mut self) -> std::result::Result<(), std::io::Error> {
+            Ok(())
+        }
+    }
+
+    #[test]
+    fn empty_new() {
+        let mut source = EventSourceImpl::new(SourceMock::new(&vec![]));
+        assert_eq!(
+            source.available_events(),
+            0,
+            "zero events should be available"
+        );
+        let mut buffer = [0u8, 80];
+        assert_eq!(
+            source.read(&mut buffer).unwrap(),
+            0,
+            "zero events should be read"
+        );
+    }
+
+    #[test]
+    fn empty_receive() {
+        let mut source = EventSourceImpl::new(SourceMock::new(&vec![]));
+        assert_eq!(
+            source.receive_events(|_| true).unwrap(),
+            0,
+            "zero events should be received"
+        );
+        let mut buffer = [0u8, 80];
+        assert_eq!(
+            source.read(&mut buffer).unwrap(),
+            0,
+            "zero events should be read"
+        );
+    }
+
+    fn instantiate_input_events(count: usize) -> Vec<input_event> {
+        let mut ret: Vec<input_event> = Vec::with_capacity(count);
+        for idx in 0..count {
+            ret.push(input_event {
+                timestamp_fields: [0, 0],
+                type_: 3 * (idx as u16) + 1,
+                code: 3 * (idx as u16) + 2,
+                value: 3 * (idx as u32) + 3,
+            });
+        }
+        ret
+    }
+
+    fn assert_events_match(e1: &virtio_input_event, e2: &input_event) {
+        assert_eq!(e1.type_, Le16::from(e2.type_), "type should match");
+        assert_eq!(e1.code, Le16::from(e2.code), "code should match");
+        assert_eq!(e1.value, Le32::from(e2.value), "value should match");
+    }
+
+    #[test]
+    fn partial_read() {
+        let evts = instantiate_input_events(4usize);
+        let mut source = EventSourceImpl::new(SourceMock::new(&evts));
+        assert_eq!(
+            source.receive_events(|_| true).unwrap(),
+            evts.len(),
+            "should receive all events"
+        );
+        let mut evt = virtio_input_event {
+            type_: Le16::from(0),
+            code: Le16::from(0),
+            value: Le32::from(0),
+        };
+        assert_eq!(
+            source.read(evt.as_mut_slice()).unwrap(),
+            virtio_input_event::EVENT_SIZE,
+            "should read a single event"
+        );
+        assert_events_match(&evt, &evts[0]);
+    }
+
+    #[test]
+    fn exact_read() {
+        const EVENT_COUNT: usize = 4;
+        let evts = instantiate_input_events(EVENT_COUNT);
+        let mut source = EventSourceImpl::new(SourceMock::new(&evts));
+        assert_eq!(
+            source.receive_events(|_| true).unwrap(),
+            evts.len(),
+            "should receive all events"
+        );
+        let mut vio_evts = [0u8; EVENT_COUNT * size_of::<virtio_input_event>()];
+        assert_eq!(
+            source.read(&mut vio_evts).unwrap(),
+            EVENT_COUNT * virtio_input_event::EVENT_SIZE,
+            "should read all events"
+        );
+
+        let mut chunks = vio_evts.chunks_exact(virtio_input_event::EVENT_SIZE);
+        for idx in 0..EVENT_COUNT {
+            let evt = virtio_input_event::from_slice(chunks.next().unwrap()).unwrap();
+            assert_events_match(&evt, &evts[idx]);
+        }
+    }
+
+    #[test]
+    fn over_read() {
+        const EVENT_COUNT: usize = 4;
+        let evts = instantiate_input_events(EVENT_COUNT);
+        let mut source = EventSourceImpl::new(SourceMock::new(&evts));
+        assert_eq!(
+            source.receive_events(|_| true).unwrap(),
+            evts.len(),
+            "should receive all events"
+        );
+        let mut vio_evts = [0u8; 2 * EVENT_COUNT * size_of::<virtio_input_event>()];
+        assert_eq!(
+            source.read(&mut vio_evts).unwrap(),
+            EVENT_COUNT * virtio_input_event::EVENT_SIZE,
+            "should only read available events"
+        );
+
+        let mut chunks = vio_evts.chunks_exact(virtio_input_event::EVENT_SIZE);
+        for idx in 0..EVENT_COUNT {
+            let evt = virtio_input_event::from_slice(chunks.next().unwrap()).unwrap();
+            assert_events_match(&evt, &evts[idx]);
+        }
+    }
+
+    #[test]
+    fn incomplete_read() {
+        const EVENT_COUNT: usize = 4;
+        let evts = instantiate_input_events(EVENT_COUNT);
+        let mut source = EventSourceImpl::new(SourceMock::new(&evts));
+        assert_eq!(
+            source.receive_events(|_| true).unwrap(),
+            evts.len(),
+            "should receive all events"
+        );
+        let mut vio_evts = [0u8; 3];
+        assert_eq!(
+            source.read(&mut vio_evts).unwrap(),
+            0,
+            "shouldn't read incomplete events"
+        );
+    }
+}
diff --git a/devices/src/virtio/input/mod.rs b/devices/src/virtio/input/mod.rs
new file mode 100644
index 0000000..205d82f
--- /dev/null
+++ b/devices/src/virtio/input/mod.rs
@@ -0,0 +1,731 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#[allow(dead_code)]
+mod constants;
+mod defaults;
+mod evdev;
+mod event_source;
+
+use self::constants::*;
+
+use std::os::unix::io::{AsRawFd, RawFd};
+
+use data_model::{DataInit, Le16, Le32};
+use sys_util::{error, warn, EventFd, GuestMemory, PollContext, PollToken};
+
+use self::event_source::{input_event, EvdevEventSource, EventSource, SocketEventSource};
+use super::{Queue, VirtioDevice, INTERRUPT_STATUS_USED_RING, TYPE_INPUT};
+use std::cmp::min;
+use std::collections::BTreeMap;
+use std::fmt::{self, Display};
+use std::io::Read;
+use std::io::Write;
+use std::mem::size_of;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+use std::thread;
+
+const EVENT_QUEUE_SIZE: u16 = 64;
+const STATUS_QUEUE_SIZE: u16 = 64;
+const QUEUE_SIZES: &[u16] = &[EVENT_QUEUE_SIZE, STATUS_QUEUE_SIZE];
+
+#[derive(Debug)]
+pub enum InputError {
+    /// Failed to write events to the source
+    EventsWriteError(sys_util::GuestMemoryError),
+    /// Failed to read events from the source
+    EventsReadError(std::io::Error),
+    // Failed to get name of event device
+    EvdevIdError(sys_util::Error),
+    // Failed to get name of event device
+    EvdevNameError(sys_util::Error),
+    // Failed to get serial name of event device
+    EvdevSerialError(sys_util::Error),
+    // Failed to get properties of event device
+    EvdevPropertiesError(sys_util::Error),
+    // Failed to get event types supported by device
+    EvdevEventTypesError(sys_util::Error),
+    // Failed to get axis information of event device
+    EvdevAbsInfoError(sys_util::Error),
+    // Failed to grab event device
+    EvdevGrabError(sys_util::Error),
+}
+pub type Result<T> = std::result::Result<T, InputError>;
+
+impl Display for InputError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::InputError::*;
+
+        match self {
+            EventsWriteError(e) => write!(f, "failed to write events to the source: {}", e),
+            EventsReadError(e) => write!(f, "failed to read events from the source: {}", e),
+            EvdevIdError(e) => write!(f, "failed to get id of event device: {}", e),
+            EvdevNameError(e) => write!(f, "failed to get name of event device: {}", e),
+            EvdevSerialError(e) => write!(f, "failed to get serial name of event device: {}", e),
+            EvdevPropertiesError(e) => write!(f, "failed to get properties of event device: {}", e),
+            EvdevEventTypesError(e) => {
+                write!(f, "failed to get event types supported by device: {}", e)
+            }
+            EvdevAbsInfoError(e) => {
+                write!(f, "failed to get axis information of event device: {}", e)
+            }
+            EvdevGrabError(e) => write!(f, "failed to grab event device: {}", e),
+        }
+    }
+}
+
+#[derive(Copy, Clone, Default, Debug)]
+#[repr(C)]
+pub struct virtio_input_device_ids {
+    bustype: Le16,
+    vendor: Le16,
+    product: Le16,
+    version: Le16,
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_input_device_ids {}
+
+impl virtio_input_device_ids {
+    fn new(bustype: u16, product: u16, vendor: u16, version: u16) -> virtio_input_device_ids {
+        virtio_input_device_ids {
+            bustype: Le16::from(bustype),
+            vendor: Le16::from(vendor),
+            product: Le16::from(product),
+            version: Le16::from(version),
+        }
+    }
+}
+
+#[derive(Copy, Clone, Default, Debug)]
+#[repr(C)]
+pub struct virtio_input_absinfo {
+    min: Le32,
+    max: Le32,
+    fuzz: Le32,
+    flat: Le32,
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_input_absinfo {}
+
+impl virtio_input_absinfo {
+    fn new(min: u32, max: u32, fuzz: u32, flat: u32) -> virtio_input_absinfo {
+        virtio_input_absinfo {
+            min: Le32::from(min),
+            max: Le32::from(max),
+            fuzz: Le32::from(fuzz),
+            flat: Le32::from(flat),
+        }
+    }
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+struct virtio_input_config {
+    select: u8,
+    subsel: u8,
+    size: u8,
+    reserved: [u8; 5],
+    payload: [u8; 128],
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_input_config {}
+
+impl virtio_input_config {
+    fn new() -> virtio_input_config {
+        virtio_input_config {
+            select: 0,
+            subsel: 0,
+            size: 0,
+            reserved: [0u8; 5],
+            payload: [0u8; 128],
+        }
+    }
+
+    fn set_payload_slice(&mut self, slice: &[u8]) {
+        let bytes_written = match (&mut self.payload[..]).write(slice) {
+            Ok(x) => x,
+            Err(_) => {
+                // This won't happen because write is guaranteed to succeed with slices
+                unreachable!();
+            }
+        };
+        self.size = bytes_written as u8;
+        if bytes_written < slice.len() {
+            // This shouldn't happen since everywhere this function is called the size is guaranteed
+            // to be at most 128 bytes (the size of the payload)
+            warn!("Slice is too long to fit in payload");
+        }
+    }
+
+    fn set_payload_bitmap(&mut self, bitmap: &virtio_input_bitmap) {
+        self.size = bitmap.min_size();
+        self.payload.copy_from_slice(&bitmap.bitmap);
+    }
+
+    fn set_absinfo(&mut self, absinfo: &virtio_input_absinfo) {
+        self.set_payload_slice(absinfo.as_slice());
+    }
+
+    fn set_device_ids(&mut self, device_ids: &virtio_input_device_ids) {
+        self.set_payload_slice(device_ids.as_slice());
+    }
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct virtio_input_bitmap {
+    bitmap: [u8; 128],
+}
+
+impl virtio_input_bitmap {
+    fn new(bitmap: [u8; 128]) -> virtio_input_bitmap {
+        virtio_input_bitmap { bitmap }
+    }
+
+    fn len(&self) -> usize {
+        self.bitmap.len()
+    }
+
+    // Creates a bitmap from an array of bit indices
+    fn from_bits(set_indices: &[u16]) -> virtio_input_bitmap {
+        let mut ret = virtio_input_bitmap { bitmap: [0u8; 128] };
+        for idx in set_indices {
+            let byte_pos = (idx / 8) as usize;
+            let bit_byte = 1u8 << (idx % 8);
+            if byte_pos < ret.len() {
+                ret.bitmap[byte_pos] |= bit_byte;
+            } else {
+                // This would only happen if new event codes (or types, or ABS_*, etc) are defined to be
+                // larger than or equal to 1024, in which case a new version of the virtio input
+                // protocol needs to be defined.
+                // There is nothing we can do about this error except log it.
+                error!("Attempted to set an out of bounds bit: {}", idx);
+            }
+        }
+        ret
+    }
+
+    // Returns the length of the minimum array that can hold all set bits in the map
+    fn min_size(&self) -> u8 {
+        self.bitmap
+            .iter()
+            .rposition(|v| *v != 0)
+            .map_or(0, |i| i + 1) as u8
+    }
+}
+
+pub struct VirtioInputConfig {
+    select: u8,
+    subsel: u8,
+    device_ids: virtio_input_device_ids,
+    name: Vec<u8>,
+    serial_name: Vec<u8>,
+    properties: virtio_input_bitmap,
+    supported_events: BTreeMap<u16, virtio_input_bitmap>,
+    axis_info: BTreeMap<u16, virtio_input_absinfo>,
+}
+
+impl VirtioInputConfig {
+    const CONFIG_MEM_SIZE: usize = size_of::<virtio_input_config>();
+
+    fn new(
+        device_ids: virtio_input_device_ids,
+        name: Vec<u8>,
+        serial_name: Vec<u8>,
+        properties: virtio_input_bitmap,
+        supported_events: BTreeMap<u16, virtio_input_bitmap>,
+        axis_info: BTreeMap<u16, virtio_input_absinfo>,
+    ) -> VirtioInputConfig {
+        VirtioInputConfig {
+            select: 0,
+            subsel: 0,
+            device_ids,
+            name,
+            serial_name,
+            properties,
+            supported_events,
+            axis_info,
+        }
+    }
+
+    fn from_evdev<T: AsRawFd>(source: &T) -> Result<VirtioInputConfig> {
+        Ok(VirtioInputConfig::new(
+            evdev::device_ids(source)?,
+            evdev::name(source)?,
+            evdev::serial_name(source)?,
+            evdev::properties(source)?,
+            evdev::supported_events(source)?,
+            evdev::abs_info(source),
+        ))
+    }
+
+    fn validate_read_offsets(&self, offset: usize, len: usize) -> bool {
+        if offset + len > VirtioInputConfig::CONFIG_MEM_SIZE {
+            error!(
+                "Attempt to read from invalid config range: [{}..{}], valid ranges in [0..{}]",
+                offset,
+                offset + len,
+                VirtioInputConfig::CONFIG_MEM_SIZE
+            );
+            return false;
+        }
+        true
+    }
+
+    fn build_config_memory(&self) -> virtio_input_config {
+        let mut cfg = virtio_input_config::new();
+        cfg.select = self.select;
+        cfg.subsel = self.subsel;
+        match self.select {
+            VIRTIO_INPUT_CFG_ID_NAME => {
+                cfg.set_payload_slice(&self.name);
+            }
+            VIRTIO_INPUT_CFG_ID_SERIAL => {
+                cfg.set_payload_slice(&self.serial_name);
+            }
+            VIRTIO_INPUT_CFG_PROP_BITS => {
+                cfg.set_payload_bitmap(&self.properties);
+            }
+            VIRTIO_INPUT_CFG_EV_BITS => {
+                let ev_type = self.subsel as u16;
+                // zero is a special case: return all supported event types (just like EVIOCGBIT)
+                if ev_type == 0 {
+                    let events_bm = virtio_input_bitmap::from_bits(
+                        &self.supported_events.keys().cloned().collect::<Vec<u16>>(),
+                    );
+                    cfg.set_payload_bitmap(&events_bm);
+                } else if let Some(supported_codes) = self.supported_events.get(&ev_type) {
+                    cfg.set_payload_bitmap(&supported_codes);
+                }
+            }
+            VIRTIO_INPUT_CFG_ABS_INFO => {
+                let abs_axis = self.subsel as u16;
+                if let Some(absinfo) = self.axis_info.get(&abs_axis) {
+                    cfg.set_absinfo(absinfo);
+                } // else all zeroes in the payload
+            }
+            VIRTIO_INPUT_CFG_ID_DEVIDS => {
+                cfg.set_device_ids(&self.device_ids);
+            }
+            _ => {
+                warn!("Unsuported virtio input config selection: {}", self.select);
+            }
+        }
+        cfg
+    }
+
+    fn read(&self, offset: usize, data: &mut [u8]) {
+        let data_len = data.len();
+        if self.validate_read_offsets(offset, data_len) {
+            let config = self.build_config_memory();
+            data.clone_from_slice(&config.as_slice()[offset..offset + data_len]);
+        }
+    }
+
+    fn validate_write_offsets(&self, offset: usize, len: usize) -> bool {
+        const MAX_WRITABLE_BYTES: usize = 2;
+        if offset + len > MAX_WRITABLE_BYTES {
+            error!(
+                "Attempt to write to invalid config range: [{}..{}], valid ranges in [0..{}]",
+                offset,
+                offset + len,
+                MAX_WRITABLE_BYTES
+            );
+            return false;
+        }
+        true
+    }
+
+    fn write(&mut self, offset: usize, data: &[u8]) {
+        let len = data.len();
+        if self.validate_write_offsets(offset, len) {
+            let mut selectors: [u8; 2] = [self.select, self.subsel];
+            selectors[offset..offset + len].clone_from_slice(&data);
+            self.select = selectors[0];
+            self.subsel = selectors[1];
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+struct virtio_input_event {
+    type_: Le16,
+    code: Le16,
+    value: Le32,
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_input_event {}
+
+impl virtio_input_event {
+    const EVENT_SIZE: usize = size_of::<virtio_input_event>();
+    fn new(type_: u16, code: u16, value: u32) -> virtio_input_event {
+        virtio_input_event {
+            type_: Le16::from(type_),
+            code: Le16::from(code),
+            value: Le32::from(value),
+        }
+    }
+
+    fn from_input_event(other: &input_event) -> virtio_input_event {
+        virtio_input_event {
+            type_: Le16::from(other.type_),
+            code: Le16::from(other.code),
+            value: Le32::from(other.value),
+        }
+    }
+}
+
+struct Worker<T: EventSource> {
+    event_source: T,
+    event_queue: Queue,
+    status_queue: Queue,
+    guest_memory: GuestMemory,
+    interrupt_status: Arc<AtomicUsize>,
+    interrupt_evt: EventFd,
+    interrupt_resample_evt: EventFd,
+}
+
+impl<T: EventSource> Worker<T> {
+    fn signal_used_queue(&self) {
+        self.interrupt_status
+            .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
+        self.interrupt_evt.write(1).unwrap();
+    }
+
+    // Send events from the source to the guest
+    fn send_events(&mut self) -> bool {
+        let queue = &mut self.event_queue;
+        let mut needs_interrupt = false;
+
+        // Only consume from the queue iterator if we know we have events to send
+        while self.event_source.available_events_count() > 0 {
+            match queue.pop(&self.guest_memory) {
+                None => {
+                    break;
+                }
+                Some(avail_desc) => {
+                    if !avail_desc.is_write_only() {
+                        panic!("Received a read only descriptor on event queue");
+                    }
+                    let avail_events_size =
+                        self.event_source.available_events_count() * virtio_input_event::EVENT_SIZE;
+                    let len = min(avail_desc.len as usize, avail_events_size);
+                    if let Err(e) =
+                        self.guest_memory
+                            .read_to_memory(avail_desc.addr, &self.event_source, len)
+                    {
+                        // Read is guaranteed to succeed here, so the only possible failure would be
+                        // writing outside the guest memory region, which would mean the address and
+                        // length given in the queue descriptor are wrong.
+                        panic!("failed reading events into guest memory: {}", e);
+                    }
+
+                    queue.add_used(&self.guest_memory, avail_desc.index, len as u32);
+                    needs_interrupt = true;
+                }
+            }
+        }
+
+        needs_interrupt
+    }
+
+    fn process_status_queue(&mut self) -> Result<bool> {
+        let queue = &mut self.status_queue;
+
+        let mut needs_interrupt = false;
+        while let Some(avail_desc) = queue.pop(&self.guest_memory) {
+            if !avail_desc.is_read_only() {
+                panic!("Received a writable descriptor on status queue");
+            }
+            let len = avail_desc.len as usize;
+            if len % virtio_input_event::EVENT_SIZE != 0 {
+                warn!(
+                    "Ignoring buffer of unexpected size on status queue: {:0}",
+                    len
+                );
+            } else {
+                self.guest_memory
+                    .write_from_memory(avail_desc.addr, &self.event_source, len)
+                    .map_err(InputError::EventsWriteError)?;
+            }
+
+            queue.add_used(&self.guest_memory, avail_desc.index, len as u32);
+            needs_interrupt = true;
+        }
+
+        Ok(needs_interrupt)
+    }
+
+    fn run(
+        &mut self,
+        event_queue_evt_fd: EventFd,
+        status_queue_evt_fd: EventFd,
+        kill_evt: EventFd,
+    ) {
+        if let Err(e) = self.event_source.init() {
+            error!("failed initializing event source: {}", e);
+            return;
+        }
+
+        #[derive(PollToken)]
+        enum Token {
+            EventQAvailable,
+            StatusQAvailable,
+            InputEventsAvailable,
+            InterruptResample,
+            Kill,
+        }
+        let poll_ctx: PollContext<Token> = match PollContext::new()
+            .and_then(|pc| {
+                pc.add(&event_queue_evt_fd, Token::EventQAvailable)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| {
+                pc.add(&status_queue_evt_fd, Token::StatusQAvailable)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| {
+                pc.add(&self.event_source, Token::InputEventsAvailable)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| {
+                pc.add(&self.interrupt_resample_evt, Token::InterruptResample)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc)))
+        {
+            Ok(poll_ctx) => poll_ctx,
+            Err(e) => {
+                error!("failed creating PollContext: {}", e);
+                return;
+            }
+        };
+
+        'poll: loop {
+            let poll_events = match poll_ctx.wait() {
+                Ok(poll_events) => poll_events,
+                Err(e) => {
+                    error!("failed polling for events: {}", e);
+                    break;
+                }
+            };
+
+            let mut needs_interrupt = false;
+            for poll_event in poll_events.iter_readable() {
+                match poll_event.token() {
+                    Token::EventQAvailable => {
+                        if let Err(e) = event_queue_evt_fd.read() {
+                            error!("failed reading event queue EventFd: {}", e);
+                            break 'poll;
+                        }
+                        needs_interrupt |= self.send_events();
+                    }
+                    Token::StatusQAvailable => {
+                        if let Err(e) = status_queue_evt_fd.read() {
+                            error!("failed reading status queue EventFd: {}", e);
+                            break 'poll;
+                        }
+                        match self.process_status_queue() {
+                            Ok(b) => needs_interrupt |= b,
+                            Err(e) => error!("failed processing status events: {}", e),
+                        }
+                    }
+                    Token::InputEventsAvailable => match self.event_source.receive_events() {
+                        Err(e) => error!("error receiving events: {}", e),
+                        Ok(_cnt) => needs_interrupt |= self.send_events(),
+                    },
+                    Token::InterruptResample => {
+                        let _ = self.interrupt_resample_evt.read();
+                        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
+                            self.interrupt_evt.write(1).unwrap();
+                        }
+                    }
+                    Token::Kill => {
+                        let _ = kill_evt.read();
+                        break 'poll;
+                    }
+                }
+            }
+            if needs_interrupt {
+                self.signal_used_queue();
+            }
+        }
+
+        if let Err(e) = self.event_source.finalize() {
+            error!("failed finalizing event source: {}", e);
+            return;
+        }
+    }
+}
+
+/// Virtio input device
+
+pub struct Input<T: EventSource> {
+    kill_evt: Option<EventFd>,
+    config: VirtioInputConfig,
+    source: Option<T>,
+}
+
+impl<T: EventSource> Drop for Input<T> {
+    fn drop(&mut self) {
+        if let Some(kill_evt) = self.kill_evt.take() {
+            // Ignore the result because there is nothing we can do about it.
+            let _ = kill_evt.write(1);
+        }
+    }
+}
+
+impl<T> VirtioDevice for Input<T>
+where
+    T: 'static + EventSource + Send,
+{
+    fn keep_fds(&self) -> Vec<RawFd> {
+        if let Some(source) = &self.source {
+            return vec![source.as_raw_fd()];
+        }
+        Vec::new()
+    }
+
+    fn device_type(&self) -> u32 {
+        TYPE_INPUT
+    }
+
+    fn queue_max_sizes(&self) -> &[u16] {
+        QUEUE_SIZES
+    }
+
+    fn read_config(&self, offset: u64, data: &mut [u8]) {
+        self.config.read(offset as usize, data);
+    }
+
+    fn write_config(&mut self, offset: u64, data: &[u8]) {
+        self.config.write(offset as usize, data);
+    }
+
+    fn activate(
+        &mut self,
+        mem: GuestMemory,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        status: Arc<AtomicUsize>,
+        mut queues: Vec<Queue>,
+        mut queue_evts: Vec<EventFd>,
+    ) {
+        if queues.len() != 2 || queue_evts.len() != 2 {
+            return;
+        }
+
+        let (self_kill_evt, kill_evt) = match EventFd::new().and_then(|e| Ok((e.try_clone()?, e))) {
+            Ok(v) => v,
+            Err(e) => {
+                error!("failed to create kill EventFd pair: {}", e);
+                return;
+            }
+        };
+        self.kill_evt = Some(self_kill_evt);
+
+        // Status is queue 1, event is queue 0
+        let status_queue = queues.remove(1);
+        let status_queue_evt_fd = queue_evts.remove(1);
+
+        let event_queue = queues.remove(0);
+        let event_queue_evt_fd = queue_evts.remove(0);
+
+        if let Some(source) = self.source.take() {
+            let worker_result = thread::Builder::new()
+                .name(String::from("virtio_input"))
+                .spawn(move || {
+                    let mut worker = Worker {
+                        event_source: source,
+                        event_queue,
+                        status_queue,
+                        guest_memory: mem,
+                        interrupt_status: status,
+                        interrupt_evt,
+                        interrupt_resample_evt,
+                    };
+                    worker.run(event_queue_evt_fd, status_queue_evt_fd, kill_evt);
+                });
+
+            if let Err(e) = worker_result {
+                error!("failed to spawn virtio_input worker: {}", e);
+                return;
+            }
+        } else {
+            error!("tried to activate device without a source for events");
+            return;
+        }
+    }
+}
+
+/// Creates a new virtio input device from an event device node
+pub fn new_evdev<T>(source: T) -> Result<Input<EvdevEventSource<T>>>
+where
+    T: Read + Write + AsRawFd,
+{
+    Ok(Input {
+        kill_evt: None,
+        config: VirtioInputConfig::from_evdev(&source)?,
+        source: Some(EvdevEventSource::new(source)),
+    })
+}
+
+/// Creates a new virtio touch device which supports single touch only.
+pub fn new_single_touch<T>(
+    source: T,
+    width: u32,
+    height: u32,
+) -> Result<Input<SocketEventSource<T>>>
+where
+    T: Read + Write + AsRawFd,
+{
+    Ok(Input {
+        kill_evt: None,
+        config: defaults::new_single_touch_config(width, height),
+        source: Some(SocketEventSource::new(source)),
+    })
+}
+
+/// Creates a new virtio trackpad device which supports (single) touch, primary and secondary
+/// buttons as well as X and Y axis.
+pub fn new_trackpad<T>(source: T, width: u32, height: u32) -> Result<Input<SocketEventSource<T>>>
+where
+    T: Read + Write + AsRawFd,
+{
+    Ok(Input {
+        kill_evt: None,
+        config: defaults::new_trackpad_config(width, height),
+        source: Some(SocketEventSource::new(source)),
+    })
+}
+
+/// Creates a new virtio mouse which supports primary, secondary, wheel and REL events.
+pub fn new_mouse<T>(source: T) -> Result<Input<SocketEventSource<T>>>
+where
+    T: Read + Write + AsRawFd,
+{
+    Ok(Input {
+        kill_evt: None,
+        config: defaults::new_mouse_config(),
+        source: Some(SocketEventSource::new(source)),
+    })
+}
+
+/// Creates a new virtio keyboard, which supports the same events as an en-us physical keyboard.
+pub fn new_keyboard<T>(source: T) -> Result<Input<SocketEventSource<T>>>
+where
+    T: Read + Write + AsRawFd,
+{
+    Ok(Input {
+        kill_evt: None,
+        config: defaults::new_keyboard_config(),
+        source: Some(SocketEventSource::new(source)),
+    })
+}
diff --git a/devices/src/virtio/mod.rs b/devices/src/virtio/mod.rs
new file mode 100644
index 0000000..3531ccd
--- /dev/null
+++ b/devices/src/virtio/mod.rs
@@ -0,0 +1,87 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Implements virtio devices, queues, and transport mechanisms.
+
+mod balloon;
+mod block;
+#[cfg(feature = "gpu")]
+mod gpu;
+mod input;
+mod net;
+mod p9;
+mod pmem;
+mod queue;
+mod rng;
+#[cfg(feature = "tpm")]
+mod tpm;
+mod virtio_device;
+mod virtio_pci_common_config;
+mod virtio_pci_device;
+mod wl;
+
+pub mod resource_bridge;
+pub mod vhost;
+
+pub use self::balloon::*;
+pub use self::block::*;
+#[cfg(feature = "gpu")]
+pub use self::gpu::*;
+pub use self::input::*;
+pub use self::net::*;
+pub use self::p9::*;
+pub use self::pmem::*;
+pub use self::queue::*;
+pub use self::rng::*;
+#[cfg(feature = "tpm")]
+pub use self::tpm::*;
+pub use self::virtio_device::*;
+pub use self::virtio_pci_device::*;
+pub use self::wl::*;
+
+const DEVICE_ACKNOWLEDGE: u32 = 0x01;
+const DEVICE_DRIVER: u32 = 0x02;
+const DEVICE_DRIVER_OK: u32 = 0x04;
+const DEVICE_FEATURES_OK: u32 = 0x08;
+const DEVICE_FAILED: u32 = 0x80;
+
+// Types taken from linux/virtio_ids.h
+const TYPE_NET: u32 = 1;
+const TYPE_BLOCK: u32 = 2;
+const TYPE_RNG: u32 = 4;
+const TYPE_BALLOON: u32 = 5;
+#[allow(dead_code)]
+const TYPE_GPU: u32 = 16;
+const TYPE_9P: u32 = 9;
+const TYPE_INPUT: u32 = 18;
+const TYPE_VSOCK: u32 = 19;
+const TYPE_PMEM: u32 = 27;
+// Additional types invented by crosvm
+const TYPE_WL: u32 = 30;
+#[cfg(feature = "tpm")]
+const TYPE_TPM: u32 = 31;
+
+const VIRTIO_F_VERSION_1: u32 = 32;
+
+const INTERRUPT_STATUS_USED_RING: u32 = 0x1;
+const INTERRUPT_STATUS_CONFIG_CHANGED: u32 = 0x2;
+
+/// Offset from the base MMIO address of a virtio device used by the guest to notify the device of
+/// queue events.
+pub const NOTIFY_REG_OFFSET: u32 = 0x50;
+
+/// Returns a string representation of the given virtio device type number.
+pub fn type_to_str(type_: u32) -> Option<&'static str> {
+    Some(match type_ {
+        TYPE_NET => "net",
+        TYPE_BLOCK => "block",
+        TYPE_RNG => "rng",
+        TYPE_BALLOON => "balloon",
+        TYPE_GPU => "gpu",
+        TYPE_9P => "9p",
+        TYPE_VSOCK => "vsock",
+        TYPE_WL => "wl",
+        _ => return None,
+    })
+}
diff --git a/devices/src/virtio/net.rs b/devices/src/virtio/net.rs
new file mode 100644
index 0000000..61a82cc
--- /dev/null
+++ b/devices/src/virtio/net.rs
@@ -0,0 +1,520 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::cmp;
+use std::fmt::{self, Display};
+use std::mem;
+use std::net::Ipv4Addr;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+use std::thread;
+
+use libc::EAGAIN;
+use net_sys;
+use net_util::{Error as TapError, MacAddress, TapT};
+use sys_util::Error as SysError;
+use sys_util::{error, warn, EventFd, GuestMemory, PollContext, PollToken};
+use virtio_sys::virtio_net::virtio_net_hdr_v1;
+use virtio_sys::{vhost, virtio_net};
+
+use super::{Queue, VirtioDevice, INTERRUPT_STATUS_USED_RING, TYPE_NET};
+
+/// The maximum buffer size when segmentation offload is enabled. This
+/// includes the 12-byte virtio net header.
+/// http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html#x1-1740003
+const MAX_BUFFER_SIZE: usize = 65562;
+const QUEUE_SIZE: u16 = 256;
+const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE, QUEUE_SIZE];
+
+#[derive(Debug)]
+pub enum NetError {
+    /// Creating kill eventfd failed.
+    CreateKillEventFd(SysError),
+    /// Creating PollContext failed.
+    CreatePollContext(SysError),
+    /// Cloning kill eventfd failed.
+    CloneKillEventFd(SysError),
+    /// Open tap device failed.
+    TapOpen(TapError),
+    /// Setting tap IP failed.
+    TapSetIp(TapError),
+    /// Setting tap netmask failed.
+    TapSetNetmask(TapError),
+    /// Setting tap mac address failed.
+    TapSetMacAddress(TapError),
+    /// Setting tap interface offload flags failed.
+    TapSetOffload(TapError),
+    /// Setting vnet header size failed.
+    TapSetVnetHdrSize(TapError),
+    /// Enabling tap interface failed.
+    TapEnable(TapError),
+    /// Validating tap interface failed.
+    TapValidate(String),
+    /// Error while polling for events.
+    PollError(SysError),
+}
+
+impl Display for NetError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::NetError::*;
+
+        match self {
+            CreateKillEventFd(e) => write!(f, "failed to create kill eventfd: {}", e),
+            CreatePollContext(e) => write!(f, "failed to create poll context: {}", e),
+            CloneKillEventFd(e) => write!(f, "failed to clone kill eventfd: {}", e),
+            TapOpen(e) => write!(f, "failed to open tap device: {}", e),
+            TapSetIp(e) => write!(f, "failed to set tap IP: {}", e),
+            TapSetNetmask(e) => write!(f, "failed to set tap netmask: {}", e),
+            TapSetMacAddress(e) => write!(f, "failed to set tap mac address: {}", e),
+            TapSetOffload(e) => write!(f, "failed to set tap interface offload flags: {}", e),
+            TapSetVnetHdrSize(e) => write!(f, "failed to set vnet header size: {}", e),
+            TapEnable(e) => write!(f, "failed to enable tap interface: {}", e),
+            TapValidate(s) => write!(f, "failed to validate tap interface: {}", s),
+            PollError(e) => write!(f, "error while polling for events: {}", e),
+        }
+    }
+}
+
+struct Worker<T: TapT> {
+    mem: GuestMemory,
+    rx_queue: Queue,
+    tx_queue: Queue,
+    tap: T,
+    interrupt_status: Arc<AtomicUsize>,
+    interrupt_evt: EventFd,
+    interrupt_resample_evt: EventFd,
+    rx_buf: [u8; MAX_BUFFER_SIZE],
+    rx_count: usize,
+    deferred_rx: bool,
+    // TODO(smbarber): http://crbug.com/753630
+    // Remove once MRG_RXBUF is supported and this variable is actually used.
+    #[allow(dead_code)]
+    acked_features: u64,
+}
+
+impl<T> Worker<T>
+where
+    T: TapT,
+{
+    fn signal_used_queue(&self) {
+        self.interrupt_status
+            .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
+        self.interrupt_evt.write(1).unwrap();
+    }
+
+    // Copies a single frame from `self.rx_buf` into the guest. Returns true
+    // if a buffer was used, and false if the frame must be deferred until a buffer
+    // is made available by the driver.
+    fn rx_single_frame(&mut self) -> bool {
+        let mut next_desc = self.rx_queue.pop(&self.mem);
+
+        if next_desc.is_none() {
+            return false;
+        }
+
+        // We just checked that the head descriptor exists.
+        let head_index = next_desc.as_ref().unwrap().index;
+        let mut write_count = 0;
+
+        // Copy from frame into buffer, which may span multiple descriptors.
+        loop {
+            match next_desc {
+                Some(desc) => {
+                    if !desc.is_write_only() {
+                        break;
+                    }
+                    let limit = cmp::min(write_count + desc.len as usize, self.rx_count);
+                    let source_slice = &self.rx_buf[write_count..limit];
+                    let write_result = self.mem.write_at_addr(source_slice, desc.addr);
+
+                    match write_result {
+                        Ok(sz) => {
+                            write_count += sz;
+                        }
+                        Err(e) => {
+                            warn!("net: rx: failed to write slice: {}", e);
+                            break;
+                        }
+                    };
+
+                    if write_count >= self.rx_count {
+                        break;
+                    }
+                    next_desc = desc.next_descriptor();
+                }
+                None => {
+                    warn!(
+                        "net: rx: buffer is too small to hold frame of size {}",
+                        self.rx_count
+                    );
+                    break;
+                }
+            }
+        }
+
+        self.rx_queue
+            .add_used(&self.mem, head_index, write_count as u32);
+
+        // Interrupt the guest immediately for received frames to
+        // reduce latency.
+        self.signal_used_queue();
+
+        true
+    }
+
+    fn process_rx(&mut self) {
+        // Read as many frames as possible.
+        loop {
+            let res = self.tap.read(&mut self.rx_buf);
+            match res {
+                Ok(count) => {
+                    self.rx_count = count;
+                    if !self.rx_single_frame() {
+                        self.deferred_rx = true;
+                        break;
+                    }
+                }
+                Err(e) => {
+                    // The tap device is nonblocking, so any error aside from EAGAIN is
+                    // unexpected.
+                    if e.raw_os_error().unwrap() != EAGAIN {
+                        warn!("net: rx: failed to read tap: {}", e);
+                    }
+                    break;
+                }
+            }
+        }
+    }
+
+    fn process_tx(&mut self) {
+        let mut frame = [0u8; MAX_BUFFER_SIZE];
+
+        while let Some(avail_desc) = self.tx_queue.pop(&self.mem) {
+            let head_index = avail_desc.index;
+            let mut next_desc = Some(avail_desc);
+            let mut read_count = 0;
+
+            // Copy buffer from across multiple descriptors.
+            while let Some(desc) = next_desc {
+                if desc.is_write_only() {
+                    break;
+                }
+                let limit = cmp::min(read_count + desc.len as usize, frame.len());
+                let read_result = self
+                    .mem
+                    .read_at_addr(&mut frame[read_count..limit as usize], desc.addr);
+                match read_result {
+                    Ok(sz) => {
+                        read_count += sz;
+                    }
+                    Err(e) => {
+                        warn!("net: tx: failed to read slice: {}", e);
+                        break;
+                    }
+                }
+                next_desc = desc.next_descriptor();
+            }
+
+            let write_result = self.tap.write(&frame[..read_count as usize]);
+            match write_result {
+                Ok(_) => {}
+                Err(e) => {
+                    warn!("net: tx: error failed to write to tap: {}", e);
+                }
+            };
+
+            self.tx_queue.add_used(&self.mem, head_index, 0);
+        }
+
+        self.signal_used_queue();
+    }
+
+    fn run(
+        &mut self,
+        rx_queue_evt: EventFd,
+        tx_queue_evt: EventFd,
+        kill_evt: EventFd,
+    ) -> Result<(), NetError> {
+        #[derive(PollToken)]
+        enum Token {
+            // A frame is available for reading from the tap device to receive in the guest.
+            RxTap,
+            // The guest has made a buffer available to receive a frame into.
+            RxQueue,
+            // The transmit queue has a frame that is ready to send from the guest.
+            TxQueue,
+            // Check if any interrupts need to be re-asserted.
+            InterruptResample,
+            // crosvm has requested the device to shut down.
+            Kill,
+        }
+
+        let poll_ctx: PollContext<Token> = PollContext::new()
+            .and_then(|pc| pc.add(&self.tap, Token::RxTap).and(Ok(pc)))
+            .and_then(|pc| pc.add(&rx_queue_evt, Token::RxQueue).and(Ok(pc)))
+            .and_then(|pc| pc.add(&tx_queue_evt, Token::TxQueue).and(Ok(pc)))
+            .and_then(|pc| {
+                pc.add(&self.interrupt_resample_evt, Token::InterruptResample)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc)))
+            .map_err(NetError::CreatePollContext)?;
+
+        'poll: loop {
+            let events = poll_ctx.wait().map_err(NetError::PollError)?;
+            for event in events.iter_readable() {
+                match event.token() {
+                    Token::RxTap => {
+                        // Process a deferred frame first if available. Don't read from tap again
+                        // until we manage to receive this deferred frame.
+                        if self.deferred_rx {
+                            if self.rx_single_frame() {
+                                self.deferred_rx = false;
+                            } else {
+                                continue;
+                            }
+                        }
+                        self.process_rx();
+                    }
+                    Token::RxQueue => {
+                        if let Err(e) = rx_queue_evt.read() {
+                            error!("net: error reading rx queue EventFd: {}", e);
+                            break 'poll;
+                        }
+                        // There should be a buffer available now to receive the frame into.
+                        if self.deferred_rx && self.rx_single_frame() {
+                            self.deferred_rx = false;
+                        }
+                    }
+                    Token::TxQueue => {
+                        if let Err(e) = tx_queue_evt.read() {
+                            error!("net: error reading tx queue EventFd: {}", e);
+                            break 'poll;
+                        }
+                        self.process_tx();
+                    }
+                    Token::InterruptResample => {
+                        let _ = self.interrupt_resample_evt.read();
+                        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
+                            self.interrupt_evt.write(1).unwrap();
+                        }
+                    }
+                    Token::Kill => break 'poll,
+                }
+            }
+        }
+        Ok(())
+    }
+}
+
+pub struct Net<T: TapT> {
+    workers_kill_evt: Option<EventFd>,
+    kill_evt: EventFd,
+    tap: Option<T>,
+    avail_features: u64,
+    acked_features: u64,
+}
+
+impl<T> Net<T>
+where
+    T: TapT,
+{
+    /// Create a new virtio network device with the given IP address and
+    /// netmask.
+    pub fn new(
+        ip_addr: Ipv4Addr,
+        netmask: Ipv4Addr,
+        mac_addr: MacAddress,
+    ) -> Result<Net<T>, NetError> {
+        let tap: T = T::new(true).map_err(NetError::TapOpen)?;
+        tap.set_ip_addr(ip_addr).map_err(NetError::TapSetIp)?;
+        tap.set_netmask(netmask).map_err(NetError::TapSetNetmask)?;
+        tap.set_mac_address(mac_addr)
+            .map_err(NetError::TapSetMacAddress)?;
+
+        tap.enable().map_err(NetError::TapEnable)?;
+
+        Net::from(tap)
+    }
+
+    /// Creates a new virtio network device from a tap device that has already been
+    /// configured.
+    pub fn from(tap: T) -> Result<Net<T>, NetError> {
+        // This would also validate a tap created by Self::new(), but that's a good thing as it
+        // would ensure that any changes in the creation procedure are matched in the validation.
+        // Plus we still need to set the offload and vnet_hdr_size values.
+        validate_and_configure_tap(&tap)?;
+
+        let avail_features = 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
+            | 1 << virtio_net::VIRTIO_NET_F_CSUM
+            | 1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4
+            | 1 << virtio_net::VIRTIO_NET_F_GUEST_UFO
+            | 1 << virtio_net::VIRTIO_NET_F_HOST_TSO4
+            | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO
+            | 1 << vhost::VIRTIO_F_VERSION_1;
+
+        let kill_evt = EventFd::new().map_err(NetError::CreateKillEventFd)?;
+        Ok(Net {
+            workers_kill_evt: Some(kill_evt.try_clone().map_err(NetError::CloneKillEventFd)?),
+            kill_evt,
+            tap: Some(tap),
+            avail_features,
+            acked_features: 0u64,
+        })
+    }
+}
+
+// Ensure that the tap interface has the correct flags and sets the offload and VNET header size
+// to the appropriate values.
+fn validate_and_configure_tap<T: TapT>(tap: &T) -> Result<(), NetError> {
+    let flags = tap.if_flags();
+    let required_flags = [
+        (net_sys::IFF_TAP, "IFF_TAP"),
+        (net_sys::IFF_NO_PI, "IFF_NO_PI"),
+        (net_sys::IFF_VNET_HDR, "IFF_VNET_HDR"),
+    ];
+    let missing_flags = required_flags
+        .iter()
+        .filter_map(
+            |(value, name)| {
+                if value & flags == 0 {
+                    Some(name)
+                } else {
+                    None
+                }
+            },
+        )
+        .collect::<Vec<_>>();
+
+    if !missing_flags.is_empty() {
+        return Err(NetError::TapValidate(format!(
+            "Missing flags: {:?}",
+            missing_flags
+        )));
+    }
+
+    // Set offload flags to match the virtio features below.
+    tap.set_offload(
+        net_sys::TUN_F_CSUM | net_sys::TUN_F_UFO | net_sys::TUN_F_TSO4 | net_sys::TUN_F_TSO6,
+    )
+    .map_err(NetError::TapSetOffload)?;
+
+    let vnet_hdr_size = mem::size_of::<virtio_net_hdr_v1>() as i32;
+    tap.set_vnet_hdr_size(vnet_hdr_size)
+        .map_err(NetError::TapSetVnetHdrSize)?;
+
+    Ok(())
+}
+
+impl<T> Drop for Net<T>
+where
+    T: TapT,
+{
+    fn drop(&mut self) {
+        // Only kill the child if it claimed its eventfd.
+        if self.workers_kill_evt.is_none() {
+            // Ignore the result because there is nothing we can do about it.
+            let _ = self.kill_evt.write(1);
+        }
+    }
+}
+
+impl<T> VirtioDevice for Net<T>
+where
+    T: 'static + TapT,
+{
+    fn keep_fds(&self) -> Vec<RawFd> {
+        let mut keep_fds = Vec::new();
+
+        if let Some(tap) = &self.tap {
+            keep_fds.push(tap.as_raw_fd());
+        }
+
+        if let Some(workers_kill_evt) = &self.workers_kill_evt {
+            keep_fds.push(workers_kill_evt.as_raw_fd());
+        }
+
+        keep_fds
+    }
+
+    fn device_type(&self) -> u32 {
+        TYPE_NET
+    }
+
+    fn queue_max_sizes(&self) -> &[u16] {
+        QUEUE_SIZES
+    }
+
+    fn features(&self) -> u64 {
+        self.avail_features
+    }
+
+    fn ack_features(&mut self, value: u64) {
+        let mut v = value;
+
+        // Check if the guest is ACK'ing a feature that we didn't claim to have.
+        let unrequested_features = v & !self.avail_features;
+        if unrequested_features != 0 {
+            warn!("net: virtio net got unknown feature ack: {:x}", v);
+
+            // Don't count these features as acked.
+            v &= !unrequested_features;
+        }
+        self.acked_features |= v;
+    }
+
+    fn activate(
+        &mut self,
+        mem: GuestMemory,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        status: Arc<AtomicUsize>,
+        mut queues: Vec<Queue>,
+        mut queue_evts: Vec<EventFd>,
+    ) {
+        if queues.len() != 2 || queue_evts.len() != 2 {
+            error!("net: expected 2 queues, got {}", queues.len());
+            return;
+        }
+
+        if let Some(tap) = self.tap.take() {
+            if let Some(kill_evt) = self.workers_kill_evt.take() {
+                let acked_features = self.acked_features;
+                let worker_result =
+                    thread::Builder::new()
+                        .name("virtio_net".to_string())
+                        .spawn(move || {
+                            // First queue is rx, second is tx.
+                            let rx_queue = queues.remove(0);
+                            let tx_queue = queues.remove(0);
+                            let mut worker = Worker {
+                                mem,
+                                rx_queue,
+                                tx_queue,
+                                tap,
+                                interrupt_status: status,
+                                interrupt_evt,
+                                interrupt_resample_evt,
+                                rx_buf: [0u8; MAX_BUFFER_SIZE],
+                                rx_count: 0,
+                                deferred_rx: false,
+                                acked_features,
+                            };
+                            let rx_queue_evt = queue_evts.remove(0);
+                            let tx_queue_evt = queue_evts.remove(0);
+                            let result = worker.run(rx_queue_evt, tx_queue_evt, kill_evt);
+                            if let Err(e) = result {
+                                error!("net worker thread exited with error: {}", e);
+                            }
+                        });
+
+                if let Err(e) = worker_result {
+                    error!("failed to spawn virtio_net worker: {}", e);
+                    return;
+                }
+            }
+        }
+    }
+}
diff --git a/devices/src/virtio/p9.rs b/devices/src/virtio/p9.rs
new file mode 100644
index 0000000..b5d0842
--- /dev/null
+++ b/devices/src/virtio/p9.rs
@@ -0,0 +1,443 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::cmp::min;
+use std::fmt::{self, Display};
+use std::io::{self, Read, Write};
+use std::iter::Peekable;
+use std::mem;
+use std::os::unix::io::RawFd;
+use std::path::{Path, PathBuf};
+use std::result;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+use std::thread;
+
+use p9;
+use sys_util::{
+    error, warn, Error as SysError, EventFd, GuestAddress, GuestMemory, PollContext, PollToken,
+};
+use virtio_sys::vhost::VIRTIO_F_VERSION_1;
+
+use super::{DescriptorChain, Queue, VirtioDevice, INTERRUPT_STATUS_USED_RING, TYPE_9P};
+
+const QUEUE_SIZE: u16 = 128;
+const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE];
+
+// The only virtio_9p feature.
+const VIRTIO_9P_MOUNT_TAG: u8 = 0;
+
+/// Errors that occur during operation of a virtio 9P device.
+#[derive(Debug)]
+pub enum P9Error {
+    /// The tag for the 9P device was too large to fit in the config space.
+    TagTooLong(usize),
+    /// The root directory for the 9P server is not absolute.
+    RootNotAbsolute(PathBuf),
+    /// Creating PollContext failed.
+    CreatePollContext(SysError),
+    /// Error while polling for events.
+    PollError(SysError),
+    /// Error while reading from the virtio queue's EventFd.
+    ReadQueueEventFd(SysError),
+    /// A request is missing readable descriptors.
+    NoReadableDescriptors,
+    /// A request is missing writable descriptors.
+    NoWritableDescriptors,
+    /// A descriptor contained an invalid guest address range.
+    InvalidGuestAddress(GuestAddress, u32),
+    /// Failed to signal the virio used queue.
+    SignalUsedQueue(SysError),
+    /// An internal I/O error occurred.
+    Internal(io::Error),
+}
+
+impl std::error::Error for P9Error {}
+
+impl Display for P9Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::P9Error::*;
+
+        match self {
+            TagTooLong(len) => write!(
+                f,
+                "P9 device tag is too long: len = {}, max = {}",
+                len,
+                ::std::u16::MAX
+            ),
+            RootNotAbsolute(buf) => write!(
+                f,
+                "P9 root directory is not absolute: root = {}",
+                buf.display()
+            ),
+            CreatePollContext(err) => write!(f, "failed to create PollContext: {}", err),
+            PollError(err) => write!(f, "failed to poll events: {}", err),
+            ReadQueueEventFd(err) => write!(f, "failed to read from virtio queue EventFd: {}", err),
+            NoReadableDescriptors => write!(f, "request does not have any readable descriptors"),
+            NoWritableDescriptors => write!(f, "request does not have any writable descriptors"),
+            InvalidGuestAddress(addr, len) => write!(
+                f,
+                "descriptor contained invalid guest address range: address = {}, len = {}",
+                addr, len
+            ),
+            SignalUsedQueue(err) => write!(f, "failed to signal used queue: {}", err),
+            Internal(err) => write!(f, "P9 internal server error: {}", err),
+        }
+    }
+}
+
+pub type P9Result<T> = result::Result<T, P9Error>;
+
+struct Reader<'a, I>
+where
+    I: Iterator<Item = DescriptorChain<'a>>,
+{
+    mem: &'a GuestMemory,
+    offset: u32,
+    iter: Peekable<I>,
+}
+
+impl<'a, I> Read for Reader<'a, I>
+where
+    I: Iterator<Item = DescriptorChain<'a>>,
+{
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let needs_advance = if let Some(current) = self.iter.peek() {
+            self.offset >= current.len
+        } else {
+            false
+        };
+
+        if needs_advance {
+            self.offset = 0;
+            self.iter.next();
+        }
+
+        if let Some(current) = self.iter.peek() {
+            debug_assert!(current.is_read_only());
+            let addr = current
+                .addr
+                .checked_add(self.offset as u64)
+                .ok_or_else(|| {
+                    io::Error::new(
+                        io::ErrorKind::InvalidData,
+                        P9Error::InvalidGuestAddress(current.addr, current.len),
+                    )
+                })?;
+            let len = min(buf.len(), (current.len - self.offset) as usize);
+            let count = self
+                .mem
+                .read_at_addr(&mut buf[..len], addr)
+                .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
+
+            // |count| has to fit into a u32 because it must be less than or equal to
+            // |current.len|, which does fit into a u32.
+            self.offset += count as u32;
+
+            Ok(count)
+        } else {
+            // Nothing left to read.
+            Ok(0)
+        }
+    }
+}
+
+struct Writer<'a, I>
+where
+    I: Iterator<Item = DescriptorChain<'a>>,
+{
+    mem: &'a GuestMemory,
+    bytes_written: u32,
+    offset: u32,
+    iter: Peekable<I>,
+}
+
+impl<'a, I> Write for Writer<'a, I>
+where
+    I: Iterator<Item = DescriptorChain<'a>>,
+{
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let needs_advance = if let Some(current) = self.iter.peek() {
+            self.offset >= current.len
+        } else {
+            false
+        };
+
+        if needs_advance {
+            self.offset = 0;
+            self.iter.next();
+        }
+
+        if let Some(current) = self.iter.peek() {
+            debug_assert!(current.is_write_only());
+            let addr = current
+                .addr
+                .checked_add(self.offset as u64)
+                .ok_or_else(|| {
+                    io::Error::new(
+                        io::ErrorKind::InvalidData,
+                        P9Error::InvalidGuestAddress(current.addr, current.len),
+                    )
+                })?;
+
+            let len = min(buf.len(), (current.len - self.offset) as usize);
+            let count = self
+                .mem
+                .write_at_addr(&buf[..len], addr)
+                .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
+
+            // |count| has to fit into a u32 because it must be less than or equal to
+            // |current.len|, which does fit into a u32.
+            self.offset += count as u32;
+            self.bytes_written += count as u32;
+
+            Ok(count)
+        } else {
+            // No more room in the descriptor chain.
+            Ok(0)
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        // Nothing to flush since the writes go straight into the buffer.
+        Ok(())
+    }
+}
+
+struct Worker {
+    mem: GuestMemory,
+    queue: Queue,
+    server: p9::Server,
+    irq_status: Arc<AtomicUsize>,
+    irq_evt: EventFd,
+    interrupt_resample_evt: EventFd,
+}
+
+impl Worker {
+    fn signal_used_queue(&self) -> P9Result<()> {
+        self.irq_status
+            .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
+        self.irq_evt.write(1).map_err(P9Error::SignalUsedQueue)
+    }
+
+    fn process_queue(&mut self) -> P9Result<()> {
+        while let Some(avail_desc) = self.queue.pop(&self.mem) {
+            let mut reader = Reader {
+                mem: &self.mem,
+                offset: 0,
+                iter: avail_desc.clone().into_iter().readable().peekable(),
+            };
+            let mut writer = Writer {
+                mem: &self.mem,
+                bytes_written: 0,
+                offset: 0,
+                iter: avail_desc.clone().into_iter().writable().peekable(),
+            };
+
+            self.server
+                .handle_message(&mut reader, &mut writer)
+                .map_err(P9Error::Internal)?;
+
+            self.queue
+                .add_used(&self.mem, avail_desc.index, writer.bytes_written);
+        }
+
+        self.signal_used_queue()?;
+
+        Ok(())
+    }
+
+    fn run(&mut self, queue_evt: EventFd, kill_evt: EventFd) -> P9Result<()> {
+        #[derive(PollToken)]
+        enum Token {
+            // A request is ready on the queue.
+            QueueReady,
+            // Check if any interrupts need to be re-asserted.
+            InterruptResample,
+            // The parent thread requested an exit.
+            Kill,
+        }
+
+        let poll_ctx: PollContext<Token> = PollContext::new()
+            .and_then(|pc| pc.add(&queue_evt, Token::QueueReady).and(Ok(pc)))
+            .and_then(|pc| {
+                pc.add(&self.interrupt_resample_evt, Token::InterruptResample)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc)))
+            .map_err(P9Error::CreatePollContext)?;
+
+        loop {
+            let events = poll_ctx.wait().map_err(P9Error::PollError)?;
+            for event in events.iter_readable() {
+                match event.token() {
+                    Token::QueueReady => {
+                        queue_evt.read().map_err(P9Error::ReadQueueEventFd)?;
+                        self.process_queue()?;
+                    }
+                    Token::InterruptResample => {
+                        let _ = self.interrupt_resample_evt.read();
+                        if self.irq_status.load(Ordering::SeqCst) != 0 {
+                            self.irq_evt.write(1).unwrap();
+                        }
+                    }
+                    Token::Kill => return Ok(()),
+                }
+            }
+        }
+    }
+}
+
+/// Virtio device for sharing specific directories on the host system with the guest VM.
+pub struct P9 {
+    config: Vec<u8>,
+    server: Option<p9::Server>,
+    kill_evt: Option<EventFd>,
+    avail_features: u64,
+    acked_features: u64,
+    worker: Option<thread::JoinHandle<P9Result<()>>>,
+}
+
+impl P9 {
+    pub fn new<P: AsRef<Path>>(root: P, tag: &str) -> P9Result<P9> {
+        if tag.len() > ::std::u16::MAX as usize {
+            return Err(P9Error::TagTooLong(tag.len()));
+        }
+
+        if !root.as_ref().is_absolute() {
+            return Err(P9Error::RootNotAbsolute(root.as_ref().into()));
+        }
+
+        let len = tag.len() as u16;
+        let mut cfg = Vec::with_capacity(tag.len() + mem::size_of::<u16>());
+        cfg.push(len as u8);
+        cfg.push((len >> 8) as u8);
+
+        cfg.write_all(tag.as_bytes()).map_err(P9Error::Internal)?;
+
+        Ok(P9 {
+            config: cfg,
+            server: Some(p9::Server::new(root)),
+            kill_evt: None,
+            avail_features: 1 << VIRTIO_9P_MOUNT_TAG | 1 << VIRTIO_F_VERSION_1,
+            acked_features: 0,
+            worker: None,
+        })
+    }
+}
+
+impl VirtioDevice for P9 {
+    fn keep_fds(&self) -> Vec<RawFd> {
+        Vec::new()
+    }
+
+    fn device_type(&self) -> u32 {
+        TYPE_9P
+    }
+
+    fn queue_max_sizes(&self) -> &[u16] {
+        QUEUE_SIZES
+    }
+
+    fn features(&self) -> u64 {
+        self.avail_features
+    }
+
+    fn ack_features(&mut self, value: u64) {
+        let mut v = value;
+
+        // Check if the guest is ACK'ing a feature that we didn't claim to have.
+        let unrequested_features = v & !self.avail_features;
+        if unrequested_features != 0 {
+            warn!("virtio_9p got unknown feature ack: {:x}", v);
+
+            // Don't count these features as acked.
+            v &= !unrequested_features;
+        }
+        self.acked_features |= v;
+    }
+
+    fn read_config(&self, offset: u64, data: &mut [u8]) {
+        if offset >= self.config.len() as u64 {
+            // Nothing to see here.
+            return;
+        }
+
+        // The config length cannot be more than ::std::u16::MAX + mem::size_of::<u16>(), which
+        // is significantly smaller than ::std::usize::MAX on the architectures we care about so
+        // if we reach this point then we know that `offset` will fit into a usize.
+        let offset = offset as usize;
+        let len = min(data.len(), self.config.len() - offset);
+        data[..len].copy_from_slice(&self.config[offset..offset + len])
+    }
+
+    fn activate(
+        &mut self,
+        guest_mem: GuestMemory,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        status: Arc<AtomicUsize>,
+        mut queues: Vec<Queue>,
+        mut queue_evts: Vec<EventFd>,
+    ) {
+        if queues.len() != 1 || queue_evts.len() != 1 {
+            return;
+        }
+
+        let (self_kill_evt, kill_evt) = match EventFd::new().and_then(|e| Ok((e.try_clone()?, e))) {
+            Ok(v) => v,
+            Err(e) => {
+                error!("failed creating kill EventFd pair: {}", e);
+                return;
+            }
+        };
+        self.kill_evt = Some(self_kill_evt);
+
+        if let Some(server) = self.server.take() {
+            let worker_result =
+                thread::Builder::new()
+                    .name("virtio_9p".to_string())
+                    .spawn(move || {
+                        let mut worker = Worker {
+                            mem: guest_mem,
+                            queue: queues.remove(0),
+                            server,
+                            irq_status: status,
+                            irq_evt: interrupt_evt,
+                            interrupt_resample_evt,
+                        };
+
+                        worker.run(queue_evts.remove(0), kill_evt)
+                    });
+
+            match worker_result {
+                Ok(worker) => self.worker = Some(worker),
+                Err(e) => error!("failed to spawn virtio_9p worker: {}", e),
+            }
+        }
+    }
+}
+
+impl Drop for P9 {
+    fn drop(&mut self) {
+        if let Some(kill_evt) = self.kill_evt.take() {
+            if let Err(e) = kill_evt.write(1) {
+                error!("failed to kill virtio_9p worker thread: {}", e);
+                return;
+            }
+
+            // Only wait on the child thread if we were able to send it a kill event.
+            if let Some(worker) = self.worker.take() {
+                match worker.join() {
+                    Ok(r) => {
+                        if let Err(e) = r {
+                            error!("virtio_9p worker thread exited with error: {}", e)
+                        }
+                    }
+                    Err(e) => error!("virtio_9p worker thread panicked: {:?}", e),
+                }
+            }
+        }
+    }
+}
diff --git a/devices/src/virtio/pmem.rs b/devices/src/virtio/pmem.rs
new file mode 100644
index 0000000..5a4fa32
--- /dev/null
+++ b/devices/src/virtio/pmem.rs
@@ -0,0 +1,367 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::cmp;
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::io::Write;
+use std::mem::{size_of, size_of_val};
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::result;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+use std::thread;
+
+use sys_util::Result as SysResult;
+use sys_util::{
+    error, EventFd, GuestAddress, GuestMemory, GuestMemoryError, PollContext, PollToken,
+};
+
+use data_model::{DataInit, Le32, Le64};
+
+use super::{
+    DescriptorChain, Queue, VirtioDevice, INTERRUPT_STATUS_USED_RING, TYPE_PMEM, VIRTIO_F_VERSION_1,
+};
+
+const QUEUE_SIZE: u16 = 256;
+const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE];
+
+const VIRTIO_PMEM_REQ_TYPE_FLUSH: u32 = 0;
+const VIRTIO_PMEM_RESP_TYPE_OK: u32 = 0;
+const VIRTIO_PMEM_RESP_TYPE_EIO: u32 = 1;
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+struct virtio_pmem_config {
+    start_address: Le64,
+    size: Le64,
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_pmem_config {}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+struct virtio_pmem_resp {
+    status_code: Le32,
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_pmem_resp {}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+struct virtio_pmem_req {
+    type_: Le32,
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for virtio_pmem_req {}
+
+#[derive(Debug)]
+enum ParseError {
+    /// Guest gave us bad memory addresses.
+    GuestMemory(GuestMemoryError),
+    /// Guest gave us a write only descriptor that protocol says to read from.
+    UnexpectedWriteOnlyDescriptor,
+    /// Guest gave us a read only descriptor that protocol says to write to.
+    UnexpectedReadOnlyDescriptor,
+    /// Guest gave us too few descriptors in a descriptor chain.
+    DescriptorChainTooShort,
+    /// Guest gave us a buffer that was too short to use.
+    BufferLengthTooSmall,
+    /// Guest sent us invalid request.
+    InvalidRequest,
+}
+
+impl Display for ParseError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::ParseError::*;
+
+        match self {
+            BufferLengthTooSmall => write!(f, "buffer length too small"),
+            DescriptorChainTooShort => write!(f, "descriptor chain too short"),
+            GuestMemory(e) => write!(f, "bad guest memory address: {}", e),
+            InvalidRequest => write!(f, "invalid request"),
+            UnexpectedReadOnlyDescriptor => write!(f, "unexpected read-only descriptor"),
+            UnexpectedWriteOnlyDescriptor => write!(f, "unexpected write-only descriptor"),
+        }
+    }
+}
+
+enum Request {
+    Flush { status_address: GuestAddress },
+}
+
+impl Request {
+    fn parse(
+        avail_desc: &DescriptorChain,
+        memory: &GuestMemory,
+    ) -> result::Result<Request, ParseError> {
+        // The head contains the request type which MUST be readable.
+        if avail_desc.is_write_only() {
+            return Err(ParseError::UnexpectedWriteOnlyDescriptor);
+        }
+
+        if avail_desc.len as usize != size_of::<virtio_pmem_req>() {
+            return Err(ParseError::InvalidRequest);
+        }
+
+        let request: virtio_pmem_req = memory
+            .read_obj_from_addr(avail_desc.addr)
+            .map_err(ParseError::GuestMemory)?;
+
+        // Currently, there is only one virtio-pmem request, FLUSH.
+        if request.type_ != VIRTIO_PMEM_REQ_TYPE_FLUSH {
+            error!("unknown request type: {}", request.type_.to_native());
+            return Err(ParseError::InvalidRequest);
+        }
+
+        let status_desc = avail_desc
+            .next_descriptor()
+            .ok_or(ParseError::DescriptorChainTooShort)?;
+
+        // The status MUST always be writable
+        if status_desc.is_read_only() {
+            return Err(ParseError::UnexpectedReadOnlyDescriptor);
+        }
+
+        if (status_desc.len as usize) < size_of::<virtio_pmem_resp>() {
+            return Err(ParseError::BufferLengthTooSmall);
+        }
+
+        Ok(Request::Flush {
+            status_address: status_desc.addr,
+        })
+    }
+}
+
+struct Worker {
+    queue: Queue,
+    memory: GuestMemory,
+    disk_image: File,
+    interrupt_status: Arc<AtomicUsize>,
+    interrupt_event: EventFd,
+    interrupt_resample_event: EventFd,
+}
+
+impl Worker {
+    fn process_queue(&mut self) -> bool {
+        let mut needs_interrupt = false;
+        while let Some(avail_desc) = self.queue.pop(&self.memory) {
+            let len;
+            match Request::parse(&avail_desc, &self.memory) {
+                Ok(Request::Flush { status_address }) => {
+                    let status_code = match self.disk_image.sync_all() {
+                        Ok(()) => VIRTIO_PMEM_RESP_TYPE_OK,
+                        Err(e) => {
+                            error!("failed flushing disk image: {}", e);
+                            VIRTIO_PMEM_RESP_TYPE_EIO
+                        }
+                    };
+
+                    let response = virtio_pmem_resp {
+                        status_code: status_code.into(),
+                    };
+                    len = match self.memory.write_obj_at_addr(response, status_address) {
+                        Ok(_) => size_of::<virtio_pmem_resp>() as u32,
+                        Err(e) => {
+                            error!("bad guest memory address: {}", e);
+                            0
+                        }
+                    }
+                }
+                Err(e) => {
+                    error!("failed processing available descriptor chain: {}", e);
+                    len = 0;
+                }
+            }
+            self.queue.add_used(&self.memory, avail_desc.index, len);
+            needs_interrupt = true;
+        }
+
+        needs_interrupt
+    }
+
+    fn signal_used_queue(&self) {
+        self.interrupt_status
+            .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
+        self.interrupt_event.write(1).unwrap();
+    }
+
+    fn run(&mut self, queue_evt: EventFd, kill_evt: EventFd) {
+        #[derive(PollToken)]
+        enum Token {
+            QueueAvailable,
+            InterruptResample,
+            Kill,
+        }
+
+        let poll_ctx: PollContext<Token> = match PollContext::new()
+            .and_then(|pc| pc.add(&queue_evt, Token::QueueAvailable).and(Ok(pc)))
+            .and_then(|pc| {
+                pc.add(&self.interrupt_resample_event, Token::InterruptResample)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc)))
+        {
+            Ok(pc) => pc,
+            Err(e) => {
+                error!("failed creating PollContext: {}", e);
+                return;
+            }
+        };
+
+        'poll: loop {
+            let events = match poll_ctx.wait() {
+                Ok(v) => v,
+                Err(e) => {
+                    error!("failed polling for events: {}", e);
+                    break;
+                }
+            };
+
+            let mut needs_interrupt = false;
+            for event in events.iter_readable() {
+                match event.token() {
+                    Token::QueueAvailable => {
+                        if let Err(e) = queue_evt.read() {
+                            error!("failed reading queue EventFd: {}", e);
+                            break 'poll;
+                        }
+                        needs_interrupt |= self.process_queue();
+                    }
+                    Token::InterruptResample => {
+                        let _ = self.interrupt_resample_event.read();
+                        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
+                            self.interrupt_event.write(1).unwrap();
+                        }
+                    }
+                    Token::Kill => break 'poll,
+                }
+            }
+            if needs_interrupt {
+                self.signal_used_queue();
+            }
+        }
+    }
+}
+
+pub struct Pmem {
+    kill_event: Option<EventFd>,
+    disk_image: Option<File>,
+    mapping_address: GuestAddress,
+    mapping_size: u64,
+}
+
+impl Pmem {
+    pub fn new(
+        disk_image: File,
+        mapping_address: GuestAddress,
+        mapping_size: u64,
+    ) -> SysResult<Pmem> {
+        Ok(Pmem {
+            kill_event: None,
+            disk_image: Some(disk_image),
+            mapping_address,
+            mapping_size,
+        })
+    }
+}
+
+impl Drop for Pmem {
+    fn drop(&mut self) {
+        if let Some(kill_evt) = self.kill_event.take() {
+            // Ignore the result because there is nothing we can do about it.
+            let _ = kill_evt.write(1);
+        }
+    }
+}
+
+impl VirtioDevice for Pmem {
+    fn keep_fds(&self) -> Vec<RawFd> {
+        if let Some(disk_image) = &self.disk_image {
+            vec![disk_image.as_raw_fd()]
+        } else {
+            vec![]
+        }
+    }
+
+    fn device_type(&self) -> u32 {
+        TYPE_PMEM
+    }
+
+    fn queue_max_sizes(&self) -> &[u16] {
+        QUEUE_SIZES
+    }
+
+    fn features(&self) -> u64 {
+        1 << VIRTIO_F_VERSION_1
+    }
+
+    fn read_config(&self, offset: u64, mut data: &mut [u8]) {
+        let config = virtio_pmem_config {
+            start_address: Le64::from(self.mapping_address.offset()),
+            size: Le64::from(self.mapping_size as u64),
+        };
+        let config_len = size_of_val(&config) as u64;
+        if offset >= config_len {
+            return;
+        }
+
+        if let Some(end) = offset.checked_add(data.len() as u64) {
+            let offset = offset as usize;
+            let end = cmp::min(end, config_len) as usize;
+            // This write can't fail, offset and end are checked against config_len.
+            data.write_all(&config.as_slice()[offset..end]).unwrap();
+        }
+    }
+
+    fn activate(
+        &mut self,
+        memory: GuestMemory,
+        interrupt_event: EventFd,
+        interrupt_resample_event: EventFd,
+        status: Arc<AtomicUsize>,
+        mut queues: Vec<Queue>,
+        mut queue_events: Vec<EventFd>,
+    ) {
+        if queues.len() != 1 || queue_events.len() != 1 {
+            return;
+        }
+
+        let queue = queues.remove(0);
+        let queue_event = queue_events.remove(0);
+
+        if let Some(disk_image) = self.disk_image.take() {
+            let (self_kill_event, kill_event) =
+                match EventFd::new().and_then(|e| Ok((e.try_clone()?, e))) {
+                    Ok(v) => v,
+                    Err(e) => {
+                        error!("failed creating kill EventFd pair: {}", e);
+                        return;
+                    }
+                };
+            self.kill_event = Some(self_kill_event);
+
+            let worker_result = thread::Builder::new()
+                .name("virtio_pmem".to_string())
+                .spawn(move || {
+                    let mut worker = Worker {
+                        memory,
+                        disk_image,
+                        queue,
+                        interrupt_status: status,
+                        interrupt_event,
+                        interrupt_resample_event,
+                    };
+                    worker.run(queue_event, kill_event);
+                });
+            if let Err(e) = worker_result {
+                error!("failed to spawn virtio_pmem worker: {}", e);
+                return;
+            }
+        }
+    }
+}
diff --git a/devices/src/virtio/queue.rs b/devices/src/virtio/queue.rs
new file mode 100644
index 0000000..9324199
--- /dev/null
+++ b/devices/src/virtio/queue.rs
@@ -0,0 +1,344 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::cmp::min;
+use std::num::Wrapping;
+use std::sync::atomic::{fence, Ordering};
+
+use sys_util::{error, GuestAddress, GuestMemory};
+
+const VIRTQ_DESC_F_NEXT: u16 = 0x1;
+const VIRTQ_DESC_F_WRITE: u16 = 0x2;
+#[allow(dead_code)]
+const VIRTQ_DESC_F_INDIRECT: u16 = 0x4;
+
+/// An iterator over a single descriptor chain.  Not to be confused with AvailIter,
+/// which iterates over the descriptor chain heads in a queue.
+pub struct DescIter<'a> {
+    next: Option<DescriptorChain<'a>>,
+}
+
+impl<'a> DescIter<'a> {
+    /// Returns an iterator that only yields the readable descriptors in the chain.
+    pub fn readable(self) -> impl Iterator<Item = DescriptorChain<'a>> {
+        self.take_while(DescriptorChain::is_read_only)
+    }
+
+    /// Returns an iterator that only yields the writable descriptors in the chain.
+    pub fn writable(self) -> impl Iterator<Item = DescriptorChain<'a>> {
+        self.skip_while(DescriptorChain::is_read_only)
+    }
+}
+
+impl<'a> Iterator for DescIter<'a> {
+    type Item = DescriptorChain<'a>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if let Some(current) = self.next.take() {
+            self.next = current.next_descriptor();
+            Some(current)
+        } else {
+            None
+        }
+    }
+}
+
+/// A virtio descriptor chain.
+#[derive(Clone)]
+pub struct DescriptorChain<'a> {
+    mem: &'a GuestMemory,
+    desc_table: GuestAddress,
+    queue_size: u16,
+    ttl: u16, // used to prevent infinite chain cycles
+
+    /// Index into the descriptor table
+    pub index: u16,
+
+    /// Guest physical address of device specific data
+    pub addr: GuestAddress,
+
+    /// Length of device specific data
+    pub len: u32,
+
+    /// Includes next, write, and indirect bits
+    pub flags: u16,
+
+    /// Index into the descriptor table of the next descriptor if flags has
+    /// the next bit set
+    pub next: u16,
+}
+
+impl<'a> DescriptorChain<'a> {
+    fn checked_new(
+        mem: &GuestMemory,
+        desc_table: GuestAddress,
+        queue_size: u16,
+        index: u16,
+    ) -> Option<DescriptorChain> {
+        if index >= queue_size {
+            return None;
+        }
+
+        let desc_head = match mem.checked_offset(desc_table, (index as u64) * 16) {
+            Some(a) => a,
+            None => return None,
+        };
+        // These reads can't fail unless Guest memory is hopelessly broken.
+        let addr = GuestAddress(mem.read_obj_from_addr::<u64>(desc_head).unwrap() as u64);
+        if mem.checked_offset(desc_head, 16).is_none() {
+            return None;
+        }
+        let len: u32 = mem.read_obj_from_addr(desc_head.unchecked_add(8)).unwrap();
+        let flags: u16 = mem.read_obj_from_addr(desc_head.unchecked_add(12)).unwrap();
+        let next: u16 = mem.read_obj_from_addr(desc_head.unchecked_add(14)).unwrap();
+        let chain = DescriptorChain {
+            mem,
+            desc_table,
+            queue_size,
+            ttl: queue_size,
+            index,
+            addr,
+            len,
+            flags,
+            next,
+        };
+
+        if chain.is_valid() {
+            Some(chain)
+        } else {
+            None
+        }
+    }
+
+    #[allow(clippy::if_same_then_else)]
+    fn is_valid(&self) -> bool {
+        if self
+            .mem
+            .checked_offset(self.addr, self.len as u64)
+            .is_none()
+        {
+            false
+        } else if self.has_next() && self.next >= self.queue_size {
+            false
+        } else {
+            true
+        }
+    }
+
+    /// Gets if this descriptor chain has another descriptor chain linked after it.
+    pub fn has_next(&self) -> bool {
+        self.flags & VIRTQ_DESC_F_NEXT != 0 && self.ttl > 1
+    }
+
+    /// If the driver designated this as a write only descriptor.
+    ///
+    /// If this is false, this descriptor is read only.
+    /// Write only means the the emulated device can write and the driver can read.
+    pub fn is_write_only(&self) -> bool {
+        self.flags & VIRTQ_DESC_F_WRITE != 0
+    }
+
+    /// If the driver designated this as a read only descriptor.
+    ///
+    /// If this is false, this descriptor is write only.
+    /// Read only means the emulated device can read and the driver can write.
+    pub fn is_read_only(&self) -> bool {
+        self.flags & VIRTQ_DESC_F_WRITE == 0
+    }
+
+    /// Gets the next descriptor in this descriptor chain, if there is one.
+    ///
+    /// Note that this is distinct from the next descriptor chain returned by `AvailIter`, which is
+    /// the head of the next _available_ descriptor chain.
+    pub fn next_descriptor(&self) -> Option<DescriptorChain<'a>> {
+        if self.has_next() {
+            DescriptorChain::checked_new(self.mem, self.desc_table, self.queue_size, self.next).map(
+                |mut c| {
+                    c.ttl = self.ttl - 1;
+                    c
+                },
+            )
+        } else {
+            None
+        }
+    }
+
+    /// Produces an iterator over all the descriptors in this chain.
+    pub fn into_iter(self) -> DescIter<'a> {
+        DescIter { next: Some(self) }
+    }
+}
+
+/// Consuming iterator over all available descriptor chain heads in the queue.
+pub struct AvailIter<'a, 'b> {
+    mem: &'a GuestMemory,
+    queue: &'b mut Queue,
+}
+
+impl<'a, 'b> Iterator for AvailIter<'a, 'b> {
+    type Item = DescriptorChain<'a>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.queue.pop(self.mem)
+    }
+}
+
+#[derive(Clone)]
+/// A virtio queue's parameters.
+pub struct Queue {
+    /// The maximal size in elements offered by the device
+    pub max_size: u16,
+
+    /// The queue size in elements the driver selected
+    pub size: u16,
+
+    /// Inidcates if the queue is finished with configuration
+    pub ready: bool,
+
+    /// Guest physical address of the descriptor table
+    pub desc_table: GuestAddress,
+
+    /// Guest physical address of the available ring
+    pub avail_ring: GuestAddress,
+
+    /// Guest physical address of the used ring
+    pub used_ring: GuestAddress,
+
+    next_avail: Wrapping<u16>,
+    next_used: Wrapping<u16>,
+}
+
+impl Queue {
+    /// Constructs an empty virtio queue with the given `max_size`.
+    pub fn new(max_size: u16) -> Queue {
+        Queue {
+            max_size,
+            size: max_size,
+            ready: false,
+            desc_table: GuestAddress(0),
+            avail_ring: GuestAddress(0),
+            used_ring: GuestAddress(0),
+            next_avail: Wrapping(0),
+            next_used: Wrapping(0),
+        }
+    }
+
+    /// Return the actual size of the queue, as the driver may not set up a
+    /// queue as big as the device allows.
+    pub fn actual_size(&self) -> u16 {
+        min(self.size, self.max_size)
+    }
+
+    pub fn is_valid(&self, mem: &GuestMemory) -> bool {
+        let queue_size = self.actual_size() as usize;
+        let desc_table = self.desc_table;
+        let desc_table_size = 16 * queue_size;
+        let avail_ring = self.avail_ring;
+        let avail_ring_size = 6 + 2 * queue_size;
+        let used_ring = self.used_ring;
+        let used_ring_size = 6 + 8 * queue_size;
+        if !self.ready {
+            error!("attempt to use virtio queue that is not marked ready");
+            false
+        } else if self.size > self.max_size || self.size == 0 || (self.size & (self.size - 1)) != 0
+        {
+            error!("virtio queue with invalid size: {}", self.size);
+            false
+        } else if desc_table
+            .checked_add(desc_table_size as u64)
+            .map_or(true, |v| !mem.address_in_range(v))
+        {
+            error!(
+                "virtio queue descriptor table goes out of bounds: start:0x{:08x} size:0x{:08x}",
+                desc_table.offset(),
+                desc_table_size
+            );
+            false
+        } else if avail_ring
+            .checked_add(avail_ring_size as u64)
+            .map_or(true, |v| !mem.address_in_range(v))
+        {
+            error!(
+                "virtio queue available ring goes out of bounds: start:0x{:08x} size:0x{:08x}",
+                avail_ring.offset(),
+                avail_ring_size
+            );
+            false
+        } else if used_ring
+            .checked_add(used_ring_size as u64)
+            .map_or(true, |v| !mem.address_in_range(v))
+        {
+            error!(
+                "virtio queue used ring goes out of bounds: start:0x{:08x} size:0x{:08x}",
+                used_ring.offset(),
+                used_ring_size
+            );
+            false
+        } else {
+            true
+        }
+    }
+
+    /// If a new DescriptorHead is available, returns one and removes it from the queue.
+    pub fn pop<'a>(&mut self, mem: &'a GuestMemory) -> Option<DescriptorChain<'a>> {
+        if !self.is_valid(mem) {
+            return None;
+        }
+
+        let queue_size = self.actual_size();
+        let avail_index_addr = mem.checked_offset(self.avail_ring, 2).unwrap();
+        let avail_index: u16 = mem.read_obj_from_addr(avail_index_addr).unwrap();
+        let avail_len = Wrapping(avail_index) - self.next_avail;
+
+        if avail_len.0 > queue_size || self.next_avail == Wrapping(avail_index) {
+            return None;
+        }
+
+        let desc_idx_addr_offset = (4 + (self.next_avail.0 % queue_size) * 2) as u64;
+        let desc_idx_addr = mem.checked_offset(self.avail_ring, desc_idx_addr_offset)?;
+
+        // This index is checked below in checked_new.
+        let descriptor_index: u16 = mem.read_obj_from_addr(desc_idx_addr).unwrap();
+
+        let descriptor_chain =
+            DescriptorChain::checked_new(mem, self.desc_table, queue_size, descriptor_index);
+        if descriptor_chain.is_some() {
+            self.next_avail += Wrapping(1);
+        }
+        descriptor_chain
+    }
+
+    /// A consuming iterator over all available descriptor chain heads offered by the driver.
+    pub fn iter<'a, 'b>(&'b mut self, mem: &'a GuestMemory) -> AvailIter<'a, 'b> {
+        AvailIter { mem, queue: self }
+    }
+
+    /// Puts an available descriptor head into the used ring for use by the guest.
+    pub fn add_used(&mut self, mem: &GuestMemory, desc_index: u16, len: u32) {
+        if desc_index >= self.actual_size() {
+            error!(
+                "attempted to add out of bounds descriptor to used ring: {}",
+                desc_index
+            );
+            return;
+        }
+
+        let used_ring = self.used_ring;
+        let next_used = (self.next_used.0 % self.actual_size()) as usize;
+        let used_elem = used_ring.unchecked_add((4 + next_used * 8) as u64);
+
+        // These writes can't fail as we are guaranteed to be within the descriptor ring.
+        mem.write_obj_at_addr(desc_index as u32, used_elem).unwrap();
+        mem.write_obj_at_addr(len as u32, used_elem.unchecked_add(4))
+            .unwrap();
+
+        self.next_used += Wrapping(1);
+
+        // This fence ensures all descriptor writes are visible before the index update is.
+        fence(Ordering::Release);
+
+        mem.write_obj_at_addr(self.next_used.0 as u16, used_ring.unchecked_add(2))
+            .unwrap();
+    }
+}
diff --git a/devices/src/virtio/resource_bridge.rs b/devices/src/virtio/resource_bridge.rs
new file mode 100644
index 0000000..d3a3375
--- /dev/null
+++ b/devices/src/virtio/resource_bridge.rs
@@ -0,0 +1,30 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! This module defines the protocol between `virtio-wayland` and `virtio-gpu` for sharing resources
+//! that are backed by file descriptors.
+
+use std::fs::File;
+use std::io::Result;
+
+use msg_on_socket_derive::MsgOnSocket;
+use msg_socket::MsgSocket;
+
+#[derive(MsgOnSocket)]
+pub enum ResourceRequest {
+    GetResource { id: u32 },
+}
+
+#[derive(MsgOnSocket)]
+pub enum ResourceResponse {
+    Resource(File),
+    Invalid,
+}
+
+pub type ResourceRequestSocket = MsgSocket<ResourceRequest, ResourceResponse>;
+pub type ResourceResponseSocket = MsgSocket<ResourceResponse, ResourceRequest>;
+
+pub fn pair() -> Result<(ResourceRequestSocket, ResourceResponseSocket)> {
+    msg_socket::pair()
+}
diff --git a/devices/src/virtio/rng.rs b/devices/src/virtio/rng.rs
new file mode 100644
index 0000000..19f83bc
--- /dev/null
+++ b/devices/src/virtio/rng.rs
@@ -0,0 +1,229 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std;
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::io;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+use std::thread;
+
+use sys_util::{error, EventFd, GuestMemory, PollContext, PollToken};
+
+use super::{Queue, VirtioDevice, INTERRUPT_STATUS_USED_RING, TYPE_RNG};
+
+const QUEUE_SIZE: u16 = 256;
+const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE];
+
+#[derive(Debug)]
+pub enum RngError {
+    /// Can't access /dev/urandom
+    AccessingRandomDev(io::Error),
+}
+pub type Result<T> = std::result::Result<T, RngError>;
+
+impl Display for RngError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::RngError::*;
+
+        match self {
+            AccessingRandomDev(e) => write!(f, "failed to access /dev/urandom: {}", e),
+        }
+    }
+}
+
+struct Worker {
+    queue: Queue,
+    mem: GuestMemory,
+    random_file: File,
+    interrupt_status: Arc<AtomicUsize>,
+    interrupt_evt: EventFd,
+    interrupt_resample_evt: EventFd,
+}
+
+impl Worker {
+    fn process_queue(&mut self) -> bool {
+        let queue = &mut self.queue;
+
+        let mut needs_interrupt = false;
+        while let Some(avail_desc) = queue.pop(&self.mem) {
+            let mut len = 0;
+
+            // Drivers can only read from the random device.
+            if avail_desc.is_write_only() {
+                // Fill the read with data from the random device on the host.
+                if self
+                    .mem
+                    .read_to_memory(avail_desc.addr, &self.random_file, avail_desc.len as usize)
+                    .is_ok()
+                {
+                    len = avail_desc.len;
+                }
+            }
+
+            queue.add_used(&self.mem, avail_desc.index, len);
+            needs_interrupt = true;
+        }
+
+        needs_interrupt
+    }
+
+    fn signal_used_queue(&self) {
+        self.interrupt_status
+            .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
+        self.interrupt_evt.write(1).unwrap();
+    }
+
+    fn run(&mut self, queue_evt: EventFd, kill_evt: EventFd) {
+        #[derive(PollToken)]
+        enum Token {
+            QueueAvailable,
+            InterruptResample,
+            Kill,
+        }
+
+        let poll_ctx: PollContext<Token> = match PollContext::new()
+            .and_then(|pc| pc.add(&queue_evt, Token::QueueAvailable).and(Ok(pc)))
+            .and_then(|pc| {
+                pc.add(&self.interrupt_resample_evt, Token::InterruptResample)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc)))
+        {
+            Ok(pc) => pc,
+            Err(e) => {
+                error!("failed creating PollContext: {}", e);
+                return;
+            }
+        };
+
+        'poll: loop {
+            let events = match poll_ctx.wait() {
+                Ok(v) => v,
+                Err(e) => {
+                    error!("failed polling for events: {}", e);
+                    break;
+                }
+            };
+
+            let mut needs_interrupt = false;
+            for event in events.iter_readable() {
+                match event.token() {
+                    Token::QueueAvailable => {
+                        if let Err(e) = queue_evt.read() {
+                            error!("failed reading queue EventFd: {}", e);
+                            break 'poll;
+                        }
+                        needs_interrupt |= self.process_queue();
+                    }
+                    Token::InterruptResample => {
+                        let _ = self.interrupt_resample_evt.read();
+                        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
+                            self.interrupt_evt.write(1).unwrap();
+                        }
+                    }
+                    Token::Kill => break 'poll,
+                }
+            }
+            if needs_interrupt {
+                self.signal_used_queue();
+            }
+        }
+    }
+}
+
+/// Virtio device for exposing entropy to the guest OS through virtio.
+pub struct Rng {
+    kill_evt: Option<EventFd>,
+    random_file: Option<File>,
+}
+
+impl Rng {
+    /// Create a new virtio rng device that gets random data from /dev/urandom.
+    pub fn new() -> Result<Rng> {
+        let random_file = File::open("/dev/urandom").map_err(RngError::AccessingRandomDev)?;
+        Ok(Rng {
+            kill_evt: None,
+            random_file: Some(random_file),
+        })
+    }
+}
+
+impl Drop for Rng {
+    fn drop(&mut self) {
+        if let Some(kill_evt) = self.kill_evt.take() {
+            // Ignore the result because there is nothing we can do about it.
+            let _ = kill_evt.write(1);
+        }
+    }
+}
+
+impl VirtioDevice for Rng {
+    fn keep_fds(&self) -> Vec<RawFd> {
+        let mut keep_fds = Vec::new();
+
+        if let Some(random_file) = &self.random_file {
+            keep_fds.push(random_file.as_raw_fd());
+        }
+
+        keep_fds
+    }
+
+    fn device_type(&self) -> u32 {
+        TYPE_RNG
+    }
+
+    fn queue_max_sizes(&self) -> &[u16] {
+        QUEUE_SIZES
+    }
+
+    fn activate(
+        &mut self,
+        mem: GuestMemory,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        status: Arc<AtomicUsize>,
+        mut queues: Vec<Queue>,
+        mut queue_evts: Vec<EventFd>,
+    ) {
+        if queues.len() != 1 || queue_evts.len() != 1 {
+            return;
+        }
+
+        let (self_kill_evt, kill_evt) = match EventFd::new().and_then(|e| Ok((e.try_clone()?, e))) {
+            Ok(v) => v,
+            Err(e) => {
+                error!("failed to create kill EventFd pair: {}", e);
+                return;
+            }
+        };
+        self.kill_evt = Some(self_kill_evt);
+
+        let queue = queues.remove(0);
+
+        if let Some(random_file) = self.random_file.take() {
+            let worker_result =
+                thread::Builder::new()
+                    .name("virtio_rng".to_string())
+                    .spawn(move || {
+                        let mut worker = Worker {
+                            queue,
+                            mem,
+                            random_file,
+                            interrupt_status: status,
+                            interrupt_evt,
+                            interrupt_resample_evt,
+                        };
+                        worker.run(queue_evts.remove(0), kill_evt);
+                    });
+
+            if let Err(e) = worker_result {
+                error!("failed to spawn virtio_rng worker: {}", e);
+                return;
+            }
+        }
+    }
+}
diff --git a/devices/src/virtio/tpm.rs b/devices/src/virtio/tpm.rs
new file mode 100644
index 0000000..8715abe
--- /dev/null
+++ b/devices/src/virtio/tpm.rs
@@ -0,0 +1,338 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::env;
+use std::fmt::{self, Display};
+use std::fs;
+use std::ops::BitOrAssign;
+use std::os::unix::io::RawFd;
+use std::path::PathBuf;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+use std::thread;
+
+use sys_util::{error, EventFd, GuestMemory, GuestMemoryError, PollContext, PollToken};
+use tpm2;
+
+use super::{DescriptorChain, Queue, VirtioDevice, INTERRUPT_STATUS_USED_RING, TYPE_TPM};
+
+// A single queue of size 2. The guest kernel driver will enqueue a single
+// descriptor chain containing one command buffer and one response buffer at a
+// time.
+const QUEUE_SIZE: u16 = 2;
+const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE];
+
+// Maximum command or response message size permitted by this device
+// implementation. Named to match the equivalent constant in Linux's tpm.h.
+// There is no hard requirement that the value is the same but it makes sense.
+const TPM_BUFSIZE: usize = 4096;
+
+struct Worker {
+    queue: Queue,
+    mem: GuestMemory,
+    interrupt_status: Arc<AtomicUsize>,
+    queue_evt: EventFd,
+    kill_evt: EventFd,
+    interrupt_evt: EventFd,
+    interrupt_resample_evt: EventFd,
+    device: Device,
+}
+
+struct Device {
+    simulator: tpm2::Simulator,
+}
+
+// Checks that the input descriptor chain holds a read-only descriptor followed
+// by a write-only descriptor, as required of the guest's virtio tpm driver.
+//
+// Returns those descriptors as a tuple: `(read_desc, write_desc)`.
+fn two_input_descriptors(desc: DescriptorChain) -> Result<(DescriptorChain, DescriptorChain)> {
+    let read_desc = desc;
+    if !read_desc.is_read_only() {
+        return Err(Error::ExpectedReadOnly);
+    }
+
+    let write_desc = match read_desc.next_descriptor() {
+        Some(desc) => desc,
+        None => return Err(Error::ExpectedSecondBuffer),
+    };
+
+    if !write_desc.is_write_only() {
+        return Err(Error::ExpectedWriteOnly);
+    }
+
+    Ok((read_desc, write_desc))
+}
+
+impl Device {
+    fn perform_work(&mut self, mem: &GuestMemory, desc: DescriptorChain) -> Result<u32> {
+        let (read_desc, write_desc) = two_input_descriptors(desc)?;
+
+        if read_desc.len > TPM_BUFSIZE as u32 {
+            return Err(Error::CommandTooLong {
+                size: read_desc.len as usize,
+            });
+        }
+
+        let mut command = vec![0u8; read_desc.len as usize];
+        mem.read_exact_at_addr(&mut command, read_desc.addr)
+            .map_err(Error::Read)?;
+
+        let response = self.simulator.execute_command(&command);
+
+        if response.len() > TPM_BUFSIZE {
+            return Err(Error::ResponseTooLong {
+                size: response.len(),
+            });
+        }
+
+        if response.len() > write_desc.len as usize {
+            return Err(Error::BufferTooSmall {
+                size: write_desc.len as usize,
+                required: response.len(),
+            });
+        }
+
+        mem.write_all_at_addr(&response, write_desc.addr)
+            .map_err(Error::Write)?;
+
+        Ok(response.len() as u32)
+    }
+}
+
+impl Worker {
+    fn process_queue(&mut self) -> NeedsInterrupt {
+        let avail_desc = match self.queue.pop(&self.mem) {
+            Some(avail_desc) => avail_desc,
+            None => return NeedsInterrupt::No,
+        };
+
+        let index = avail_desc.index;
+
+        let len = match self.device.perform_work(&self.mem, avail_desc) {
+            Ok(len) => len,
+            Err(err) => {
+                error!("{}", err);
+                0
+            }
+        };
+
+        self.queue.add_used(&self.mem, index, len);
+        NeedsInterrupt::Yes
+    }
+
+    fn signal_used_queue(&self) {
+        self.interrupt_status
+            .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
+        let _ = self.interrupt_evt.write(1);
+    }
+
+    fn run(mut self) {
+        #[derive(PollToken, Debug)]
+        enum Token {
+            // A request is ready on the queue.
+            QueueAvailable,
+            // Check if any interrupts need to be re-asserted.
+            InterruptResample,
+            // The parent thread requested an exit.
+            Kill,
+        }
+
+        let poll_ctx = match PollContext::new()
+            .and_then(|pc| pc.add(&self.queue_evt, Token::QueueAvailable).and(Ok(pc)))
+            .and_then(|pc| {
+                pc.add(&self.interrupt_resample_evt, Token::InterruptResample)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| pc.add(&self.kill_evt, Token::Kill).and(Ok(pc)))
+        {
+            Ok(pc) => pc,
+            Err(e) => {
+                error!("vtpm failed creating PollContext: {}", e);
+                return;
+            }
+        };
+
+        'poll: loop {
+            let events = match poll_ctx.wait() {
+                Ok(v) => v,
+                Err(e) => {
+                    error!("vtpm failed polling for events: {}", e);
+                    break;
+                }
+            };
+
+            let mut needs_interrupt = NeedsInterrupt::No;
+            for event in events.iter_readable() {
+                match event.token() {
+                    Token::QueueAvailable => {
+                        if let Err(e) = self.queue_evt.read() {
+                            error!("vtpm failed reading queue EventFd: {}", e);
+                            break 'poll;
+                        }
+                        needs_interrupt |= self.process_queue();
+                    }
+                    Token::InterruptResample => {
+                        let _ = self.interrupt_resample_evt.read();
+                        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
+                            let _ = self.interrupt_evt.write(1);
+                        }
+                    }
+                    Token::Kill => break 'poll,
+                }
+            }
+            if needs_interrupt == NeedsInterrupt::Yes {
+                self.signal_used_queue();
+            }
+        }
+    }
+}
+
+/// Virtio vTPM device.
+pub struct Tpm {
+    storage: PathBuf,
+    kill_evt: Option<EventFd>,
+}
+
+impl Tpm {
+    pub fn new(storage: PathBuf) -> Tpm {
+        Tpm {
+            storage,
+            kill_evt: None,
+        }
+    }
+}
+
+impl Drop for Tpm {
+    fn drop(&mut self) {
+        if let Some(kill_evt) = self.kill_evt.take() {
+            let _ = kill_evt.write(1);
+        }
+    }
+}
+
+impl VirtioDevice for Tpm {
+    fn keep_fds(&self) -> Vec<RawFd> {
+        Vec::new()
+    }
+
+    fn device_type(&self) -> u32 {
+        TYPE_TPM
+    }
+
+    fn queue_max_sizes(&self) -> &[u16] {
+        QUEUE_SIZES
+    }
+
+    fn activate(
+        &mut self,
+        mem: GuestMemory,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        interrupt_status: Arc<AtomicUsize>,
+        mut queues: Vec<Queue>,
+        mut queue_evts: Vec<EventFd>,
+    ) {
+        if queues.len() != 1 || queue_evts.len() != 1 {
+            return;
+        }
+        let queue = queues.remove(0);
+        let queue_evt = queue_evts.remove(0);
+
+        if let Err(err) = fs::create_dir_all(&self.storage) {
+            error!("vtpm failed to create directory for simulator: {}", err);
+            return;
+        }
+        if let Err(err) = env::set_current_dir(&self.storage) {
+            error!("vtpm failed to change into simulator directory: {}", err);
+            return;
+        }
+        let simulator = tpm2::Simulator::singleton_in_current_directory();
+
+        let (self_kill_evt, kill_evt) = match EventFd::new().and_then(|e| Ok((e.try_clone()?, e))) {
+            Ok(v) => v,
+            Err(err) => {
+                error!("vtpm failed to create kill EventFd pair: {}", err);
+                return;
+            }
+        };
+        self.kill_evt = Some(self_kill_evt);
+
+        let worker = Worker {
+            queue,
+            mem,
+            interrupt_status,
+            queue_evt,
+            interrupt_evt,
+            interrupt_resample_evt,
+            kill_evt,
+            device: Device { simulator },
+        };
+
+        let worker_result = thread::Builder::new()
+            .name("virtio_tpm".to_string())
+            .spawn(|| worker.run());
+
+        if let Err(e) = worker_result {
+            error!("vtpm failed to spawn virtio_tpm worker: {}", e);
+            return;
+        }
+    }
+}
+
+#[derive(PartialEq)]
+enum NeedsInterrupt {
+    Yes,
+    No,
+}
+
+impl BitOrAssign for NeedsInterrupt {
+    fn bitor_assign(&mut self, rhs: NeedsInterrupt) {
+        if rhs == NeedsInterrupt::Yes {
+            *self = NeedsInterrupt::Yes;
+        }
+    }
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+enum Error {
+    ExpectedReadOnly,
+    ExpectedSecondBuffer,
+    ExpectedWriteOnly,
+    CommandTooLong { size: usize },
+    Read(GuestMemoryError),
+    ResponseTooLong { size: usize },
+    BufferTooSmall { size: usize, required: usize },
+    Write(GuestMemoryError),
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            ExpectedReadOnly => write!(f, "vtpm expected first descriptor to be read-only"),
+            ExpectedSecondBuffer => write!(f, "vtpm expected a second descriptor"),
+            ExpectedWriteOnly => write!(f, "vtpm expected second descriptor to be write-only"),
+            CommandTooLong { size } => write!(
+                f,
+                "vtpm command is too long: {} > {} bytes",
+                size, TPM_BUFSIZE
+            ),
+            Read(e) => write!(f, "vtpm failed to read from guest memory: {}", e),
+            ResponseTooLong { size } => write!(
+                f,
+                "vtpm simulator generated a response that is unexpectedly long: {} > {} bytes",
+                size, TPM_BUFSIZE
+            ),
+            BufferTooSmall { size, required } => write!(
+                f,
+                "vtpm response buffer is too small: {} < {} bytes",
+                size, required
+            ),
+            Write(e) => write!(f, "vtpm failed to write to guest memory: {}", e),
+        }
+    }
+}
diff --git a/devices/src/virtio/vhost/mod.rs b/devices/src/virtio/vhost/mod.rs
new file mode 100644
index 0000000..66c62d0
--- /dev/null
+++ b/devices/src/virtio/vhost/mod.rs
@@ -0,0 +1,116 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Implements vhost-based virtio devices.
+
+use std;
+use std::fmt::{self, Display};
+
+use net_util::Error as TapError;
+use remain::sorted;
+use sys_util::Error as SysError;
+use vhost::Error as VhostError;
+
+mod net;
+mod vsock;
+mod worker;
+
+pub use self::net::Net;
+pub use self::vsock::Vsock;
+
+#[sorted]
+#[derive(Debug)]
+pub enum Error {
+    /// Cloning kill eventfd failed.
+    CloneKillEventFd(SysError),
+    /// Creating kill eventfd failed.
+    CreateKillEventFd(SysError),
+    /// Creating poll context failed.
+    CreatePollContext(SysError),
+    /// Error while polling for events.
+    PollError(SysError),
+    /// Enabling tap interface failed.
+    TapEnable(TapError),
+    /// Open tap device failed.
+    TapOpen(TapError),
+    /// Setting tap IP failed.
+    TapSetIp(TapError),
+    /// Setting tap mac address failed.
+    TapSetMacAddress(TapError),
+    /// Setting tap netmask failed.
+    TapSetNetmask(TapError),
+    /// Setting tap interface offload flags failed.
+    TapSetOffload(TapError),
+    /// Setting vnet header size failed.
+    TapSetVnetHdrSize(TapError),
+    /// Get features failed.
+    VhostGetFeatures(VhostError),
+    /// Failed to create vhost eventfd.
+    VhostIrqCreate(SysError),
+    /// Failed to read vhost eventfd.
+    VhostIrqRead(SysError),
+    /// Net set backend failed.
+    VhostNetSetBackend(VhostError),
+    /// Failed to open vhost device.
+    VhostOpen(VhostError),
+    /// Set features failed.
+    VhostSetFeatures(VhostError),
+    /// Set mem table failed.
+    VhostSetMemTable(VhostError),
+    /// Set owner failed.
+    VhostSetOwner(VhostError),
+    /// Set vring addr failed.
+    VhostSetVringAddr(VhostError),
+    /// Set vring base failed.
+    VhostSetVringBase(VhostError),
+    /// Set vring call failed.
+    VhostSetVringCall(VhostError),
+    /// Set vring kick failed.
+    VhostSetVringKick(VhostError),
+    /// Set vring num failed.
+    VhostSetVringNum(VhostError),
+    /// Failed to set CID for guest.
+    VhostVsockSetCid(VhostError),
+    /// Failed to start vhost-vsock driver.
+    VhostVsockStart(VhostError),
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    #[remain::check]
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        #[sorted]
+        match self {
+            CloneKillEventFd(e) => write!(f, "failed to clone kill eventfd: {}", e),
+            CreateKillEventFd(e) => write!(f, "failed to create kill eventfd: {}", e),
+            CreatePollContext(e) => write!(f, "failed to create poll context: {}", e),
+            PollError(e) => write!(f, "failed polling for events: {}", e),
+            TapEnable(e) => write!(f, "failed to enable tap interface: {}", e),
+            TapOpen(e) => write!(f, "failed to open tap device: {}", e),
+            TapSetIp(e) => write!(f, "failed to set tap IP: {}", e),
+            TapSetMacAddress(e) => write!(f, "failed to set tap mac address: {}", e),
+            TapSetNetmask(e) => write!(f, "failed to set tap netmask: {}", e),
+            TapSetOffload(e) => write!(f, "failed to set tap interface offload flags: {}", e),
+            TapSetVnetHdrSize(e) => write!(f, "failed to set vnet header size: {}", e),
+            VhostGetFeatures(e) => write!(f, "failed to get features: {}", e),
+            VhostIrqCreate(e) => write!(f, "failed to create vhost eventfd: {}", e),
+            VhostIrqRead(e) => write!(f, "failed to read vhost eventfd: {}", e),
+            VhostNetSetBackend(e) => write!(f, "net set backend failed: {}", e),
+            VhostOpen(e) => write!(f, "failed to open vhost device: {}", e),
+            VhostSetFeatures(e) => write!(f, "failed to set features: {}", e),
+            VhostSetMemTable(e) => write!(f, "failed to set mem table: {}", e),
+            VhostSetOwner(e) => write!(f, "failed to set owner: {}", e),
+            VhostSetVringAddr(e) => write!(f, "failed to set vring addr: {}", e),
+            VhostSetVringBase(e) => write!(f, "failed to set vring base: {}", e),
+            VhostSetVringCall(e) => write!(f, "failed to set vring call: {}", e),
+            VhostSetVringKick(e) => write!(f, "failed to set vring kick: {}", e),
+            VhostSetVringNum(e) => write!(f, "failed to set vring num: {}", e),
+            VhostVsockSetCid(e) => write!(f, "failed to set CID for guest: {}", e),
+            VhostVsockStart(e) => write!(f, "failed to start vhost-vsock driver: {}", e),
+        }
+    }
+}
diff --git a/devices/src/virtio/vhost/net.rs b/devices/src/virtio/vhost/net.rs
new file mode 100644
index 0000000..a7eaf18
--- /dev/null
+++ b/devices/src/virtio/vhost/net.rs
@@ -0,0 +1,285 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::mem;
+use std::net::Ipv4Addr;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::sync::atomic::AtomicUsize;
+use std::sync::Arc;
+use std::thread;
+
+use net_sys;
+use net_util::{MacAddress, TapT};
+
+use ::vhost::NetT as VhostNetT;
+use sys_util::{error, warn, EventFd, GuestMemory};
+use virtio_sys::{vhost, virtio_net};
+
+use super::worker::Worker;
+use super::{Error, Result};
+use crate::virtio::{Queue, VirtioDevice, TYPE_NET};
+
+const QUEUE_SIZE: u16 = 256;
+const NUM_QUEUES: usize = 2;
+const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE; NUM_QUEUES];
+
+pub struct Net<T: TapT, U: VhostNetT<T>> {
+    workers_kill_evt: Option<EventFd>,
+    kill_evt: EventFd,
+    tap: Option<T>,
+    vhost_net_handle: Option<U>,
+    vhost_interrupt: Option<EventFd>,
+    avail_features: u64,
+    acked_features: u64,
+}
+
+impl<T, U> Net<T, U>
+where
+    T: TapT,
+    U: VhostNetT<T>,
+{
+    /// Create a new virtio network device with the given IP address and
+    /// netmask.
+    pub fn new(
+        ip_addr: Ipv4Addr,
+        netmask: Ipv4Addr,
+        mac_addr: MacAddress,
+        mem: &GuestMemory,
+    ) -> Result<Net<T, U>> {
+        let kill_evt = EventFd::new().map_err(Error::CreateKillEventFd)?;
+
+        let tap: T = T::new(true).map_err(Error::TapOpen)?;
+        tap.set_ip_addr(ip_addr).map_err(Error::TapSetIp)?;
+        tap.set_netmask(netmask).map_err(Error::TapSetNetmask)?;
+        tap.set_mac_address(mac_addr)
+            .map_err(Error::TapSetMacAddress)?;
+
+        // Set offload flags to match the virtio features below.
+        tap.set_offload(
+            net_sys::TUN_F_CSUM | net_sys::TUN_F_UFO | net_sys::TUN_F_TSO4 | net_sys::TUN_F_TSO6,
+        )
+        .map_err(Error::TapSetOffload)?;
+
+        // We declare VIRTIO_NET_F_MRG_RXBUF, so set the vnet hdr size to match.
+        let vnet_hdr_size = mem::size_of::<virtio_net::virtio_net_hdr_mrg_rxbuf>() as i32;
+        tap.set_vnet_hdr_size(vnet_hdr_size)
+            .map_err(Error::TapSetVnetHdrSize)?;
+
+        tap.enable().map_err(Error::TapEnable)?;
+        let vhost_net_handle = U::new(mem).map_err(Error::VhostOpen)?;
+
+        let avail_features = 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
+            | 1 << virtio_net::VIRTIO_NET_F_CSUM
+            | 1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4
+            | 1 << virtio_net::VIRTIO_NET_F_GUEST_UFO
+            | 1 << virtio_net::VIRTIO_NET_F_HOST_TSO4
+            | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO
+            | 1 << virtio_net::VIRTIO_NET_F_MRG_RXBUF
+            | 1 << vhost::VIRTIO_RING_F_INDIRECT_DESC
+            | 1 << vhost::VIRTIO_RING_F_EVENT_IDX
+            | 1 << vhost::VIRTIO_F_NOTIFY_ON_EMPTY
+            | 1 << vhost::VIRTIO_F_VERSION_1;
+
+        Ok(Net {
+            workers_kill_evt: Some(kill_evt.try_clone().map_err(Error::CloneKillEventFd)?),
+            kill_evt,
+            tap: Some(tap),
+            vhost_net_handle: Some(vhost_net_handle),
+            vhost_interrupt: Some(EventFd::new().map_err(Error::VhostIrqCreate)?),
+            avail_features,
+            acked_features: 0u64,
+        })
+    }
+}
+
+impl<T, U> Drop for Net<T, U>
+where
+    T: TapT,
+    U: VhostNetT<T>,
+{
+    fn drop(&mut self) {
+        // Only kill the child if it claimed its eventfd.
+        if self.workers_kill_evt.is_none() {
+            // Ignore the result because there is nothing we can do about it.
+            let _ = self.kill_evt.write(1);
+        }
+    }
+}
+
+impl<T, U> VirtioDevice for Net<T, U>
+where
+    T: TapT + 'static,
+    U: VhostNetT<T> + 'static,
+{
+    fn keep_fds(&self) -> Vec<RawFd> {
+        let mut keep_fds = Vec::new();
+
+        if let Some(tap) = &self.tap {
+            keep_fds.push(tap.as_raw_fd());
+        }
+
+        if let Some(vhost_net_handle) = &self.vhost_net_handle {
+            keep_fds.push(vhost_net_handle.as_raw_fd());
+        }
+
+        if let Some(vhost_interrupt) = &self.vhost_interrupt {
+            keep_fds.push(vhost_interrupt.as_raw_fd());
+        }
+
+        if let Some(workers_kill_evt) = &self.workers_kill_evt {
+            keep_fds.push(workers_kill_evt.as_raw_fd());
+        }
+
+        keep_fds
+    }
+
+    fn device_type(&self) -> u32 {
+        TYPE_NET
+    }
+
+    fn queue_max_sizes(&self) -> &[u16] {
+        QUEUE_SIZES
+    }
+
+    fn features(&self) -> u64 {
+        self.avail_features
+    }
+
+    fn ack_features(&mut self, value: u64) {
+        let mut v = value;
+
+        // Check if the guest is ACK'ing a feature that we didn't claim to have.
+        let unrequested_features = v & !self.avail_features;
+        if unrequested_features != 0 {
+            warn!("net: virtio net got unknown feature ack: {:x}", v);
+
+            // Don't count these features as acked.
+            v &= !unrequested_features;
+        }
+        self.acked_features |= v;
+    }
+
+    fn activate(
+        &mut self,
+        _: GuestMemory,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        status: Arc<AtomicUsize>,
+        queues: Vec<Queue>,
+        queue_evts: Vec<EventFd>,
+    ) {
+        if queues.len() != NUM_QUEUES || queue_evts.len() != NUM_QUEUES {
+            error!("net: expected {} queues, got {}", NUM_QUEUES, queues.len());
+            return;
+        }
+
+        if let Some(vhost_net_handle) = self.vhost_net_handle.take() {
+            if let Some(tap) = self.tap.take() {
+                if let Some(vhost_interrupt) = self.vhost_interrupt.take() {
+                    if let Some(kill_evt) = self.workers_kill_evt.take() {
+                        let acked_features = self.acked_features;
+                        let worker_result = thread::Builder::new()
+                            .name("vhost_net".to_string())
+                            .spawn(move || {
+                                let mut worker = Worker::new(
+                                    queues,
+                                    vhost_net_handle,
+                                    vhost_interrupt,
+                                    status,
+                                    interrupt_evt,
+                                    interrupt_resample_evt,
+                                    acked_features,
+                                );
+                                let activate_vqs = |handle: &U| -> Result<()> {
+                                    for idx in 0..NUM_QUEUES {
+                                        handle
+                                            .set_backend(idx, &tap)
+                                            .map_err(Error::VhostNetSetBackend)?;
+                                    }
+                                    Ok(())
+                                };
+                                let result =
+                                    worker.run(queue_evts, QUEUE_SIZES, kill_evt, activate_vqs);
+                                if let Err(e) = result {
+                                    error!("net worker thread exited with error: {}", e);
+                                }
+                            });
+
+                        if let Err(e) = worker_result {
+                            error!("failed to spawn vhost_net worker: {}", e);
+                            return;
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+pub mod tests {
+    use super::*;
+    use ::vhost::net::fakes::FakeNet;
+    use net_util::fakes::FakeTap;
+    use std::result;
+    use sys_util::{GuestAddress, GuestMemory, GuestMemoryError};
+
+    fn create_guest_memory() -> result::Result<GuestMemory, GuestMemoryError> {
+        let start_addr1 = GuestAddress(0x0);
+        let start_addr2 = GuestAddress(0x1000);
+        GuestMemory::new(&vec![(start_addr1, 0x1000), (start_addr2, 0x4000)])
+    }
+
+    fn create_net_common() -> Net<FakeTap, FakeNet<FakeTap>> {
+        let guest_memory = create_guest_memory().unwrap();
+        Net::<FakeTap, FakeNet<FakeTap>>::new(
+            Ipv4Addr::new(127, 0, 0, 1),
+            Ipv4Addr::new(255, 255, 255, 0),
+            "de:21:e8:47:6b:6a".parse().unwrap(),
+            &guest_memory,
+        )
+        .unwrap()
+    }
+
+    #[test]
+    fn create_net() {
+        create_net_common();
+    }
+
+    #[test]
+    fn keep_fds() {
+        let net = create_net_common();
+        let fds = net.keep_fds();
+        assert!(fds.len() >= 1, "We should have gotten at least one fd");
+    }
+
+    #[test]
+    fn features() {
+        let net = create_net_common();
+        assert_eq!(net.features(), 5117103235);
+    }
+
+    #[test]
+    fn ack_features() {
+        let mut net = create_net_common();
+        // Just testing that we don't panic, for now
+        net.ack_features(1);
+        net.ack_features(1 << 32);
+    }
+
+    #[test]
+    fn activate() {
+        let mut net = create_net_common();
+        let guest_memory = create_guest_memory().unwrap();
+        // Just testing that we don't panic, for now
+        net.activate(
+            guest_memory,
+            EventFd::new().unwrap(),
+            EventFd::new().unwrap(),
+            Arc::new(AtomicUsize::new(0)),
+            vec![Queue::new(1)],
+            vec![EventFd::new().unwrap()],
+        );
+    }
+}
diff --git a/devices/src/virtio/vhost/vsock.rs b/devices/src/virtio/vhost/vsock.rs
new file mode 100644
index 0000000..d07b639
--- /dev/null
+++ b/devices/src/virtio/vhost/vsock.rs
@@ -0,0 +1,273 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::sync::atomic::AtomicUsize;
+use std::sync::Arc;
+use std::thread;
+
+use byteorder::{ByteOrder, LittleEndian};
+
+use ::vhost::Vsock as VhostVsockHandle;
+use sys_util::{error, warn, EventFd, GuestMemory};
+use virtio_sys::vhost;
+
+use super::worker::Worker;
+use super::{Error, Result};
+use crate::virtio::{Queue, VirtioDevice, TYPE_VSOCK};
+
+const QUEUE_SIZE: u16 = 256;
+const NUM_QUEUES: usize = 3;
+const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE; NUM_QUEUES];
+
+pub struct Vsock {
+    worker_kill_evt: Option<EventFd>,
+    kill_evt: Option<EventFd>,
+    vhost_handle: Option<VhostVsockHandle>,
+    cid: u64,
+    interrupt: Option<EventFd>,
+    avail_features: u64,
+    acked_features: u64,
+}
+
+impl Vsock {
+    /// Create a new virtio-vsock device with the given VM cid.
+    pub fn new(cid: u64, mem: &GuestMemory) -> Result<Vsock> {
+        let kill_evt = EventFd::new().map_err(Error::CreateKillEventFd)?;
+        let handle = VhostVsockHandle::new(mem).map_err(Error::VhostOpen)?;
+
+        let avail_features = 1 << vhost::VIRTIO_F_NOTIFY_ON_EMPTY
+            | 1 << vhost::VIRTIO_RING_F_INDIRECT_DESC
+            | 1 << vhost::VIRTIO_RING_F_EVENT_IDX
+            | 1 << vhost::VHOST_F_LOG_ALL
+            | 1 << vhost::VIRTIO_F_ANY_LAYOUT
+            | 1 << vhost::VIRTIO_F_VERSION_1;
+
+        Ok(Vsock {
+            worker_kill_evt: Some(kill_evt.try_clone().map_err(Error::CloneKillEventFd)?),
+            kill_evt: Some(kill_evt),
+            vhost_handle: Some(handle),
+            cid,
+            interrupt: Some(EventFd::new().map_err(Error::VhostIrqCreate)?),
+            avail_features,
+            acked_features: 0,
+        })
+    }
+
+    pub fn new_for_testing(cid: u64, features: u64) -> Vsock {
+        Vsock {
+            worker_kill_evt: None,
+            kill_evt: None,
+            vhost_handle: None,
+            cid,
+            interrupt: None,
+            avail_features: features,
+            acked_features: 0,
+        }
+    }
+
+    pub fn acked_features(&self) -> u64 {
+        self.acked_features
+    }
+}
+
+impl Drop for Vsock {
+    fn drop(&mut self) {
+        // Only kill the child if it claimed its eventfd.
+        if self.worker_kill_evt.is_none() {
+            if let Some(kill_evt) = &self.kill_evt {
+                // Ignore the result because there is nothing we can do about it.
+                let _ = kill_evt.write(1);
+            }
+        }
+    }
+}
+
+impl VirtioDevice for Vsock {
+    fn keep_fds(&self) -> Vec<RawFd> {
+        let mut keep_fds = Vec::new();
+
+        if let Some(handle) = &self.vhost_handle {
+            keep_fds.push(handle.as_raw_fd());
+        }
+
+        if let Some(interrupt) = &self.interrupt {
+            keep_fds.push(interrupt.as_raw_fd());
+        }
+
+        if let Some(worker_kill_evt) = &self.worker_kill_evt {
+            keep_fds.push(worker_kill_evt.as_raw_fd());
+        }
+
+        keep_fds
+    }
+
+    fn device_type(&self) -> u32 {
+        TYPE_VSOCK
+    }
+
+    fn queue_max_sizes(&self) -> &[u16] {
+        QUEUE_SIZES
+    }
+
+    fn features(&self) -> u64 {
+        self.avail_features
+    }
+
+    fn read_config(&self, offset: u64, data: &mut [u8]) {
+        match offset {
+            0 if data.len() == 8 => LittleEndian::write_u64(data, self.cid),
+            0 if data.len() == 4 => LittleEndian::write_u32(data, (self.cid & 0xffffffff) as u32),
+            4 if data.len() == 4 => {
+                LittleEndian::write_u32(data, ((self.cid >> 32) & 0xffffffff) as u32)
+            }
+            _ => warn!(
+                "vsock: virtio-vsock received invalid read request of {} bytes at offset {}",
+                data.len(),
+                offset
+            ),
+        }
+    }
+
+    fn ack_features(&mut self, value: u64) {
+        let mut v = value;
+
+        // Check if the guest is ACK'ing a feature that we didn't claim to have.
+        let unrequested_features = v & !self.avail_features;
+        if unrequested_features != 0 {
+            warn!("vsock: virtio-vsock got unknown feature ack: {:x}", v);
+
+            // Don't count these features as acked.
+            v &= !unrequested_features;
+        }
+        self.acked_features |= v;
+    }
+
+    fn activate(
+        &mut self,
+        _: GuestMemory,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        status: Arc<AtomicUsize>,
+        queues: Vec<Queue>,
+        queue_evts: Vec<EventFd>,
+    ) {
+        if queues.len() != NUM_QUEUES || queue_evts.len() != NUM_QUEUES {
+            error!("net: expected {} queues, got {}", NUM_QUEUES, queues.len());
+            return;
+        }
+
+        if let Some(vhost_handle) = self.vhost_handle.take() {
+            if let Some(interrupt) = self.interrupt.take() {
+                if let Some(kill_evt) = self.worker_kill_evt.take() {
+                    let acked_features = self.acked_features;
+                    let cid = self.cid;
+                    let worker_result = thread::Builder::new()
+                        .name("vhost_vsock".to_string())
+                        .spawn(move || {
+                            // The third vq is an event-only vq that is not handled by the vhost
+                            // subsystem (but still needs to exist).  Split it off here.
+                            let vhost_queues = queues[..2].to_vec();
+                            let mut worker = Worker::new(
+                                vhost_queues,
+                                vhost_handle,
+                                interrupt,
+                                status,
+                                interrupt_evt,
+                                interrupt_resample_evt,
+                                acked_features,
+                            );
+                            let activate_vqs = |handle: &VhostVsockHandle| -> Result<()> {
+                                handle.set_cid(cid).map_err(Error::VhostVsockSetCid)?;
+                                handle.start().map_err(Error::VhostVsockStart)?;
+                                Ok(())
+                            };
+                            let result =
+                                worker.run(queue_evts, QUEUE_SIZES, kill_evt, activate_vqs);
+                            if let Err(e) = result {
+                                error!("vsock worker thread exited with error: {:?}", e);
+                            }
+                        });
+
+                    if let Err(e) = worker_result {
+                        error!("failed to spawn vhost_vsock worker: {}", e);
+                        return;
+                    }
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use byteorder::{ByteOrder, LittleEndian};
+    #[test]
+    fn ack_features() {
+        let cid = 5;
+        let features: u64 = (1 << 20) | (1 << 49) | (1 << 2) | (1 << 19);
+        let mut acked_features: u64 = 0;
+        let mut unavailable_features: u64 = 0;
+
+        let mut vsock = Vsock::new_for_testing(cid, features);
+        assert_eq!(acked_features, vsock.acked_features());
+
+        acked_features |= 1 << 2;
+        vsock.ack_features(acked_features);
+        assert_eq!(acked_features, vsock.acked_features());
+
+        acked_features |= 1 << 49;
+        vsock.ack_features(acked_features);
+        assert_eq!(acked_features, vsock.acked_features());
+
+        acked_features |= 1 << 60;
+        unavailable_features |= 1 << 60;
+        vsock.ack_features(acked_features);
+        assert_eq!(
+            acked_features & !unavailable_features,
+            vsock.acked_features()
+        );
+
+        acked_features |= 1 << 1;
+        unavailable_features |= 1 << 1;
+        vsock.ack_features(acked_features);
+        assert_eq!(
+            acked_features & !unavailable_features,
+            vsock.acked_features()
+        );
+    }
+
+    #[test]
+    fn read_config() {
+        let cid = 0xfca9a559fdcb9756;
+        let vsock = Vsock::new_for_testing(cid, 0);
+
+        let mut buf = [0 as u8; 8];
+        vsock.read_config(0, &mut buf);
+        assert_eq!(cid, LittleEndian::read_u64(&buf));
+
+        vsock.read_config(0, &mut buf[..4]);
+        assert_eq!((cid & 0xffffffff) as u32, LittleEndian::read_u32(&buf[..4]));
+
+        vsock.read_config(4, &mut buf[..4]);
+        assert_eq!((cid >> 32) as u32, LittleEndian::read_u32(&buf[..4]));
+
+        let data: [u8; 8] = [8, 226, 5, 46, 159, 59, 89, 77];
+        buf.copy_from_slice(&data);
+
+        vsock.read_config(12, &mut buf);
+        assert_eq!(&buf, &data);
+    }
+
+    #[test]
+    fn features() {
+        let cid = 5;
+        let features: u64 = 0xfc195ae8db88cff9;
+
+        let vsock = Vsock::new_for_testing(cid, features);
+        assert_eq!(features, vsock.features());
+    }
+}
diff --git a/devices/src/virtio/vhost/worker.rs b/devices/src/virtio/vhost/worker.rs
new file mode 100644
index 0000000..9389f82
--- /dev/null
+++ b/devices/src/virtio/vhost/worker.rs
@@ -0,0 +1,156 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::os::raw::c_ulonglong;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+
+use sys_util::{EventFd, PollContext, PollToken};
+use vhost::Vhost;
+
+use super::{Error, Result};
+use crate::virtio::{Queue, INTERRUPT_STATUS_USED_RING};
+
+/// Worker that takes care of running the vhost device.  This mainly involves forwarding interrupts
+/// from the vhost driver to the guest VM because crosvm only supports the virtio-mmio transport,
+/// which requires a bit to be set in the interrupt status register before triggering the interrupt
+/// and the vhost driver doesn't do this for us.
+pub struct Worker<T: Vhost> {
+    queues: Vec<Queue>,
+    vhost_handle: T,
+    vhost_interrupt: EventFd,
+    interrupt_status: Arc<AtomicUsize>,
+    interrupt_evt: EventFd,
+    interrupt_resample_evt: EventFd,
+    acked_features: u64,
+}
+
+impl<T: Vhost> Worker<T> {
+    pub fn new(
+        queues: Vec<Queue>,
+        vhost_handle: T,
+        vhost_interrupt: EventFd,
+        interrupt_status: Arc<AtomicUsize>,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        acked_features: u64,
+    ) -> Worker<T> {
+        Worker {
+            queues,
+            vhost_handle,
+            vhost_interrupt,
+            interrupt_status,
+            interrupt_evt,
+            interrupt_resample_evt,
+            acked_features,
+        }
+    }
+
+    fn signal_used_queue(&self) {
+        self.interrupt_status
+            .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
+        self.interrupt_evt.write(1).unwrap();
+    }
+
+    pub fn run<F>(
+        &mut self,
+        queue_evts: Vec<EventFd>,
+        queue_sizes: &[u16],
+        kill_evt: EventFd,
+        activate_vqs: F,
+    ) -> Result<()>
+    where
+        F: FnOnce(&T) -> Result<()>,
+    {
+        // Preliminary setup for vhost net.
+        self.vhost_handle
+            .set_owner()
+            .map_err(Error::VhostSetOwner)?;
+
+        let avail_features = self
+            .vhost_handle
+            .get_features()
+            .map_err(Error::VhostGetFeatures)?;
+
+        let features: c_ulonglong = self.acked_features & avail_features;
+        self.vhost_handle
+            .set_features(features)
+            .map_err(Error::VhostSetFeatures)?;
+
+        self.vhost_handle
+            .set_mem_table()
+            .map_err(Error::VhostSetMemTable)?;
+
+        for (queue_index, queue) in self.queues.iter().enumerate() {
+            self.vhost_handle
+                .set_vring_num(queue_index, queue.max_size)
+                .map_err(Error::VhostSetVringNum)?;
+
+            self.vhost_handle
+                .set_vring_addr(
+                    queue_sizes[queue_index],
+                    queue.actual_size(),
+                    queue_index,
+                    0,
+                    queue.desc_table,
+                    queue.used_ring,
+                    queue.avail_ring,
+                    None,
+                )
+                .map_err(Error::VhostSetVringAddr)?;
+            self.vhost_handle
+                .set_vring_base(queue_index, 0)
+                .map_err(Error::VhostSetVringBase)?;
+            self.vhost_handle
+                .set_vring_call(queue_index, &self.vhost_interrupt)
+                .map_err(Error::VhostSetVringCall)?;
+            self.vhost_handle
+                .set_vring_kick(queue_index, &queue_evts[queue_index])
+                .map_err(Error::VhostSetVringKick)?;
+        }
+
+        activate_vqs(&self.vhost_handle)?;
+
+        #[derive(PollToken)]
+        enum Token {
+            VhostIrq,
+            InterruptResample,
+            Kill,
+        }
+
+        let poll_ctx: PollContext<Token> = PollContext::new()
+            .and_then(|pc| pc.add(&self.vhost_interrupt, Token::VhostIrq).and(Ok(pc)))
+            .and_then(|pc| {
+                pc.add(&self.interrupt_resample_evt, Token::InterruptResample)
+                    .and(Ok(pc))
+            })
+            .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc)))
+            .map_err(Error::CreatePollContext)?;
+
+        'poll: loop {
+            let events = poll_ctx.wait().map_err(Error::PollError)?;
+
+            let mut needs_interrupt = false;
+            for event in events.iter_readable() {
+                match event.token() {
+                    Token::VhostIrq => {
+                        needs_interrupt = true;
+                        self.vhost_interrupt.read().map_err(Error::VhostIrqRead)?;
+                    }
+                    Token::InterruptResample => {
+                        let _ = self.interrupt_resample_evt.read();
+                        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
+                            self.interrupt_evt.write(1).unwrap();
+                        }
+                    }
+                    Token::Kill => break 'poll,
+                }
+            }
+            if needs_interrupt {
+                self.signal_used_queue();
+            }
+        }
+        Ok(())
+    }
+}
diff --git a/devices/src/virtio/virtio_device.rs b/devices/src/virtio/virtio_device.rs
new file mode 100644
index 0000000..d5d5266
--- /dev/null
+++ b/devices/src/virtio/virtio_device.rs
@@ -0,0 +1,88 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::os::unix::io::RawFd;
+use std::sync::atomic::AtomicUsize;
+use std::sync::Arc;
+
+use sys_util::{EventFd, GuestMemory};
+
+use super::*;
+use crate::pci::{PciBarConfiguration, PciCapability};
+
+/// Trait for virtio devices to be driven by a virtio transport.
+///
+/// The lifecycle of a virtio device is to be moved to a virtio transport, which will then query the
+/// device. Once the guest driver has configured the device, `VirtioDevice::activate` will be called
+/// and all the events, memory, and queues for device operation will be moved into the device.
+/// Optionally, a virtio device can implement device reset in which it returns said resources and
+/// resets its internal.
+pub trait VirtioDevice: Send {
+    /// Returns a label suitable for debug output.
+    fn debug_label(&self) -> String {
+        match type_to_str(self.device_type()) {
+            Some(s) => format!("virtio-{}", s),
+            None => format!("virtio (type {})", self.device_type()),
+        }
+    }
+
+    /// A vector of device-specific file descriptors that must be kept open
+    /// after jailing. Must be called before the process is jailed.
+    fn keep_fds(&self) -> Vec<RawFd>;
+
+    /// The virtio device type.
+    fn device_type(&self) -> u32;
+
+    /// The maximum size of each queue that this device supports.
+    fn queue_max_sizes(&self) -> &[u16];
+
+    /// The set of feature bits that this device supports.
+    fn features(&self) -> u64 {
+        1 << VIRTIO_F_VERSION_1
+    }
+
+    /// Acknowledges that this set of features should be enabled.
+    fn ack_features(&mut self, value: u64) {
+        let _ = value;
+    }
+
+    /// Reads this device configuration space at `offset`.
+    fn read_config(&self, offset: u64, data: &mut [u8]) {
+        let _ = offset;
+        let _ = data;
+    }
+
+    /// Writes to this device configuration space at `offset`.
+    fn write_config(&mut self, offset: u64, data: &[u8]) {
+        let _ = offset;
+        let _ = data;
+    }
+
+    /// Activates this device for real usage.
+    fn activate(
+        &mut self,
+        mem: GuestMemory,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        status: Arc<AtomicUsize>,
+        queues: Vec<Queue>,
+        queue_evts: Vec<EventFd>,
+    );
+
+    /// Optionally deactivates this device and returns ownership of the guest memory map, interrupt
+    /// event, and queue events.
+    fn reset(&mut self) -> Option<(EventFd, Vec<EventFd>)> {
+        None
+    }
+
+    /// Returns any additional BAR configuration required by the device.
+    fn get_device_bars(&self) -> Vec<PciBarConfiguration> {
+        Vec::new()
+    }
+
+    /// Returns any additional capabiltiies required by the device.
+    fn get_device_caps(&self) -> Vec<Box<dyn PciCapability>> {
+        Vec::new()
+    }
+}
diff --git a/devices/src/virtio/virtio_pci_common_config.rs b/devices/src/virtio/virtio_pci_common_config.rs
new file mode 100644
index 0000000..7f7eaca
--- /dev/null
+++ b/devices/src/virtio/virtio_pci_common_config.rs
@@ -0,0 +1,308 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use byteorder::{ByteOrder, LittleEndian};
+use sys_util::{warn, GuestAddress};
+
+use super::*;
+
+/// Contains the data for reading and writing the common configuration structure of a virtio PCI
+/// device.
+///
+/// * Registers:
+/// ** About the whole device.
+/// le32 device_feature_select;     // read-write
+/// le32 device_feature;            // read-only for driver
+/// le32 driver_feature_select;     // read-write
+/// le32 driver_feature;            // read-write
+/// le16 msix_config;               // read-write
+/// le16 num_queues;                // read-only for driver
+/// u8 device_status;               // read-write (driver_status)
+/// u8 config_generation;           // read-only for driver
+/// ** About a specific virtqueue.
+/// le16 queue_select;              // read-write
+/// le16 queue_size;                // read-write, power of 2, or 0.
+/// le16 queue_msix_vector;         // read-write
+/// le16 queue_enable;              // read-write (Ready)
+/// le16 queue_notify_off;          // read-only for driver
+/// le64 queue_desc;                // read-write
+/// le64 queue_avail;               // read-write
+/// le64 queue_used;                // read-write
+pub struct VirtioPciCommonConfig {
+    pub driver_status: u8,
+    pub config_generation: u8,
+    pub device_feature_select: u32,
+    pub driver_feature_select: u32,
+    pub queue_select: u16,
+}
+
+impl VirtioPciCommonConfig {
+    pub fn read(
+        &mut self,
+        offset: u64,
+        data: &mut [u8],
+        queues: &mut [Queue],
+        device: &mut dyn VirtioDevice,
+    ) {
+        match data.len() {
+            1 => {
+                let v = self.read_common_config_byte(offset);
+                data[0] = v;
+            }
+            2 => {
+                let v = self.read_common_config_word(offset, queues);
+                LittleEndian::write_u16(data, v);
+            }
+            4 => {
+                let v = self.read_common_config_dword(offset, device);
+                LittleEndian::write_u32(data, v);
+            }
+            8 => {
+                let v = self.read_common_config_qword(offset);
+                LittleEndian::write_u64(data, v);
+            }
+            _ => (),
+        }
+    }
+
+    pub fn write(
+        &mut self,
+        offset: u64,
+        data: &[u8],
+        queues: &mut [Queue],
+        device: &mut dyn VirtioDevice,
+    ) {
+        match data.len() {
+            1 => self.write_common_config_byte(offset, data[0]),
+            2 => self.write_common_config_word(offset, LittleEndian::read_u16(data), queues),
+            4 => {
+                self.write_common_config_dword(offset, LittleEndian::read_u32(data), queues, device)
+            }
+            8 => self.write_common_config_qword(offset, LittleEndian::read_u64(data), queues),
+            _ => (),
+        }
+    }
+
+    fn read_common_config_byte(&self, offset: u64) -> u8 {
+        // The driver is only allowed to do aligned, properly sized access.
+        match offset {
+            0x14 => self.driver_status,
+            0x15 => self.config_generation,
+            _ => 0,
+        }
+    }
+
+    fn write_common_config_byte(&mut self, offset: u64, value: u8) {
+        match offset {
+            0x14 => self.driver_status = value,
+            _ => {
+                warn!("invalid virtio config byt access: 0x{:x}", offset);
+            }
+        }
+    }
+
+    fn read_common_config_word(&self, offset: u64, queues: &[Queue]) -> u16 {
+        match offset {
+            0x10 => 0,                   // TODO msi-x (crbug/854765): self.msix_config,
+            0x12 => queues.len() as u16, // num_queues
+            0x16 => self.queue_select,
+            0x18 => self.with_queue(queues, |q| q.size).unwrap_or(0),
+            0x1c => {
+                if self.with_queue(queues, |q| q.ready).unwrap_or(false) {
+                    1
+                } else {
+                    0
+                }
+            }
+            0x1e => self.queue_select, // notify_off
+            _ => 0,
+        }
+    }
+
+    fn write_common_config_word(&mut self, offset: u64, value: u16, queues: &mut [Queue]) {
+        match offset {
+            0x10 => (), // TODO msi-x (crbug/854765): self.msix_config = value,
+            0x16 => self.queue_select = value,
+            0x18 => self.with_queue_mut(queues, |q| q.size = value),
+            0x1a => (), // TODO msi-x (crbug/854765): self.with_queue_mut(queues, |q| q.msix_vector = v),
+            0x1c => self.with_queue_mut(queues, |q| q.ready = value == 1),
+            _ => {
+                warn!("invalid virtio register word write: 0x{:x}", offset);
+            }
+        }
+    }
+
+    fn read_common_config_dword(&self, offset: u64, device: &dyn VirtioDevice) -> u32 {
+        match offset {
+            0x00 => self.device_feature_select,
+            0x04 => {
+                // Only 64 bits of features (2 pages) are defined for now, so limit
+                // device_feature_select to avoid shifting by 64 or more bits.
+                if self.device_feature_select < 2 {
+                    (device.features() >> (self.device_feature_select * 32)) as u32
+                } else {
+                    0
+                }
+            }
+            0x08 => self.driver_feature_select,
+            _ => 0,
+        }
+    }
+
+    fn write_common_config_dword(
+        &mut self,
+        offset: u64,
+        value: u32,
+        queues: &mut [Queue],
+        device: &mut dyn VirtioDevice,
+    ) {
+        fn hi(v: &mut GuestAddress, x: u32) {
+            *v = (*v & 0xffffffff) | ((x as u64) << 32)
+        }
+
+        fn lo(v: &mut GuestAddress, x: u32) {
+            *v = (*v & !0xffffffff) | (x as u64)
+        }
+
+        match offset {
+            0x00 => self.device_feature_select = value,
+            0x08 => self.driver_feature_select = value,
+            0x0c => {
+                if self.driver_feature_select < 2 {
+                    device.ack_features((value as u64) << (self.driver_feature_select * 32));
+                } else {
+                    warn!(
+                        "invalid ack_features (page {}, value 0x{:x})",
+                        self.driver_feature_select, value
+                    );
+                }
+            }
+            0x20 => self.with_queue_mut(queues, |q| lo(&mut q.desc_table, value)),
+            0x24 => self.with_queue_mut(queues, |q| hi(&mut q.desc_table, value)),
+            0x28 => self.with_queue_mut(queues, |q| lo(&mut q.avail_ring, value)),
+            0x2c => self.with_queue_mut(queues, |q| hi(&mut q.avail_ring, value)),
+            0x30 => self.with_queue_mut(queues, |q| lo(&mut q.used_ring, value)),
+            0x34 => self.with_queue_mut(queues, |q| hi(&mut q.used_ring, value)),
+            _ => {
+                warn!("invalid virtio register dword write: 0x{:x}", offset);
+            }
+        }
+    }
+
+    fn read_common_config_qword(&self, _offset: u64) -> u64 {
+        0 // Assume the guest has no reason to read write-only registers.
+    }
+
+    fn write_common_config_qword(&mut self, offset: u64, value: u64, queues: &mut [Queue]) {
+        match offset {
+            0x20 => self.with_queue_mut(queues, |q| q.desc_table = GuestAddress(value)),
+            0x28 => self.with_queue_mut(queues, |q| q.avail_ring = GuestAddress(value)),
+            0x30 => self.with_queue_mut(queues, |q| q.used_ring = GuestAddress(value)),
+            _ => {
+                warn!("invalid virtio register qword write: 0x{:x}", offset);
+            }
+        }
+    }
+
+    fn with_queue<U, F>(&self, queues: &[Queue], f: F) -> Option<U>
+    where
+        F: FnOnce(&Queue) -> U,
+    {
+        queues.get(self.queue_select as usize).map(f)
+    }
+
+    fn with_queue_mut<F: FnOnce(&mut Queue)>(&self, queues: &mut [Queue], f: F) {
+        if let Some(queue) = queues.get_mut(self.queue_select as usize) {
+            f(queue);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use std::os::unix::io::RawFd;
+    use std::sync::atomic::AtomicUsize;
+    use std::sync::Arc;
+    use sys_util::{EventFd, GuestMemory};
+
+    struct DummyDevice(u32);
+    const QUEUE_SIZE: u16 = 256;
+    const QUEUE_SIZES: &'static [u16] = &[QUEUE_SIZE];
+    const DUMMY_FEATURES: u64 = 0x5555_aaaa;
+    impl VirtioDevice for DummyDevice {
+        fn keep_fds(&self) -> Vec<RawFd> {
+            Vec::new()
+        }
+        fn device_type(&self) -> u32 {
+            return self.0;
+        }
+        fn queue_max_sizes(&self) -> &[u16] {
+            QUEUE_SIZES
+        }
+        fn activate(
+            &mut self,
+            _mem: GuestMemory,
+            _interrupt_evt: EventFd,
+            _interrupt_resample_evt: EventFd,
+            _status: Arc<AtomicUsize>,
+            _queues: Vec<Queue>,
+            _queue_evts: Vec<EventFd>,
+        ) {
+        }
+        fn features(&self) -> u64 {
+            DUMMY_FEATURES
+        }
+    }
+
+    #[test]
+    fn write_base_regs() {
+        let mut regs = VirtioPciCommonConfig {
+            driver_status: 0xaa,
+            config_generation: 0x55,
+            device_feature_select: 0x0,
+            driver_feature_select: 0x0,
+            queue_select: 0xff,
+        };
+
+        let dev = &mut DummyDevice(0) as &mut dyn VirtioDevice;
+        let mut queues = Vec::new();
+
+        // Can set all bits of driver_status.
+        regs.write(0x14, &[0x55], &mut queues, dev);
+        let mut read_back = vec![0x00];
+        regs.read(0x14, &mut read_back, &mut queues, dev);
+        assert_eq!(read_back[0], 0x55);
+
+        // The config generation register is read only.
+        regs.write(0x15, &[0xaa], &mut queues, dev);
+        let mut read_back = vec![0x00];
+        regs.read(0x15, &mut read_back, &mut queues, dev);
+        assert_eq!(read_back[0], 0x55);
+
+        // Device features is read-only and passed through from the device.
+        regs.write(0x04, &[0, 0, 0, 0], &mut queues, dev);
+        let mut read_back = vec![0, 0, 0, 0];
+        regs.read(0x04, &mut read_back, &mut queues, dev);
+        assert_eq!(LittleEndian::read_u32(&read_back), DUMMY_FEATURES as u32);
+
+        // Feature select registers are read/write.
+        regs.write(0x00, &[1, 2, 3, 4], &mut queues, dev);
+        let mut read_back = vec![0, 0, 0, 0];
+        regs.read(0x00, &mut read_back, &mut queues, dev);
+        assert_eq!(LittleEndian::read_u32(&read_back), 0x0403_0201);
+        regs.write(0x08, &[1, 2, 3, 4], &mut queues, dev);
+        let mut read_back = vec![0, 0, 0, 0];
+        regs.read(0x08, &mut read_back, &mut queues, dev);
+        assert_eq!(LittleEndian::read_u32(&read_back), 0x0403_0201);
+
+        // 'queue_select' can be read and written.
+        regs.write(0x16, &[0xaa, 0x55], &mut queues, dev);
+        let mut read_back = vec![0x00, 0x00];
+        regs.read(0x16, &mut read_back, &mut queues, dev);
+        assert_eq!(read_back[0], 0xaa);
+        assert_eq!(read_back[1], 0x55);
+    }
+}
diff --git a/devices/src/virtio/virtio_pci_device.rs b/devices/src/virtio/virtio_pci_device.rs
new file mode 100644
index 0000000..45bd423
--- /dev/null
+++ b/devices/src/virtio/virtio_pci_device.rs
@@ -0,0 +1,528 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+
+use data_model::{DataInit, Le32};
+use kvm::Datamatch;
+use resources::{Alloc, SystemAllocator};
+use sys_util::{EventFd, GuestMemory, Result};
+
+use super::*;
+use crate::pci::{
+    PciBarConfiguration, PciCapability, PciCapabilityID, PciClassCode, PciConfiguration, PciDevice,
+    PciDeviceError, PciHeaderType, PciInterruptPin, PciSubclass,
+};
+
+use self::virtio_pci_common_config::VirtioPciCommonConfig;
+
+pub enum PciCapabilityType {
+    CommonConfig = 1,
+    NotifyConfig = 2,
+    IsrConfig = 3,
+    DeviceConfig = 4,
+    PciConfig = 5,
+}
+
+#[allow(dead_code)]
+#[repr(C)]
+#[derive(Clone, Copy)]
+struct VirtioPciCap {
+    // _cap_vndr and _cap_next are autofilled based on id() in pci configuration
+    _cap_vndr: u8,    // Generic PCI field: PCI_CAP_ID_VNDR
+    _cap_next: u8,    // Generic PCI field: next ptr
+    cap_len: u8,      // Generic PCI field: capability length
+    cfg_type: u8,     // Identifies the structure.
+    bar: u8,          // Where to find it.
+    padding: [u8; 3], // Pad to full dword.
+    offset: Le32,     // Offset within bar.
+    length: Le32,     // Length of the structure, in bytes.
+}
+// It is safe to implement DataInit; all members are simple numbers and any value is valid.
+unsafe impl DataInit for VirtioPciCap {}
+
+impl PciCapability for VirtioPciCap {
+    fn bytes(&self) -> &[u8] {
+        self.as_slice()
+    }
+
+    fn id(&self) -> PciCapabilityID {
+        PciCapabilityID::VendorSpecific
+    }
+}
+
+impl VirtioPciCap {
+    pub fn new(cfg_type: PciCapabilityType, bar: u8, offset: u32, length: u32) -> Self {
+        VirtioPciCap {
+            _cap_vndr: 0,
+            _cap_next: 0,
+            cap_len: std::mem::size_of::<VirtioPciCap>() as u8,
+            cfg_type: cfg_type as u8,
+            bar,
+            padding: [0; 3],
+            offset: Le32::from(offset),
+            length: Le32::from(length),
+        }
+    }
+}
+
+#[allow(dead_code)]
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct VirtioPciNotifyCap {
+    cap: VirtioPciCap,
+    notify_off_multiplier: Le32,
+}
+// It is safe to implement DataInit; all members are simple numbers and any value is valid.
+unsafe impl DataInit for VirtioPciNotifyCap {}
+
+impl PciCapability for VirtioPciNotifyCap {
+    fn bytes(&self) -> &[u8] {
+        self.as_slice()
+    }
+
+    fn id(&self) -> PciCapabilityID {
+        PciCapabilityID::VendorSpecific
+    }
+}
+
+impl VirtioPciNotifyCap {
+    pub fn new(
+        cfg_type: PciCapabilityType,
+        bar: u8,
+        offset: u32,
+        length: u32,
+        multiplier: Le32,
+    ) -> Self {
+        VirtioPciNotifyCap {
+            cap: VirtioPciCap {
+                _cap_vndr: 0,
+                _cap_next: 0,
+                cap_len: std::mem::size_of::<VirtioPciNotifyCap>() as u8,
+                cfg_type: cfg_type as u8,
+                bar,
+                padding: [0; 3],
+                offset: Le32::from(offset),
+                length: Le32::from(length),
+            },
+            notify_off_multiplier: multiplier,
+        }
+    }
+}
+
+/// Subclasses for virtio.
+#[allow(dead_code)]
+#[derive(Copy, Clone)]
+pub enum PciVirtioSubclass {
+    NonTransitionalBase = 0xff,
+}
+
+impl PciSubclass for PciVirtioSubclass {
+    fn get_register_value(&self) -> u8 {
+        *self as u8
+    }
+}
+
+// Allocate one bar for the structs pointed to by the capability structures.
+const COMMON_CONFIG_BAR_OFFSET: u64 = 0x0000;
+const COMMON_CONFIG_SIZE: u64 = 56;
+const ISR_CONFIG_BAR_OFFSET: u64 = 0x1000;
+const ISR_CONFIG_SIZE: u64 = 1;
+const DEVICE_CONFIG_BAR_OFFSET: u64 = 0x2000;
+const DEVICE_CONFIG_SIZE: u64 = 0x1000;
+const NOTIFICATION_BAR_OFFSET: u64 = 0x3000;
+const NOTIFICATION_SIZE: u64 = 0x1000;
+const CAPABILITY_BAR_SIZE: u64 = 0x4000;
+
+const NOTIFY_OFF_MULTIPLIER: u32 = 4; // A dword per notification address.
+
+const VIRTIO_PCI_VENDOR_ID: u16 = 0x1af4;
+const VIRTIO_PCI_DEVICE_ID_BASE: u16 = 0x1040; // Add to device type to get device ID.
+
+/// Implements the
+/// [PCI](http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html#x1-650001)
+/// transport for virtio devices.
+pub struct VirtioPciDevice {
+    config_regs: PciConfiguration,
+    pci_bus_dev: Option<(u8, u8)>,
+
+    device: Box<dyn VirtioDevice>,
+    device_activated: bool,
+
+    interrupt_status: Arc<AtomicUsize>,
+    interrupt_evt: Option<EventFd>,
+    interrupt_resample_evt: Option<EventFd>,
+    queues: Vec<Queue>,
+    queue_evts: Vec<EventFd>,
+    mem: Option<GuestMemory>,
+    settings_bar: u8,
+
+    common_config: VirtioPciCommonConfig,
+}
+
+impl VirtioPciDevice {
+    /// Constructs a new PCI transport for the given virtio device.
+    pub fn new(mem: GuestMemory, device: Box<dyn VirtioDevice>) -> Result<Self> {
+        let mut queue_evts = Vec::new();
+        for _ in device.queue_max_sizes() {
+            queue_evts.push(EventFd::new()?)
+        }
+        let queues = device
+            .queue_max_sizes()
+            .iter()
+            .map(|&s| Queue::new(s))
+            .collect();
+
+        let pci_device_id = VIRTIO_PCI_DEVICE_ID_BASE + device.device_type() as u16;
+
+        let config_regs = PciConfiguration::new(
+            VIRTIO_PCI_VENDOR_ID,
+            pci_device_id,
+            PciClassCode::Other,
+            &PciVirtioSubclass::NonTransitionalBase,
+            None,
+            PciHeaderType::Device,
+            VIRTIO_PCI_VENDOR_ID,
+            pci_device_id,
+        );
+
+        Ok(VirtioPciDevice {
+            config_regs,
+            pci_bus_dev: None,
+            device,
+            device_activated: false,
+            interrupt_status: Arc::new(AtomicUsize::new(0)),
+            interrupt_evt: None,
+            interrupt_resample_evt: None,
+            queues,
+            queue_evts,
+            mem: Some(mem),
+            settings_bar: 0,
+            common_config: VirtioPciCommonConfig {
+                driver_status: 0,
+                config_generation: 0,
+                device_feature_select: 0,
+                driver_feature_select: 0,
+                queue_select: 0,
+            },
+        })
+    }
+
+    /// Gets the list of queue events that must be triggered whenever the VM writes to
+    /// `virtio::NOTIFY_REG_OFFSET` past the MMIO base. Each event must be triggered when the
+    /// value being written equals the index of the event in this list.
+    pub fn queue_evts(&self) -> &[EventFd] {
+        self.queue_evts.as_slice()
+    }
+
+    /// Gets the event this device uses to interrupt the VM when the used queue is changed.
+    pub fn interrupt_evt(&self) -> Option<&EventFd> {
+        self.interrupt_evt.as_ref()
+    }
+
+    fn is_driver_ready(&self) -> bool {
+        let ready_bits =
+            (DEVICE_ACKNOWLEDGE | DEVICE_DRIVER | DEVICE_DRIVER_OK | DEVICE_FEATURES_OK) as u8;
+        self.common_config.driver_status == ready_bits
+            && self.common_config.driver_status & DEVICE_FAILED as u8 == 0
+    }
+
+    fn are_queues_valid(&self) -> bool {
+        if let Some(mem) = self.mem.as_ref() {
+            self.queues.iter().all(|q| q.is_valid(mem))
+        } else {
+            false
+        }
+    }
+
+    fn add_settings_pci_capabilities(
+        &mut self,
+        settings_bar: u8,
+    ) -> std::result::Result<(), PciDeviceError> {
+        // Add pointers to the different configuration structures from the PCI capabilities.
+        let common_cap = VirtioPciCap::new(
+            PciCapabilityType::CommonConfig,
+            settings_bar,
+            COMMON_CONFIG_BAR_OFFSET as u32,
+            COMMON_CONFIG_SIZE as u32,
+        );
+        self.config_regs
+            .add_capability(&common_cap)
+            .map_err(PciDeviceError::CapabilitiesSetup)?;
+
+        let isr_cap = VirtioPciCap::new(
+            PciCapabilityType::IsrConfig,
+            settings_bar,
+            ISR_CONFIG_BAR_OFFSET as u32,
+            ISR_CONFIG_SIZE as u32,
+        );
+        self.config_regs
+            .add_capability(&isr_cap)
+            .map_err(PciDeviceError::CapabilitiesSetup)?;
+
+        // TODO(dgreid) - set based on device's configuration size?
+        let device_cap = VirtioPciCap::new(
+            PciCapabilityType::DeviceConfig,
+            settings_bar,
+            DEVICE_CONFIG_BAR_OFFSET as u32,
+            DEVICE_CONFIG_SIZE as u32,
+        );
+        self.config_regs
+            .add_capability(&device_cap)
+            .map_err(PciDeviceError::CapabilitiesSetup)?;
+
+        let notify_cap = VirtioPciNotifyCap::new(
+            PciCapabilityType::NotifyConfig,
+            settings_bar,
+            NOTIFICATION_BAR_OFFSET as u32,
+            NOTIFICATION_SIZE as u32,
+            Le32::from(NOTIFY_OFF_MULTIPLIER),
+        );
+        self.config_regs
+            .add_capability(&notify_cap)
+            .map_err(PciDeviceError::CapabilitiesSetup)?;
+
+        //TODO(dgreid) - How will the configuration_cap work?
+        let configuration_cap = VirtioPciCap::new(PciCapabilityType::PciConfig, 0, 0, 0);
+        self.config_regs
+            .add_capability(&configuration_cap)
+            .map_err(PciDeviceError::CapabilitiesSetup)?;
+
+        self.settings_bar = settings_bar;
+        Ok(())
+    }
+}
+
+impl PciDevice for VirtioPciDevice {
+    fn debug_label(&self) -> String {
+        format!("virtio-pci ({})", self.device.debug_label())
+    }
+
+    fn assign_bus_dev(&mut self, bus: u8, device: u8) {
+        self.pci_bus_dev = Some((bus, device));
+    }
+
+    fn keep_fds(&self) -> Vec<RawFd> {
+        let mut fds = self.device.keep_fds();
+        if let Some(interrupt_evt) = &self.interrupt_evt {
+            fds.push(interrupt_evt.as_raw_fd());
+        }
+        if let Some(interrupt_resample_evt) = &self.interrupt_resample_evt {
+            fds.push(interrupt_resample_evt.as_raw_fd());
+        }
+        fds
+    }
+
+    fn assign_irq(
+        &mut self,
+        irq_evt: EventFd,
+        irq_resample_evt: EventFd,
+        irq_num: u32,
+        irq_pin: PciInterruptPin,
+    ) {
+        self.config_regs.set_irq(irq_num as u8, irq_pin);
+        self.interrupt_evt = Some(irq_evt);
+        self.interrupt_resample_evt = Some(irq_resample_evt);
+    }
+
+    fn allocate_io_bars(
+        &mut self,
+        resources: &mut SystemAllocator,
+    ) -> std::result::Result<Vec<(u64, u64)>, PciDeviceError> {
+        let (bus, dev) = self
+            .pci_bus_dev
+            .expect("assign_bus_dev must be called prior to allocate_io_bars");
+        // Allocate one bar for the structures pointed to by the capability structures.
+        let mut ranges = Vec::new();
+        let settings_config_addr = resources
+            .mmio_allocator()
+            .allocate(
+                CAPABILITY_BAR_SIZE,
+                Alloc::PciBar { bus, dev, bar: 0 },
+                format!(
+                    "virtio-{}-cap_bar",
+                    type_to_str(self.device.device_type()).unwrap_or("?")
+                ),
+            )
+            .map_err(|e| PciDeviceError::IoAllocationFailed(CAPABILITY_BAR_SIZE, e))?;
+        let config = PciBarConfiguration::default()
+            .set_register_index(0)
+            .set_address(settings_config_addr)
+            .set_size(CAPABILITY_BAR_SIZE);
+        let settings_bar = self
+            .config_regs
+            .add_pci_bar(&config)
+            .map_err(|e| PciDeviceError::IoRegistrationFailed(settings_config_addr, e))?
+            as u8;
+        ranges.push((settings_config_addr, CAPABILITY_BAR_SIZE));
+
+        // Once the BARs are allocated, the capabilities can be added to the PCI configuration.
+        self.add_settings_pci_capabilities(settings_bar)?;
+
+        Ok(ranges)
+    }
+
+    fn allocate_device_bars(
+        &mut self,
+        resources: &mut SystemAllocator,
+    ) -> std::result::Result<Vec<(u64, u64)>, PciDeviceError> {
+        let (bus, dev) = self
+            .pci_bus_dev
+            .expect("assign_bus_dev must be called prior to allocate_device_bars");
+        let mut ranges = Vec::new();
+        for config in self.device.get_device_bars() {
+            let device_addr = resources
+                .device_allocator()
+                .allocate(
+                    config.get_size(),
+                    Alloc::PciBar {
+                        bus,
+                        dev,
+                        bar: config.get_register_index() as u8,
+                    },
+                    format!(
+                        "virtio-{}-custom_bar",
+                        type_to_str(self.device.device_type()).unwrap_or("?")
+                    ),
+                )
+                .map_err(|e| PciDeviceError::IoAllocationFailed(config.get_size(), e))?;
+            let config = config.set_address(device_addr);
+            let _device_bar = self
+                .config_regs
+                .add_pci_bar(&config)
+                .map_err(|e| PciDeviceError::IoRegistrationFailed(device_addr, e))?;
+            ranges.push((device_addr, config.get_size()));
+        }
+        Ok(ranges)
+    }
+
+    fn register_device_capabilities(&mut self) -> std::result::Result<(), PciDeviceError> {
+        for cap in self.device.get_device_caps() {
+            self.config_regs
+                .add_capability(&*cap)
+                .map_err(PciDeviceError::CapabilitiesSetup)?;
+        }
+
+        Ok(())
+    }
+
+    fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> {
+        let bar0 = self.config_regs.get_bar_addr(self.settings_bar as usize) as u64;
+        let notify_base = bar0 + NOTIFICATION_BAR_OFFSET;
+        self.queue_evts()
+            .iter()
+            .enumerate()
+            .map(|(i, event)| {
+                (
+                    event,
+                    notify_base + i as u64 * NOTIFY_OFF_MULTIPLIER as u64,
+                    Datamatch::U16(Some(i as u16)),
+                )
+            })
+            .collect()
+    }
+
+    fn config_registers(&self) -> &PciConfiguration {
+        &self.config_regs
+    }
+
+    fn config_registers_mut(&mut self) -> &mut PciConfiguration {
+        &mut self.config_regs
+    }
+
+    // Clippy: the value of COMMON_CONFIG_BAR_OFFSET happens to be zero so the
+    // expression `COMMON_CONFIG_BAR_OFFSET <= o` is always true, but this code
+    // is written such that the value of the const may be changed independently.
+    #[allow(clippy::absurd_extreme_comparisons)]
+    fn read_bar(&mut self, addr: u64, data: &mut [u8]) {
+        // The driver is only allowed to do aligned, properly sized access.
+        let bar0 = self.config_regs.get_bar_addr(self.settings_bar as usize) as u64;
+        let offset = addr - bar0;
+        match offset {
+            o if COMMON_CONFIG_BAR_OFFSET <= o
+                && o < COMMON_CONFIG_BAR_OFFSET + COMMON_CONFIG_SIZE =>
+            {
+                self.common_config.read(
+                    o - COMMON_CONFIG_BAR_OFFSET,
+                    data,
+                    &mut self.queues,
+                    self.device.as_mut(),
+                )
+            }
+            o if ISR_CONFIG_BAR_OFFSET <= o && o < ISR_CONFIG_BAR_OFFSET + ISR_CONFIG_SIZE => {
+                if let Some(v) = data.get_mut(0) {
+                    // Reading this register resets it to 0.
+                    *v = self.interrupt_status.swap(0, Ordering::SeqCst) as u8;
+                }
+            }
+            o if DEVICE_CONFIG_BAR_OFFSET <= o
+                && o < DEVICE_CONFIG_BAR_OFFSET + DEVICE_CONFIG_SIZE =>
+            {
+                self.device.read_config(o - DEVICE_CONFIG_BAR_OFFSET, data);
+            }
+            o if NOTIFICATION_BAR_OFFSET <= o
+                && o < NOTIFICATION_BAR_OFFSET + NOTIFICATION_SIZE =>
+            {
+                // Handled with ioeventfds.
+            }
+            _ => (),
+        }
+    }
+
+    #[allow(clippy::absurd_extreme_comparisons)]
+    fn write_bar(&mut self, addr: u64, data: &[u8]) {
+        let bar0 = self.config_regs.get_bar_addr(self.settings_bar as usize) as u64;
+        let offset = addr - bar0;
+        match offset {
+            o if COMMON_CONFIG_BAR_OFFSET <= o
+                && o < COMMON_CONFIG_BAR_OFFSET + COMMON_CONFIG_SIZE =>
+            {
+                self.common_config.write(
+                    o - COMMON_CONFIG_BAR_OFFSET,
+                    data,
+                    &mut self.queues,
+                    self.device.as_mut(),
+                )
+            }
+            o if ISR_CONFIG_BAR_OFFSET <= o && o < ISR_CONFIG_BAR_OFFSET + ISR_CONFIG_SIZE => {
+                if let Some(v) = data.get(0) {
+                    self.interrupt_status
+                        .fetch_and(!(*v as usize), Ordering::SeqCst);
+                }
+            }
+            o if DEVICE_CONFIG_BAR_OFFSET <= o
+                && o < DEVICE_CONFIG_BAR_OFFSET + DEVICE_CONFIG_SIZE =>
+            {
+                self.device.write_config(o - DEVICE_CONFIG_BAR_OFFSET, data);
+            }
+            o if NOTIFICATION_BAR_OFFSET <= o
+                && o < NOTIFICATION_BAR_OFFSET + NOTIFICATION_SIZE =>
+            {
+                // Handled with ioeventfds.
+            }
+            _ => (),
+        };
+
+        if !self.device_activated && self.is_driver_ready() && self.are_queues_valid() {
+            if let Some(interrupt_evt) = self.interrupt_evt.take() {
+                if let Some(interrupt_resample_evt) = self.interrupt_resample_evt.take() {
+                    if let Some(mem) = self.mem.take() {
+                        self.device.activate(
+                            mem,
+                            interrupt_evt,
+                            interrupt_resample_evt,
+                            self.interrupt_status.clone(),
+                            self.queues.clone(),
+                            self.queue_evts.split_off(0),
+                        );
+                        self.device_activated = true;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/devices/src/virtio/wl.rs b/devices/src/virtio/wl.rs
new file mode 100644
index 0000000..dd8ce86
--- /dev/null
+++ b/devices/src/virtio/wl.rs
@@ -0,0 +1,1791 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! This module implements the virtio wayland used by the guest to access the host's wayland server.
+//!
+//! The virtio wayland protocol is done over two queues: `in` and `out`. The `in` queue is used for
+//! sending commands to the guest that are generated by the host, usually messages from the wayland
+//! server. The `out` queue is for commands from the guest, usually requests to allocate shared
+//! memory, open a wayland server connection, or send data over an existing connection.
+//!
+//! Each `WlVfd` represents one virtual file descriptor created by either the guest or the host.
+//! Virtual file descriptors contain actual file descriptors, either a shared memory file descriptor
+//! or a unix domain socket to the wayland server. In the shared memory case, there is also an
+//! associated slot that indicates which KVM memory slot the memory is installed into, as well as a
+//! page frame number that the guest can access the memory from.
+//!
+//! The types starting with `Ctrl` are structures representing the virtio wayland protocol "on the
+//! wire." They are decoded/encoded as some variant of `WlOp` for requests and `WlResp` for
+//! responses.
+//!
+//! There is one `WlState` instance that contains every known vfd and the current state of `in`
+//! queue. The `in` queue requires extra state to buffer messages to the guest in case the `in`
+//! queue is already full. The `WlState` also has a control socket necessary to fulfill certain
+//! requests, such as those registering guest memory.
+//!
+//! The `Worker` is responsible for the poll loop over all possible events, encoding/decoding from
+//! the virtio queue, and routing messages in and out of `WlState`. Possible events include the kill
+//! event, available descriptors on the `in` or `out` queue, and incoming data on any vfd's socket.
+
+use std::cell::RefCell;
+use std::collections::btree_map::Entry;
+use std::collections::{BTreeMap as Map, BTreeSet as Set, VecDeque};
+use std::convert::From;
+use std::error::Error as StdError;
+use std::ffi::CStr;
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::io::{self, Read, Seek, SeekFrom};
+use std::mem::{size_of, size_of_val};
+#[cfg(feature = "wl-dmabuf")]
+use std::os::raw::{c_uint, c_ulonglong};
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::os::unix::net::UnixStream;
+use std::path::{Path, PathBuf};
+use std::rc::Rc;
+use std::result;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+use std::thread;
+use std::time::Duration;
+
+#[cfg(feature = "wl-dmabuf")]
+use libc::{dup, EBADF, EINVAL};
+
+use data_model::VolatileMemoryError;
+use data_model::*;
+
+use msg_socket::{MsgError, MsgReceiver, MsgSender};
+#[cfg(feature = "wl-dmabuf")]
+use resources::GpuMemoryDesc;
+#[cfg(feature = "wl-dmabuf")]
+use sys_util::ioctl_iow_nr;
+use sys_util::{
+    error, pipe, round_up_to_page_size, warn, Error, EventFd, FileFlags, FileReadWriteVolatile,
+    GuestAddress, GuestMemory, GuestMemoryError, PollContext, PollToken, Result, ScmSocket,
+    SharedMemory,
+};
+
+#[cfg(feature = "wl-dmabuf")]
+use sys_util::ioctl_with_ref;
+
+use super::resource_bridge::*;
+use super::{
+    DescriptorChain, Queue, VirtioDevice, INTERRUPT_STATUS_USED_RING, TYPE_WL, VIRTIO_F_VERSION_1,
+};
+use vm_control::{MaybeOwnedFd, VmMemoryControlRequestSocket, VmMemoryRequest, VmMemoryResponse};
+
+const VIRTWL_SEND_MAX_ALLOCS: usize = 28;
+const VIRTIO_WL_CMD_VFD_NEW: u32 = 256;
+const VIRTIO_WL_CMD_VFD_CLOSE: u32 = 257;
+const VIRTIO_WL_CMD_VFD_SEND: u32 = 258;
+const VIRTIO_WL_CMD_VFD_RECV: u32 = 259;
+const VIRTIO_WL_CMD_VFD_NEW_CTX: u32 = 260;
+const VIRTIO_WL_CMD_VFD_NEW_PIPE: u32 = 261;
+const VIRTIO_WL_CMD_VFD_HUP: u32 = 262;
+#[cfg(feature = "wl-dmabuf")]
+const VIRTIO_WL_CMD_VFD_NEW_DMABUF: u32 = 263;
+#[cfg(feature = "wl-dmabuf")]
+const VIRTIO_WL_CMD_VFD_DMABUF_SYNC: u32 = 264;
+#[cfg(feature = "gpu")]
+const VIRTIO_WL_CMD_VFD_SEND_FOREIGN_ID: u32 = 265;
+const VIRTIO_WL_RESP_OK: u32 = 4096;
+const VIRTIO_WL_RESP_VFD_NEW: u32 = 4097;
+#[cfg(feature = "wl-dmabuf")]
+const VIRTIO_WL_RESP_VFD_NEW_DMABUF: u32 = 4098;
+const VIRTIO_WL_RESP_ERR: u32 = 4352;
+const VIRTIO_WL_RESP_OUT_OF_MEMORY: u32 = 4353;
+const VIRTIO_WL_RESP_INVALID_ID: u32 = 4354;
+const VIRTIO_WL_RESP_INVALID_TYPE: u32 = 4355;
+const VIRTIO_WL_RESP_INVALID_FLAGS: u32 = 4356;
+const VIRTIO_WL_RESP_INVALID_CMD: u32 = 4357;
+const VIRTIO_WL_VFD_WRITE: u32 = 0x1;
+const VIRTIO_WL_VFD_READ: u32 = 0x2;
+const VIRTIO_WL_VFD_MAP: u32 = 0x2;
+const VIRTIO_WL_VFD_CONTROL: u32 = 0x4;
+const VIRTIO_WL_F_TRANS_FLAGS: u32 = 0x01;
+
+const QUEUE_SIZE: u16 = 16;
+const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE, QUEUE_SIZE];
+
+const NEXT_VFD_ID_BASE: u32 = 0x40000000;
+const VFD_ID_HOST_MASK: u32 = NEXT_VFD_ID_BASE;
+// Each in-vq buffer is one page, so we need to leave space for the control header and the maximum
+// number of allocs.
+const IN_BUFFER_LEN: usize =
+    0x1000 - size_of::<CtrlVfdRecv>() - VIRTWL_SEND_MAX_ALLOCS * size_of::<Le32>();
+
+#[cfg(feature = "wl-dmabuf")]
+const VIRTIO_WL_VFD_DMABUF_SYNC_VALID_FLAG_MASK: u32 = 0x7;
+
+#[cfg(feature = "wl-dmabuf")]
+const DMA_BUF_IOCTL_BASE: c_uint = 0x62;
+
+#[cfg(feature = "wl-dmabuf")]
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct dma_buf_sync {
+    flags: c_ulonglong,
+}
+
+#[cfg(feature = "wl-dmabuf")]
+ioctl_iow_nr!(DMA_BUF_IOCTL_SYNC, DMA_BUF_IOCTL_BASE, 0, dma_buf_sync);
+
+const VIRTIO_WL_CTRL_VFD_SEND_KIND_LOCAL: u32 = 0;
+const VIRTIO_WL_CTRL_VFD_SEND_KIND_VIRTGPU: u32 = 1;
+
+fn parse_new(addr: GuestAddress, mem: &GuestMemory) -> WlResult<WlOp> {
+    const ID_OFFSET: u64 = 8;
+    const FLAGS_OFFSET: u64 = 12;
+    const SIZE_OFFSET: u64 = 24;
+
+    let id: Le32 = mem.read_obj_from_addr(
+        mem.checked_offset(addr, ID_OFFSET)
+            .ok_or(WlError::CheckedOffset)?,
+    )?;
+    let flags: Le32 = mem.read_obj_from_addr(
+        mem.checked_offset(addr, FLAGS_OFFSET)
+            .ok_or(WlError::CheckedOffset)?,
+    )?;
+    let size: Le32 = mem.read_obj_from_addr(
+        mem.checked_offset(addr, SIZE_OFFSET)
+            .ok_or(WlError::CheckedOffset)?,
+    )?;
+    Ok(WlOp::NewAlloc {
+        id: id.into(),
+        flags: flags.into(),
+        size: size.into(),
+    })
+}
+
+fn parse_new_pipe(addr: GuestAddress, mem: &GuestMemory) -> WlResult<WlOp> {
+    const ID_OFFSET: u64 = 8;
+    const FLAGS_OFFSET: u64 = 12;
+
+    let id: Le32 = mem.read_obj_from_addr(
+        mem.checked_offset(addr, ID_OFFSET)
+            .ok_or(WlError::CheckedOffset)?,
+    )?;
+    let flags: Le32 = mem.read_obj_from_addr(
+        mem.checked_offset(addr, FLAGS_OFFSET)
+            .ok_or(WlError::CheckedOffset)?,
+    )?;
+    Ok(WlOp::NewPipe {
+        id: id.into(),
+        flags: flags.into(),
+    })
+}
+
+#[cfg(feature = "wl-dmabuf")]
+fn parse_new_dmabuf(addr: GuestAddress, mem: &GuestMemory) -> WlResult<WlOp> {
+    const ID_OFFSET: u64 = 8;
+    const WIDTH_OFFSET: u64 = 28;
+    const HEIGHT_OFFSET: u64 = 32;
+    const FORMAT_OFFSET: u64 = 36;
+
+    let id: Le32 = mem.read_obj_from_addr(
+        mem.checked_offset(addr, ID_OFFSET)
+            .ok_or(WlError::CheckedOffset)?,
+    )?;
+    let width: Le32 = mem.read_obj_from_addr(
+        mem.checked_offset(addr, WIDTH_OFFSET)
+            .ok_or(WlError::CheckedOffset)?,
+    )?;
+    let height: Le32 = mem.read_obj_from_addr(
+        mem.checked_offset(addr, HEIGHT_OFFSET)
+            .ok_or(WlError::CheckedOffset)?,
+    )?;
+    let format: Le32 = mem.read_obj_from_addr(
+        mem.checked_offset(addr, FORMAT_OFFSET)
+            .ok_or(WlError::CheckedOffset)?,
+    )?;
+    Ok(WlOp::NewDmabuf {
+        id: id.into(),
+        width: width.into(),
+        height: height.into(),
+        format: format.into(),
+    })
+}
+
+#[cfg(feature = "wl-dmabuf")]
+fn parse_dmabuf_sync(addr: GuestAddress, mem: &GuestMemory) -> WlResult<WlOp> {
+    const ID_OFFSET: u64 = 8;
+    const FLAGS_OFFSET: u64 = 12;
+    let id: Le32 = mem.read_obj_from_addr(
+        mem.checked_offset(addr, ID_OFFSET)
+            .ok_or(WlError::CheckedOffset)?,
+    )?;
+    let flags: Le32 = mem.read_obj_from_addr(
+        mem.checked_offset(addr, FLAGS_OFFSET)
+            .ok_or(WlError::CheckedOffset)?,
+    )?;
+    Ok(WlOp::DmabufSync {
+        id: id.into(),
+        flags: flags.into(),
+    })
+}
+
+fn parse_send(addr: GuestAddress, len: u32, foreign_id: bool, mem: &GuestMemory) -> WlResult<WlOp> {
+    const ID_OFFSET: u64 = 8;
+    const VFD_COUNT_OFFSET: u64 = 12;
+    const VFDS_OFFSET: u64 = 16;
+
+    let id: Le32 = mem.read_obj_from_addr(
+        mem.checked_offset(addr, ID_OFFSET)
+            .ok_or(WlError::CheckedOffset)?,
+    )?;
+    let vfd_count: Le32 = mem.read_obj_from_addr(
+        mem.checked_offset(addr, VFD_COUNT_OFFSET)
+            .ok_or(WlError::CheckedOffset)?,
+    )?;
+    let vfd_count: u32 = vfd_count.into();
+    let vfds_addr = mem
+        .checked_offset(addr, VFDS_OFFSET)
+        .ok_or(WlError::CheckedOffset)?;
+    let vfds_element_size = if foreign_id {
+        size_of::<CtrlVfdSendVfd>()
+    } else {
+        size_of::<Le32>()
+    } as u32;
+    let data_addr = mem
+        .checked_offset(vfds_addr, (vfd_count * vfds_element_size) as u64)
+        .ok_or(WlError::CheckedOffset)?;
+    Ok(WlOp::Send {
+        id: id.into(),
+        foreign_id,
+        vfds_addr,
+        vfd_count,
+        data_addr,
+        data_len: len - (VFDS_OFFSET as u32) - vfd_count * vfds_element_size,
+    })
+}
+
+fn parse_id(addr: GuestAddress, mem: &GuestMemory) -> WlResult<u32> {
+    const ID_OFFSET: u64 = 8;
+    let id: Le32 = mem.read_obj_from_addr(
+        mem.checked_offset(addr, ID_OFFSET)
+            .ok_or(WlError::CheckedOffset)?,
+    )?;
+    Ok(id.into())
+}
+
+fn parse_desc(desc: &DescriptorChain, mem: &GuestMemory) -> WlResult<WlOp> {
+    let type_: Le32 = mem.read_obj_from_addr(desc.addr)?;
+    match type_.into() {
+        VIRTIO_WL_CMD_VFD_NEW => parse_new(desc.addr, mem),
+        VIRTIO_WL_CMD_VFD_CLOSE => Ok(WlOp::Close {
+            id: parse_id(desc.addr, mem)?,
+        }),
+        VIRTIO_WL_CMD_VFD_SEND => parse_send(desc.addr, desc.len, false, mem),
+        VIRTIO_WL_CMD_VFD_NEW_CTX => Ok(WlOp::NewCtx {
+            id: parse_id(desc.addr, mem)?,
+        }),
+        VIRTIO_WL_CMD_VFD_NEW_PIPE => parse_new_pipe(desc.addr, mem),
+        #[cfg(feature = "wl-dmabuf")]
+        VIRTIO_WL_CMD_VFD_NEW_DMABUF => parse_new_dmabuf(desc.addr, mem),
+        #[cfg(feature = "wl-dmabuf")]
+        VIRTIO_WL_CMD_VFD_DMABUF_SYNC => parse_dmabuf_sync(desc.addr, mem),
+        #[cfg(feature = "gpu")]
+        VIRTIO_WL_CMD_VFD_SEND_FOREIGN_ID => parse_send(desc.addr, desc.len, true, mem),
+        v => Ok(WlOp::InvalidCommand { op_type: v }),
+    }
+}
+
+fn encode_vfd_new(
+    desc_mem: VolatileSlice,
+    resp: bool,
+    vfd_id: u32,
+    flags: u32,
+    pfn: u64,
+    size: u32,
+) -> WlResult<u32> {
+    let ctrl_vfd_new = CtrlVfdNew {
+        hdr: CtrlHeader {
+            type_: Le32::from(if resp {
+                VIRTIO_WL_RESP_VFD_NEW
+            } else {
+                VIRTIO_WL_CMD_VFD_NEW
+            }),
+            flags: Le32::from(0),
+        },
+        id: Le32::from(vfd_id),
+        flags: Le32::from(flags),
+        pfn: Le64::from(pfn),
+        size: Le32::from(size),
+    };
+
+    desc_mem.get_ref(0)?.store(ctrl_vfd_new);
+    Ok(size_of::<CtrlVfdNew>() as u32)
+}
+
+#[cfg(feature = "wl-dmabuf")]
+fn encode_vfd_new_dmabuf(
+    desc_mem: VolatileSlice,
+    vfd_id: u32,
+    flags: u32,
+    pfn: u64,
+    size: u32,
+    desc: GpuMemoryDesc,
+) -> WlResult<u32> {
+    let ctrl_vfd_new_dmabuf = CtrlVfdNewDmabuf {
+        hdr: CtrlHeader {
+            type_: Le32::from(VIRTIO_WL_RESP_VFD_NEW_DMABUF),
+            flags: Le32::from(0),
+        },
+        id: Le32::from(vfd_id),
+        flags: Le32::from(flags),
+        pfn: Le64::from(pfn),
+        size: Le32::from(size),
+        width: Le32::from(0),
+        height: Le32::from(0),
+        format: Le32::from(0),
+        stride0: Le32::from(desc.planes[0].stride),
+        stride1: Le32::from(desc.planes[1].stride),
+        stride2: Le32::from(desc.planes[2].stride),
+        offset0: Le32::from(desc.planes[0].offset),
+        offset1: Le32::from(desc.planes[1].offset),
+        offset2: Le32::from(desc.planes[2].offset),
+    };
+
+    desc_mem.get_ref(0)?.store(ctrl_vfd_new_dmabuf);
+    Ok(size_of::<CtrlVfdNewDmabuf>() as u32)
+}
+
+fn encode_vfd_recv(
+    desc_mem: VolatileSlice,
+    vfd_id: u32,
+    data: &[u8],
+    vfd_ids: &[u32],
+) -> WlResult<u32> {
+    let ctrl_vfd_recv = CtrlVfdRecv {
+        hdr: CtrlHeader {
+            type_: Le32::from(VIRTIO_WL_CMD_VFD_RECV),
+            flags: Le32::from(0),
+        },
+        id: Le32::from(vfd_id),
+        vfd_count: Le32::from(vfd_ids.len() as u32),
+    };
+    desc_mem.get_ref(0)?.store(ctrl_vfd_recv);
+
+    let vfd_slice = desc_mem.get_slice(
+        size_of::<CtrlVfdRecv>() as u64,
+        (vfd_ids.len() * size_of::<Le32>()) as u64,
+    )?;
+    for (i, &recv_vfd_id) in vfd_ids.iter().enumerate() {
+        vfd_slice
+            .get_ref((size_of::<Le32>() * i) as u64)?
+            .store(recv_vfd_id);
+    }
+
+    let data_slice = desc_mem.get_slice(
+        (size_of::<CtrlVfdRecv>() + vfd_ids.len() * size_of::<Le32>()) as u64,
+        data.len() as u64,
+    )?;
+    data_slice.copy_from(data);
+
+    Ok((size_of::<CtrlVfdRecv>() + vfd_ids.len() * size_of::<Le32>() + data.len()) as u32)
+}
+
+fn encode_vfd_hup(desc_mem: VolatileSlice, vfd_id: u32) -> WlResult<u32> {
+    let ctrl_vfd_new = CtrlVfd {
+        hdr: CtrlHeader {
+            type_: Le32::from(VIRTIO_WL_CMD_VFD_HUP),
+            flags: Le32::from(0),
+        },
+        id: Le32::from(vfd_id),
+    };
+
+    desc_mem.get_ref(0)?.store(ctrl_vfd_new);
+    Ok(size_of_val(&ctrl_vfd_new) as u32)
+}
+
+fn encode_resp(desc_mem: VolatileSlice, resp: WlResp) -> WlResult<u32> {
+    match resp {
+        WlResp::VfdNew {
+            id,
+            flags,
+            pfn,
+            size,
+            resp,
+        } => encode_vfd_new(desc_mem, resp, id, flags, pfn, size),
+        #[cfg(feature = "wl-dmabuf")]
+        WlResp::VfdNewDmabuf {
+            id,
+            flags,
+            pfn,
+            size,
+            desc,
+        } => encode_vfd_new_dmabuf(desc_mem, id, flags, pfn, size, desc),
+        WlResp::VfdRecv { id, data, vfds } => encode_vfd_recv(desc_mem, id, data, vfds),
+        WlResp::VfdHup { id } => encode_vfd_hup(desc_mem, id),
+        r => {
+            desc_mem.get_ref(0)?.store(Le32::from(r.get_code()));
+            Ok(size_of::<Le32>() as u32)
+        }
+    }
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+enum WlError {
+    NewAlloc(Error),
+    NewPipe(Error),
+    AllocSetSize(Error),
+    SocketConnect(io::Error),
+    SocketNonBlock(io::Error),
+    VmControl(MsgError),
+    VmBadResponse,
+    CheckedOffset,
+    GuestMemory(GuestMemoryError),
+    VolatileMemory(VolatileMemoryError),
+    SendVfd(Error),
+    WritePipe(io::Error),
+    RecvVfd(Error),
+    ReadPipe(io::Error),
+    PollContextAdd(Error),
+    DmabufSync(io::Error),
+}
+
+impl Display for WlError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::WlError::*;
+
+        match self {
+            NewAlloc(e) => write!(f, "failed to create shared memory allocation: {}", e),
+            NewPipe(e) => write!(f, "failed to create pipe: {}", e),
+            AllocSetSize(e) => write!(f, "failed to set size of shared memory: {}", e),
+            SocketConnect(e) => write!(f, "failed to connect socket: {}", e),
+            SocketNonBlock(e) => write!(f, "failed to set socket as non-blocking: {}", e),
+            VmControl(e) => write!(f, "failed to control parent VM: {}", e),
+            VmBadResponse => write!(f, "invalid response from parent VM"),
+            CheckedOffset => write!(f, "overflow in calculation"),
+            GuestMemory(e) => write!(f, "access violation in guest memory: {}", e),
+            VolatileMemory(e) => write!(f, "access violating in guest volatile memory: {}", e),
+            SendVfd(e) => write!(f, "failed to send on a socket: {}", e),
+            WritePipe(e) => write!(f, "failed to write to a pipe: {}", e),
+            RecvVfd(e) => write!(f, "failed to recv on a socket: {}", e),
+            ReadPipe(e) => write!(f, "failed to read a pipe: {}", e),
+            PollContextAdd(e) => write!(f, "failed to listen to FD on poll context: {}", e),
+            DmabufSync(e) => write!(f, "failed to synchronize DMABuf access: {}", e),
+        }
+    }
+}
+
+impl std::error::Error for WlError {}
+
+type WlResult<T> = result::Result<T, WlError>;
+
+impl From<GuestMemoryError> for WlError {
+    fn from(e: GuestMemoryError) -> WlError {
+        WlError::GuestMemory(e)
+    }
+}
+
+impl From<VolatileMemoryError> for WlError {
+    fn from(e: VolatileMemoryError) -> WlError {
+        WlError::VolatileMemory(e)
+    }
+}
+
+#[derive(Clone)]
+struct VmRequester {
+    inner: Rc<RefCell<VmMemoryControlRequestSocket>>,
+}
+
+impl VmRequester {
+    fn new(vm_socket: VmMemoryControlRequestSocket) -> VmRequester {
+        VmRequester {
+            inner: Rc::new(RefCell::new(vm_socket)),
+        }
+    }
+
+    fn request(&self, request: VmMemoryRequest) -> WlResult<VmMemoryResponse> {
+        let mut inner = self.inner.borrow_mut();
+        let vm_socket = &mut *inner;
+        vm_socket.send(&request).map_err(WlError::VmControl)?;
+        vm_socket.recv().map_err(WlError::VmControl)
+    }
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct CtrlHeader {
+    type_: Le32,
+    flags: Le32,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct CtrlVfdNew {
+    hdr: CtrlHeader,
+    id: Le32,
+    flags: Le32,
+    pfn: Le64,
+    size: Le32,
+}
+
+unsafe impl DataInit for CtrlVfdNew {}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+#[cfg(feature = "wl-dmabuf")]
+struct CtrlVfdNewDmabuf {
+    hdr: CtrlHeader,
+    id: Le32,
+    flags: Le32,
+    pfn: Le64,
+    size: Le32,
+    width: Le32,
+    height: Le32,
+    format: Le32,
+    stride0: Le32,
+    stride1: Le32,
+    stride2: Le32,
+    offset0: Le32,
+    offset1: Le32,
+    offset2: Le32,
+}
+
+#[cfg(feature = "wl-dmabuf")]
+unsafe impl DataInit for CtrlVfdNewDmabuf {}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct CtrlVfdRecv {
+    hdr: CtrlHeader,
+    id: Le32,
+    vfd_count: Le32,
+}
+
+unsafe impl DataInit for CtrlVfdRecv {}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct CtrlVfd {
+    hdr: CtrlHeader,
+    id: Le32,
+}
+
+unsafe impl DataInit for CtrlVfd {}
+
+#[repr(C)]
+#[derive(Copy, Clone, Default)]
+struct CtrlVfdSendVfd {
+    kind: Le32,
+    id: Le32,
+}
+
+unsafe impl DataInit for CtrlVfdSendVfd {}
+
+#[derive(Debug)]
+enum WlOp {
+    NewAlloc {
+        id: u32,
+        flags: u32,
+        size: u32,
+    },
+    Close {
+        id: u32,
+    },
+    Send {
+        id: u32,
+        foreign_id: bool,
+        vfds_addr: GuestAddress,
+        vfd_count: u32,
+        data_addr: GuestAddress,
+        data_len: u32,
+    },
+    NewCtx {
+        id: u32,
+    },
+    NewPipe {
+        id: u32,
+        flags: u32,
+    },
+    #[cfg(feature = "wl-dmabuf")]
+    NewDmabuf {
+        id: u32,
+        width: u32,
+        height: u32,
+        format: u32,
+    },
+    #[cfg(feature = "wl-dmabuf")]
+    DmabufSync {
+        id: u32,
+        flags: u32,
+    },
+    InvalidCommand {
+        op_type: u32,
+    },
+}
+
+#[derive(Debug)]
+#[allow(dead_code)]
+enum WlResp<'a> {
+    Ok,
+    VfdNew {
+        id: u32,
+        flags: u32,
+        pfn: u64,
+        size: u32,
+        // The VfdNew variant can be either a response or a command depending on this `resp`. This
+        // is important for the `get_code` method.
+        resp: bool,
+    },
+    #[cfg(feature = "wl-dmabuf")]
+    VfdNewDmabuf {
+        id: u32,
+        flags: u32,
+        pfn: u64,
+        size: u32,
+        desc: GpuMemoryDesc,
+    },
+    VfdRecv {
+        id: u32,
+        data: &'a [u8],
+        vfds: &'a [u32],
+    },
+    VfdHup {
+        id: u32,
+    },
+    Err(Box<dyn StdError>),
+    OutOfMemory,
+    InvalidId,
+    InvalidType,
+    InvalidFlags,
+    InvalidCommand,
+}
+
+impl<'a> WlResp<'a> {
+    fn get_code(&self) -> u32 {
+        match *self {
+            WlResp::Ok => VIRTIO_WL_RESP_OK,
+            WlResp::VfdNew { resp, .. } => {
+                if resp {
+                    VIRTIO_WL_RESP_VFD_NEW
+                } else {
+                    VIRTIO_WL_CMD_VFD_NEW
+                }
+            }
+            #[cfg(feature = "wl-dmabuf")]
+            WlResp::VfdNewDmabuf { .. } => VIRTIO_WL_RESP_VFD_NEW_DMABUF,
+            WlResp::VfdRecv { .. } => VIRTIO_WL_CMD_VFD_RECV,
+            WlResp::VfdHup { .. } => VIRTIO_WL_CMD_VFD_HUP,
+            WlResp::Err(_) => VIRTIO_WL_RESP_ERR,
+            WlResp::OutOfMemory => VIRTIO_WL_RESP_OUT_OF_MEMORY,
+            WlResp::InvalidId => VIRTIO_WL_RESP_INVALID_ID,
+            WlResp::InvalidType => VIRTIO_WL_RESP_INVALID_TYPE,
+            WlResp::InvalidFlags => VIRTIO_WL_RESP_INVALID_FLAGS,
+            WlResp::InvalidCommand => VIRTIO_WL_RESP_INVALID_CMD,
+        }
+    }
+}
+
+#[derive(Default)]
+struct WlVfd {
+    socket: Option<UnixStream>,
+    guest_shared_memory: Option<(u64 /* size */, File)>,
+    remote_pipe: Option<File>,
+    local_pipe: Option<(u32 /* flags */, File)>,
+    slot: Option<(u32 /* slot */, u64 /* pfn */, VmRequester)>,
+    #[cfg(feature = "wl-dmabuf")]
+    is_dmabuf: bool,
+}
+
+impl fmt::Debug for WlVfd {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "WlVfd {{")?;
+        if let Some(s) = &self.socket {
+            write!(f, " socket: {}", s.as_raw_fd())?;
+        }
+        if let Some((slot, pfn, _)) = &self.slot {
+            write!(f, " slot: {} pfn: {}", slot, pfn)?;
+        }
+        if let Some(s) = &self.remote_pipe {
+            write!(f, " remote: {}", s.as_raw_fd())?;
+        }
+        if let Some((_, s)) = &self.local_pipe {
+            write!(f, " local: {}", s.as_raw_fd())?;
+        }
+        write!(f, " }}")
+    }
+}
+
+impl WlVfd {
+    fn connect<P: AsRef<Path>>(path: P) -> WlResult<WlVfd> {
+        let socket = UnixStream::connect(path).map_err(WlError::SocketConnect)?;
+        socket
+            .set_nonblocking(true)
+            .map_err(WlError::SocketNonBlock)?;
+        let mut vfd = WlVfd::default();
+        vfd.socket = Some(socket);
+        Ok(vfd)
+    }
+
+    fn allocate(vm: VmRequester, size: u64) -> WlResult<WlVfd> {
+        let size_page_aligned = round_up_to_page_size(size as usize) as u64;
+        let mut vfd_shm =
+            SharedMemory::new(Some(CStr::from_bytes_with_nul(b"virtwl_alloc\0").unwrap()))
+                .map_err(WlError::NewAlloc)?;
+        vfd_shm
+            .set_size(size_page_aligned)
+            .map_err(WlError::AllocSetSize)?;
+        let register_response = vm.request(VmMemoryRequest::RegisterMemory(
+            MaybeOwnedFd::Borrowed(vfd_shm.as_raw_fd()),
+            vfd_shm.size() as usize,
+        ))?;
+        match register_response {
+            VmMemoryResponse::RegisterMemory { pfn, slot } => {
+                let mut vfd = WlVfd::default();
+                vfd.guest_shared_memory = Some((vfd_shm.size(), vfd_shm.into()));
+                vfd.slot = Some((slot, pfn, vm));
+                Ok(vfd)
+            }
+            _ => Err(WlError::VmBadResponse),
+        }
+    }
+
+    #[cfg(feature = "wl-dmabuf")]
+    fn dmabuf(
+        vm: VmRequester,
+        width: u32,
+        height: u32,
+        format: u32,
+    ) -> WlResult<(WlVfd, GpuMemoryDesc)> {
+        let allocate_and_register_gpu_memory_response =
+            vm.request(VmMemoryRequest::AllocateAndRegisterGpuMemory {
+                width,
+                height,
+                format,
+            })?;
+        match allocate_and_register_gpu_memory_response {
+            VmMemoryResponse::AllocateAndRegisterGpuMemory {
+                fd,
+                pfn,
+                slot,
+                desc,
+            } => {
+                let mut vfd = WlVfd::default();
+                // Duplicate FD for shared memory instance.
+                let raw_fd = unsafe { File::from_raw_fd(dup(fd.as_raw_fd())) };
+                let vfd_shm = SharedMemory::from_raw_fd(raw_fd).map_err(WlError::NewAlloc)?;
+                vfd.guest_shared_memory = Some((vfd_shm.size(), vfd_shm.into()));
+                vfd.slot = Some((slot, pfn, vm));
+                vfd.is_dmabuf = true;
+                Ok((vfd, desc))
+            }
+            _ => Err(WlError::VmBadResponse),
+        }
+    }
+
+    #[cfg(feature = "wl-dmabuf")]
+    fn dmabuf_sync(&self, flags: u32) -> WlResult<()> {
+        if !self.is_dmabuf {
+            return Err(WlError::DmabufSync(io::Error::from_raw_os_error(EINVAL)));
+        }
+
+        match &self.guest_shared_memory {
+            Some((_, fd)) => {
+                let sync = dma_buf_sync {
+                    flags: flags as u64,
+                };
+                // Safe as fd is a valid dmabuf and incorrect flags will return an error.
+                if unsafe { ioctl_with_ref(fd, DMA_BUF_IOCTL_SYNC(), &sync) } < 0 {
+                    Err(WlError::DmabufSync(io::Error::last_os_error()))
+                } else {
+                    Ok(())
+                }
+            }
+            None => Err(WlError::DmabufSync(io::Error::from_raw_os_error(EBADF))),
+        }
+    }
+
+    fn pipe_remote_read_local_write() -> WlResult<WlVfd> {
+        let (read_pipe, write_pipe) = pipe(true).map_err(WlError::NewPipe)?;
+        let mut vfd = WlVfd::default();
+        vfd.remote_pipe = Some(read_pipe);
+        vfd.local_pipe = Some((VIRTIO_WL_VFD_WRITE, write_pipe));
+        Ok(vfd)
+    }
+
+    fn pipe_remote_write_local_read() -> WlResult<WlVfd> {
+        let (read_pipe, write_pipe) = pipe(true).map_err(WlError::NewPipe)?;
+        let mut vfd = WlVfd::default();
+        vfd.remote_pipe = Some(write_pipe);
+        vfd.local_pipe = Some((VIRTIO_WL_VFD_READ, read_pipe));
+        Ok(vfd)
+    }
+
+    fn from_file(vm: VmRequester, mut fd: File) -> WlResult<WlVfd> {
+        // We need to determine if the given file is more like shared memory or a pipe/socket. A
+        // quick and easy check is to seek to the end of the file. If it works we assume it's not a
+        // pipe/socket because those have no end. We can even use that seek location as an indicator
+        // for how big the shared memory chunk to map into guest memory is. If seeking to the end
+        // fails, we assume it's a socket or pipe with read/write semantics.
+        match fd.seek(SeekFrom::End(0)) {
+            Ok(fd_size) => {
+                let size = round_up_to_page_size(fd_size as usize) as u64;
+                let register_response = vm.request(VmMemoryRequest::RegisterMemory(
+                    MaybeOwnedFd::Borrowed(fd.as_raw_fd()),
+                    size as usize,
+                ))?;
+
+                match register_response {
+                    VmMemoryResponse::RegisterMemory { pfn, slot } => {
+                        let mut vfd = WlVfd::default();
+                        vfd.guest_shared_memory = Some((size, fd));
+                        vfd.slot = Some((slot, pfn, vm));
+                        Ok(vfd)
+                    }
+                    _ => Err(WlError::VmBadResponse),
+                }
+            }
+            _ => {
+                let flags = match FileFlags::from_file(&fd) {
+                    Ok(FileFlags::Read) => VIRTIO_WL_VFD_READ,
+                    Ok(FileFlags::Write) => VIRTIO_WL_VFD_WRITE,
+                    Ok(FileFlags::ReadWrite) => VIRTIO_WL_VFD_READ | VIRTIO_WL_VFD_WRITE,
+                    _ => 0,
+                };
+                let mut vfd = WlVfd::default();
+                vfd.local_pipe = Some((flags, fd));
+                Ok(vfd)
+            }
+        }
+    }
+
+    fn flags(&self, use_transition_flags: bool) -> u32 {
+        let mut flags = 0;
+        if use_transition_flags {
+            if self.socket.is_some() {
+                flags |= VIRTIO_WL_VFD_WRITE | VIRTIO_WL_VFD_READ;
+            }
+            if let Some((f, _)) = self.local_pipe {
+                flags |= f;
+            }
+        } else {
+            if self.socket.is_some() {
+                flags |= VIRTIO_WL_VFD_CONTROL;
+            }
+            if self.slot.is_some() {
+                flags |= VIRTIO_WL_VFD_WRITE | VIRTIO_WL_VFD_MAP
+            }
+        }
+        flags
+    }
+
+    // Page frame number in the guest this VFD was mapped at.
+    fn pfn(&self) -> Option<u64> {
+        self.slot.as_ref().map(|s| s.1)
+    }
+
+    // Size in bytes of the shared memory VFD.
+    fn size(&self) -> Option<u64> {
+        self.guest_shared_memory.as_ref().map(|&(size, _)| size)
+    }
+
+    // The FD that gets sent if this VFD is sent over a socket.
+    fn send_fd(&self) -> Option<RawFd> {
+        self.guest_shared_memory
+            .as_ref()
+            .map(|(_, fd)| fd.as_raw_fd())
+            .or(self.socket.as_ref().map(|s| s.as_raw_fd()))
+            .or(self.remote_pipe.as_ref().map(|p| p.as_raw_fd()))
+    }
+
+    // The FD that is used for polling for events on this VFD.
+    fn poll_fd(&self) -> Option<&dyn AsRawFd> {
+        self.socket
+            .as_ref()
+            .map(|s| s as &dyn AsRawFd)
+            .or(self.local_pipe.as_ref().map(|(_, p)| p as &dyn AsRawFd))
+    }
+
+    // Sends data/files from the guest to the host over this VFD.
+    fn send(&mut self, fds: &[RawFd], data: VolatileSlice) -> WlResult<WlResp> {
+        if let Some(socket) = &self.socket {
+            socket.send_with_fds(data, fds).map_err(WlError::SendVfd)?;
+            Ok(WlResp::Ok)
+        } else if let Some((_, local_pipe)) = &mut self.local_pipe {
+            // Impossible to send fds over a simple pipe.
+            if !fds.is_empty() {
+                return Ok(WlResp::InvalidType);
+            }
+            local_pipe
+                .write_volatile(data)
+                .map_err(WlError::WritePipe)?;
+            Ok(WlResp::Ok)
+        } else {
+            Ok(WlResp::InvalidType)
+        }
+    }
+
+    // Receives data/files from the host for this VFD and queues it for the guest.
+    fn recv(&mut self, in_file_queue: &mut Vec<File>) -> WlResult<Vec<u8>> {
+        if let Some(socket) = self.socket.take() {
+            let mut buf = vec![0; IN_BUFFER_LEN];
+            let mut fd_buf = [0; VIRTWL_SEND_MAX_ALLOCS];
+            // If any errors happen, the socket will get dropped, preventing more reading.
+            let (len, file_count) = socket
+                .recv_with_fds(&mut buf[..], &mut fd_buf)
+                .map_err(WlError::RecvVfd)?;
+            // If any data gets read, the put the socket back for future recv operations.
+            if len != 0 || file_count != 0 {
+                buf.truncate(len);
+                buf.shrink_to_fit();
+                self.socket = Some(socket);
+                // Safe because the first file_counts fds from recv_with_fds are owned by us and
+                // valid.
+                in_file_queue.extend(
+                    fd_buf[..file_count]
+                        .iter()
+                        .map(|&fd| unsafe { File::from_raw_fd(fd) }),
+                );
+                return Ok(buf);
+            }
+            Ok(Vec::new())
+        } else if let Some((flags, mut local_pipe)) = self.local_pipe.take() {
+            let mut buf = Vec::new();
+            buf.resize(IN_BUFFER_LEN, 0);
+            let len = local_pipe.read(&mut buf[..]).map_err(WlError::ReadPipe)?;
+            if len != 0 {
+                buf.truncate(len);
+                buf.shrink_to_fit();
+                self.local_pipe = Some((flags, local_pipe));
+                return Ok(buf);
+            }
+            Ok(Vec::new())
+        } else {
+            Ok(Vec::new())
+        }
+    }
+
+    // Called after this VFD is sent over a socket to ensure the local end of the VFD receives hang
+    // up events.
+    fn close_remote(&mut self) {
+        self.remote_pipe = None;
+    }
+
+    fn close(&mut self) -> WlResult<()> {
+        if let Some((slot, _, vm)) = self.slot.take() {
+            vm.request(VmMemoryRequest::UnregisterMemory(slot))?;
+        }
+        self.socket = None;
+        self.remote_pipe = None;
+        self.local_pipe = None;
+        Ok(())
+    }
+}
+
+impl Drop for WlVfd {
+    fn drop(&mut self) {
+        let _ = self.close();
+    }
+}
+
+#[derive(Debug)]
+enum WlRecv {
+    Vfd { id: u32 },
+    Data { buf: Vec<u8> },
+    Hup,
+}
+
+struct WlState {
+    wayland_path: PathBuf,
+    vm: VmRequester,
+    resource_bridge: Option<ResourceRequestSocket>,
+    use_transition_flags: bool,
+    poll_ctx: PollContext<u32>,
+    vfds: Map<u32, WlVfd>,
+    next_vfd_id: u32,
+    in_file_queue: Vec<File>,
+    in_queue: VecDeque<(u32 /* vfd_id */, WlRecv)>,
+    current_recv_vfd: Option<u32>,
+    recv_vfds: Vec<u32>,
+}
+
+impl WlState {
+    fn new(
+        wayland_path: PathBuf,
+        vm_socket: VmMemoryControlRequestSocket,
+        use_transition_flags: bool,
+        resource_bridge: Option<ResourceRequestSocket>,
+    ) -> WlState {
+        WlState {
+            wayland_path,
+            vm: VmRequester::new(vm_socket),
+            resource_bridge,
+            poll_ctx: PollContext::new().expect("failed to create PollContext"),
+            use_transition_flags,
+            vfds: Map::new(),
+            next_vfd_id: NEXT_VFD_ID_BASE,
+            in_file_queue: Vec::new(),
+            in_queue: VecDeque::new(),
+            current_recv_vfd: None,
+            recv_vfds: Vec::new(),
+        }
+    }
+
+    fn new_pipe(&mut self, id: u32, flags: u32) -> WlResult<WlResp> {
+        if id & VFD_ID_HOST_MASK != 0 {
+            return Ok(WlResp::InvalidId);
+        }
+
+        if flags & !(VIRTIO_WL_VFD_WRITE | VIRTIO_WL_VFD_READ) != 0 {
+            return Ok(WlResp::InvalidFlags);
+        }
+
+        if flags & VIRTIO_WL_VFD_WRITE != 0 && flags & VIRTIO_WL_VFD_READ != 0 {
+            return Ok(WlResp::InvalidFlags);
+        }
+
+        match self.vfds.entry(id) {
+            Entry::Vacant(entry) => {
+                let vfd = if flags & VIRTIO_WL_VFD_WRITE != 0 {
+                    WlVfd::pipe_remote_read_local_write()?
+                } else if flags & VIRTIO_WL_VFD_READ != 0 {
+                    WlVfd::pipe_remote_write_local_read()?
+                } else {
+                    return Ok(WlResp::InvalidFlags);
+                };
+                self.poll_ctx
+                    .add(vfd.poll_fd().unwrap(), id)
+                    .map_err(WlError::PollContextAdd)?;
+                let resp = WlResp::VfdNew {
+                    id,
+                    flags: 0,
+                    pfn: 0,
+                    size: 0,
+                    resp: true,
+                };
+                entry.insert(vfd);
+                Ok(resp)
+            }
+            Entry::Occupied(_) => Ok(WlResp::InvalidId),
+        }
+    }
+
+    fn new_alloc(&mut self, id: u32, flags: u32, size: u32) -> WlResult<WlResp> {
+        if id & VFD_ID_HOST_MASK != 0 {
+            return Ok(WlResp::InvalidId);
+        }
+
+        if self.use_transition_flags {
+            if flags != 0 {
+                return Ok(WlResp::InvalidFlags);
+            }
+        } else if flags & !(VIRTIO_WL_VFD_WRITE | VIRTIO_WL_VFD_MAP) != 0 {
+            return Ok(WlResp::Err(Box::from("invalid flags")));
+        }
+
+        match self.vfds.entry(id) {
+            Entry::Vacant(entry) => {
+                let vfd = WlVfd::allocate(self.vm.clone(), size as u64)?;
+                let resp = WlResp::VfdNew {
+                    id,
+                    flags,
+                    pfn: vfd.pfn().unwrap_or_default(),
+                    size: vfd.size().unwrap_or_default() as u32,
+                    resp: true,
+                };
+                entry.insert(vfd);
+                Ok(resp)
+            }
+            Entry::Occupied(_) => Ok(WlResp::InvalidId),
+        }
+    }
+
+    #[cfg(feature = "wl-dmabuf")]
+    fn new_dmabuf(&mut self, id: u32, width: u32, height: u32, format: u32) -> WlResult<WlResp> {
+        if id & VFD_ID_HOST_MASK != 0 {
+            return Ok(WlResp::InvalidId);
+        }
+
+        match self.vfds.entry(id) {
+            Entry::Vacant(entry) => {
+                let (vfd, desc) = WlVfd::dmabuf(self.vm.clone(), width, height, format)?;
+                let resp = WlResp::VfdNewDmabuf {
+                    id,
+                    flags: 0,
+                    pfn: vfd.pfn().unwrap_or_default(),
+                    size: vfd.size().unwrap_or_default() as u32,
+                    desc,
+                };
+                entry.insert(vfd);
+                Ok(resp)
+            }
+            Entry::Occupied(_) => Ok(WlResp::InvalidId),
+        }
+    }
+
+    #[cfg(feature = "wl-dmabuf")]
+    fn dmabuf_sync(&mut self, vfd_id: u32, flags: u32) -> WlResult<WlResp> {
+        if flags & !(VIRTIO_WL_VFD_DMABUF_SYNC_VALID_FLAG_MASK) != 0 {
+            return Ok(WlResp::InvalidFlags);
+        }
+
+        match self.vfds.get_mut(&vfd_id) {
+            Some(vfd) => {
+                vfd.dmabuf_sync(flags)?;
+                Ok(WlResp::Ok)
+            }
+            None => Ok(WlResp::InvalidId),
+        }
+    }
+
+    fn new_context(&mut self, id: u32) -> WlResult<WlResp> {
+        if id & VFD_ID_HOST_MASK != 0 {
+            return Ok(WlResp::InvalidId);
+        }
+
+        let flags = if self.use_transition_flags {
+            VIRTIO_WL_VFD_WRITE | VIRTIO_WL_VFD_READ
+        } else {
+            VIRTIO_WL_VFD_CONTROL
+        };
+
+        match self.vfds.entry(id) {
+            Entry::Vacant(entry) => {
+                let vfd = entry.insert(WlVfd::connect(&self.wayland_path)?);
+                self.poll_ctx
+                    .add(vfd.poll_fd().unwrap(), id)
+                    .map_err(WlError::PollContextAdd)?;
+                Ok(WlResp::VfdNew {
+                    id,
+                    flags,
+                    pfn: 0,
+                    size: 0,
+                    resp: true,
+                })
+            }
+            Entry::Occupied(_) => Ok(WlResp::InvalidId),
+        }
+    }
+
+    fn process_poll_context(&mut self) {
+        let events = match self.poll_ctx.wait_timeout(Duration::from_secs(0)) {
+            Ok(v) => v.to_owned(),
+            Err(e) => {
+                error!("failed polling for vfd evens: {}", e);
+                return;
+            }
+        };
+
+        for event in events.as_ref().iter_readable() {
+            if let Err(e) = self.recv(event.token()) {
+                error!("failed to recv from vfd: {}", e)
+            }
+        }
+
+        for event in events.as_ref().iter_hungup() {
+            if !event.readable() {
+                let vfd_id = event.token();
+                if let Some(fd) = self.vfds.get(&vfd_id).and_then(|vfd| vfd.poll_fd()) {
+                    if let Err(e) = self.poll_ctx.delete(fd) {
+                        warn!("failed to remove hungup vfd from poll context: {}", e);
+                    }
+                }
+                self.in_queue.push_back((vfd_id, WlRecv::Hup));
+            }
+        }
+    }
+
+    fn close(&mut self, vfd_id: u32) -> WlResult<WlResp> {
+        let mut to_delete = Set::new();
+        for (dest_vfd_id, q) in &self.in_queue {
+            if *dest_vfd_id == vfd_id {
+                if let WlRecv::Vfd { id } = q {
+                    to_delete.insert(*id);
+                }
+            }
+        }
+        for vfd_id in to_delete {
+            // Sorry sub-error, we can't have cascading errors leaving us in an inconsistent state.
+            let _ = self.close(vfd_id);
+        }
+        match self.vfds.remove(&vfd_id) {
+            Some(mut vfd) => {
+                self.in_queue.retain(|&(id, _)| id != vfd_id);
+                vfd.close()?;
+                Ok(WlResp::Ok)
+            }
+            None => Ok(WlResp::InvalidId),
+        }
+    }
+
+    fn send(
+        &mut self,
+        vfd_id: u32,
+        foreign_id: bool,
+        vfds: VolatileSlice,
+        data: VolatileSlice,
+    ) -> WlResult<WlResp> {
+        // First stage gathers and normalizes all id information from guest memory.
+        let mut send_vfd_ids = [CtrlVfdSendVfd::default(); VIRTWL_SEND_MAX_ALLOCS];
+        let vfd_count = if foreign_id {
+            vfds.copy_to(&mut send_vfd_ids[..]);
+            vfds.size() as usize / size_of::<CtrlVfdSendVfd>()
+        } else {
+            let vfd_count = vfds.size() as usize / size_of::<Le32>();
+            let mut vfd_ids = [Le32::from(0); VIRTWL_SEND_MAX_ALLOCS];
+            vfds.copy_to(&mut vfd_ids[..]);
+            send_vfd_ids[..vfd_count]
+                .iter_mut()
+                .zip(&vfd_ids[..vfd_count])
+                .for_each(|(send_vfd_id, &vfd_id)| {
+                    *send_vfd_id = CtrlVfdSendVfd {
+                        kind: Le32::from(VIRTIO_WL_CTRL_VFD_SEND_KIND_LOCAL),
+                        id: vfd_id,
+                    }
+                });
+            vfd_count
+        };
+
+        // Next stage collects corresponding file descriptors for each id.
+        let mut fds = [0; VIRTWL_SEND_MAX_ALLOCS];
+        #[cfg(feature = "gpu")]
+        let mut bridged_files = Vec::new();
+        for (&send_vfd_id, fd) in send_vfd_ids[..vfd_count].iter().zip(fds.iter_mut()) {
+            let id = send_vfd_id.id.to_native();
+            match send_vfd_id.kind.to_native() {
+                VIRTIO_WL_CTRL_VFD_SEND_KIND_LOCAL => match self.vfds.get(&id) {
+                    Some(vfd) => match vfd.send_fd() {
+                        Some(vfd_fd) => *fd = vfd_fd,
+                        None => return Ok(WlResp::InvalidType),
+                    },
+                    None => {
+                        warn!("attempt to send non-existant vfd 0x{:08x}", id);
+                        return Ok(WlResp::InvalidId);
+                    }
+                },
+                #[cfg(feature = "gpu")]
+                VIRTIO_WL_CTRL_VFD_SEND_KIND_VIRTGPU if self.resource_bridge.is_some() => {
+                    if let Err(e) = self
+                        .resource_bridge
+                        .as_ref()
+                        .unwrap()
+                        .send(&ResourceRequest::GetResource { id })
+                    {
+                        error!("error sending resource bridge request: {}", e);
+                        return Ok(WlResp::InvalidId);
+                    }
+                    match self.resource_bridge.as_ref().unwrap().recv() {
+                        Ok(ResourceResponse::Resource(bridged_file)) => {
+                            *fd = bridged_file.as_raw_fd();
+                            bridged_files.push(bridged_file);
+                        }
+                        Ok(ResourceResponse::Invalid) => {
+                            warn!("attempt to send non-existant gpu resource {}", id);
+                            return Ok(WlResp::InvalidId);
+                        }
+                        Err(e) => {
+                            error!("error receiving resource bridge response: {}", e);
+                            // If there was an error with the resource bridge, it can no longer be
+                            // trusted to continue to function.
+                            self.resource_bridge = None;
+                            return Ok(WlResp::InvalidId);
+                        }
+                    }
+                }
+                VIRTIO_WL_CTRL_VFD_SEND_KIND_VIRTGPU => {
+                    let _ = self.resource_bridge.as_ref();
+                    warn!("attempt to send foreign resource kind but feature is disabled");
+                }
+                kind => {
+                    warn!(
+                        "attempt to send unknown foreign resource kind: {} id: {:08x}",
+                        kind, id
+                    );
+                    return Ok(WlResp::InvalidId);
+                }
+            }
+        }
+
+        // Final stage sends file descriptors and data to the target vfd's socket.
+        match self.vfds.get_mut(&vfd_id) {
+            Some(vfd) => match vfd.send(&fds[..vfd_count], data)? {
+                WlResp::Ok => {}
+                _ => return Ok(WlResp::InvalidType),
+            },
+            None => return Ok(WlResp::InvalidId),
+        }
+        // The vfds with remote FDs need to be closed so that the local side can receive
+        // hangup events.
+        for &send_vfd_id in &send_vfd_ids[..vfd_count] {
+            if send_vfd_id.kind == VIRTIO_WL_CTRL_VFD_SEND_KIND_LOCAL {
+                if let Some(vfd) = self.vfds.get_mut(&send_vfd_id.id.into()) {
+                    vfd.close_remote();
+                }
+            }
+        }
+        Ok(WlResp::Ok)
+    }
+
+    fn recv(&mut self, vfd_id: u32) -> WlResult<()> {
+        let buf = match self.vfds.get_mut(&vfd_id) {
+            Some(vfd) => vfd.recv(&mut self.in_file_queue)?,
+            None => return Ok(()),
+        };
+        if self.in_file_queue.is_empty() && buf.is_empty() {
+            self.in_queue.push_back((vfd_id, WlRecv::Hup));
+            return Ok(());
+        }
+        for file in self.in_file_queue.drain(..) {
+            let vfd = WlVfd::from_file(self.vm.clone(), file)?;
+            if let Some(poll_fd) = vfd.poll_fd() {
+                self.poll_ctx
+                    .add(poll_fd, self.next_vfd_id)
+                    .map_err(WlError::PollContextAdd)?;
+            }
+            self.vfds.insert(self.next_vfd_id, vfd);
+            self.in_queue.push_back((
+                vfd_id,
+                WlRecv::Vfd {
+                    id: self.next_vfd_id,
+                },
+            ));
+            self.next_vfd_id += 1;
+        }
+        self.in_queue.push_back((vfd_id, WlRecv::Data { buf }));
+
+        Ok(())
+    }
+
+    fn execute(&mut self, mem: &GuestMemory, op: WlOp) -> WlResult<WlResp> {
+        match op {
+            WlOp::NewAlloc { id, flags, size } => self.new_alloc(id, flags, size),
+            WlOp::Close { id } => self.close(id),
+            WlOp::Send {
+                id,
+                foreign_id,
+                vfds_addr,
+                vfd_count,
+                data_addr,
+                data_len,
+            } => {
+                let vfd_size = if foreign_id {
+                    size_of::<CtrlVfdSendVfd>()
+                } else {
+                    size_of::<Le32>()
+                } as u32;
+                let vfd_mem = mem.get_slice(vfds_addr.0, (vfd_count * vfd_size) as u64)?;
+                let data_mem = mem.get_slice(data_addr.0, data_len as u64)?;
+                self.send(id, foreign_id, vfd_mem, data_mem)
+            }
+            WlOp::NewCtx { id } => self.new_context(id),
+            WlOp::NewPipe { id, flags } => self.new_pipe(id, flags),
+            #[cfg(feature = "wl-dmabuf")]
+            WlOp::NewDmabuf {
+                id,
+                width,
+                height,
+                format,
+            } => self.new_dmabuf(id, width, height, format),
+            #[cfg(feature = "wl-dmabuf")]
+            WlOp::DmabufSync { id, flags } => self.dmabuf_sync(id, flags),
+            WlOp::InvalidCommand { op_type } => {
+                warn!("unexpected command {}", op_type);
+                Ok(WlResp::InvalidCommand)
+            }
+        }
+    }
+
+    fn next_recv(&self) -> Option<WlResp> {
+        if let Some(q) = self.in_queue.front() {
+            match *q {
+                (vfd_id, WlRecv::Vfd { id }) => {
+                    if self.current_recv_vfd.is_none() || self.current_recv_vfd == Some(vfd_id) {
+                        match self.vfds.get(&id) {
+                            Some(vfd) => Some(WlResp::VfdNew {
+                                id,
+                                flags: vfd.flags(self.use_transition_flags),
+                                pfn: vfd.pfn().unwrap_or_default(),
+                                size: vfd.size().unwrap_or_default() as u32,
+                                resp: false,
+                            }),
+                            _ => Some(WlResp::VfdNew {
+                                id,
+                                flags: 0,
+                                pfn: 0,
+                                size: 0,
+                                resp: false,
+                            }),
+                        }
+                    } else {
+                        Some(WlResp::VfdRecv {
+                            id: self.current_recv_vfd.unwrap(),
+                            data: &[],
+                            vfds: &self.recv_vfds[..],
+                        })
+                    }
+                }
+                (vfd_id, WlRecv::Data { ref buf }) => {
+                    if self.current_recv_vfd.is_none() || self.current_recv_vfd == Some(vfd_id) {
+                        Some(WlResp::VfdRecv {
+                            id: vfd_id,
+                            data: &buf[..],
+                            vfds: &self.recv_vfds[..],
+                        })
+                    } else {
+                        Some(WlResp::VfdRecv {
+                            id: self.current_recv_vfd.unwrap(),
+                            data: &[],
+                            vfds: &self.recv_vfds[..],
+                        })
+                    }
+                }
+                (vfd_id, WlRecv::Hup) => Some(WlResp::VfdHup { id: vfd_id }),
+            }
+        } else {
+            None
+        }
+    }
+
+    fn pop_recv(&mut self) {
+        if let Some(q) = self.in_queue.front() {
+            match *q {
+                (vfd_id, WlRecv::Vfd { id }) => {
+                    if self.current_recv_vfd.is_none() || self.current_recv_vfd == Some(vfd_id) {
+                        self.recv_vfds.push(id);
+                        self.current_recv_vfd = Some(vfd_id);
+                    } else {
+                        self.recv_vfds.clear();
+                        self.current_recv_vfd = None;
+                        return;
+                    }
+                }
+                (vfd_id, WlRecv::Data { .. }) => {
+                    self.recv_vfds.clear();
+                    self.current_recv_vfd = None;
+                    if !(self.current_recv_vfd.is_none() || self.current_recv_vfd == Some(vfd_id)) {
+                        return;
+                    }
+                }
+                (_, WlRecv::Hup) => {
+                    self.recv_vfds.clear();
+                    self.current_recv_vfd = None;
+                }
+            }
+        }
+        self.in_queue.pop_front();
+    }
+}
+
+struct Worker {
+    mem: GuestMemory,
+    interrupt_evt: EventFd,
+    interrupt_resample_evt: EventFd,
+    interrupt_status: Arc<AtomicUsize>,
+    in_queue: Queue,
+    out_queue: Queue,
+    state: WlState,
+    in_desc_chains: VecDeque<(u16, GuestAddress, u32)>,
+}
+
+impl Worker {
+    fn new(
+        mem: GuestMemory,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        interrupt_status: Arc<AtomicUsize>,
+        in_queue: Queue,
+        out_queue: Queue,
+        wayland_path: PathBuf,
+        vm_socket: VmMemoryControlRequestSocket,
+        use_transition_flags: bool,
+        resource_bridge: Option<ResourceRequestSocket>,
+    ) -> Worker {
+        Worker {
+            mem,
+            interrupt_evt,
+            interrupt_resample_evt,
+            interrupt_status,
+            in_queue,
+            out_queue,
+            state: WlState::new(
+                wayland_path,
+                vm_socket,
+                use_transition_flags,
+                resource_bridge,
+            ),
+            in_desc_chains: VecDeque::with_capacity(QUEUE_SIZE as usize),
+        }
+    }
+
+    fn signal_used_queue(&self) {
+        self.interrupt_status
+            .fetch_or(INTERRUPT_STATUS_USED_RING as usize, Ordering::SeqCst);
+        let _ = self.interrupt_evt.write(1);
+    }
+
+    fn run(&mut self, mut queue_evts: Vec<EventFd>, kill_evt: EventFd) {
+        let in_queue_evt = queue_evts.remove(0);
+        let out_queue_evt = queue_evts.remove(0);
+        #[derive(PollToken)]
+        enum Token {
+            InQueue,
+            OutQueue,
+            Kill,
+            State,
+            InterruptResample,
+        }
+
+        let poll_ctx: PollContext<Token> = match PollContext::new()
+            .and_then(|pc| pc.add(&in_queue_evt, Token::InQueue).and(Ok(pc)))
+            .and_then(|pc| pc.add(&out_queue_evt, Token::OutQueue).and(Ok(pc)))
+            .and_then(|pc| pc.add(&kill_evt, Token::Kill).and(Ok(pc)))
+            .and_then(|pc| pc.add(&self.state.poll_ctx, Token::State).and(Ok(pc)))
+            .and_then(|pc| {
+                pc.add(&self.interrupt_resample_evt, Token::InterruptResample)
+                    .and(Ok(pc))
+            }) {
+            Ok(pc) => pc,
+            Err(e) => {
+                error!("failed creating PollContext: {}", e);
+                return;
+            }
+        };
+
+        'poll: loop {
+            let mut signal_used = false;
+            let events = match poll_ctx.wait() {
+                Ok(v) => v,
+                Err(e) => {
+                    error!("failed polling for events: {}", e);
+                    break;
+                }
+            };
+
+            for event in &events {
+                match event.token() {
+                    Token::InQueue => {
+                        let _ = in_queue_evt.read();
+                        // Used to buffer descriptor indexes that are invalid for our uses.
+                        let mut rejects = [0u16; QUEUE_SIZE as usize];
+                        let mut rejects_len = 0;
+                        let min_in_desc_len = (size_of::<CtrlVfdRecv>()
+                            + size_of::<Le32>() * VIRTWL_SEND_MAX_ALLOCS)
+                            as u32;
+                        self.in_desc_chains
+                            .extend(self.in_queue.iter(&self.mem).filter_map(|d| {
+                                if d.len >= min_in_desc_len && d.is_write_only() {
+                                    Some((d.index, d.addr, d.len))
+                                } else {
+                                    // Can not use queue.add_used directly because it's being borrowed
+                                    // for the iterator chain, so we buffer the descriptor index in
+                                    // rejects.
+                                    rejects[rejects_len] = d.index;
+                                    rejects_len += 1;
+                                    None
+                                }
+                            }));
+                        for &reject in &rejects[..rejects_len] {
+                            signal_used = true;
+                            self.in_queue.add_used(&self.mem, reject, 0);
+                        }
+                    }
+                    Token::OutQueue => {
+                        let _ = out_queue_evt.read();
+                        let min_resp_desc_len = size_of::<CtrlHeader>() as u32;
+                        while let Some(desc) = self.out_queue.pop(&self.mem) {
+                            // Expects that each descriptor chain is made of one "in" followed by
+                            // one "out" descriptor.
+                            if !desc.is_write_only() {
+                                if let Some(resp_desc) = desc.next_descriptor() {
+                                    if resp_desc.is_write_only()
+                                        && resp_desc.len >= min_resp_desc_len
+                                    {
+                                        let resp = match parse_desc(&desc, &self.mem) {
+                                            Ok(op) => match self.state.execute(&self.mem, op) {
+                                                Ok(r) => r,
+                                                Err(e) => WlResp::Err(Box::new(e)),
+                                            },
+                                            Err(e) => WlResp::Err(Box::new(e)),
+                                        };
+
+                                        let resp_mem = self
+                                            .mem
+                                            .get_slice(resp_desc.addr.0, resp_desc.len as u64)
+                                            .unwrap();
+                                        let used_len =
+                                            encode_resp(resp_mem, resp).unwrap_or_default();
+
+                                        self.out_queue.add_used(&self.mem, desc.index, used_len);
+                                        signal_used = true;
+                                    }
+                                }
+                            } else {
+                                // Chains that are unusable get sent straight back to the used
+                                // queue.
+                                self.out_queue.add_used(&self.mem, desc.index, 0);
+                                signal_used = true;
+                            }
+                        }
+                    }
+                    Token::Kill => break 'poll,
+                    Token::State => self.state.process_poll_context(),
+                    Token::InterruptResample => {
+                        let _ = self.interrupt_resample_evt.read();
+                        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
+                            self.interrupt_evt.write(1).unwrap();
+                        }
+                    }
+                }
+            }
+
+            // Because this loop should be retried after the in queue is usable or after one of the
+            // VFDs was read, we do it after the poll event responses.
+            while !self.in_desc_chains.is_empty() {
+                let mut should_pop = false;
+                if let Some(in_resp) = self.state.next_recv() {
+                    // self.in_desc_chains is not empty (checked by loop condition) so unwrap is
+                    // safe.
+                    let (index, addr, desc_len) = self.in_desc_chains.pop_front().unwrap();
+                    // This memory location is valid because it came from a queue which always
+                    // checks the descriptor memory locations.
+                    let desc_mem = self.mem.get_slice(addr.0, desc_len as u64).unwrap();
+                    let len = match encode_resp(desc_mem, in_resp) {
+                        Ok(len) => {
+                            should_pop = true;
+                            len
+                        }
+                        Err(e) => {
+                            error!("failed to encode response to descriptor chain: {}", e);
+                            0
+                        }
+                    };
+                    signal_used = true;
+                    self.in_queue.add_used(&self.mem, index, len);
+                } else {
+                    break;
+                }
+                if should_pop {
+                    self.state.pop_recv();
+                }
+            }
+
+            if signal_used {
+                self.signal_used_queue();
+            }
+        }
+    }
+}
+
+pub struct Wl {
+    kill_evt: Option<EventFd>,
+    wayland_path: PathBuf,
+    vm_socket: Option<VmMemoryControlRequestSocket>,
+    resource_bridge: Option<ResourceRequestSocket>,
+    use_transition_flags: bool,
+}
+
+impl Wl {
+    pub fn new<P: AsRef<Path>>(
+        wayland_path: P,
+        vm_socket: VmMemoryControlRequestSocket,
+        resource_bridge: Option<ResourceRequestSocket>,
+    ) -> Result<Wl> {
+        Ok(Wl {
+            kill_evt: None,
+            wayland_path: wayland_path.as_ref().to_owned(),
+            vm_socket: Some(vm_socket),
+            resource_bridge,
+            use_transition_flags: false,
+        })
+    }
+}
+
+impl Drop for Wl {
+    fn drop(&mut self) {
+        if let Some(kill_evt) = self.kill_evt.take() {
+            // Ignore the result because there is nothing we can do about it.
+            let _ = kill_evt.write(1);
+        }
+    }
+}
+
+impl VirtioDevice for Wl {
+    fn keep_fds(&self) -> Vec<RawFd> {
+        let mut keep_fds = Vec::new();
+
+        if let Some(vm_socket) = &self.vm_socket {
+            keep_fds.push(vm_socket.as_raw_fd());
+        }
+        if let Some(resource_bridge) = &self.resource_bridge {
+            keep_fds.push(resource_bridge.as_raw_fd());
+        }
+
+        keep_fds
+    }
+
+    fn device_type(&self) -> u32 {
+        TYPE_WL
+    }
+
+    fn queue_max_sizes(&self) -> &[u16] {
+        QUEUE_SIZES
+    }
+
+    fn features(&self) -> u64 {
+        1 << VIRTIO_WL_F_TRANS_FLAGS | 1 << VIRTIO_F_VERSION_1
+    }
+
+    fn ack_features(&mut self, value: u64) {
+        if value & (1 << VIRTIO_WL_F_TRANS_FLAGS) != 0 {
+            self.use_transition_flags = true;
+        }
+    }
+
+    fn activate(
+        &mut self,
+        mem: GuestMemory,
+        interrupt_evt: EventFd,
+        interrupt_resample_evt: EventFd,
+        status: Arc<AtomicUsize>,
+        mut queues: Vec<Queue>,
+        queue_evts: Vec<EventFd>,
+    ) {
+        if queues.len() != QUEUE_SIZES.len() || queue_evts.len() != QUEUE_SIZES.len() {
+            return;
+        }
+
+        let (self_kill_evt, kill_evt) = match EventFd::new().and_then(|e| Ok((e.try_clone()?, e))) {
+            Ok(v) => v,
+            Err(e) => {
+                error!("failed creating kill EventFd pair: {}", e);
+                return;
+            }
+        };
+        self.kill_evt = Some(self_kill_evt);
+
+        if let Some(vm_socket) = self.vm_socket.take() {
+            let wayland_path = self.wayland_path.clone();
+            let use_transition_flags = self.use_transition_flags;
+            let resource_bridge = self.resource_bridge.take();
+            let worker_result =
+                thread::Builder::new()
+                    .name("virtio_wl".to_string())
+                    .spawn(move || {
+                        Worker::new(
+                            mem,
+                            interrupt_evt,
+                            interrupt_resample_evt,
+                            status,
+                            queues.remove(0),
+                            queues.remove(0),
+                            wayland_path,
+                            vm_socket,
+                            use_transition_flags,
+                            resource_bridge,
+                        )
+                        .run(queue_evts, kill_evt);
+                    });
+
+            if let Err(e) = worker_result {
+                error!("failed to spawn virtio_wl worker: {}", e);
+                return;
+            }
+        }
+    }
+}
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000..dea2fc4
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,149 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+FROM debian:stretch
+LABEL description="Test crosvm using a command like the following: \
+docker run --privileged -v /dev/log:/dev/log -v <path to crosvm>:/platform/crosvm:ro <crosvm base image>"
+
+RUN apt-get update && apt-get install -y \
+    autoconf \
+    automake \
+    curl \
+    gcc \
+    g++ \
+    git \
+    libcap-dev \
+    libdbus-1-dev \
+    libdrm-dev \
+    libfdt-dev \
+    libegl1-mesa-dev \
+    libgl1-mesa-dev \
+    libgles1-mesa-dev \
+    libgles2-mesa-dev \
+    libssl1.0-dev \
+    libtool \
+    libusb-1.0-0-dev \
+    libwayland-dev \
+    make \
+    nasm \
+    ninja-build \
+    pkg-config \
+    protobuf-compiler \
+    python3
+
+ENV RUSTUP_HOME=/usr/local/rustup \
+    CARGO_HOME=/usr/local/cargo \
+    PATH=/usr/local/cargo/bin:$PATH \
+    RUST_VERSION=1.35.0 \
+    RUSTFLAGS='--cfg hermetic'
+
+# Debian usually has an old rust version in the repository. Instead of using that, we use rustup to
+# pull in a toolchain versions of our choosing.
+RUN curl -LO "https://static.rust-lang.org/rustup/archive/1.14.0/x86_64-unknown-linux-gnu/rustup-init" \
+    && echo "0077ff9c19f722e2be202698c037413099e1188c0c233c12a2297bf18e9ff6e7 *rustup-init" | sha256sum -c - \
+    && chmod +x rustup-init \
+    && ./rustup-init -y --no-modify-path --default-toolchain $RUST_VERSION \
+    && rustup component add rustfmt-preview \
+    && rm rustup-init \
+    && chmod -R a+w $RUSTUP_HOME $CARGO_HOME \
+    && rustup --version \
+    && cargo --version \
+    && rustc --version
+
+# Warms up the cargo registry cache for future cargo runs. Cargo will still update the cache using a
+# git pull, but it only needs to download files that were changed since this image was built.
+RUN cargo install thisiznotarealpackage -q || true
+
+# Used /scratch for building dependencies which are too new or don't exist on Debian stretch.
+WORKDIR /scratch
+
+# minijail does not exist in upstream linux distros.
+RUN git clone https://android.googlesource.com/platform/external/minijail \
+    && cd minijail \
+    && make -j$(nproc) \
+    && cp libminijail.so /usr/lib/x86_64-linux-gnu/
+
+# The gbm used by upstream linux distros is not compatible with crosvm, which must use Chrome OS's
+# minigbm.
+RUN dpkg --force-depends -r libgbm1
+RUN git clone https://chromium.googlesource.com/chromiumos/platform/minigbm \
+    && cd minigbm \
+    && sed 's/-Wall/-Wno-maybe-uninitialized/g' -i Makefile \
+    && make install -j$(nproc)
+
+# New libepoxy requires newer meson than is in Debian stretch.
+ARG MESON_COMMIT=master
+RUN git clone https://github.com/mesonbuild/meson \
+    && cd meson \
+    && git checkout $MESON_COMMIT \
+    && ln -s $PWD/meson.py /usr/bin/meson
+
+# New libepoxy has EGL_KHR_DEBUG entry points needed by crosvm.
+ARG LIBEPOXY_COMMIT=master
+RUN git clone https://github.com/anholt/libepoxy.git \
+    && cd libepoxy \
+    && git checkout $LIBEPOXY_COMMIT \
+    && mkdir build \
+    && cd build \
+    && meson \
+    && ninja install
+
+# virglrenderer is under heavy development on master and we want the very latest.
+RUN git clone https://gitlab.freedesktop.org/virgl/virglrenderer.git \
+    && cd virglrenderer \
+    && ./autogen.sh \
+    && make install -j$(nproc)
+
+# Install libtpm2 so that tpm2-sys/build.rs does not try to build it in place in
+# the read-only source directory.
+ARG TPM2_COMMIT=master
+RUN git clone https://chromium.googlesource.com/chromiumos/third_party/tpm2 \
+    && cd tpm2 \
+    && git checkout $TPM2_COMMIT \
+    && make -j$(nproc) \
+    && cp build/libtpm2.a /lib
+
+# Install librendernodehost
+ARG PLATFORM2_COMMIT=master
+RUN git clone https://chromium.googlesource.com/chromiumos/platform2 \
+    && cd platform2 \
+    && git checkout $PLATFORM2_COMMIT \
+    && cd rendernodehost \
+    && gcc -c src.c -o src.o \
+    && ar rcs librendernodehost.a src.o \
+    && cp librendernodehost.a /lib
+
+# Set up sysroot from which system_api proto files are built.
+ENV SYSROOT=/sysroot
+RUN mkdir -p $SYSROOT/usr/include/chromeos/dbus/trunks \
+    && cp platform2/trunks/interface.proto \
+        $SYSROOT/usr/include/chromeos/dbus/trunks
+
+# Inform pkg-config where libraries we install are placed.
+COPY pkgconfig/* /usr/lib/pkgconfig
+
+# Reduces image size and prevents accidentally using /scratch files
+RUN rm -r /scratch /usr/bin/meson
+
+# The manual installation of shared objects requires an ld.so.cache refresh.
+RUN ldconfig
+
+# Pull down repositories that crosvm depends on to cros checkout-like locations.
+ENV CROS_ROOT=/
+ENV THIRD_PARTY_ROOT=$CROS_ROOT/third_party
+RUN mkdir -p $THIRD_PARTY_ROOT
+ENV PLATFORM_ROOT=$CROS_ROOT/platform
+RUN mkdir -p $PLATFORM_ROOT
+
+# Pull the cras library for audio access.
+ARG ADHD_COMMIT=master
+RUN git clone https://chromium.googlesource.com/chromiumos/third_party/adhd $THIRD_PARTY_ROOT/adhd \
+    && cd $THIRD_PARTY_ROOT/adhd \
+    && git checkout $ADHD_COMMIT
+
+# The /build directory is used so that the bind mounted /platform/crosvm volume
+# does not get scribbled on.
+ENV CARGO_TARGET_DIR=/build
+RUN mkdir -p $CARGO_TARGET_DIR
+WORKDIR /platform/crosvm
diff --git a/docker/Dockerfile.crosvm b/docker/Dockerfile.crosvm
new file mode 100644
index 0000000..3a7f293
--- /dev/null
+++ b/docker/Dockerfile.crosvm
@@ -0,0 +1,16 @@
+FROM crosvm-base
+
+COPY . /platform/crosvm
+
+RUN cargo install --features 'default-no-sandbox wl-dmabuf gpu' --path . --root /usr
+
+ARG UID=1000
+ARG GID=1000
+
+RUN export uid=$UID gid=$GID && \
+    mkdir -p /home/chronos && \
+    echo "chronos:x:${uid}:${gid}:Developer,,,:/home/chronos:/bin/bash" >> /etc/passwd && \
+    echo "chronos:x:${uid}:" >> /etc/group && \
+    chown ${uid}:${gid} -R /home/chronos
+
+ENTRYPOINT ["crosvm"]
diff --git a/docker/README.md b/docker/README.md
new file mode 100644
index 0000000..df38448
--- /dev/null
+++ b/docker/README.md
@@ -0,0 +1,47 @@
+# Docker for Building/Running crosvm
+
+This module contains various pieces of Docker infrastructure for supporting crosvm outside of Chrome
+OS environments. This includes the kokoro build environment.
+
+[TOC]
+
+## Introduction
+
+Ordinarily, crosvm is built using the standard `cargo build` command inside of a Chrome OS chroot.
+The chroot requirement is there because of various path dependencies in the crosvm `Cargo.toml` are
+targeted to paths outside of the crosvm repo itself. If one were to checkout crosvm in isolation,
+`cargo build` would be inadequate, failing with an error related to these missing paths.
+Additionally, crosvm depends on native packages that are not ordinarily available from an OS package
+manager (e.g. minijail) or have been forked in the Chrome OS project in an incompatible fashion
+(libusb).
+
+## `crosvm-base` Docker Image
+
+To support building crosvm outside of a Chrome OS chroot, this modules contains a `Dockerfile` that
+is used to build the `crosvm-base` docker image. Part of that image build process is downloading
+various repos, checking out pinned commits (specified in `checkout_commits.env`), and installing
+them. For the path dependencies in the `Cargo.toml`, the `Dockerfile` downloads and places the
+source code in the correct spot relative to the crosvm source repository. The `crosvm-base` build
+step stops short of actually building crosvm. It doesn't even have the source code for crosvm. The
+intent here is to use `crosvm-base` for building and running any version of crosvm.
+
+To build the `crosvm-base` image, run `build_crosvm_base.sh`. The script will automatically use the
+checkouts from `checkout_commits.env` which can be reconfigured to point to any commit desired. To
+upgrade `checkout_commits.sh` to the HEAD of each remote master branch, run the
+`upgrade_checkout_commits.sh` script.
+
+## `crosvm` Docker Image
+
+After generating a `crosvm-base`, the system is ready to build crosvm into its own `crosvm` docker
+image. The resulting docker image will be capable of running VMs without fear of missing native
+dependencies. Run the `build_crosvm.sh` script to build crosvm into a docker image. Once that
+completes, use the `crosvm_wrapper.sh` script to run crosvm within the docker image. That script
+will pass the arguments given to it verbatim to crosvm. In addition, the current working directory
+is bind mounted into the container so that file paths passed to `crosvm_wrapper.sh` should work as
+long as they are relative paths to files contained in the working directory.
+
+## `smoke_test`
+
+There is a convenience wrapper for `smoke_test` that uses the `crosvm` docker image to execute
+all the tests. Run `wrapped_smoke_test.sh` after building `crosvm-base` docker image to run the
+`smoke_test` within docker.
diff --git a/docker/build_crosvm.sh b/docker/build_crosvm.sh
new file mode 100755
index 0000000..3c6d359
--- /dev/null
+++ b/docker/build_crosvm.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -ex
+cd "${0%/*}"
+
+src_root="$(realpath ..)"
+
+docker build -t crosvm -f Dockerfile.crosvm --build-arg UID --build-arg GID "${src_root}"
diff --git a/docker/build_crosvm_base.sh b/docker/build_crosvm_base.sh
new file mode 100755
index 0000000..2041384
--- /dev/null
+++ b/docker/build_crosvm_base.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -ex
+cd "${0%/*}"
+
+gen_build_args() {
+    for arg in $(cat ./checkout_commits.env); do
+        echo --build-arg "${arg}"
+    done
+}
+
+docker build $(gen_build_args) -t crosvm-base .
diff --git a/docker/checkout_commits.env b/docker/checkout_commits.env
new file mode 100644
index 0000000..6d77478
--- /dev/null
+++ b/docker/checkout_commits.env
@@ -0,0 +1,5 @@
+MESON_COMMIT=5a0fec13b6463f45f88860d67e8fb50f34c8d739
+LIBEPOXY_COMMIT=d536f78db81853b18ffc733af8a1474e9ca08950
+TPM2_COMMIT=1dba349a7b272071d613869adaaef7bd576ae0c2
+PLATFORM2_COMMIT=c08db1d4dc6d91230fe3820a736b7ebd2c6e901d
+ADHD_COMMIT=40a296cfff7b88f2c14701627cff4c233d94a975
diff --git a/docker/crosvm_wrapper.sh b/docker/crosvm_wrapper.sh
new file mode 100755
index 0000000..33891d6
--- /dev/null
+++ b/docker/crosvm_wrapper.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -ex
+cd "${0%/*}"
+
+exec docker run -it --rm \
+    --privileged \
+    -e DISPLAY=$DISPLAY -e XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR \
+    -v /dev/log:/dev/log \
+    -v /tmp/.X11-unix:/tmp/.X11-unix \
+    --volume "$PWD":/wd \
+    --workdir /wd \
+    crosvm \
+    "$@"
diff --git a/docker/pkgconfig/libtpm2.pc b/docker/pkgconfig/libtpm2.pc
new file mode 100644
index 0000000..c9ff8f0
--- /dev/null
+++ b/docker/pkgconfig/libtpm2.pc
@@ -0,0 +1,5 @@
+Name: tpm2
+Description: TPM simulator extracted from the TCG TPM 2.0 library specification
+Version: 2.0.0
+Requires.private: libcrypto
+Libs: -L/lib -ltpm2
diff --git a/docker/upgrade_checkout_commits.sh b/docker/upgrade_checkout_commits.sh
new file mode 100755
index 0000000..4a4d3e0
--- /dev/null
+++ b/docker/upgrade_checkout_commits.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+cd "${0%/*}"
+
+remotes=(
+    "https://github.com/mesonbuild/meson"
+    "https://github.com/anholt/libepoxy.git"
+    "https://chromium.googlesource.com/chromiumos/third_party/tpm2"
+    "https://chromium.googlesource.com/chromiumos/platform2"
+    "https://chromium.googlesource.com/chromiumos/third_party/adhd"
+)
+
+keys=(
+    "MESON_COMMIT"
+    "LIBEPOXY_COMMIT"
+    "TPM2_COMMIT"
+    "PLATFORM2_COMMIT"
+    "ADHD_COMMIT"
+)
+
+for (( i=0; i<${#remotes[*]}; ++i)); do
+    remote="${remotes[$i]}"
+    key="${keys[$i]}"
+    remote_chunk=$(git ls-remote --exit-code "${remote}" refs/heads/master)
+    commit=$(echo "${remote_chunk}" | cut -f 1 -)
+    echo $key=$commit
+done
diff --git a/docker/wrapped_smoke_test.sh b/docker/wrapped_smoke_test.sh
new file mode 100755
index 0000000..324ab7c
--- /dev/null
+++ b/docker/wrapped_smoke_test.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -ex
+cd "${0%/*}"
+
+src_root="$(realpath ..)"
+
+docker run \
+    --rm \
+    --privileged \
+    -e TEST_RUNNER_FLAGS='--format terse' \
+    -v /dev/log:/dev/log \
+    -v "${src_root}":/platform/crosvm:ro \
+    crosvm-base \
+    bin/smoke_test
+
diff --git a/enumn/Cargo.toml b/enumn/Cargo.toml
new file mode 100644
index 0000000..1708678
--- /dev/null
+++ b/enumn/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "enumn"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro2 = "0.4"
+quote = "0.6"
+syn = "0.15"
diff --git a/enumn/src/lib.rs b/enumn/src/lib.rs
new file mode 100644
index 0000000..7a04303
--- /dev/null
+++ b/enumn/src/lib.rs
@@ -0,0 +1,207 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Convert number to enum.
+//!
+//! This crate provides a derive macro to generate a function for converting a
+//! primitive integer into the corresponding variant of an enum.
+//!
+//! The generated function is named `n` and has the following signature:
+//!
+//! ```rust
+//! # const IGNORE: &str = stringify! {
+//! impl YourEnum {
+//!     pub fn n(value: Repr) -> Option<Self>;
+//! }
+//! # };
+//! ```
+//!
+//! where `Repr` is an integer type of the right size as described in more
+//! detail below.
+//!
+//! # Example
+//!
+//! ```rust
+//! use enumn::N;
+//!
+//! #[derive(PartialEq, Debug, N)]
+//! enum Status {
+//!     LegendaryTriumph,
+//!     QualifiedSuccess,
+//!     FortuitousRevival,
+//!     IndeterminateStalemate,
+//!     RecoverableSetback,
+//!     DireMisadventure,
+//!     AbjectFailure,
+//! }
+//!
+//! fn main() {
+//!     let s = Status::n(1);
+//!     assert_eq!(s, Some(Status::QualifiedSuccess));
+//!
+//!     let s = Status::n(9);
+//!     assert_eq!(s, None);
+//! }
+//! ```
+//!
+//! # Signature
+//!
+//! The generated signature depends on whether the enum has a `#[repr(..)]`
+//! attribute. If a `repr` is specified, the input to `n` will be required to be
+//! of that type.
+//!
+//! ```ignore
+//! use enumn::N;
+//!
+//! #[derive(N)]
+//! #[repr(u8)]
+//! enum E {
+//!     /* ... */
+//!     # IGNORE
+//! }
+//!
+//! // expands to:
+//! impl E {
+//!     pub fn n(value: u8) -> Option<Self> {
+//!         /* ... */
+//!         # unimplemented!()
+//!     }
+//! }
+//! ```
+//!
+//! On the other hand if no `repr` is specified then we get a signature that is
+//! generic over a variety of possible types.
+//!
+//! ```ignore
+//! # enum E {}
+//! #
+//! impl E {
+//!     pub fn n<REPR: Into<i64>>(value: REPR) -> Option<Self> {
+//!         /* ... */
+//!         # unimplemented!()
+//!     }
+//! }
+//! ```
+//!
+//! # Discriminants
+//!
+//! The conversion respects explictly specified enum discriminants. Consider
+//! this enum:
+//!
+//! ```rust
+//! use enumn::N;
+//!
+//! #[derive(N)]
+//! enum Letter {
+//!     A = 65,
+//!     B = 66,
+//! }
+//! ```
+//!
+//! Here `Letter::n(65)` would return `Some(Letter::A)`.
+
+#![recursion_limit = "128"]
+
+extern crate proc_macro;
+
+#[cfg(test)]
+mod tests;
+
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::parse::Error;
+use syn::{parse_macro_input, parse_quote, Data, DeriveInput, Fields, Meta, NestedMeta};
+
+fn testable_derive(input: DeriveInput) -> proc_macro2::TokenStream {
+    let variants = match input.data {
+        Data::Enum(data) => data.variants,
+        Data::Struct(_) | Data::Union(_) => panic!("input must be an enum"),
+    };
+
+    for variant in &variants {
+        match variant.fields {
+            Fields::Unit => {}
+            Fields::Named(_) | Fields::Unnamed(_) => {
+                let span = variant.ident.span();
+                let err = Error::new(span, "enumn: variant with data is not supported");
+                return err.to_compile_error();
+            }
+        }
+    }
+
+    // Parse repr attribute like #[repr(u16)].
+    let mut repr = None;
+    for attr in input.attrs {
+        if let Ok(Meta::List(list)) = attr.parse_meta() {
+            if list.ident == "repr" {
+                if let Some(NestedMeta::Meta(Meta::Word(word))) = list.nested.into_iter().next() {
+                    match word.to_string().as_str() {
+                        "u8" | "u16" | "u32" | "u64" | "u128" | "usize" | "i8" | "i16" | "i32"
+                        | "i64" | "i128" | "isize" => {
+                            repr = Some(word);
+                        }
+                        _ => {}
+                    }
+                }
+            }
+        }
+    }
+
+    let signature;
+    let value;
+    match &repr {
+        Some(repr) => {
+            signature = quote! {
+                fn n(value: #repr)
+            };
+            value = quote!(value);
+        }
+        None => {
+            repr = Some(parse_quote!(i64));
+            signature = quote! {
+                fn n<REPR: Into<i64>>(value: REPR)
+            };
+            value = quote! {
+                <REPR as Into<i64>>::into(value)
+            };
+        }
+    }
+
+    let ident = input.ident;
+    let declare_discriminants = variants.iter().map(|variant| {
+        let variant = &variant.ident;
+        quote! {
+            const #variant: #repr = #ident::#variant as #repr;
+        }
+    });
+    let match_discriminants = variants.iter().map(|variant| {
+        let variant = &variant.ident;
+        quote! {
+            discriminant::#variant => Some(#ident::#variant),
+        }
+    });
+
+    quote! {
+        #[allow(non_upper_case_globals)]
+        impl #ident {
+            pub #signature -> Option<Self> {
+                struct discriminant;
+                impl discriminant {
+                    #(#declare_discriminants)*
+                }
+                match #value {
+                    #(#match_discriminants)*
+                    _ => None,
+                }
+            }
+        }
+    }
+}
+
+#[proc_macro_derive(N)]
+pub fn derive(input: TokenStream) -> TokenStream {
+    let input = parse_macro_input!(input as DeriveInput);
+    let expanded = testable_derive(input);
+    TokenStream::from(expanded)
+}
diff --git a/enumn/src/tests.rs b/enumn/src/tests.rs
new file mode 100644
index 0000000..cf5dd42
--- /dev/null
+++ b/enumn/src/tests.rs
@@ -0,0 +1,71 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use quote::quote;
+use syn::{parse_quote, DeriveInput};
+
+#[test]
+fn test_repr() {
+    let input: DeriveInput = parse_quote! {
+        #[repr(u8)]
+        enum E {
+            A,
+            B,
+            C,
+        }
+    };
+    let actual = crate::testable_derive(input);
+    let expected = quote! {
+        #[allow(non_upper_case_globals)]
+        impl E {
+            pub fn n(value: u8) -> Option<Self> {
+                struct discriminant;
+                impl discriminant {
+                    const A: u8 = E::A as u8;
+                    const B: u8 = E::B as u8;
+                    const C: u8 = E::C as u8;
+                }
+                match value {
+                    discriminant::A => Some(E::A),
+                    discriminant::B => Some(E::B),
+                    discriminant::C => Some(E::C),
+                    _ => None,
+                }
+            }
+        }
+    };
+    assert_eq!(actual.to_string(), expected.to_string());
+}
+
+#[test]
+fn test_no_repr() {
+    let input: DeriveInput = parse_quote! {
+        enum E {
+            A,
+            B,
+            C,
+        }
+    };
+    let actual = crate::testable_derive(input);
+    let expected = quote! {
+        #[allow(non_upper_case_globals)]
+        impl E {
+            pub fn n<REPR: Into<i64>>(value: REPR) -> Option<Self> {
+                struct discriminant;
+                impl discriminant {
+                    const A: i64 = E::A as i64;
+                    const B: i64 = E::B as i64;
+                    const C: i64 = E::C as i64;
+                }
+                match <REPR as Into<i64>>::into(value) {
+                    discriminant::A => Some(E::A),
+                    discriminant::B => Some(E::B),
+                    discriminant::C => Some(E::C),
+                    _ => None,
+                }
+            }
+        }
+    };
+    assert_eq!(actual.to_string(), expected.to_string());
+}
diff --git a/fuzz/.gitignore b/fuzz/.gitignore
new file mode 100644
index 0000000..a092511
--- /dev/null
+++ b/fuzz/.gitignore
@@ -0,0 +1,3 @@
+target
+corpus
+artifacts
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
new file mode 100644
index 0000000..5e63344
--- /dev/null
+++ b/fuzz/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "crosvm-fuzz"
+version = "0.0.1"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+devices = { path = "../devices" }
+kernel_loader = { path = "../kernel_loader" }
+libc = "*"
+qcow = { path = "../qcow" }
+sys_util = { path = "../sys_util" }
+
+# Prevent this from interfering with workspaces
+[workspace]
+members = ["."]
+
+[[bin]]
+name = "crosvm_block_fuzzer"
+path = "block_fuzzer.rs"
+
+[[bin]]
+name = "crosvm_qcow_fuzzer"
+path = "qcow_fuzzer.rs"
+
+[[bin]]
+name = "crosvm_zimage_fuzzer"
+path = "zimage_fuzzer.rs"
diff --git a/fuzz/OWNERS b/fuzz/OWNERS
new file mode 100644
index 0000000..8c53fc5
--- /dev/null
+++ b/fuzz/OWNERS
@@ -0,0 +1 @@
+dgreid@chromium.org
diff --git a/fuzz/block_fuzzer.rs b/fuzz/block_fuzzer.rs
new file mode 100644
index 0000000..f315a87
--- /dev/null
+++ b/fuzz/block_fuzzer.rs
@@ -0,0 +1,117 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![no_main]
+
+use std::fs::File;
+use std::io::{Cursor, Read, Seek, SeekFrom};
+use std::mem::size_of;
+use std::os::unix::io::{AsRawFd, FromRawFd};
+use std::panic;
+use std::process;
+use std::slice;
+use std::sync::atomic::AtomicUsize;
+use std::sync::Arc;
+
+use devices::virtio::{Block, Queue, VirtioDevice};
+use sys_util::{EventFd, GuestAddress, GuestMemory, SharedMemory};
+
+const MEM_SIZE: u64 = 256 * 1024 * 1024;
+const DESC_SIZE: u64 = 16; // Bytes in one virtio descriptor.
+const QUEUE_SIZE: u16 = 16; // Max entries in the queue.
+const CMD_SIZE: usize = 16; // Bytes in the command.
+
+// Take the first 64 bits of data as an address and the next 64 bits as data to
+// store there. The rest of the data is used as a qcow image.
+#[export_name = "LLVMFuzzerTestOneInput"]
+pub fn test_one_input(data: *const u8, size: usize) -> i32 {
+    // We cannot unwind past ffi boundaries.
+    panic::catch_unwind(|| {
+        // Safe because the libfuzzer runtime will guarantee that `data` is at least
+        // `size` bytes long and that it will be valid for the lifetime of this
+        // function.
+        let bytes = unsafe { slice::from_raw_parts(data, size) };
+        let size_u64 = size_of::<u64>();
+        let mem = GuestMemory::new(&[(GuestAddress(0), MEM_SIZE)]).unwrap();
+
+        // The fuzz data is interpreted as:
+        // starting index 8 bytes
+        // command location 8 bytes
+        // command 16 bytes
+        // descriptors circular buffer 16 bytes * 3
+        if bytes.len() < 4 * size_u64 {
+            // Need an index to start.
+            return;
+        }
+
+        let mut data_image = Cursor::new(bytes);
+
+        let first_index = read_u64(&mut data_image);
+        if first_index > MEM_SIZE / DESC_SIZE {
+            return;
+        }
+        let first_offset = first_index * DESC_SIZE;
+        if first_offset as usize + size_u64 > bytes.len() {
+            return;
+        }
+
+        let command_addr = read_u64(&mut data_image);
+        if command_addr > MEM_SIZE - CMD_SIZE as u64 {
+            return;
+        }
+        if mem
+            .write_all_at_addr(
+                &bytes[2 * size_u64..(2 * size_u64) + CMD_SIZE],
+                GuestAddress(command_addr as u64),
+            )
+            .is_err()
+        {
+            return;
+        }
+
+        data_image.seek(SeekFrom::Start(first_offset)).unwrap();
+        let desc_table = read_u64(&mut data_image);
+
+        if mem
+            .write_all_at_addr(&bytes[32..], GuestAddress(desc_table as u64))
+            .is_err()
+        {
+            return;
+        }
+
+        let mut q = Queue::new(QUEUE_SIZE);
+        q.ready = true;
+        q.size = QUEUE_SIZE / 2;
+        q.max_size = QUEUE_SIZE;
+
+        let queue_evts: Vec<EventFd> = vec![EventFd::new().unwrap()];
+        let queue_fd = queue_evts[0].as_raw_fd();
+        let queue_evt = unsafe { EventFd::from_raw_fd(libc::dup(queue_fd)) };
+
+        let shm = SharedMemory::new(None).unwrap();
+        let disk_file: File = shm.into();
+        let mut block = Block::new(disk_file, false, None).unwrap();
+
+        block.activate(
+            mem,
+            EventFd::new().unwrap(),
+            EventFd::new().unwrap(),
+            Arc::new(AtomicUsize::new(0)),
+            vec![q],
+            queue_evts,
+        );
+
+        queue_evt.write(77).unwrap(); // Rings the doorbell, any byte will do.
+    })
+    .err()
+    .map(|_| process::abort());
+
+    0
+}
+
+fn read_u64<T: Read>(readable: &mut T) -> u64 {
+    let mut buf = [0u8; size_of::<u64>()];
+    readable.read_exact(&mut buf[..]).unwrap();
+    u64::from_le_bytes(buf)
+}
diff --git a/fuzz/qcow_fuzzer.rs b/fuzz/qcow_fuzzer.rs
new file mode 100644
index 0000000..e6175ff
--- /dev/null
+++ b/fuzz/qcow_fuzzer.rs
@@ -0,0 +1,54 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![no_main]
+
+use qcow::QcowFile;
+use sys_util::SharedMemory;
+
+use std::fs::File;
+use std::io::{Cursor, Read, Seek, SeekFrom, Write};
+use std::mem::size_of;
+use std::panic;
+use std::process;
+use std::slice;
+
+// Take the first 64 bits of data as an address and the next 64 bits as data to
+// store there. The rest of the data is used as a qcow image.
+#[export_name = "LLVMFuzzerTestOneInput"]
+pub fn test_one_input(data: *const u8, size: usize) -> i32 {
+    // We cannot unwind past ffi boundaries.
+    panic::catch_unwind(|| {
+        // Safe because the libfuzzer runtime will guarantee that `data` is at least
+        // `size` bytes long and that it will be valid for the lifetime of this
+        // function.
+        let bytes = unsafe { slice::from_raw_parts(data, size) };
+        if bytes.len() < 16 {
+            // Need an address and data, each are 8 bytes.
+            return;
+        }
+        let mut disk_image = Cursor::new(bytes);
+        let addr = read_u64(&mut disk_image);
+        let value = read_u64(&mut disk_image);
+        let shm = SharedMemory::new(None).unwrap();
+        let mut disk_file: File = shm.into();
+        disk_file.write_all(&bytes[16..]).unwrap();
+        disk_file.seek(SeekFrom::Start(0)).unwrap();
+        if let Ok(mut qcow) = QcowFile::from(disk_file) {
+            if qcow.seek(SeekFrom::Start(addr)).is_ok() {
+                let _ = qcow.write_all(&value.to_le_bytes());
+            }
+        }
+    })
+    .err()
+    .map(|_| process::abort());
+
+    0
+}
+
+fn read_u64<T: Read>(readable: &mut T) -> u64 {
+    let mut buf = [0u8; size_of::<u64>()];
+    readable.read_exact(&mut buf[..]).unwrap();
+    u64::from_le_bytes(buf)
+}
diff --git a/fuzz/zimage_fuzzer.rs b/fuzz/zimage_fuzzer.rs
new file mode 100644
index 0000000..f4aeb3f
--- /dev/null
+++ b/fuzz/zimage_fuzzer.rs
@@ -0,0 +1,40 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![no_main]
+
+use sys_util::{GuestAddress, GuestMemory, SharedMemory};
+
+use std::fs::File;
+use std::io::Write;
+use std::panic;
+use std::process;
+use std::slice;
+
+fn make_elf_bin(elf_bytes: &[u8]) -> File {
+    let mut shm = SharedMemory::new(None).expect("failed to create shared memory");
+    shm.set_size(elf_bytes.len() as u64)
+        .expect("failed to set shared memory size");
+    shm.write_all(elf_bytes)
+        .expect("failed to write elf to shared memoy");
+    shm.into()
+}
+
+#[export_name = "LLVMFuzzerTestOneInput"]
+pub fn test_one_input(data: *const u8, size: usize) -> i32 {
+    // We cannot unwind past ffi boundaries.
+    panic::catch_unwind(|| {
+        // Safe because the libfuzzer runtime will guarantee that `data` is at least
+        // `size` bytes long and that it will be valid for the lifetime of this
+        // function.
+        let bytes = unsafe { slice::from_raw_parts(data, size) };
+        let mut kimage = make_elf_bin(bytes);
+        let mem = GuestMemory::new(&[(GuestAddress(0), bytes.len() as u64 + 0x1000)]).unwrap();
+        let _ = kernel_loader::load_kernel(&mem, GuestAddress(0), &mut kimage);
+    })
+    .err()
+    .map(|_| process::abort());
+
+    0
+}
diff --git a/gpu_buffer/Cargo.toml b/gpu_buffer/Cargo.toml
new file mode 100644
index 0000000..553e608
--- /dev/null
+++ b/gpu_buffer/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "gpu_buffer"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+data_model = { path = "../data_model" }
+sys_util = { path = "../sys_util" }
diff --git a/gpu_buffer/src/drm_formats.rs b/gpu_buffer/src/drm_formats.rs
new file mode 100644
index 0000000..bad5646
--- /dev/null
+++ b/gpu_buffer/src/drm_formats.rs
@@ -0,0 +1,72 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![allow(dead_code)]
+
+pub const DRM_FORMAT_C8: [u8; 4] = [b'C', b'8', b' ', b' '];
+pub const DRM_FORMAT_R8: [u8; 4] = [b'R', b'8', b' ', b' '];
+pub const DRM_FORMAT_R16: [u8; 4] = [b'R', b'1', b'6', b' '];
+pub const DRM_FORMAT_RG88: [u8; 4] = [b'R', b'G', b'8', b'8'];
+pub const DRM_FORMAT_GR88: [u8; 4] = [b'G', b'R', b'8', b'8'];
+pub const DRM_FORMAT_RG1616: [u8; 4] = [b'R', b'G', b'3', b'2'];
+pub const DRM_FORMAT_GR1616: [u8; 4] = [b'G', b'R', b'3', b'2'];
+pub const DRM_FORMAT_RGB332: [u8; 4] = [b'R', b'G', b'B', b'8'];
+pub const DRM_FORMAT_BGR233: [u8; 4] = [b'B', b'G', b'R', b'8'];
+pub const DRM_FORMAT_XRGB4444: [u8; 4] = [b'X', b'R', b'1', b'2'];
+pub const DRM_FORMAT_XBGR4444: [u8; 4] = [b'X', b'B', b'1', b'2'];
+pub const DRM_FORMAT_RGBX4444: [u8; 4] = [b'R', b'X', b'1', b'2'];
+pub const DRM_FORMAT_BGRX4444: [u8; 4] = [b'B', b'X', b'1', b'2'];
+pub const DRM_FORMAT_ARGB4444: [u8; 4] = [b'A', b'R', b'1', b'2'];
+pub const DRM_FORMAT_ABGR4444: [u8; 4] = [b'A', b'B', b'1', b'2'];
+pub const DRM_FORMAT_RGBA4444: [u8; 4] = [b'R', b'A', b'1', b'2'];
+pub const DRM_FORMAT_BGRA4444: [u8; 4] = [b'B', b'A', b'1', b'2'];
+pub const DRM_FORMAT_XRGB1555: [u8; 4] = [b'X', b'R', b'1', b'5'];
+pub const DRM_FORMAT_XBGR1555: [u8; 4] = [b'X', b'B', b'1', b'5'];
+pub const DRM_FORMAT_RGBX5551: [u8; 4] = [b'R', b'X', b'1', b'5'];
+pub const DRM_FORMAT_BGRX5551: [u8; 4] = [b'B', b'X', b'1', b'5'];
+pub const DRM_FORMAT_ARGB1555: [u8; 4] = [b'A', b'R', b'1', b'5'];
+pub const DRM_FORMAT_ABGR1555: [u8; 4] = [b'A', b'B', b'1', b'5'];
+pub const DRM_FORMAT_RGBA5551: [u8; 4] = [b'R', b'A', b'1', b'5'];
+pub const DRM_FORMAT_BGRA5551: [u8; 4] = [b'B', b'A', b'1', b'5'];
+pub const DRM_FORMAT_RGB565: [u8; 4] = [b'R', b'G', b'1', b'6'];
+pub const DRM_FORMAT_BGR565: [u8; 4] = [b'B', b'G', b'1', b'6'];
+pub const DRM_FORMAT_RGB888: [u8; 4] = [b'R', b'G', b'2', b'4'];
+pub const DRM_FORMAT_BGR888: [u8; 4] = [b'B', b'G', b'2', b'4'];
+pub const DRM_FORMAT_XRGB8888: [u8; 4] = [b'X', b'R', b'2', b'4'];
+pub const DRM_FORMAT_XBGR8888: [u8; 4] = [b'X', b'B', b'2', b'4'];
+pub const DRM_FORMAT_RGBX8888: [u8; 4] = [b'R', b'X', b'2', b'4'];
+pub const DRM_FORMAT_BGRX8888: [u8; 4] = [b'B', b'X', b'2', b'4'];
+pub const DRM_FORMAT_ARGB8888: [u8; 4] = [b'A', b'R', b'2', b'4'];
+pub const DRM_FORMAT_ABGR8888: [u8; 4] = [b'A', b'B', b'2', b'4'];
+pub const DRM_FORMAT_RGBA8888: [u8; 4] = [b'R', b'A', b'2', b'4'];
+pub const DRM_FORMAT_BGRA8888: [u8; 4] = [b'B', b'A', b'2', b'4'];
+pub const DRM_FORMAT_XRGB2101010: [u8; 4] = [b'X', b'R', b'3', b'0'];
+pub const DRM_FORMAT_XBGR2101010: [u8; 4] = [b'X', b'B', b'3', b'0'];
+pub const DRM_FORMAT_RGBX1010102: [u8; 4] = [b'R', b'X', b'3', b'0'];
+pub const DRM_FORMAT_BGRX1010102: [u8; 4] = [b'B', b'X', b'3', b'0'];
+pub const DRM_FORMAT_ARGB2101010: [u8; 4] = [b'A', b'R', b'3', b'0'];
+pub const DRM_FORMAT_ABGR2101010: [u8; 4] = [b'A', b'B', b'3', b'0'];
+pub const DRM_FORMAT_RGBA1010102: [u8; 4] = [b'R', b'A', b'3', b'0'];
+pub const DRM_FORMAT_BGRA1010102: [u8; 4] = [b'B', b'A', b'3', b'0'];
+pub const DRM_FORMAT_YUYV: [u8; 4] = [b'Y', b'U', b'Y', b'V'];
+pub const DRM_FORMAT_YVYU: [u8; 4] = [b'Y', b'V', b'Y', b'U'];
+pub const DRM_FORMAT_UYVY: [u8; 4] = [b'U', b'Y', b'V', b'Y'];
+pub const DRM_FORMAT_VYUY: [u8; 4] = [b'V', b'Y', b'U', b'Y'];
+pub const DRM_FORMAT_AYUV: [u8; 4] = [b'A', b'Y', b'U', b'V'];
+pub const DRM_FORMAT_NV12: [u8; 4] = [b'N', b'V', b'1', b'2'];
+pub const DRM_FORMAT_NV21: [u8; 4] = [b'N', b'V', b'2', b'1'];
+pub const DRM_FORMAT_NV16: [u8; 4] = [b'N', b'V', b'1', b'6'];
+pub const DRM_FORMAT_NV61: [u8; 4] = [b'N', b'V', b'6', b'1'];
+pub const DRM_FORMAT_NV24: [u8; 4] = [b'N', b'V', b'2', b'4'];
+pub const DRM_FORMAT_NV42: [u8; 4] = [b'N', b'V', b'4', b'2'];
+pub const DRM_FORMAT_YUV410: [u8; 4] = [b'Y', b'U', b'V', b'9'];
+pub const DRM_FORMAT_YVU410: [u8; 4] = [b'Y', b'V', b'U', b'9'];
+pub const DRM_FORMAT_YUV411: [u8; 4] = [b'Y', b'U', b'1', b'1'];
+pub const DRM_FORMAT_YVU411: [u8; 4] = [b'Y', b'V', b'1', b'1'];
+pub const DRM_FORMAT_YUV420: [u8; 4] = [b'Y', b'U', b'1', b'2'];
+pub const DRM_FORMAT_YVU420: [u8; 4] = [b'Y', b'V', b'1', b'2'];
+pub const DRM_FORMAT_YUV422: [u8; 4] = [b'Y', b'U', b'1', b'6'];
+pub const DRM_FORMAT_YVU422: [u8; 4] = [b'Y', b'V', b'1', b'6'];
+pub const DRM_FORMAT_YUV444: [u8; 4] = [b'Y', b'U', b'2', b'4'];
+pub const DRM_FORMAT_YVU444: [u8; 4] = [b'Y', b'V', b'2', b'4'];
diff --git a/gpu_buffer/src/lib.rs b/gpu_buffer/src/lib.rs
new file mode 100644
index 0000000..16aae50
--- /dev/null
+++ b/gpu_buffer/src/lib.rs
@@ -0,0 +1,853 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! A crate for creating [DRM](https://en.wikipedia.org/wiki/Direct_Rendering_Manager) managed
+//! buffer objects. Such objects are useful for exporting as DMABUFs/prime FDs, texturing, render
+//! targets, memory mapping, and scanout.
+//!
+//! # Examples
+//!
+//! ```rust
+//! # use std::error::Error;
+//! # use std::fs::File;
+//! # use std::result::Result;
+//! # use gpu_buffer::*;
+//! # fn test() -> Result<(), Box<Error>> {
+//! let drm_card = File::open("/dev/dri/card0")?;
+//! let device = Device::new(drm_card).map_err(|_| "failed to create device")?;
+//! let bo = device
+//!     .create_buffer(1024,
+//!                    512,
+//!                    Format::new(b'X', b'R', b'2', b'4'),
+//!                    Flags::empty().use_scanout(true))
+//!     .map_err(|_| "failed to create buffer")?;
+//! assert_eq!(bo.width(), 1024);
+//! assert_eq!(bo.height(), 512);
+//! assert_eq!(bo.format(), Format::new(b'X', b'R', b'2', b'4'));
+//! assert_eq!(bo.num_planes(), 1);
+//! # Ok(())
+//! # }
+//! ```
+
+mod drm_formats;
+mod raw;
+pub mod rendernode;
+
+use std::cmp::min;
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::isize;
+use std::os::raw::c_void;
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::ptr::null_mut;
+use std::rc::Rc;
+use std::result::Result;
+
+use data_model::{VolatileMemory, VolatileMemoryError, VolatileSlice};
+
+use crate::drm_formats::*;
+use crate::raw::*;
+
+const MAP_FAILED: *mut c_void = (-1isize as *mut _);
+
+#[derive(Debug)]
+pub enum Error {
+    GbmFailed,
+    ExportFailed(sys_util::Error),
+    MapFailed,
+    UnknownFormat(Format),
+    CheckedArithmetic {
+        field1: (&'static str, usize),
+        field2: (&'static str, usize),
+        op: &'static str,
+    },
+    InvalidPrecondition {
+        field1: (&'static str, usize),
+        field2: (&'static str, usize),
+        op: &'static str,
+    },
+    Memcopy(VolatileMemoryError),
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            GbmFailed => write!(f, "internal GBM failure"),
+            ExportFailed(e) => write!(f, "export failed: {}", e),
+            MapFailed => write!(f, "map failed"),
+            CheckedArithmetic {
+                field1: (label1, value1),
+                field2: (label2, value2),
+                op,
+            } => write!(
+                f,
+                "arithmetic failed: {}({}) {} {}({})",
+                label1, value1, op, label2, value2
+            ),
+            InvalidPrecondition {
+                field1: (label1, value1),
+                field2: (label2, value2),
+                op,
+            } => write!(
+                f,
+                "invalid precondition: {}({}) {} {}({})",
+                label1, value1, op, label2, value2
+            ),
+            UnknownFormat(format) => write!(f, "unknown format {:?}", format),
+            Memcopy(e) => write!(f, "error copying memory: {}", e),
+        }
+    }
+}
+
+macro_rules! checked_arithmetic {
+    ($x:ident $op:ident $y:ident $op_name:expr) => {
+        $x.$op($y).ok_or_else(|| Error::CheckedArithmetic {
+            field1: (stringify!($x), $x as usize),
+            field2: (stringify!($y), $y as usize),
+            op: $op_name,
+        })
+    };
+    ($x:ident + $y:ident) => {
+        checked_arithmetic!($x checked_add $y "+")
+    };
+    ($x:ident - $y:ident) => {
+        checked_arithmetic!($x checked_sub $y "-")
+    };
+    ($x:ident * $y:ident) => {
+        checked_arithmetic!($x checked_mul $y "*")
+    };
+}
+
+macro_rules! checked_range {
+    ($x:expr; <= $y:expr) => {
+        if $x <= $y {
+            Ok(())
+        } else {
+            Err(Error::InvalidPrecondition {
+                field1: (stringify!($x), $x as usize),
+                field2: (stringify!($y), $y as usize),
+                op: "<=",
+            })
+        }
+    };
+    ($x:ident <= $y:ident) => {
+        check_range!($x; <= $y)
+    };
+}
+
+/// A [fourcc](https://en.wikipedia.org/wiki/FourCC) format identifier.
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub struct Format(u32);
+
+impl Format {
+    /// Constructs a format identifer using a fourcc byte sequence.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use gpu_buffer::Format;
+    ///
+    /// let format = Format::new(b'X', b'R', b'2', b'4');
+    /// println!("format: {:?}", format);
+    /// ```
+    #[inline(always)]
+    pub fn new(a: u8, b: u8, c: u8, d: u8) -> Format {
+        Format(a as u32 | (b as u32) << 8 | (c as u32) << 16 | (d as u32) << 24)
+    }
+
+    /// Returns the fourcc code as a sequence of bytes.
+    #[inline(always)]
+    pub fn to_bytes(&self) -> [u8; 4] {
+        let f = self.0;
+        [f as u8, (f >> 8) as u8, (f >> 16) as u8, (f >> 24) as u8]
+    }
+
+    /// Returns the number of bytes per pixel for the given plane, suitable for making copies
+    /// to/from the plane.
+    pub fn bytes_per_pixel(&self, plane: usize) -> Option<usize> {
+        let b = self.to_bytes();
+
+        // NV12 and NV21 have 2 planes with 1 byte per pixel.
+        if (b == DRM_FORMAT_NV12 || b == DRM_FORMAT_NV21) && plane < 2 {
+            return Some(1);
+        }
+
+        // YVU420 has 3 planes, all with the same 1 byte per pixel.
+        if b == DRM_FORMAT_YVU420 && plane < 3 {
+            return Some(1);
+        }
+
+        if plane != 0 {
+            return None;
+        }
+
+        let bpp = match self.to_bytes() {
+            DRM_FORMAT_BGR233 => 1,
+            DRM_FORMAT_C8 => 1,
+            DRM_FORMAT_R8 => 1,
+            DRM_FORMAT_RGB332 => 1,
+            DRM_FORMAT_ABGR1555 => 2,
+            DRM_FORMAT_ABGR4444 => 2,
+            DRM_FORMAT_ARGB1555 => 2,
+            DRM_FORMAT_ARGB4444 => 2,
+            DRM_FORMAT_BGR565 => 2,
+            DRM_FORMAT_BGRA4444 => 2,
+            DRM_FORMAT_BGRA5551 => 2,
+            DRM_FORMAT_BGRX4444 => 2,
+            DRM_FORMAT_BGRX5551 => 2,
+            DRM_FORMAT_GR88 => 2,
+            DRM_FORMAT_RG88 => 2,
+            DRM_FORMAT_RGB565 => 2,
+            DRM_FORMAT_RGBA4444 => 2,
+            DRM_FORMAT_RGBA5551 => 2,
+            DRM_FORMAT_RGBX4444 => 2,
+            DRM_FORMAT_RGBX5551 => 2,
+            DRM_FORMAT_UYVY => 2,
+            DRM_FORMAT_VYUY => 2,
+            DRM_FORMAT_XBGR1555 => 2,
+            DRM_FORMAT_XBGR4444 => 2,
+            DRM_FORMAT_XRGB1555 => 2,
+            DRM_FORMAT_XRGB4444 => 2,
+            DRM_FORMAT_YUYV => 2,
+            DRM_FORMAT_YVYU => 2,
+            DRM_FORMAT_BGR888 => 3,
+            DRM_FORMAT_RGB888 => 3,
+            DRM_FORMAT_ABGR2101010 => 4,
+            DRM_FORMAT_ABGR8888 => 4,
+            DRM_FORMAT_ARGB2101010 => 4,
+            DRM_FORMAT_ARGB8888 => 4,
+            DRM_FORMAT_AYUV => 4,
+            DRM_FORMAT_BGRA1010102 => 4,
+            DRM_FORMAT_BGRA8888 => 4,
+            DRM_FORMAT_BGRX1010102 => 4,
+            DRM_FORMAT_BGRX8888 => 4,
+            DRM_FORMAT_RGBA1010102 => 4,
+            DRM_FORMAT_RGBA8888 => 4,
+            DRM_FORMAT_RGBX1010102 => 4,
+            DRM_FORMAT_RGBX8888 => 4,
+            DRM_FORMAT_XBGR2101010 => 4,
+            DRM_FORMAT_XBGR8888 => 4,
+            DRM_FORMAT_XRGB2101010 => 4,
+            DRM_FORMAT_XRGB8888 => 4,
+            _ => return None,
+        };
+        Some(bpp)
+    }
+}
+
+impl From<u32> for Format {
+    fn from(u: u32) -> Format {
+        Format(u)
+    }
+}
+
+impl From<Format> for u32 {
+    fn from(f: Format) -> u32 {
+        f.0
+    }
+}
+
+impl fmt::Debug for Format {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let b = self.to_bytes();
+        if b.iter().all(u8::is_ascii_graphic) {
+            write!(
+                f,
+                "fourcc({}{}{}{})",
+                b[0] as char, b[1] as char, b[2] as char, b[3] as char
+            )
+        } else {
+            write!(
+                f,
+                "fourcc(0x{:02x}{:02x}{:02x}{:02x})",
+                b[0], b[1], b[2], b[3]
+            )
+        }
+    }
+}
+
+/// Usage flags for constructing a buffer object.
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub struct Flags(u32);
+
+impl Flags {
+    /// Returns empty set of flags.
+    #[inline(always)]
+    pub fn empty() -> Flags {
+        Flags(0)
+    }
+
+    /// Returns the given set of raw `GBM_BO` flags wrapped in a `Flags` struct.
+    #[inline(always)]
+    pub fn new(raw: u32) -> Flags {
+        Flags(raw)
+    }
+
+    /// Sets the scanout flag's presence
+    #[inline(always)]
+    pub fn use_scanout(self, e: bool) -> Flags {
+        if e {
+            Flags(self.0 | GBM_BO_USE_SCANOUT)
+        } else {
+            Flags(self.0 & !GBM_BO_USE_SCANOUT)
+        }
+    }
+
+    /// Sets the cursor flag's presence
+    #[inline(always)]
+    pub fn use_cursor(self, e: bool) -> Flags {
+        if e {
+            Flags(self.0 | GBM_BO_USE_CURSOR)
+        } else {
+            Flags(self.0 & !GBM_BO_USE_CURSOR)
+        }
+    }
+
+    /// Sets the cursor 64x64 flag's presence
+    #[inline(always)]
+    pub fn use_cursor64(self, e: bool) -> Flags {
+        if e {
+            Flags(self.0 | GBM_BO_USE_CURSOR_64X64)
+        } else {
+            Flags(self.0 & !GBM_BO_USE_CURSOR_64X64)
+        }
+    }
+
+    /// Sets the rendering flag's presence
+    #[inline(always)]
+    pub fn use_rendering(self, e: bool) -> Flags {
+        if e {
+            Flags(self.0 | GBM_BO_USE_RENDERING)
+        } else {
+            Flags(self.0 & !GBM_BO_USE_RENDERING)
+        }
+    }
+
+    /// Sets the linear flag's presence
+    #[inline(always)]
+    pub fn use_linear(self, e: bool) -> Flags {
+        if e {
+            Flags(self.0 | GBM_BO_USE_LINEAR)
+        } else {
+            Flags(self.0 & !GBM_BO_USE_LINEAR)
+        }
+    }
+
+    /// Sets the texturing flag's presence
+    #[inline(always)]
+    pub fn use_texturing(self, e: bool) -> Flags {
+        if e {
+            Flags(self.0 | GBM_BO_USE_TEXTURING)
+        } else {
+            Flags(self.0 & !GBM_BO_USE_TEXTURING)
+        }
+    }
+}
+
+struct DeviceInner {
+    _fd: File,
+    gbm: *mut gbm_device,
+}
+
+impl Drop for DeviceInner {
+    fn drop(self: &mut DeviceInner) {
+        // Safe because DeviceInner is only constructed with a valid gbm_device.
+        unsafe {
+            gbm_device_destroy(self.gbm);
+        }
+    }
+}
+
+/// A device capable of allocating `Buffer`.
+#[derive(Clone)]
+pub struct Device(Rc<DeviceInner>);
+
+impl Device {
+    /// Returns a new `Device` using the given `fd` opened from a device in `/dev/dri/`.
+    pub fn new(fd: File) -> Result<Device, ()> {
+        // gbm_create_device is safe to call with a valid fd, and we check that a valid one is
+        // returned. The FD is not of the appropriate kind (i.e. not a DRM device),
+        // gbm_create_device should reject it.
+        let gbm = unsafe { gbm_create_device(fd.as_raw_fd()) };
+        if gbm.is_null() {
+            Err(())
+        } else {
+            Ok(Device(Rc::new(DeviceInner { _fd: fd, gbm })))
+        }
+    }
+
+    /// Creates a new buffer with the given metadata.
+    pub fn create_buffer(
+        &self,
+        width: u32,
+        height: u32,
+        format: Format,
+        usage: Flags,
+    ) -> Result<Buffer, Error> {
+        // This is safe because only a valid gbm_device is used and the return value is checked.
+        let bo = unsafe { gbm_bo_create(self.0.gbm, width, height, format.0, usage.0) };
+        if bo.is_null() {
+            Err(Error::GbmFailed)
+        } else {
+            Ok(Buffer(bo, self.clone()))
+        }
+    }
+}
+
+/// An allocation from a `Device`.
+pub struct Buffer(*mut gbm_bo, Device);
+
+impl Buffer {
+    /// The device
+    pub fn device(&self) -> &Device {
+        &self.1
+    }
+
+    /// Width in pixels.
+    pub fn width(&self) -> u32 {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_width(self.0) }
+    }
+
+    /// Height in pixels.
+    pub fn height(&self) -> u32 {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_height(self.0) }
+    }
+
+    /// Length in bytes of one row of the buffer.
+    pub fn stride(&self) -> u32 {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_stride(self.0) }
+    }
+
+    /// Length in bytes of the stride or tiling.
+    pub fn stride_or_tiling(&self) -> u32 {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_stride_or_tiling(self.0) }
+    }
+
+    /// `Format` of the buffer.
+    pub fn format(&self) -> Format {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { Format(gbm_bo_get_format(self.0)) }
+    }
+
+    /// Format modifier flags for the buffer.
+    pub fn format_modifier(&self) -> u64 {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_modifier(self.0) }
+    }
+
+    /// Number of planes present in this buffer.
+    pub fn num_planes(&self) -> usize {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_plane_count(self.0) }
+    }
+
+    /// Handle as u64 for the given plane.
+    pub fn plane_handle(&self, plane: usize) -> u64 {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_handle_for_plane(self.0, plane).u64 }
+    }
+
+    /// Offset in bytes for the given plane.
+    pub fn plane_offset(&self, plane: usize) -> u32 {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_offset(self.0, plane) }
+    }
+
+    /// Length in bytes of one row for the given plane.
+    pub fn plane_stride(&self, plane: usize) -> u32 {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_stride_for_plane(self.0, plane) }
+    }
+
+    /// Size of a plane, in bytes.
+    pub fn plane_size(&self, plane: usize) -> u32 {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_plane_size(self.0, plane) }
+    }
+
+    /// Exports a new dmabuf/prime file descriptor for the given plane.
+    pub fn export_plane_fd(&self, plane: usize) -> Result<File, i32> {
+        // This is always safe to call with a valid gbm_bo pointer.
+        match unsafe { gbm_bo_get_plane_fd(self.0, plane) } {
+            fd if fd >= 0 => Ok(unsafe { File::from_raw_fd(fd) }),
+            ret => Err(ret),
+        }
+    }
+
+    fn map(
+        &self,
+        x: u32,
+        y: u32,
+        width: u32,
+        height: u32,
+        plane: usize,
+        flags: u32,
+    ) -> Result<BufferMapping, Error> {
+        checked_range!(checked_arithmetic!(x + width)?; <= self.width())?;
+        checked_range!(checked_arithmetic!(y + height)?; <= self.height())?;
+        checked_range!(plane; <= self.num_planes())?;
+
+        let bytes_per_pixel = self
+            .format()
+            .bytes_per_pixel(plane)
+            .ok_or(Error::UnknownFormat(self.format()))? as u32;
+
+        let mut stride = 0;
+        let mut map_data = null_mut();
+        // Safe because only a valid gbm_bo object is used and the return value is checked. Only
+        // pointers coerced from stack references are used for returned values, and we trust gbm to
+        // only write as many bytes as the size of the pointed to values.
+        let mapping = unsafe {
+            gbm_bo_map(
+                self.0,
+                x,
+                y,
+                width,
+                height,
+                flags,
+                &mut stride,
+                &mut map_data,
+                plane,
+            )
+        };
+        if mapping == MAP_FAILED {
+            return Err(Error::MapFailed);
+        }
+
+        // The size of returned slice is equal the size of a row in bytes multiplied by the height
+        // of the mapped region, subtracted by the offset into the first mapped row. The 'x' and
+        // 'y's in the below diagram of a 2D buffer are bytes in the mapping. The first 'y' is what
+        // the mapping points to in memory, and the '-'s are unmapped bytes of the buffer.
+        // |----------|
+        // |--stride--|
+        // |-----yyyyx| h
+        // |xxxxxyyyyx| e
+        // |xxxxxyyyyx| i
+        // |xxxxxyyyyx| g
+        // |xxxxxyyyyx| h
+        // |xxxxxyyyyx| t
+        // |----------|
+        let size = checked_arithmetic!(stride * height)?;
+        let x_offset_bytes = checked_arithmetic!(x * bytes_per_pixel)?;
+        let slice_size = checked_arithmetic!(size - x_offset_bytes)? as u64;
+
+        Ok(BufferMapping {
+            // Safe because the chunk of memory starting at mapping with size `slice_size` is valid
+            // and tied to the lifetime of `buffer_mapping`.
+            slice: unsafe { VolatileSlice::new(mapping as *mut u8, slice_size) },
+            stride,
+            map_data,
+            buffer: self,
+        })
+    }
+
+    /// Reads the given subsection of the buffer to `dst`.
+    pub fn read_to_volatile(
+        &self,
+        x: u32,
+        y: u32,
+        width: u32,
+        height: u32,
+        plane: usize,
+        dst: VolatileSlice,
+    ) -> Result<(), Error> {
+        if width == 0 || height == 0 {
+            return Ok(());
+        }
+
+        let mapping = self.map(x, y, width, height, plane, GBM_BO_TRANSFER_READ)?;
+
+        if x == 0 && width == self.width() {
+            mapping.as_volatile_slice().copy_to_volatile_slice(dst);
+        } else {
+            // This path is more complicated because there are gaps in the data between lines.
+            let width = width as u64;
+            let stride = mapping.stride() as u64;
+            let bytes_per_pixel = match self.format().bytes_per_pixel(plane) {
+                Some(bpp) => bpp as u64,
+                None => return Err(Error::UnknownFormat(self.format())),
+            };
+            let line_copy_size = checked_arithmetic!(width * bytes_per_pixel)?;
+            let src = mapping.as_volatile_slice();
+            for yy in 0..(height as u64) {
+                let line_offset = checked_arithmetic!(yy * stride)?;
+                let src_line = src
+                    .get_slice(line_offset, line_copy_size)
+                    .map_err(Error::Memcopy)?;
+                let dst_line = dst
+                    .get_slice(line_offset, line_copy_size)
+                    .map_err(Error::Memcopy)?;
+                src_line.copy_to_volatile_slice(dst_line);
+            }
+        }
+
+        Ok(())
+    }
+
+    /// Writes to the given subsection of the buffer from `sgs`.
+    pub fn write_from_sg<'a, S: Iterator<Item = VolatileSlice<'a>>>(
+        &self,
+        x: u32,
+        y: u32,
+        width: u32,
+        height: u32,
+        plane: usize,
+        src_offset: usize,
+        mut sgs: S,
+    ) -> Result<(), Error> {
+        if width == 0 || height == 0 {
+            return Ok(());
+        }
+
+        checked_range!(src_offset; <= isize::MAX as usize)?;
+
+        let mapping = self.map(x, y, width, height, plane, GBM_BO_TRANSFER_WRITE)?;
+        let mut dst_slice = mapping.as_volatile_slice();
+        let stride = mapping.stride() as u64;
+        let mut height = height as u64;
+        let mut src_offset = src_offset as u64;
+
+        if x == 0 && width == self.width() {
+            // This path is a simple copy from the scatter gather iterator to the buffer objection,
+            // with no gaps in the data.
+            let mut copy_size = checked_arithmetic!(stride * height)?;
+            for sg in sgs {
+                // Skip src_offset into this scatter gather item, or the entire thing if offset is
+                // larger.
+                let sg_size = match sg.size().checked_sub(src_offset) {
+                    Some(sg_remaining_size) => sg_remaining_size,
+                    None => {
+                        src_offset -= sg.size();
+                        continue;
+                    }
+                };
+                let copy_sg_size = min(sg_size, copy_size);
+                let src_slice = sg
+                    .get_slice(src_offset, copy_sg_size)
+                    .map_err(Error::Memcopy)?;
+                src_slice.copy_to_volatile_slice(dst_slice);
+
+                src_offset = 0;
+                dst_slice = dst_slice.offset(copy_sg_size).map_err(Error::Memcopy)?;
+                copy_size -= copy_sg_size;
+                if copy_size == 0 {
+                    break;
+                }
+            }
+        } else {
+            let width = width as u64;
+            // This path is more complicated because there are gaps in the data between lines.
+            let bytes_per_pixel = self.format().bytes_per_pixel(plane).unwrap_or(0) as u64;
+            let line_copy_size = checked_arithmetic!(width * bytes_per_pixel)?;
+            let line_end_skip = checked_arithmetic!(stride - line_copy_size)?;
+            let mut remaining_line_copy_size = line_copy_size;
+            let mut sg_opt = sgs.next();
+            while let Some(sg) = sg_opt {
+                // Skip src_offset into this scatter gather item, or the entire thing if offset is
+                // larger.
+                let sg_size = match sg.size().checked_sub(src_offset) {
+                    None | Some(0) => {
+                        src_offset -= sg.size();
+                        sg_opt = sgs.next();
+                        continue;
+                    }
+                    Some(sg_remaining_size) => sg_remaining_size,
+                };
+                let copy_sg_size = min(sg_size, remaining_line_copy_size);
+                let src_slice = sg
+                    .get_slice(src_offset, copy_sg_size)
+                    .map_err(Error::Memcopy)?;
+                src_slice.copy_to_volatile_slice(dst_slice);
+
+                src_offset += copy_sg_size;
+                dst_slice = dst_slice.offset(copy_sg_size).map_err(Error::Memcopy)?;
+                remaining_line_copy_size -= copy_sg_size;
+                if remaining_line_copy_size == 0 {
+                    remaining_line_copy_size = line_copy_size;
+                    height -= 1;
+                    if height == 0 {
+                        break;
+                    }
+
+                    src_offset += line_end_skip;
+                    dst_slice = dst_slice.offset(line_end_skip).map_err(Error::Memcopy)?;
+                }
+            }
+        }
+
+        Ok(())
+    }
+}
+
+impl Drop for Buffer {
+    fn drop(&mut self) {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_destroy(self.0) }
+    }
+}
+
+impl AsRawFd for Buffer {
+    fn as_raw_fd(&self) -> RawFd {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_fd(self.0) }
+    }
+}
+
+struct BufferMapping<'a> {
+    slice: VolatileSlice<'a>,
+    stride: u32,
+    map_data: *mut c_void,
+    buffer: &'a Buffer,
+}
+
+impl<'a> BufferMapping<'a> {
+    fn as_volatile_slice(&self) -> VolatileSlice {
+        self.slice
+    }
+
+    fn stride(&self) -> u32 {
+        self.stride
+    }
+}
+
+impl<'a> Drop for BufferMapping<'a> {
+    fn drop(&mut self) {
+        // safe because the gbm_bo is assumed to be valid and the map_data is the same one given by
+        // gbm_bo_map.
+        unsafe {
+            gbm_bo_unmap(self.buffer.0, self.map_data);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use data_model::VolatileMemory;
+    use std::fmt::Write;
+
+    #[test]
+    fn format_debug() {
+        let f = Format::new(b'X', b'R', b'2', b'4');
+        let mut buf = String::new();
+        write!(&mut buf, "{:?}", f).unwrap();
+        assert_eq!(buf, "fourcc(XR24)");
+
+        let f = Format::new(0, 1, 2, 16);
+        let mut buf = String::new();
+        write!(&mut buf, "{:?}", f).unwrap();
+        assert_eq!(buf, "fourcc(0x00010210)");
+    }
+
+    #[test]
+    fn format_bytes_per_pixel() {
+        let f = Format::new(b'X', b'R', b'2', b'4');
+        assert_eq!(f.bytes_per_pixel(0), Some(4));
+        assert_eq!(f.bytes_per_pixel(1), None);
+        let f = Format::new(b'N', b'V', b'1', b'2');
+        assert_eq!(f.bytes_per_pixel(0), Some(1));
+        assert_eq!(f.bytes_per_pixel(1), Some(1));
+        assert_eq!(f.bytes_per_pixel(2), None);
+        let f = Format::new(b'R', b'8', b' ', b' ');
+        assert_eq!(f.bytes_per_pixel(0), Some(1));
+        assert_eq!(f.bytes_per_pixel(1), None);
+        let f = Format::new(b'B', b'G', b'2', b'4');
+        assert_eq!(f.bytes_per_pixel(0), Some(3));
+        assert_eq!(f.bytes_per_pixel(1), None);
+        let f = Format::new(b'G', b'R', b'8', b'8');
+        assert_eq!(f.bytes_per_pixel(0), Some(2));
+        assert_eq!(f.bytes_per_pixel(1), None);
+        let f = Format::new(b'Z', b'A', b'C', b'H');
+        assert_eq!(f.bytes_per_pixel(0), None);
+    }
+
+    #[test]
+    #[ignore] // no access to /dev/dri
+    fn open_device() {
+        let drm_card = File::open("/dev/dri/card0").expect("failed to open card");
+        Device::new(drm_card).expect("failed to create device with card");
+    }
+
+    #[test]
+    #[ignore] // no access to /dev/dri
+    fn create_buffer() {
+        let drm_card = File::open("/dev/dri/card0").expect("failed to open card");
+        let device = Device::new(drm_card).expect("failed to create device with card");
+        let bo = device
+            .create_buffer(
+                1024,
+                512,
+                Format::new(b'X', b'R', b'2', b'4'),
+                Flags::empty().use_scanout(true),
+            )
+            .expect("failed to create buffer");
+
+        assert_eq!(bo.width(), 1024);
+        assert_eq!(bo.height(), 512);
+        assert_eq!(bo.format(), Format::new(b'X', b'R', b'2', b'4'));
+        assert_eq!(bo.num_planes(), 1);
+    }
+
+    #[test]
+    #[ignore] // no access to /dev/dri
+    fn export_buffer() {
+        let drm_card = File::open("/dev/dri/card0").expect("failed to open card");
+        let device = Device::new(drm_card).expect("failed to create device with card");
+        let bo = device
+            .create_buffer(
+                1024,
+                1024,
+                Format::new(b'X', b'R', b'2', b'4'),
+                Flags::empty().use_scanout(true),
+            )
+            .expect("failed to create buffer");
+        bo.export_plane_fd(0).expect("failed to export plane");
+    }
+
+    #[test]
+    #[ignore] // no access to /dev/dri
+    fn buffer_transfer() {
+        let drm_card = File::open("/dev/dri/card0").expect("failed to open card");
+        let device = Device::new(drm_card).expect("failed to create device with card");
+        let bo = device
+            .create_buffer(
+                1024,
+                1024,
+                Format::new(b'X', b'R', b'2', b'4'),
+                Flags::empty().use_scanout(true).use_linear(true),
+            )
+            .expect("failed to create buffer");
+        let mut dst: Vec<u8> = Vec::new();
+        dst.resize((bo.stride() * bo.height()) as usize, 0x4A);
+        let dst_len = dst.len() as u64;
+        bo.write_from_sg(
+            0,
+            0,
+            1024,
+            1024,
+            0,
+            0,
+            [dst.as_mut_slice().get_slice(0, dst_len).unwrap()]
+                .iter()
+                .cloned(),
+        )
+        .expect("failed to read bo");
+        bo.read_to_volatile(
+            0,
+            0,
+            1024,
+            1024,
+            0,
+            dst.as_mut_slice().get_slice(0, dst_len).unwrap(),
+        )
+        .expect("failed to read bo");
+        assert!(dst.iter().all(|&x| x == 0x4A));
+    }
+}
diff --git a/gpu_buffer/src/raw.rs b/gpu_buffer/src/raw.rs
new file mode 100644
index 0000000..b4255ca
--- /dev/null
+++ b/gpu_buffer/src/raw.rs
@@ -0,0 +1,215 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generated with bindgen --whitelist-function='gbm_.*' --whitelist-type='gbm_.*' minigbm/gbm.h
+// Hand-modified by zachr
+
+#![allow(dead_code)]
+
+use std::os::raw::{c_char, c_int, c_void};
+
+/// \file gbm.h
+/// \brief Generic Buffer Manager
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gbm_device {
+    _unused: [u8; 0],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gbm_bo {
+    _unused: [u8; 0],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gbm_surface {
+    _unused: [u8; 0],
+}
+/// Abstraction representing the handle to a buffer allocated by the
+/// manager
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union gbm_bo_handle {
+    pub ptr: *mut c_void,
+    pub s32: i32,
+    pub u32: u32,
+    pub s64: i64,
+    pub u64: u64,
+    _bindgen_union_align: u64,
+}
+
+/// Buffer is going to be presented to the screen using an API such as KMS
+pub const GBM_BO_USE_SCANOUT: gbm_bo_flags = 1;
+/// Buffer is going to be used as cursor
+pub const GBM_BO_USE_CURSOR: gbm_bo_flags = 2;
+/// Deprecated
+pub const GBM_BO_USE_CURSOR_64X64: gbm_bo_flags = 2;
+/// Buffer is to be used for rendering - for example it is going to be used
+/// as the storage for a color buffer
+pub const GBM_BO_USE_RENDERING: gbm_bo_flags = 4;
+/// Deprecated
+pub const GBM_BO_USE_WRITE: gbm_bo_flags = 8;
+/// Buffer is guaranteed to be laid out linearly in memory. That is, the
+/// buffer is laid out as an array with 'height' blocks, each block with
+/// length 'stride'. Each stride is in the same order as the rows of the
+/// buffer. This is intended to be used with buffers that will be accessed
+/// via dma-buf mmap().
+pub const GBM_BO_USE_LINEAR: gbm_bo_flags = 16;
+/// The buffer will be used as a texture that will be sampled from.
+pub const GBM_BO_USE_TEXTURING: gbm_bo_flags = 32;
+/// The buffer will be written to by a camera subsystem.
+pub const GBM_BO_USE_CAMERA_WRITE: gbm_bo_flags = 64;
+/// The buffer will be read from by a camera subsystem.
+pub const GBM_BO_USE_CAMERA_READ: gbm_bo_flags = 128;
+/// Buffer inaccessible to unprivileged users.
+pub const GBM_BO_USE_PROTECTED: gbm_bo_flags = 256;
+/// These flags specify the frequency of software access. These flags do not
+/// guarantee the buffer is linear, but do guarantee gbm_bo_map(..) will
+/// present a linear view.
+pub const GBM_BO_USE_SW_READ_OFTEN: gbm_bo_flags = 512;
+/// These flags specify the frequency of software access. These flags do not
+/// guarantee the buffer is linear, but do guarantee gbm_bo_map(..) will
+/// present a linear view.
+pub const GBM_BO_USE_SW_READ_RARELY: gbm_bo_flags = 1024;
+/// These flags specify the frequency of software access. These flags do not
+/// guarantee the buffer is linear, but do guarantee gbm_bo_map(..) will
+/// present a linear view.
+pub const GBM_BO_USE_SW_WRITE_OFTEN: gbm_bo_flags = 2048;
+/// These flags specify the frequency of software access. These flags do not
+/// guarantee the buffer is linear, but do guarantee gbm_bo_map(..) will
+/// present a linear view.
+pub const GBM_BO_USE_SW_WRITE_RARELY: gbm_bo_flags = 4096;
+/// Flags to indicate the intended use for the buffer - these are passed into
+/// gbm_bo_create(). The caller must set the union of all the flags that are
+/// appropriate
+///
+/// \sa Use gbm_device_is_format_supported() to check if the combination of format
+/// and use flags are supported
+#[allow(non_camel_case_types)]
+pub type gbm_bo_flags = u32;
+
+#[link(name = "gbm")]
+extern "C" {
+    pub fn gbm_device_get_fd(gbm: *mut gbm_device) -> c_int;
+    pub fn gbm_device_get_backend_name(gbm: *mut gbm_device) -> *const c_char;
+    pub fn gbm_device_is_format_supported(gbm: *mut gbm_device, format: u32, usage: u32) -> c_int;
+    pub fn gbm_device_destroy(gbm: *mut gbm_device);
+    pub fn gbm_create_device(fd: c_int) -> *mut gbm_device;
+    pub fn gbm_bo_create(
+        gbm: *mut gbm_device,
+        width: u32,
+        height: u32,
+        format: u32,
+        flags: u32,
+    ) -> *mut gbm_bo;
+    pub fn gbm_bo_create_with_modifiers(
+        gbm: *mut gbm_device,
+        width: u32,
+        height: u32,
+        format: u32,
+        modifiers: *const u64,
+        count: u32,
+    ) -> *mut gbm_bo;
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gbm_import_fd_data {
+    pub fd: c_int,
+    pub width: u32,
+    pub height: u32,
+    pub stride: u32,
+    pub format: u32,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gbm_import_fd_planar_data {
+    pub fds: [c_int; 4usize],
+    pub width: u32,
+    pub height: u32,
+    pub format: u32,
+    pub strides: [u32; 4usize],
+    pub offsets: [u32; 4usize],
+    pub format_modifiers: [u64; 4usize],
+}
+
+extern "C" {
+    pub fn gbm_bo_import(
+        gbm: *mut gbm_device,
+        type_: u32,
+        buffer: *mut c_void,
+        usage: u32,
+    ) -> *mut gbm_bo;
+}
+
+/// Buffer contents read back (or accessed directly) at transfer
+/// create time.
+pub const GBM_BO_TRANSFER_READ: gbm_bo_transfer_flags = 1;
+/// Buffer contents will be written back at unmap time
+/// (or modified as a result of being accessed directly).
+pub const GBM_BO_TRANSFER_WRITE: gbm_bo_transfer_flags = 2;
+/// Read/modify/write
+pub const GBM_BO_TRANSFER_READ_WRITE: gbm_bo_transfer_flags = 3;
+
+/// Flags to indicate the type of mapping for the buffer - these are
+/// passed into gbm_bo_map(). The caller must set the union of all the
+/// flags that are appropriate.
+///
+/// These flags are independent of the GBM_BO_USE_* creation flags. However,
+/// mapping the buffer may require copying to/from a staging buffer.
+///
+/// See also: pipe_transfer_usage
+#[allow(non_camel_case_types)]
+pub type gbm_bo_transfer_flags = u32;
+
+extern "C" {
+    pub fn gbm_bo_map(
+        bo: *mut gbm_bo,
+        x: u32,
+        y: u32,
+        width: u32,
+        height: u32,
+        flags: u32,
+        stride: *mut u32,
+        map_data: *mut *mut c_void,
+        plane: usize,
+    ) -> *mut c_void;
+    pub fn gbm_bo_unmap(bo: *mut gbm_bo, map_data: *mut c_void);
+    pub fn gbm_bo_get_width(bo: *mut gbm_bo) -> u32;
+    pub fn gbm_bo_get_height(bo: *mut gbm_bo) -> u32;
+    pub fn gbm_bo_get_stride(bo: *mut gbm_bo) -> u32;
+    pub fn gbm_bo_get_stride_or_tiling(bo: *mut gbm_bo) -> u32;
+    pub fn gbm_bo_get_format(bo: *mut gbm_bo) -> u32;
+    pub fn gbm_bo_get_modifier(bo: *mut gbm_bo) -> u64;
+    pub fn gbm_bo_get_device(bo: *mut gbm_bo) -> *mut gbm_device;
+    pub fn gbm_bo_get_handle(bo: *mut gbm_bo) -> gbm_bo_handle;
+    pub fn gbm_bo_get_fd(bo: *mut gbm_bo) -> c_int;
+    pub fn gbm_bo_get_plane_count(bo: *mut gbm_bo) -> usize;
+    pub fn gbm_bo_get_handle_for_plane(bo: *mut gbm_bo, plane: usize) -> gbm_bo_handle;
+    pub fn gbm_bo_get_plane_fd(bo: *mut gbm_bo, plane: usize) -> c_int;
+    pub fn gbm_bo_get_offset(bo: *mut gbm_bo, plane: usize) -> u32;
+    pub fn gbm_bo_get_plane_size(bo: *mut gbm_bo, plane: usize) -> u32;
+    pub fn gbm_bo_get_stride_for_plane(bo: *mut gbm_bo, plane: usize) -> u32;
+    pub fn gbm_bo_get_plane_format_modifier(bo: *mut gbm_bo, plane: usize) -> u64;
+    // Did not generate cleanly by bindgen. Redone manually by zachr.
+    pub fn gbm_bo_set_user_data(
+        bo: *mut gbm_bo,
+        data: *mut c_void,
+        destroy_user_data: extern "C" fn(bo: *mut gbm_bo, data: *mut c_void),
+    );
+    pub fn gbm_bo_get_user_data(bo: *mut gbm_bo) -> *mut c_void;
+    pub fn gbm_bo_destroy(bo: *mut gbm_bo);
+    pub fn gbm_surface_create(
+        gbm: *mut gbm_device,
+        width: u32,
+        height: u32,
+        format: u32,
+        flags: u32,
+    ) -> *mut gbm_surface;
+    pub fn gbm_surface_lock_front_buffer(surface: *mut gbm_surface) -> *mut gbm_bo;
+    pub fn gbm_surface_release_buffer(surface: *mut gbm_surface, bo: *mut gbm_bo);
+    pub fn gbm_surface_has_free_buffers(surface: *mut gbm_surface) -> c_int;
+    pub fn gbm_surface_destroy(surface: *mut gbm_surface);
+}
diff --git a/gpu_buffer/src/rendernode.rs b/gpu_buffer/src/rendernode.rs
new file mode 100644
index 0000000..503d712
--- /dev/null
+++ b/gpu_buffer/src/rendernode.rs
@@ -0,0 +1,116 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::ffi::CString;
+use std::fs::{File, OpenOptions};
+#[cfg(target_pointer_width = "64")]
+use std::os::raw::c_ulong;
+use std::os::raw::{c_char, c_int, c_uint};
+use std::path::Path;
+use std::ptr::null_mut;
+
+use sys_util::{ioctl_iowr_nr, ioctl_with_mut_ref};
+
+// Consistent with __kernel_size_t in include/uapi/asm-generic/posix_types.h.
+#[cfg(not(target_pointer_width = "64"))]
+#[allow(non_camel_case_types)]
+type __kernel_size_t = c_uint;
+#[cfg(target_pointer_width = "64")]
+#[allow(non_camel_case_types)]
+type __kernel_size_t = c_ulong;
+
+const DRM_IOCTL_BASE: c_uint = 0x64;
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct drm_version {
+    version_major: c_int,
+    version_minor: c_int,
+    version_patchlevel: c_int,
+    name_len: __kernel_size_t,
+    name: *mut c_char,
+    date_len: __kernel_size_t,
+    date: *mut c_char,
+    desc_len: __kernel_size_t,
+    desc: *mut c_char,
+}
+
+ioctl_iowr_nr!(DRM_IOCTL_VERSION, DRM_IOCTL_BASE, 0x0, drm_version);
+
+fn get_drm_device_name(fd: &File) -> Result<String, ()> {
+    let mut version = drm_version {
+        version_major: 0,
+        version_minor: 0,
+        version_patchlevel: 0,
+        name_len: 0,
+        name: null_mut(),
+        date_len: 0,
+        date: null_mut(),
+        desc_len: 0,
+        desc: null_mut(),
+    };
+
+    // Get the length of the device name.
+    if unsafe { ioctl_with_mut_ref(fd, DRM_IOCTL_VERSION(), &mut version) } < 0 {
+        return Err(());
+    }
+
+    // Enough bytes to hold the device name and terminating null character.
+    let mut name_bytes: Vec<u8> = vec![0; (version.name_len + 1) as usize];
+    let mut version = drm_version {
+        version_major: 0,
+        version_minor: 0,
+        version_patchlevel: 0,
+        name_len: name_bytes.len() as __kernel_size_t,
+        name: name_bytes.as_mut_ptr() as *mut c_char,
+        date_len: 0,
+        date: null_mut(),
+        desc_len: 0,
+        desc: null_mut(),
+    };
+
+    // Safe as no more than name_len + 1 bytes will be written to name.
+    if unsafe { ioctl_with_mut_ref(fd, DRM_IOCTL_VERSION(), &mut version) } < 0 {
+        return Err(());
+    }
+
+    Ok(CString::new(&name_bytes[..(version.name_len as usize)])
+        .map_err(|_| ())?
+        .into_string()
+        .map_err(|_| ())?)
+}
+
+/// Returns a `fd` for an opened rendernode device, while filtering out specified
+/// undesired drivers.
+pub fn open_device(undesired: &[&str]) -> Result<File, ()> {
+    const DRM_DIR_NAME: &str = "/dev/dri";
+    const DRM_MAX_MINOR: u32 = 15;
+    const RENDER_NODE_START: u32 = 128;
+
+    for n in RENDER_NODE_START..=RENDER_NODE_START + DRM_MAX_MINOR {
+        let path = Path::new(DRM_DIR_NAME).join(format!("renderD{}", n));
+
+        if let Ok(fd) = OpenOptions::new().read(true).write(true).open(path) {
+            if let Ok(name) = get_drm_device_name(&fd) {
+                if !undesired.iter().any(|item| *item == name) {
+                    return Ok(fd);
+                }
+            }
+        }
+    }
+
+    Err(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    #[ignore] // no access to /dev/dri
+    fn open_rendernode_device() {
+        let undesired: &[&str] = &["bad_driver", "another_bad_driver"];
+        open_device(undesired).expect("failed to open rendernode");
+    }
+}
diff --git a/gpu_display/Cargo.toml b/gpu_display/Cargo.toml
new file mode 100644
index 0000000..0177f1e
--- /dev/null
+++ b/gpu_display/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "gpu_display"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+data_model = { path = "../data_model" }
+libc = "*"
+sys_util = { path = "../sys_util" }
+
+[build-dependencies]
+cc = "=1.0.25"
diff --git a/gpu_display/build.rs b/gpu_display/build.rs
new file mode 100644
index 0000000..69c0fae
--- /dev/null
+++ b/gpu_display/build.rs
@@ -0,0 +1,98 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::env;
+use std::ffi::OsStr;
+use std::fs;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+
+// Performs a recursive search for a file with name under path and returns the full path if such a
+// file is found.
+fn scan_path<P: AsRef<Path>, O: AsRef<OsStr>>(path: P, name: O) -> Option<PathBuf> {
+    for entry in fs::read_dir(path).ok()? {
+        if let Ok(entry) = entry {
+            let file_type = match entry.file_type() {
+                Ok(t) => t,
+                Err(_) => continue,
+            };
+
+            if file_type.is_file() && entry.file_name() == name.as_ref() {
+                return Some(entry.path());
+            } else if file_type.is_dir() {
+                if let Some(found) = scan_path(entry.path(), name.as_ref()) {
+                    return Some(found);
+                }
+            }
+        }
+    }
+    None
+}
+
+// Searches for the given protocol in both the system wide and bundles protocols path.
+fn find_protocol(name: &str) -> PathBuf {
+    let protocols_path =
+        env::var("WAYLAND_PROTOCOLS_PATH").unwrap_or("/usr/share/wayland-protocols".to_owned());
+    let protocol_file_name = PathBuf::from(format!("{}.xml", name));
+
+    // Prioritize the systems wayland protocols before using the bundled ones.
+    if let Some(found) = scan_path(protocols_path, &protocol_file_name) {
+        return found;
+    }
+
+    // Use bundled protocols as a fallback.
+    let protocol_path = Path::new("protocol").join(protocol_file_name);
+    assert!(
+        protocol_path.is_file(),
+        "unable to locate wayland protocol specification for `{}`",
+        name
+    );
+    protocol_path
+}
+
+fn compile_protocol<P: AsRef<Path>>(name: &str, out: P) -> PathBuf {
+    let in_protocol = find_protocol(name);
+    println!("cargo:rerun-if-changed={}", in_protocol.display());
+    let out_code = out.as_ref().join(format!("{}.c", name));
+    let out_header = out.as_ref().join(format!("{}.h", name));
+    eprintln!("building protocol: {}", name);
+    Command::new("wayland-scanner")
+        .arg("code")
+        .arg(&in_protocol)
+        .arg(&out_code)
+        .output()
+        .unwrap();
+    Command::new("wayland-scanner")
+        .arg("client-header")
+        .arg(&in_protocol)
+        .arg(&out_header)
+        .output()
+        .unwrap();
+    out_code
+}
+
+fn main() {
+    println!("cargo:rerun-if-env-changed=WAYLAND_PROTOCOLS_PATH");
+    let out_dir = env::var("OUT_DIR").unwrap();
+
+    let mut build = cc::Build::new();
+    build.warnings(true);
+    build.warnings_into_errors(true);
+    build.include(&out_dir);
+    build.flag("-std=gnu11");
+    build.file("src/display_wl.c");
+    println!("cargo:rerun-if-changed=src/display_wl.c");
+
+    for protocol in &[
+        "aura-shell",
+        "linux-dmabuf-unstable-v1",
+        "xdg-shell-unstable-v6",
+        "viewporter",
+    ] {
+        build.file(compile_protocol(protocol, &out_dir));
+    }
+    build.compile("display_wl");
+
+    println!("cargo:rustc-link-lib=dylib=wayland-client");
+}
diff --git a/gpu_display/examples/simple.rs b/gpu_display/examples/simple.rs
new file mode 100644
index 0000000..140e6cc
--- /dev/null
+++ b/gpu_display/examples/simple.rs
@@ -0,0 +1,13 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use gpu_display::*;
+
+fn main() {
+    let mut disp = GpuDisplay::new("/run/wayland-0").unwrap();
+    let surface_id = disp.create_surface(None, 1280, 1024).unwrap();
+    while !disp.close_requested(surface_id) {
+        disp.dispatch_events();
+    }
+}
diff --git a/gpu_display/protocol/aura-shell.xml b/gpu_display/protocol/aura-shell.xml
new file mode 100644
index 0000000..74189f0
--- /dev/null
+++ b/gpu_display/protocol/aura-shell.xml
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="aura_shell">
+  <copyright>
+    Copyright 2017 The Chromium Authors.
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+  <interface name="zaura_shell" version="6">
+    <description summary="aura_shell">
+      The global interface exposing aura shell capabilities is used to
+      instantiate an interface extension for a wl_surface object.
+      This extended interface will then allow the client to use aura shell
+      specific functionality.
+    </description>
+    <enum name="error">
+      <entry name="aura_surface_exists" value="0"
+       summary="the surface already has an aura surface object associated"/>
+      <entry name="aura_output_exists" value="1"
+       summary="the output already has an aura output object associated"/>
+    </enum>
+    <request name="get_aura_surface">
+      <description summary="extend surface interface for aura shell">
+  Instantiate an interface extension for the given wl_surface to
+  provide aura shell functionality. If the given wl_surface is not
+  associated with a shell surface, the shell_surface_missing protocol
+  error is raised.
+      </description>
+      <arg name="id" type="new_id" interface="zaura_surface"
+     summary="the new aura surface interface id"/>
+      <arg name="surface" type="object" interface="wl_surface"
+     summary="the surface"/>
+    </request>
+    <!-- Version 2 additions -->
+    <request name="get_aura_output" since="2">
+      <description summary="extend output interface for aura shell">
+  Instantiate an interface extension for the given wl_output to
+  provide aura shell functionality.
+      </description>
+      <arg name="id" type="new_id" interface="zaura_output"
+     summary="the new aura output interface id"/>
+      <arg name="output" type="object" interface="wl_output"
+     summary="the output"/>
+    </request>
+  </interface>
+  <interface name="zaura_surface" version="5">
+    <description summary="aura shell interface to a wl_surface">
+      An additional interface to a wl_surface object, which allows the
+      client to access aura shell specific functionality for surface.
+    </description>
+    <enum name="frame_type">
+      <description summary="different frame types">
+  Frame types that can be used to decorate a surface.
+      </description>
+      <entry name="none" value="0" summary="no frame"/>
+      <entry name="normal" value="1" summary="caption with shadow" />
+      <entry name="shadow" value="2" summary="shadow only"/>
+    </enum>
+    <request name="set_frame">
+      <description summary="request a frame for surface">
+  Suggests a surface should use a specific frame.
+      </description>
+      <arg name="type" type="uint" summary="the new frame type"/>
+    </request>
+    <!-- Version 2 additions -->
+    <request name="set_parent" since="2">
+      <description summary="set the parent of this surface">
+  Set the "parent" of this surface. "x" and "y" arguments specify the
+  initial position for surface relative to parent.
+      </description>
+      <arg name="parent" type="object" interface="zaura_surface" allow-null="true"/>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+    </request>
+    <!-- Version 3 additions -->
+    <request name="set_frame_colors" since="3">
+      <description summary="set the frame colors of this surface">
+  Set the frame colors.
+      </description>
+      <arg name="active_color" type="uint" summary="32 bit ARGB color value, not premultiplied"/>
+      <arg name="inactive_color" type="uint" summary="32 bit ARGB color value, not premultiplied"/>
+    </request>
+    <!-- Version 4 additions -->
+    <request name="set_startup_id" since="4">
+      <description summary="set the startup ID of this surface">
+  Set the startup ID.
+      </description>
+      <arg name="startup_id" type="string" allow-null="true"/>
+    </request>
+    <!-- Version 5 additions -->
+    <request name="set_application_id" since="5">
+      <description summary="set the application ID of this surface">
+  Set the application ID.
+      </description>
+      <arg name="application_id" type="string" allow-null="true"/>
+    </request>
+  </interface>
+  <interface name="zaura_output" version="6">
+    <description summary="aura shell interface to a wl_output">
+      An additional interface to a wl_output object, which allows the
+      client to access aura shell specific functionality for output.
+    </description>
+    <!-- Version 2 additions -->
+    <enum name="scale_property" bitfield="true">
+      <description summary="scale information">
+  These flags describe properties of an output scale.
+  They are used in the flags bitfield of the scale event.
+      </description>
+      <entry name="current" value="0x1"
+       summary="indicates this is the current scale"/>
+      <entry name="preferred" value="0x2"
+       summary="indicates this is the preferred scale"/>
+    </enum>
+    <enum name="scale_factor">
+      <entry name="0400" value="400"/>
+      <entry name="0500" value="500"/>
+      <entry name="0550" value="550"/>
+      <entry name="0600" value="600"/>
+      <entry name="0625" value="625"/>
+      <entry name="0650" value="650"/>
+      <entry name="0700" value="700"/>
+      <entry name="0750" value="750"/>
+      <entry name="0800" value="800"/>
+      <entry name="0850" value="850"/>
+      <entry name="0900" value="900"/>
+      <entry name="0950" value="950"/>
+      <entry name="1000" value="1000"/>
+      <entry name="1050" value="1050"/>
+      <entry name="1100" value="1100"/>
+      <entry name="1150" value="1150"/>
+      <entry name="1125" value="1125"/>
+      <entry name="1200" value="1200"/>
+      <entry name="1250" value="1250"/>
+      <entry name="1300" value="1300"/>
+      <entry name="1400" value="1400"/>
+      <entry name="1450" value="1450"/>
+      <entry name="1500" value="1500"/>
+      <entry name="1600" value="1600"/>
+      <entry name="1750" value="1750"/>
+      <entry name="1800" value="1800"/>
+      <entry name="2000" value="2000"/>
+      <entry name="2200" value="2200"/>
+      <entry name="2250" value="2250"/>
+      <entry name="2500" value="2500"/>
+      <entry name="2750" value="2750"/>
+      <entry name="3000" value="3000"/>
+      <entry name="3500" value="3500"/>
+      <entry name="4000" value="4000"/>
+      <entry name="4500" value="4500"/>
+      <entry name="5000" value="5000"/>
+    </enum>
+    <event name="scale" since="2">
+      <description summary="advertise available scales for the output">
+  The scale event describes an available scale for the output.
+  The event is sent when binding to the output object and there
+  will always be one scale, the current scale. The event is sent
+  again if an output changes scale, for the scale that is now
+  current. In other words, the current scale is always the last
+  scale that was received with the current flag set.
+      </description>
+      <arg name="flags" type="uint" enum="scale_property" summary="bitfield of scale flags"/>
+      <arg name="scale" type="uint" enum="scale_factor" summary="output scale"/>
+    </event>
+    <!-- Version 5 additions -->
+    <enum name="connection_type">
+      <entry name="unknown" value="0"/>
+      <entry name="internal" value="1"/>
+    </enum>
+    <event name="connection" since="5">
+      <description summary="advertise connection for the output">
+  The connection event describes how the output is connected.
+  The event is sent when binding to the output object.
+      </description>
+      <arg name="connection" type="uint" enum="connection_type" summary="output connection"/>
+    </event>
+    <event name="device_scale_factor" since="5">
+      <description summary="advertise device scale factor for the output">
+  This event describes the device specific scale factor for the output.
+  The device specific scale factor is not expected the change during
+  the lifetime of the output. And it is not limited to an integer value
+  like the scale factor provided by wl_output interface. The exact
+  contents scale used by the compositor can be determined by combining
+  this device scale factor with the current output scale.
+  The event is sent when binding to the output object.
+      </description>
+      <arg name="scale" type="uint" enum="scale_factor" summary="output device scale factor"/>
+    </event>
+ </interface>
+</protocol>
diff --git a/gpu_display/protocol/linux-dmabuf-unstable-v1.xml b/gpu_display/protocol/linux-dmabuf-unstable-v1.xml
new file mode 100644
index 0000000..154afe2
--- /dev/null
+++ b/gpu_display/protocol/linux-dmabuf-unstable-v1.xml
@@ -0,0 +1,348 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="linux_dmabuf_unstable_v1">
+
+  <copyright>
+    Copyright © 2014, 2015 Collabora, Ltd.
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="zwp_linux_dmabuf_v1" version="3">
+    <description summary="factory for creating dmabuf-based wl_buffers">
+      Following the interfaces from:
+      https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_image_dma_buf_import.txt
+      and the Linux DRM sub-system's AddFb2 ioctl.
+
+      This interface offers ways to create generic dmabuf-based
+      wl_buffers. Immediately after a client binds to this interface,
+      the set of supported formats and format modifiers is sent with
+      'format' and 'modifier' events.
+
+      The following are required from clients:
+
+      - Clients must ensure that either all data in the dma-buf is
+        coherent for all subsequent read access or that coherency is
+        correctly handled by the underlying kernel-side dma-buf
+        implementation.
+
+      - Don't make any more attachments after sending the buffer to the
+        compositor. Making more attachments later increases the risk of
+        the compositor not being able to use (re-import) an existing
+        dmabuf-based wl_buffer.
+
+      The underlying graphics stack must ensure the following:
+
+      - The dmabuf file descriptors relayed to the server will stay valid
+        for the whole lifetime of the wl_buffer. This means the server may
+        at any time use those fds to import the dmabuf into any kernel
+        sub-system that might accept it.
+
+      To create a wl_buffer from one or more dmabufs, a client creates a
+      zwp_linux_dmabuf_params_v1 object with a zwp_linux_dmabuf_v1.create_params
+      request. All planes required by the intended format are added with
+      the 'add' request. Finally, a 'create' or 'create_immed' request is
+      issued, which has the following outcome depending on the import success.
+
+      The 'create' request,
+      - on success, triggers a 'created' event which provides the final
+        wl_buffer to the client.
+      - on failure, triggers a 'failed' event to convey that the server
+        cannot use the dmabufs received from the client.
+
+      For the 'create_immed' request,
+      - on success, the server immediately imports the added dmabufs to
+        create a wl_buffer. No event is sent from the server in this case.
+      - on failure, the server can choose to either:
+        - terminate the client by raising a fatal error.
+        - mark the wl_buffer as failed, and send a 'failed' event to the
+          client. If the client uses a failed wl_buffer as an argument to any
+          request, the behaviour is compositor implementation-defined.
+
+      Warning! The protocol described in this file is experimental and
+      backward incompatible changes may be made. Backward compatible changes
+      may be added together with the corresponding interface version bump.
+      Backward incompatible changes are done by bumping the version number in
+      the protocol and interface names and resetting the interface version.
+      Once the protocol is to be declared stable, the 'z' prefix and the
+      version number in the protocol and interface names are removed and the
+      interface version number is reset.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind the factory">
+        Objects created through this interface, especially wl_buffers, will
+        remain valid.
+      </description>
+    </request>
+
+    <request name="create_params">
+      <description summary="create a temporary object for buffer parameters">
+        This temporary object is used to collect multiple dmabuf handles into
+        a single batch to create a wl_buffer. It can only be used once and
+        should be destroyed after a 'created' or 'failed' event has been
+        received.
+      </description>
+      <arg name="params_id" type="new_id" interface="zwp_linux_buffer_params_v1"
+           summary="the new temporary"/>
+    </request>
+
+    <event name="format">
+      <description summary="supported buffer format">
+        This event advertises one buffer format that the server supports.
+        All the supported formats are advertised once when the client
+        binds to this interface. A roundtrip after binding guarantees
+        that the client has received all supported formats.
+
+        For the definition of the format codes, see the
+        zwp_linux_buffer_params_v1::create request.
+
+        Warning: the 'format' event is likely to be deprecated and replaced
+        with the 'modifier' event introduced in zwp_linux_dmabuf_v1
+        version 3, described below. Please refrain from using the information
+        received from this event.
+      </description>
+      <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+    </event>
+
+    <event name="modifier" since="3">
+      <description summary="supported buffer format modifier">
+        This event advertises the formats that the server supports, along with
+        the modifiers supported for each format. All the supported modifiers
+        for all the supported formats are advertised once when the client
+        binds to this interface. A roundtrip after binding guarantees that
+        the client has received all supported format-modifier pairs.
+
+        For the definition of the format and modifier codes, see the
+        zwp_linux_buffer_params_v1::create request.
+      </description>
+      <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+      <arg name="modifier_hi" type="uint"
+           summary="high 32 bits of layout modifier"/>
+      <arg name="modifier_lo" type="uint"
+           summary="low 32 bits of layout modifier"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_linux_buffer_params_v1" version="3">
+    <description summary="parameters for creating a dmabuf-based wl_buffer">
+      This temporary object is a collection of dmabufs and other
+      parameters that together form a single logical buffer. The temporary
+      object may eventually create one wl_buffer unless cancelled by
+      destroying it before requesting 'create'.
+
+      Single-planar formats only require one dmabuf, however
+      multi-planar formats may require more than one dmabuf. For all
+      formats, an 'add' request must be called once per plane (even if the
+      underlying dmabuf fd is identical).
+
+      You must use consecutive plane indices ('plane_idx' argument for 'add')
+      from zero to the number of planes used by the drm_fourcc format code.
+      All planes required by the format must be given exactly once, but can
+      be given in any order. Each plane index can be set only once.
+    </description>
+
+    <enum name="error">
+      <entry name="already_used" value="0"
+             summary="the dmabuf_batch object has already been used to create a wl_buffer"/>
+      <entry name="plane_idx" value="1"
+             summary="plane index out of bounds"/>
+      <entry name="plane_set" value="2"
+             summary="the plane index was already set"/>
+      <entry name="incomplete" value="3"
+             summary="missing or too many planes to create a buffer"/>
+      <entry name="invalid_format" value="4"
+             summary="format not supported"/>
+      <entry name="invalid_dimensions" value="5"
+             summary="invalid width or height"/>
+      <entry name="out_of_bounds" value="6"
+             summary="offset + stride * height goes out of dmabuf bounds"/>
+      <entry name="invalid_wl_buffer" value="7"
+             summary="invalid wl_buffer resulted from importing dmabufs via
+               the create_immed request on given buffer_params"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="delete this object, used or not">
+        Cleans up the temporary data sent to the server for dmabuf-based
+        wl_buffer creation.
+      </description>
+    </request>
+
+    <request name="add">
+      <description summary="add a dmabuf to the temporary set">
+        This request adds one dmabuf to the set in this
+        zwp_linux_buffer_params_v1.
+
+        The 64-bit unsigned value combined from modifier_hi and modifier_lo
+        is the dmabuf layout modifier. DRM AddFB2 ioctl calls this the
+        fb modifier, which is defined in drm_mode.h of Linux UAPI.
+        This is an opaque token. Drivers use this token to express tiling,
+        compression, etc. driver-specific modifications to the base format
+        defined by the DRM fourcc code.
+
+        This request raises the PLANE_IDX error if plane_idx is too large.
+        The error PLANE_SET is raised if attempting to set a plane that
+        was already set.
+      </description>
+      <arg name="fd" type="fd" summary="dmabuf fd"/>
+      <arg name="plane_idx" type="uint" summary="plane index"/>
+      <arg name="offset" type="uint" summary="offset in bytes"/>
+      <arg name="stride" type="uint" summary="stride in bytes"/>
+      <arg name="modifier_hi" type="uint"
+           summary="high 32 bits of layout modifier"/>
+      <arg name="modifier_lo" type="uint"
+           summary="low 32 bits of layout modifier"/>
+    </request>
+
+    <enum name="flags">
+      <entry name="y_invert" value="1" summary="contents are y-inverted"/>
+      <entry name="interlaced" value="2" summary="content is interlaced"/>
+      <entry name="bottom_first" value="4" summary="bottom field first"/>
+    </enum>
+
+    <request name="create">
+      <description summary="create a wl_buffer from the given dmabufs">
+        This asks for creation of a wl_buffer from the added dmabuf
+        buffers. The wl_buffer is not created immediately but returned via
+        the 'created' event if the dmabuf sharing succeeds. The sharing
+        may fail at runtime for reasons a client cannot predict, in
+        which case the 'failed' event is triggered.
+
+        The 'format' argument is a DRM_FORMAT code, as defined by the
+        libdrm's drm_fourcc.h. The Linux kernel's DRM sub-system is the
+        authoritative source on how the format codes should work.
+
+        The 'flags' is a bitfield of the flags defined in enum "flags".
+        'y_invert' means the that the image needs to be y-flipped.
+
+        Flag 'interlaced' means that the frame in the buffer is not
+        progressive as usual, but interlaced. An interlaced buffer as
+        supported here must always contain both top and bottom fields.
+        The top field always begins on the first pixel row. The temporal
+        ordering between the two fields is top field first, unless
+        'bottom_first' is specified. It is undefined whether 'bottom_first'
+        is ignored if 'interlaced' is not set.
+
+        This protocol does not convey any information about field rate,
+        duration, or timing, other than the relative ordering between the
+        two fields in one buffer. A compositor may have to estimate the
+        intended field rate from the incoming buffer rate. It is undefined
+        whether the time of receiving wl_surface.commit with a new buffer
+        attached, applying the wl_surface state, wl_surface.frame callback
+        trigger, presentation, or any other point in the compositor cycle
+        is used to measure the frame or field times. There is no support
+        for detecting missed or late frames/fields/buffers either, and
+        there is no support whatsoever for cooperating with interlaced
+        compositor output.
+
+        The composited image quality resulting from the use of interlaced
+        buffers is explicitly undefined. A compositor may use elaborate
+        hardware features or software to deinterlace and create progressive
+        output frames from a sequence of interlaced input buffers, or it
+        may produce substandard image quality. However, compositors that
+        cannot guarantee reasonable image quality in all cases are recommended
+        to just reject all interlaced buffers.
+
+        Any argument errors, including non-positive width or height,
+        mismatch between the number of planes and the format, bad
+        format, bad offset or stride, may be indicated by fatal protocol
+        errors: INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS,
+        OUT_OF_BOUNDS.
+
+        Dmabuf import errors in the server that are not obvious client
+        bugs are returned via the 'failed' event as non-fatal. This
+        allows attempting dmabuf sharing and falling back in the client
+        if it fails.
+
+        This request can be sent only once in the object's lifetime, after
+        which the only legal request is destroy. This object should be
+        destroyed after issuing a 'create' request. Attempting to use this
+        object after issuing 'create' raises ALREADY_USED protocol error.
+
+        It is not mandatory to issue 'create'. If a client wants to
+        cancel the buffer creation, it can just destroy this object.
+      </description>
+      <arg name="width" type="int" summary="base plane width in pixels"/>
+      <arg name="height" type="int" summary="base plane height in pixels"/>
+      <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+      <arg name="flags" type="uint" summary="see enum flags"/>
+    </request>
+
+    <event name="created">
+      <description summary="buffer creation succeeded">
+        This event indicates that the attempted buffer creation was
+        successful. It provides the new wl_buffer referencing the dmabuf(s).
+
+        Upon receiving this event, the client should destroy the
+        zlinux_dmabuf_params object.
+      </description>
+      <arg name="buffer" type="new_id" interface="wl_buffer"
+           summary="the newly created wl_buffer"/>
+    </event>
+
+    <event name="failed">
+      <description summary="buffer creation failed">
+        This event indicates that the attempted buffer creation has
+        failed. It usually means that one of the dmabuf constraints
+        has not been fulfilled.
+
+        Upon receiving this event, the client should destroy the
+        zlinux_buffer_params object.
+      </description>
+    </event>
+
+    <request name="create_immed" since="2">
+      <description summary="immediately create a wl_buffer from the given
+                     dmabufs">
+        This asks for immediate creation of a wl_buffer by importing the
+        added dmabufs.
+
+        In case of import success, no event is sent from the server, and the
+        wl_buffer is ready to be used by the client.
+
+        Upon import failure, either of the following may happen, as seen fit
+        by the implementation:
+        - the client is terminated with one of the following fatal protocol
+          errors:
+          - INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS,
+            in case of argument errors such as mismatch between the number
+            of planes and the format, bad format, non-positive width or
+            height, or bad offset or stride.
+          - INVALID_WL_BUFFER, in case the cause for failure is unknown or
+            plaform specific.
+        - the server creates an invalid wl_buffer, marks it as failed and
+          sends a 'failed' event to the client. The result of using this
+          invalid wl_buffer as an argument in any request by the client is
+          defined by the compositor implementation.
+
+        This takes the same arguments as a 'create' request, and obeys the
+        same restrictions.
+      </description>
+      <arg name="buffer_id" type="new_id" interface="wl_buffer"
+           summary="id for the newly created wl_buffer"/>
+      <arg name="width" type="int" summary="base plane width in pixels"/>
+      <arg name="height" type="int" summary="base plane height in pixels"/>
+      <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+      <arg name="flags" type="uint" summary="see enum flags"/>
+    </request>
+
+  </interface>
+
+</protocol>
diff --git a/gpu_display/protocol/viewporter.xml b/gpu_display/protocol/viewporter.xml
new file mode 100644
index 0000000..c732d8c
--- /dev/null
+++ b/gpu_display/protocol/viewporter.xml
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="viewporter">
+
+  <copyright>
+    Copyright © 2013-2016 Collabora, Ltd.
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="wp_viewporter" version="1">
+    <description summary="surface cropping and scaling">
+      The global interface exposing surface cropping and scaling
+      capabilities is used to instantiate an interface extension for a
+      wl_surface object. This extended interface will then allow
+      cropping and scaling the surface contents, effectively
+      disconnecting the direct relationship between the buffer and the
+      surface size.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind from the cropping and scaling interface">
+	Informs the server that the client will not be using this
+	protocol object anymore. This does not affect any other objects,
+	wp_viewport objects included.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="viewport_exists" value="0"
+             summary="the surface already has a viewport object associated"/>
+    </enum>
+
+    <request name="get_viewport">
+      <description summary="extend surface interface for crop and scale">
+	Instantiate an interface extension for the given wl_surface to
+	crop and scale its content. If the given wl_surface already has
+	a wp_viewport object associated, the viewport_exists
+	protocol error is raised.
+      </description>
+      <arg name="id" type="new_id" interface="wp_viewport"
+           summary="the new viewport interface id"/>
+      <arg name="surface" type="object" interface="wl_surface"
+           summary="the surface"/>
+    </request>
+  </interface>
+
+  <interface name="wp_viewport" version="1">
+    <description summary="crop and scale interface to a wl_surface">
+      An additional interface to a wl_surface object, which allows the
+      client to specify the cropping and scaling of the surface
+      contents.
+
+      This interface works with two concepts: the source rectangle (src_x,
+      src_y, src_width, src_height), and the destination size (dst_width,
+      dst_height). The contents of the source rectangle are scaled to the
+      destination size, and content outside the source rectangle is ignored.
+      This state is double-buffered, and is applied on the next
+      wl_surface.commit.
+
+      The two parts of crop and scale state are independent: the source
+      rectangle, and the destination size. Initially both are unset, that
+      is, no scaling is applied. The whole of the current wl_buffer is
+      used as the source, and the surface size is as defined in
+      wl_surface.attach.
+
+      If the destination size is set, it causes the surface size to become
+      dst_width, dst_height. The source (rectangle) is scaled to exactly
+      this size. This overrides whatever the attached wl_buffer size is,
+      unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
+      has no content and therefore no size. Otherwise, the size is always
+      at least 1x1 in surface local coordinates.
+
+      If the source rectangle is set, it defines what area of the wl_buffer is
+      taken as the source. If the source rectangle is set and the destination
+      size is not set, then src_width and src_height must be integers, and the
+      surface size becomes the source rectangle size. This results in cropping
+      without scaling. If src_width or src_height are not integers and
+      destination size is not set, the bad_size protocol error is raised when
+      the surface state is applied.
+
+      The coordinate transformations from buffer pixel coordinates up to
+      the surface-local coordinates happen in the following order:
+        1. buffer_transform (wl_surface.set_buffer_transform)
+        2. buffer_scale (wl_surface.set_buffer_scale)
+        3. crop and scale (wp_viewport.set*)
+      This means, that the source rectangle coordinates of crop and scale
+      are given in the coordinates after the buffer transform and scale,
+      i.e. in the coordinates that would be the surface-local coordinates
+      if the crop and scale was not applied.
+
+      If src_x or src_y are negative, the bad_value protocol error is raised.
+      Otherwise, if the source rectangle is partially or completely outside of
+      the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
+      when the surface state is applied. A NULL wl_buffer does not raise the
+      out_of_buffer error.
+
+      The x, y arguments of wl_surface.attach are applied as normal to
+      the surface. They indicate how many pixels to remove from the
+      surface size from the left and the top. In other words, they are
+      still in the surface-local coordinate system, just like dst_width
+      and dst_height are.
+
+      If the wl_surface associated with the wp_viewport is destroyed,
+      all wp_viewport requests except 'destroy' raise the protocol error
+      no_surface.
+
+      If the wp_viewport object is destroyed, the crop and scale
+      state is removed from the wl_surface. The change will be applied
+      on the next wl_surface.commit.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="remove scaling and cropping from the surface">
+	The associated wl_surface's crop and scale state is removed.
+	The change is applied on the next wl_surface.commit.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="bad_value" value="0"
+	     summary="negative or zero values in width or height"/>
+      <entry name="bad_size" value="1"
+	     summary="destination size is not integer"/>
+      <entry name="out_of_buffer" value="2"
+	     summary="source rectangle extends outside of the content area"/>
+      <entry name="no_surface" value="3"
+	     summary="the wl_surface was destroyed"/>
+    </enum>
+
+    <request name="set_source">
+      <description summary="set the source rectangle for cropping">
+	Set the source rectangle of the associated wl_surface. See
+	wp_viewport for the description, and relation to the wl_buffer
+	size.
+
+	If all of x, y, width and height are -1.0, the source rectangle is
+	unset instead. Any other set of values where width or height are zero
+	or negative, or x or y are negative, raise the bad_value protocol
+	error.
+
+	The crop and scale state is double-buffered state, and will be
+	applied on the next wl_surface.commit.
+      </description>
+      <arg name="x" type="fixed" summary="source rectangle x"/>
+      <arg name="y" type="fixed" summary="source rectangle y"/>
+      <arg name="width" type="fixed" summary="source rectangle width"/>
+      <arg name="height" type="fixed" summary="source rectangle height"/>
+    </request>
+
+    <request name="set_destination">
+      <description summary="set the surface size for scaling">
+	Set the destination size of the associated wl_surface. See
+	wp_viewport for the description, and relation to the wl_buffer
+	size.
+
+	If width is -1 and height is -1, the destination size is unset
+	instead. Any other pair of values for width and height that
+	contains zero or negative values raises the bad_value protocol
+	error.
+
+	The crop and scale state is double-buffered state, and will be
+	applied on the next wl_surface.commit.
+      </description>
+      <arg name="width" type="int" summary="surface width"/>
+      <arg name="height" type="int" summary="surface height"/>
+    </request>
+  </interface>
+
+</protocol>
diff --git a/gpu_display/protocol/xdg-shell-unstable-v6.xml b/gpu_display/protocol/xdg-shell-unstable-v6.xml
new file mode 100644
index 0000000..1c0f924
--- /dev/null
+++ b/gpu_display/protocol/xdg-shell-unstable-v6.xml
@@ -0,0 +1,1044 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_shell_unstable_v6">
+
+  <copyright>
+    Copyright © 2008-2013 Kristian Høgsberg
+    Copyright © 2013      Rafael Antognolli
+    Copyright © 2013      Jasper St. Pierre
+    Copyright © 2010-2013 Intel Corporation
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="zxdg_shell_v6" version="1">
+    <description summary="create desktop-style surfaces">
+      xdg_shell allows clients to turn a wl_surface into a "real window"
+      which can be dragged, resized, stacked, and moved around by the
+      user. Everything about this interface is suited towards traditional
+      desktop environments.
+    </description>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+      <entry name="defunct_surfaces" value="1"
+	     summary="xdg_shell was destroyed before children"/>
+      <entry name="not_the_topmost_popup" value="2"
+	     summary="the client tried to map or destroy a non-topmost popup"/>
+      <entry name="invalid_popup_parent" value="3"
+	     summary="the client specified an invalid popup parent surface"/>
+      <entry name="invalid_surface_state" value="4"
+	     summary="the client provided an invalid surface state"/>
+      <entry name="invalid_positioner" value="5"
+	     summary="the client provided an invalid positioner"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy xdg_shell">
+	Destroy this xdg_shell object.
+
+	Destroying a bound xdg_shell object while there are surfaces
+	still alive created by this xdg_shell object instance is illegal
+	and will result in a protocol error.
+      </description>
+    </request>
+
+    <request name="create_positioner">
+      <description summary="create a positioner object">
+	Create a positioner object. A positioner object is used to position
+	surfaces relative to some parent surface. See the interface description
+	and xdg_surface.get_popup for details.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_positioner_v6"/>
+    </request>
+
+    <request name="get_xdg_surface">
+      <description summary="create a shell surface from a surface">
+	This creates an xdg_surface for the given surface. While xdg_surface
+	itself is not a role, the corresponding surface may only be assigned
+	a role extending xdg_surface, such as xdg_toplevel or xdg_popup.
+
+	This creates an xdg_surface for the given surface. An xdg_surface is
+	used as basis to define a role to a given surface, such as xdg_toplevel
+	or xdg_popup. It also manages functionality shared between xdg_surface
+	based surface roles.
+
+	See the documentation of xdg_surface for more details about what an
+	xdg_surface is and how it is used.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_surface_v6"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+
+    <request name="pong">
+      <description summary="respond to a ping event">
+	A client must respond to a ping event with a pong request or
+	the client may be deemed unresponsive. See xdg_shell.ping.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the ping event"/>
+    </request>
+
+    <event name="ping">
+      <description summary="check if the client is alive">
+	The ping event asks the client if it's still alive. Pass the
+	serial specified in the event back to the compositor by sending
+	a "pong" request back with the specified serial. See xdg_shell.ping.
+
+	Compositors can use this to determine if the client is still
+	alive. It's unspecified what will happen if the client doesn't
+	respond to the ping request, or in what timeframe. Clients should
+	try to respond in a reasonable amount of time.
+
+	A compositor is free to ping in any way it wants, but a client must
+	always respond to any xdg_shell object it created.
+      </description>
+      <arg name="serial" type="uint" summary="pass this to the pong request"/>
+    </event>
+  </interface>
+
+  <interface name="zxdg_positioner_v6" version="1">
+    <description summary="child surface positioner">
+      The xdg_positioner provides a collection of rules for the placement of a
+      child surface relative to a parent surface. Rules can be defined to ensure
+      the child surface remains within the visible area's borders, and to
+      specify how the child surface changes its position, such as sliding along
+      an axis, or flipping around a rectangle. These positioner-created rules are
+      constrained by the requirement that a child surface must intersect with or
+      be at least partially adjacent to its parent surface.
+
+      See the various requests for details about possible rules.
+
+      At the time of the request, the compositor makes a copy of the rules
+      specified by the xdg_positioner. Thus, after the request is complete the
+      xdg_positioner object can be destroyed or reused; further changes to the
+      object will have no effect on previous usages.
+
+      For an xdg_positioner object to be considered complete, it must have a
+      non-zero size set by set_size, and a non-zero anchor rectangle set by
+      set_anchor_rect. Passing an incomplete xdg_positioner object when
+      positioning a surface raises an error.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_input" value="0" summary="invalid input provided"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_positioner object">
+	Notify the compositor that the xdg_positioner will no longer be used.
+      </description>
+    </request>
+
+    <request name="set_size">
+      <description summary="set the size of the to-be positioned rectangle">
+	Set the size of the surface that is to be positioned with the positioner
+	object. The size is in surface-local coordinates and corresponds to the
+	window geometry. See xdg_surface.set_window_geometry.
+
+	If a zero or negative size is set the invalid_input error is raised.
+      </description>
+      <arg name="width" type="int" summary="width of positioned rectangle"/>
+      <arg name="height" type="int" summary="height of positioned rectangle"/>
+    </request>
+
+    <request name="set_anchor_rect">
+      <description summary="set the anchor rectangle within the parent surface">
+	Specify the anchor rectangle within the parent surface that the child
+	surface will be placed relative to. The rectangle is relative to the
+	window geometry as defined by xdg_surface.set_window_geometry of the
+	parent surface. The rectangle must be at least 1x1 large.
+
+	When the xdg_positioner object is used to position a child surface, the
+	anchor rectangle may not extend outside the window geometry of the
+	positioned child's parent surface.
+
+	If a zero or negative size is set the invalid_input error is raised.
+      </description>
+      <arg name="x" type="int" summary="x position of anchor rectangle"/>
+      <arg name="y" type="int" summary="y position of anchor rectangle"/>
+      <arg name="width" type="int" summary="width of anchor rectangle"/>
+      <arg name="height" type="int" summary="height of anchor rectangle"/>
+    </request>
+
+    <enum name="anchor" bitfield="true">
+      <entry name="none" value="0"
+	     summary="the center of the anchor rectangle"/>
+      <entry name="top" value="1"
+	     summary="the top edge of the anchor rectangle"/>
+      <entry name="bottom" value="2"
+	     summary="the bottom edge of the anchor rectangle"/>
+      <entry name="left" value="4"
+	     summary="the left edge of the anchor rectangle"/>
+      <entry name="right" value="8"
+	     summary="the right edge of the anchor rectangle"/>
+    </enum>
+
+    <request name="set_anchor">
+      <description summary="set anchor rectangle anchor edges">
+	Defines a set of edges for the anchor rectangle. These are used to
+	derive an anchor point that the child surface will be positioned
+	relative to. If two orthogonal edges are specified (e.g. 'top' and
+	'left'), then the anchor point will be the intersection of the edges
+	(e.g. the top left position of the rectangle); otherwise, the derived
+	anchor point will be centered on the specified edge, or in the center of
+	the anchor rectangle if no edge is specified.
+
+	If two parallel anchor edges are specified (e.g. 'left' and 'right'),
+	the invalid_input error is raised.
+      </description>
+      <arg name="anchor" type="uint" enum="anchor"
+	   summary="bit mask of anchor edges"/>
+    </request>
+
+    <enum name="gravity" bitfield="true">
+      <entry name="none" value="0"
+	     summary="center over the anchor edge"/>
+      <entry name="top" value="1"
+	     summary="position above the anchor edge"/>
+      <entry name="bottom" value="2"
+	     summary="position below the anchor edge"/>
+      <entry name="left" value="4"
+	     summary="position to the left of the anchor edge"/>
+      <entry name="right" value="8"
+	     summary="position to the right of the anchor edge"/>
+    </enum>
+
+    <request name="set_gravity">
+      <description summary="set child surface gravity">
+	Defines in what direction a surface should be positioned, relative to
+	the anchor point of the parent surface. If two orthogonal gravities are
+	specified (e.g. 'bottom' and 'right'), then the child surface will be
+	placed in the specified direction; otherwise, the child surface will be
+	centered over the anchor point on any axis that had no gravity
+	specified.
+
+	If two parallel gravities are specified (e.g. 'left' and 'right'), the
+	invalid_input error is raised.
+      </description>
+      <arg name="gravity" type="uint" enum="gravity"
+	   summary="bit mask of gravity directions"/>
+    </request>
+
+    <enum name="constraint_adjustment" bitfield="true">
+      <description summary="constraint adjustments">
+	The constraint adjustment value define ways the compositor will adjust
+	the position of the surface, if the unadjusted position would result
+	in the surface being partly constrained.
+
+	Whether a surface is considered 'constrained' is left to the compositor
+	to determine. For example, the surface may be partly outside the
+	compositor's defined 'work area', thus necessitating the child surface's
+	position be adjusted until it is entirely inside the work area.
+
+	The adjustments can be combined, according to a defined precedence: 1)
+	Flip, 2) Slide, 3) Resize.
+      </description>
+      <entry name="none" value="0">
+	<description summary="don't move the child surface when constrained">
+	  Don't alter the surface position even if it is constrained on some
+	  axis, for example partially outside the edge of a monitor.
+	</description>
+      </entry>
+      <entry name="slide_x" value="1">
+	<description summary="move along the x axis until unconstrained">
+	  Slide the surface along the x axis until it is no longer constrained.
+
+	  First try to slide towards the direction of the gravity on the x axis
+	  until either the edge in the opposite direction of the gravity is
+	  unconstrained or the edge in the direction of the gravity is
+	  constrained.
+
+	  Then try to slide towards the opposite direction of the gravity on the
+	  x axis until either the edge in the direction of the gravity is
+	  unconstrained or the edge in the opposite direction of the gravity is
+	  constrained.
+	</description>
+      </entry>
+      <entry name="slide_y" value="2">
+	<description summary="move along the y axis until unconstrained">
+	  Slide the surface along the y axis until it is no longer constrained.
+
+	  First try to slide towards the direction of the gravity on the y axis
+	  until either the edge in the opposite direction of the gravity is
+	  unconstrained or the edge in the direction of the gravity is
+	  constrained.
+
+	  Then try to slide towards the opposite direction of the gravity on the
+	  y axis until either the edge in the direction of the gravity is
+	  unconstrained or the edge in the opposite direction of the gravity is
+	  constrained.
+	</description>
+      </entry>
+      <entry name="flip_x" value="4">
+	<description summary="invert the anchor and gravity on the x axis">
+	  Invert the anchor and gravity on the x axis if the surface is
+	  constrained on the x axis. For example, if the left edge of the
+	  surface is constrained, the gravity is 'left' and the anchor is
+	  'left', change the gravity to 'right' and the anchor to 'right'.
+
+	  If the adjusted position also ends up being constrained, the resulting
+	  position of the flip_x adjustment will be the one before the
+	  adjustment.
+	</description>
+      </entry>
+      <entry name="flip_y" value="8">
+	<description summary="invert the anchor and gravity on the y axis">
+	  Invert the anchor and gravity on the y axis if the surface is
+	  constrained on the y axis. For example, if the bottom edge of the
+	  surface is constrained, the gravity is 'bottom' and the anchor is
+	  'bottom', change the gravity to 'top' and the anchor to 'top'.
+
+	  If the adjusted position also ends up being constrained, the resulting
+	  position of the flip_y adjustment will be the one before the
+	  adjustment.
+	</description>
+      </entry>
+      <entry name="resize_x" value="16">
+	<description summary="horizontally resize the surface">
+	  Resize the surface horizontally so that it is completely
+	  unconstrained.
+	</description>
+      </entry>
+      <entry name="resize_y" value="32">
+	<description summary="vertically resize the surface">
+	  Resize the surface vertically so that it is completely unconstrained.
+	</description>
+      </entry>
+    </enum>
+
+    <request name="set_constraint_adjustment">
+      <description summary="set the adjustment to be done when constrained">
+	Specify how the window should be positioned if the originally intended
+	position caused the surface to be constrained, meaning at least
+	partially outside positioning boundaries set by the compositor. The
+	adjustment is set by constructing a bitmask describing the adjustment to
+	be made when the surface is constrained on that axis.
+
+	If no bit for one axis is set, the compositor will assume that the child
+	surface should not change its position on that axis when constrained.
+
+	If more than one bit for one axis is set, the order of how adjustments
+	are applied is specified in the corresponding adjustment descriptions.
+
+	The default adjustment is none.
+      </description>
+      <arg name="constraint_adjustment" type="uint"
+	   summary="bit mask of constraint adjustments"/>
+    </request>
+
+    <request name="set_offset">
+      <description summary="set surface position offset">
+	Specify the surface position offset relative to the position of the
+	anchor on the anchor rectangle and the anchor on the surface. For
+	example if the anchor of the anchor rectangle is at (x, y), the surface
+	has the gravity bottom|right, and the offset is (ox, oy), the calculated
+	surface position will be (x + ox, y + oy). The offset position of the
+	surface is the one used for constraint testing. See
+	set_constraint_adjustment.
+
+	An example use case is placing a popup menu on top of a user interface
+	element, while aligning the user interface element of the parent surface
+	with some user interface element placed somewhere in the popup surface.
+      </description>
+      <arg name="x" type="int" summary="surface position x offset"/>
+      <arg name="y" type="int" summary="surface position y offset"/>
+    </request>
+  </interface>
+
+  <interface name="zxdg_surface_v6" version="1">
+    <description summary="desktop user interface surface base interface">
+      An interface that may be implemented by a wl_surface, for
+      implementations that provide a desktop-style user interface.
+
+      It provides a base set of functionality required to construct user
+      interface elements requiring management by the compositor, such as
+      toplevel windows, menus, etc. The types of functionality are split into
+      xdg_surface roles.
+
+      Creating an xdg_surface does not set the role for a wl_surface. In order
+      to map an xdg_surface, the client must create a role-specific object
+      using, e.g., get_toplevel, get_popup. The wl_surface for any given
+      xdg_surface can have at most one role, and may not be assigned any role
+      not based on xdg_surface.
+
+      A role must be assigned before any other requests are made to the
+      xdg_surface object.
+
+      The client must call wl_surface.commit on the corresponding wl_surface
+      for the xdg_surface state to take effect.
+
+      Creating an xdg_surface from a wl_surface which has a buffer attached or
+      committed is a client error, and any attempts by a client to attach or
+      manipulate a buffer prior to the first xdg_surface.configure call must
+      also be treated as errors.
+
+      For a surface to be mapped by the compositor, the following conditions
+      must be met: (1) the client has assigned a xdg_surface based role to the
+      surface, (2) the client has set and committed the xdg_surface state and
+      the role dependent state to the surface and (3) the client has committed a
+      buffer to the surface.
+    </description>
+
+    <enum name="error">
+      <entry name="not_constructed" value="1"/>
+      <entry name="already_constructed" value="2"/>
+      <entry name="unconfigured_buffer" value="3"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_surface">
+	Destroy the xdg_surface object. An xdg_surface must only be destroyed
+	after its role object has been destroyed.
+      </description>
+    </request>
+
+    <request name="get_toplevel">
+      <description summary="assign the xdg_toplevel surface role">
+	This creates an xdg_toplevel object for the given xdg_surface and gives
+	the associated wl_surface the xdg_toplevel role.
+
+	See the documentation of xdg_toplevel for more details about what an
+	xdg_toplevel is and how it is used.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_toplevel_v6"/>
+    </request>
+
+    <request name="get_popup">
+      <description summary="assign the xdg_popup surface role">
+	This creates an xdg_popup object for the given xdg_surface and gives the
+	associated wl_surface the xdg_popup role.
+
+	See the documentation of xdg_popup for more details about what an
+	xdg_popup is and how it is used.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_popup_v6"/>
+      <arg name="parent" type="object" interface="zxdg_surface_v6"/>
+      <arg name="positioner" type="object" interface="zxdg_positioner_v6"/>
+    </request>
+
+    <request name="set_window_geometry">
+      <description summary="set the new window geometry">
+	The window geometry of a surface is its "visible bounds" from the
+	user's perspective. Client-side decorations often have invisible
+	portions like drop-shadows which should be ignored for the
+	purposes of aligning, placing and constraining windows.
+
+	The window geometry is double buffered, and will be applied at the
+	time wl_surface.commit of the corresponding wl_surface is called.
+
+	Once the window geometry of the surface is set, it is not possible to
+	unset it, and it will remain the same until set_window_geometry is
+	called again, even if a new subsurface or buffer is attached.
+
+	If never set, the value is the full bounds of the surface,
+	including any subsurfaces. This updates dynamically on every
+	commit. This unset is meant for extremely simple clients.
+
+	The arguments are given in the surface-local coordinate space of
+	the wl_surface associated with this xdg_surface.
+
+	The width and height must be greater than zero. Setting an invalid size
+	will raise an error. When applied, the effective window geometry will be
+	the set window geometry clamped to the bounding rectangle of the
+	combined geometry of the surface of the xdg_surface and the associated
+	subsurfaces.
+      </description>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="ack_configure">
+      <description summary="ack a configure event">
+	When a configure event is received, if a client commits the
+	surface in response to the configure event, then the client
+	must make an ack_configure request sometime before the commit
+	request, passing along the serial of the configure event.
+
+	For instance, for toplevel surfaces the compositor might use this
+	information to move a surface to the top left only when the client has
+	drawn itself for the maximized or fullscreen state.
+
+	If the client receives multiple configure events before it
+	can respond to one, it only has to ack the last configure event.
+
+	A client is not required to commit immediately after sending
+	an ack_configure request - it may even ack_configure several times
+	before its next surface commit.
+
+	A client may send multiple ack_configure requests before committing, but
+	only the last request sent before a commit indicates which configure
+	event the client really is responding to.
+      </description>
+      <arg name="serial" type="uint" summary="the serial from the configure event"/>
+    </request>
+
+    <event name="configure">
+      <description summary="suggest a surface change">
+	The configure event marks the end of a configure sequence. A configure
+	sequence is a set of one or more events configuring the state of the
+	xdg_surface, including the final xdg_surface.configure event.
+
+	Where applicable, xdg_surface surface roles will during a configure
+	sequence extend this event as a latched state sent as events before the
+	xdg_surface.configure event. Such events should be considered to make up
+	a set of atomically applied configuration states, where the
+	xdg_surface.configure commits the accumulated state.
+
+	Clients should arrange their surface for the new states, and then send
+	an ack_configure request with the serial sent in this configure event at
+	some point before committing the new surface.
+
+	If the client receives multiple configure events before it can respond
+	to one, it is free to discard all but the last event it received.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the configure event"/>
+    </event>
+  </interface>
+
+  <interface name="zxdg_toplevel_v6" version="1">
+    <description summary="toplevel surface">
+      This interface defines an xdg_surface role which allows a surface to,
+      among other things, set window-like properties such as maximize,
+      fullscreen, and minimize, set application-specific metadata like title and
+      id, and well as trigger user interactive operations such as interactive
+      resize and move.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_toplevel">
+	Unmap and destroy the window. The window will be effectively
+	hidden from the user's point of view, and all state like
+	maximization, fullscreen, and so on, will be lost.
+      </description>
+    </request>
+
+    <request name="set_parent">
+      <description summary="set the parent of this surface">
+	Set the "parent" of this surface. This window should be stacked
+	above a parent. The parent surface must be mapped as long as this
+	surface is mapped.
+
+	Parent windows should be set on dialogs, toolboxes, or other
+	"auxiliary" surfaces, so that the parent is raised when the dialog
+	is raised.
+      </description>
+      <arg name="parent" type="object" interface="zxdg_toplevel_v6" allow-null="true"/>
+    </request>
+
+    <request name="set_title">
+      <description summary="set surface title">
+	Set a short title for the surface.
+
+	This string may be used to identify the surface in a task bar,
+	window list, or other user interface elements provided by the
+	compositor.
+
+	The string must be encoded in UTF-8.
+      </description>
+      <arg name="title" type="string"/>
+    </request>
+
+    <request name="set_app_id">
+      <description summary="set application ID">
+	Set an application identifier for the surface.
+
+	The app ID identifies the general class of applications to which
+	the surface belongs. The compositor can use this to group multiple
+	surfaces together, or to determine how to launch a new application.
+
+	For D-Bus activatable applications, the app ID is used as the D-Bus
+	service name.
+
+	The compositor shell will try to group application surfaces together
+	by their app ID. As a best practice, it is suggested to select app
+	ID's that match the basename of the application's .desktop file.
+	For example, "org.freedesktop.FooViewer" where the .desktop file is
+	"org.freedesktop.FooViewer.desktop".
+
+	See the desktop-entry specification [0] for more details on
+	application identifiers and how they relate to well-known D-Bus
+	names and .desktop files.
+
+	[0] http://standards.freedesktop.org/desktop-entry-spec/
+      </description>
+      <arg name="app_id" type="string"/>
+    </request>
+
+    <request name="show_window_menu">
+      <description summary="show the window menu">
+	Clients implementing client-side decorations might want to show
+	a context menu when right-clicking on the decorations, giving the
+	user a menu that they can use to maximize or minimize the window.
+
+	This request asks the compositor to pop up such a window menu at
+	the given position, relative to the local surface coordinates of
+	the parent surface. There are no guarantees as to what menu items
+	the window menu contains.
+
+	This request must be used in response to some sort of user action
+	like a button press, key press, or touch down event.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+      <arg name="x" type="int" summary="the x position to pop up the window menu at"/>
+      <arg name="y" type="int" summary="the y position to pop up the window menu at"/>
+    </request>
+
+    <request name="move">
+      <description summary="start an interactive move">
+	Start an interactive, user-driven move of the surface.
+
+	This request must be used in response to some sort of user action
+	like a button press, key press, or touch down event. The passed
+	serial is used to determine the type of interactive move (touch,
+	pointer, etc).
+
+	The server may ignore move requests depending on the state of
+	the surface (e.g. fullscreen or maximized), or if the passed serial
+	is no longer valid.
+
+	If triggered, the surface will lose the focus of the device
+	(wl_pointer, wl_touch, etc) used for the move. It is up to the
+	compositor to visually indicate that the move is taking place, such as
+	updating a pointer cursor, during the move. There is no guarantee
+	that the device focus will return when the move is completed.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+    </request>
+
+    <enum name="resize_edge">
+      <description summary="edge values for resizing">
+	These values are used to indicate which edge of a surface
+	is being dragged in a resize operation.
+      </description>
+      <entry name="none" value="0"/>
+      <entry name="top" value="1"/>
+      <entry name="bottom" value="2"/>
+      <entry name="left" value="4"/>
+      <entry name="top_left" value="5"/>
+      <entry name="bottom_left" value="6"/>
+      <entry name="right" value="8"/>
+      <entry name="top_right" value="9"/>
+      <entry name="bottom_right" value="10"/>
+    </enum>
+
+    <request name="resize">
+      <description summary="start an interactive resize">
+	Start a user-driven, interactive resize of the surface.
+
+	This request must be used in response to some sort of user action
+	like a button press, key press, or touch down event. The passed
+	serial is used to determine the type of interactive resize (touch,
+	pointer, etc).
+
+	The server may ignore resize requests depending on the state of
+	the surface (e.g. fullscreen or maximized).
+
+	If triggered, the client will receive configure events with the
+	"resize" state enum value and the expected sizes. See the "resize"
+	enum value for more details about what is required. The client
+	must also acknowledge configure events using "ack_configure". After
+	the resize is completed, the client will receive another "configure"
+	event without the resize state.
+
+	If triggered, the surface also will lose the focus of the device
+	(wl_pointer, wl_touch, etc) used for the resize. It is up to the
+	compositor to visually indicate that the resize is taking place,
+	such as updating a pointer cursor, during the resize. There is no
+	guarantee that the device focus will return when the resize is
+	completed.
+
+	The edges parameter specifies how the surface should be resized,
+	and is one of the values of the resize_edge enum. The compositor
+	may use this information to update the surface position for
+	example when dragging the top left corner. The compositor may also
+	use this information to adapt its behavior, e.g. choose an
+	appropriate cursor image.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+      <arg name="edges" type="uint" summary="which edge or corner is being dragged"/>
+    </request>
+
+    <enum name="state">
+      <description summary="types of state on the surface">
+	The different state values used on the surface. This is designed for
+	state values like maximized, fullscreen. It is paired with the
+	configure event to ensure that both the client and the compositor
+	setting the state can be synchronized.
+
+	States set in this way are double-buffered. They will get applied on
+	the next commit.
+      </description>
+      <entry name="maximized" value="1" summary="the surface is maximized">
+	<description summary="the surface is maximized">
+	  The surface is maximized. The window geometry specified in the configure
+	  event must be obeyed by the client.
+	</description>
+      </entry>
+      <entry name="fullscreen" value="2" summary="the surface is fullscreen">
+	<description summary="the surface is fullscreen">
+	  The surface is fullscreen. The window geometry specified in the configure
+	  event must be obeyed by the client.
+	</description>
+      </entry>
+      <entry name="resizing" value="3" summary="the surface is being resized">
+	<description summary="the surface is being resized">
+	  The surface is being resized. The window geometry specified in the
+	  configure event is a maximum; the client cannot resize beyond it.
+	  Clients that have aspect ratio or cell sizing configuration can use
+	  a smaller size, however.
+	</description>
+      </entry>
+      <entry name="activated" value="4" summary="the surface is now activated">
+	<description summary="the surface is now activated">
+	  Client window decorations should be painted as if the window is
+	  active. Do not assume this means that the window actually has
+	  keyboard or pointer focus.
+	</description>
+      </entry>
+    </enum>
+
+    <request name="set_max_size">
+      <description summary="set the maximum size">
+	Set a maximum size for the window.
+
+	The client can specify a maximum size so that the compositor does
+	not try to configure the window beyond this size.
+
+	The width and height arguments are in window geometry coordinates.
+	See xdg_surface.set_window_geometry.
+
+	Values set in this way are double-buffered. They will get applied
+	on the next commit.
+
+	The compositor can use this information to allow or disallow
+	different states like maximize or fullscreen and draw accurate
+	animations.
+
+	Similarly, a tiling window manager may use this information to
+	place and resize client windows in a more effective way.
+
+	The client should not rely on the compositor to obey the maximum
+	size. The compositor may decide to ignore the values set by the
+	client and request a larger size.
+
+	If never set, or a value of zero in the request, means that the
+	client has no expected maximum size in the given dimension.
+	As a result, a client wishing to reset the maximum size
+	to an unspecified state can use zero for width and height in the
+	request.
+
+	Requesting a maximum size to be smaller than the minimum size of
+	a surface is illegal and will result in a protocol error.
+
+	The width and height must be greater than or equal to zero. Using
+	strictly negative values for width and height will result in a
+	protocol error.
+      </description>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="set_min_size">
+      <description summary="set the minimum size">
+	Set a minimum size for the window.
+
+	The client can specify a minimum size so that the compositor does
+	not try to configure the window below this size.
+
+	The width and height arguments are in window geometry coordinates.
+	See xdg_surface.set_window_geometry.
+
+	Values set in this way are double-buffered. They will get applied
+	on the next commit.
+
+	The compositor can use this information to allow or disallow
+	different states like maximize or fullscreen and draw accurate
+	animations.
+
+	Similarly, a tiling window manager may use this information to
+	place and resize client windows in a more effective way.
+
+	The client should not rely on the compositor to obey the minimum
+	size. The compositor may decide to ignore the values set by the
+	client and request a smaller size.
+
+	If never set, or a value of zero in the request, means that the
+	client has no expected minimum size in the given dimension.
+	As a result, a client wishing to reset the minimum size
+	to an unspecified state can use zero for width and height in the
+	request.
+
+	Requesting a minimum size to be larger than the maximum size of
+	a surface is illegal and will result in a protocol error.
+
+	The width and height must be greater than or equal to zero. Using
+	strictly negative values for width and height will result in a
+	protocol error.
+      </description>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="set_maximized">
+      <description summary="maximize the window">
+	Maximize the surface.
+
+	After requesting that the surface should be maximized, the compositor
+	will respond by emitting a configure event with the "maximized" state
+	and the required window geometry. The client should then update its
+	content, drawing it in a maximized state, i.e. without shadow or other
+	decoration outside of the window geometry. The client must also
+	acknowledge the configure when committing the new content (see
+	ack_configure).
+
+	It is up to the compositor to decide how and where to maximize the
+	surface, for example which output and what region of the screen should
+	be used.
+
+	If the surface was already maximized, the compositor will still emit
+	a configure event with the "maximized" state.
+      </description>
+    </request>
+
+    <request name="unset_maximized">
+      <description summary="unmaximize the window">
+	Unmaximize the surface.
+
+	After requesting that the surface should be unmaximized, the compositor
+	will respond by emitting a configure event without the "maximized"
+	state. If available, the compositor will include the window geometry
+	dimensions the window had prior to being maximized in the configure
+	request. The client must then update its content, drawing it in a
+	regular state, i.e. potentially with shadow, etc. The client must also
+	acknowledge the configure when committing the new content (see
+	ack_configure).
+
+	It is up to the compositor to position the surface after it was
+	unmaximized; usually the position the surface had before maximizing, if
+	applicable.
+
+	If the surface was already not maximized, the compositor will still
+	emit a configure event without the "maximized" state.
+      </description>
+    </request>
+
+    <request name="set_fullscreen">
+      <description summary="set the window as fullscreen on a monitor">
+	Make the surface fullscreen.
+
+	You can specify an output that you would prefer to be fullscreen.
+	If this value is NULL, it's up to the compositor to choose which
+	display will be used to map this surface.
+
+	If the surface doesn't cover the whole output, the compositor will
+	position the surface in the center of the output and compensate with
+	black borders filling the rest of the output.
+      </description>
+      <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+    </request>
+    <request name="unset_fullscreen" />
+
+    <request name="set_minimized">
+      <description summary="set the window as minimized">
+	Request that the compositor minimize your surface. There is no
+	way to know if the surface is currently minimized, nor is there
+	any way to unset minimization on this surface.
+
+	If you are looking to throttle redrawing when minimized, please
+	instead use the wl_surface.frame event for this, as this will
+	also work with live previews on windows in Alt-Tab, Expose or
+	similar compositor features.
+      </description>
+    </request>
+
+    <event name="configure">
+      <description summary="suggest a surface change">
+	This configure event asks the client to resize its toplevel surface or
+	to change its state. The configured state should not be applied
+	immediately. See xdg_surface.configure for details.
+
+	The width and height arguments specify a hint to the window
+	about how its surface should be resized in window geometry
+	coordinates. See set_window_geometry.
+
+	If the width or height arguments are zero, it means the client
+	should decide its own window dimension. This may happen when the
+	compositor needs to configure the state of the surface but doesn't
+	have any information about any previous or expected dimension.
+
+	The states listed in the event specify how the width/height
+	arguments should be interpreted, and possibly how it should be
+	drawn.
+
+	Clients must send an ack_configure in response to this event. See
+	xdg_surface.configure and xdg_surface.ack_configure for details.
+      </description>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+      <arg name="states" type="array"/>
+    </event>
+
+    <event name="close">
+      <description summary="surface wants to be closed">
+	The close event is sent by the compositor when the user
+	wants the surface to be closed. This should be equivalent to
+	the user clicking the close button in client-side decorations,
+	if your application has any.
+
+	This is only a request that the user intends to close the
+	window. The client may choose to ignore this request, or show
+	a dialog to ask the user to save their data, etc.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="zxdg_popup_v6" version="1">
+    <description summary="short-lived, popup surfaces for menus">
+      A popup surface is a short-lived, temporary surface. It can be used to
+      implement for example menus, popovers, tooltips and other similar user
+      interface concepts.
+
+      A popup can be made to take an explicit grab. See xdg_popup.grab for
+      details.
+
+      When the popup is dismissed, a popup_done event will be sent out, and at
+      the same time the surface will be unmapped. See the xdg_popup.popup_done
+      event for details.
+
+      Explicitly destroying the xdg_popup object will also dismiss the popup and
+      unmap the surface. Clients that want to dismiss the popup when another
+      surface of their own is clicked should dismiss the popup using the destroy
+      request.
+
+      The parent surface must have either the xdg_toplevel or xdg_popup surface
+      role.
+
+      A newly created xdg_popup will be stacked on top of all previously created
+      xdg_popup surfaces associated with the same xdg_toplevel.
+
+      The parent of an xdg_popup must be mapped (see the xdg_surface
+      description) before the xdg_popup itself.
+
+      The x and y arguments passed when creating the popup object specify
+      where the top left of the popup should be placed, relative to the
+      local surface coordinates of the parent surface. See
+      xdg_surface.get_popup. An xdg_popup must intersect with or be at least
+      partially adjacent to its parent surface.
+
+      The client must call wl_surface.commit on the corresponding wl_surface
+      for the xdg_popup state to take effect.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_grab" value="0"
+	     summary="tried to grab after being mapped"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="remove xdg_popup interface">
+	This destroys the popup. Explicitly destroying the xdg_popup
+	object will also dismiss the popup, and unmap the surface.
+
+	If this xdg_popup is not the "topmost" popup, a protocol error
+	will be sent.
+      </description>
+    </request>
+
+    <request name="grab">
+      <description summary="make the popup take an explicit grab">
+	This request makes the created popup take an explicit grab. An explicit
+	grab will be dismissed when the user dismisses the popup, or when the
+	client destroys the xdg_popup. This can be done by the user clicking
+	outside the surface, using the keyboard, or even locking the screen
+	through closing the lid or a timeout.
+
+	If the compositor denies the grab, the popup will be immediately
+	dismissed.
+
+	This request must be used in response to some sort of user action like a
+	button press, key press, or touch down event. The serial number of the
+	event should be passed as 'serial'.
+
+	The parent of a grabbing popup must either be an xdg_toplevel surface or
+	another xdg_popup with an explicit grab. If the parent is another
+	xdg_popup it means that the popups are nested, with this popup now being
+	the topmost popup.
+
+	Nested popups must be destroyed in the reverse order they were created
+	in, e.g. the only popup you are allowed to destroy at all times is the
+	topmost one.
+
+	When compositors choose to dismiss a popup, they may dismiss every
+	nested grabbing popup as well. When a compositor dismisses popups, it
+	will follow the same dismissing order as required from the client.
+
+	The parent of a grabbing popup must either be another xdg_popup with an
+	active explicit grab, or an xdg_popup or xdg_toplevel, if there are no
+	explicit grabs already taken.
+
+	If the topmost grabbing popup is destroyed, the grab will be returned to
+	the parent of the popup, if that parent previously had an explicit grab.
+
+	If the parent is a grabbing popup which has already been dismissed, this
+	popup will be immediately dismissed. If the parent is a popup that did
+	not take an explicit grab, an error will be raised.
+
+	During a popup grab, the client owning the grab will receive pointer
+	and touch events for all their surfaces as normal (similar to an
+	"owner-events" grab in X11 parlance), while the top most grabbing popup
+	will always have keyboard focus.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat"
+	   summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+    </request>
+
+    <event name="configure">
+      <description summary="configure the popup surface">
+	This event asks the popup surface to configure itself given the
+	configuration. The configured state should not be applied immediately.
+	See xdg_surface.configure for details.
+
+	The x and y arguments represent the position the popup was placed at
+	given the xdg_positioner rule, relative to the upper left corner of the
+	window geometry of the parent surface.
+      </description>
+      <arg name="x" type="int"
+	   summary="x position relative to parent surface window geometry"/>
+      <arg name="y" type="int"
+	   summary="y position relative to parent surface window geometry"/>
+      <arg name="width" type="int" summary="window geometry width"/>
+      <arg name="height" type="int" summary="window geometry height"/>
+    </event>
+
+    <event name="popup_done">
+      <description summary="popup interaction is done">
+	The popup_done event is sent out when a popup is dismissed by the
+	compositor. The client should destroy the xdg_popup object at this
+	point.
+      </description>
+    </event>
+
+  </interface>
+</protocol>
diff --git a/gpu_display/src/display_wl.c b/gpu_display/src/display_wl.c
new file mode 100644
index 0000000..fce0ee0
--- /dev/null
+++ b/gpu_display/src/display_wl.c
@@ -0,0 +1,781 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <assert.h>
+#include <memory.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "aura-shell.h"
+#include "linux-dmabuf-unstable-v1.h"
+#include "viewporter.h"
+#include "xdg-shell-unstable-v6.h"
+#include <wayland-client-core.h>
+#include <wayland-client-protocol.h>
+#include <wayland-client.h>
+
+#define DEFAULT_SCALE 2
+#define MAX_BUFFER_COUNT 64
+
+struct dwl_context;
+
+struct interfaces {
+	struct dwl_context *context;
+	struct wl_compositor *compositor;
+	struct wl_subcompositor *subcompositor;
+	struct wl_shm *shm;
+	struct wl_shell *shell;
+	struct wl_seat *seat;
+	struct zaura_shell *aura; // optional
+	struct zwp_linux_dmabuf_v1 *linux_dmabuf;
+	struct zxdg_shell_v6 *xdg_shell;
+	struct wp_viewporter *viewporter; // optional
+};
+
+struct output {
+	struct wl_output *output;
+	struct zaura_output *aura_output;
+	struct dwl_context *context;
+	uint32_t id;
+	uint32_t current_scale;
+	uint32_t device_scale_factor;
+	bool internal;
+};
+
+struct dwl_context {
+	struct wl_display *display;
+	struct interfaces ifaces;
+	bool output_added;
+	struct output outputs[8];
+};
+
+#define outputs_for_each(context, pos, output)                                 \
+	for (pos = 0, output = &context->outputs[pos];                         \
+	     pos < (sizeof(context->outputs) / sizeof(context->outputs[0]));   \
+	     pos++, output = &context->outputs[pos])
+
+struct dwl_dmabuf {
+	uint32_t width;
+	uint32_t height;
+	bool in_use;
+	struct wl_buffer *buffer;
+};
+
+struct dwl_surface {
+	struct dwl_context *context;
+	struct wl_surface *surface;
+	struct zaura_surface *aura;
+	struct zxdg_surface_v6 *xdg;
+	struct zxdg_toplevel_v6 *toplevel;
+	struct wp_viewport *viewport;
+	struct wl_subsurface *subsurface;
+	uint32_t width;
+	uint32_t height;
+	double scale;
+	bool close_requested;
+	size_t buffer_count;
+	uint64_t buffer_use_bit_mask;
+	struct wl_buffer *buffers[0];
+};
+
+static_assert(sizeof(((struct dwl_surface *)0)->buffer_use_bit_mask) * 8 >=
+		  MAX_BUFFER_COUNT,
+	      "not enough bits in buffer_use_bit_mask");
+
+static void output_geometry(void *data, struct wl_output *output, int x, int y,
+			    int physical_width, int physical_height,
+			    int subpixel, const char *make, const char *model,
+			    int transform)
+{
+	(void)data;
+	(void)output;
+	(void)x;
+	(void)y;
+	(void)physical_width;
+	(void)physical_height;
+	(void)subpixel;
+	(void)make;
+	(void)model;
+	(void)transform;
+}
+
+static void output_mode(void *data, struct wl_output *output, uint32_t flags,
+			int width, int height, int refresh)
+{
+	(void)data;
+	(void)output;
+	(void)flags;
+	(void)width;
+	(void)height;
+	(void)refresh;
+}
+
+static void output_done(void *data, struct wl_output *output)
+{
+	(void)data;
+	(void)output;
+}
+
+static void output_scale(void *data, struct wl_output *wl_output,
+			 int32_t scale_factor)
+{
+	(void)wl_output;
+	struct output *output = (struct output *)data;
+	struct dwl_context *context = output->context;
+
+	// If the aura interface is available, we prefer the scale factor
+	// reported by that.
+	if (context->ifaces.aura)
+		return;
+
+	output->current_scale = 1000 * scale_factor;
+}
+
+static const struct wl_output_listener output_listener = {
+    .geometry = output_geometry,
+    .mode = output_mode,
+    .done = output_done,
+    .scale = output_scale};
+
+static void aura_output_scale(void *data, struct zaura_output *aura_output,
+			      uint32_t flags, uint32_t scale)
+{
+	(void)aura_output;
+	struct output *output = (struct output *)data;
+	if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT) {
+		output->current_scale = scale;
+	}
+}
+
+static void aura_output_connection(void *data, struct zaura_output *aura_output,
+				   uint32_t connection)
+{
+	(void)aura_output;
+	struct output *output = (struct output *)data;
+	output->internal = connection == ZAURA_OUTPUT_CONNECTION_TYPE_INTERNAL;
+}
+
+static void aura_output_device_scale_factor(void *data,
+					    struct zaura_output *aura_output,
+					    uint32_t device_scale_factor)
+{
+	(void)aura_output;
+	struct output *output = (struct output *)data;
+	output->device_scale_factor = device_scale_factor;
+}
+
+static const struct zaura_output_listener aura_output_listener = {
+    .scale = aura_output_scale,
+    .connection = aura_output_connection,
+    .device_scale_factor = aura_output_device_scale_factor};
+
+static void dwl_context_output_add(struct dwl_context *context,
+				   struct wl_output *wl_output, uint32_t id)
+{
+	size_t i;
+	struct output *output;
+	outputs_for_each(context, i, output)
+	{
+		if (output->output == NULL) {
+			context->output_added = true;
+			output->id = id;
+			output->output = wl_output;
+			output->context = context;
+			output->current_scale = 1000;
+			output->device_scale_factor = 1000;
+			// This is a fun little hack from reveman. The idea is
+			// that the first display will be internal and never get
+			// removed.
+			output->internal = i == 0;
+			wl_output_add_listener(output->output, &output_listener,
+					       output);
+			return;
+		}
+	}
+}
+
+static void dwl_context_output_remove_destroy(struct dwl_context *context,
+					      uint32_t id)
+{
+	size_t i;
+	struct output *output;
+	outputs_for_each(context, i, output)
+	{
+		if (output->id == id) {
+			if (output->aura_output)
+				zaura_output_destroy(output->aura_output);
+			wl_output_destroy(output->output);
+			memset(output, 0, sizeof(struct output));
+			return;
+		}
+	}
+}
+
+static void dwl_context_output_get_aura(struct dwl_context *context)
+{
+	if (!context->ifaces.aura)
+		return;
+
+	size_t i;
+	struct output *output;
+	outputs_for_each(context, i, output)
+	{
+		if (output->output != NULL && output->aura_output == NULL) {
+			output->aura_output = zaura_shell_get_aura_output(
+			    context->ifaces.aura, output->output);
+			zaura_output_add_listener(
+			    output->aura_output, &aura_output_listener, output);
+		}
+	}
+}
+
+static void registry_global(void *data, struct wl_registry *registry,
+			    uint32_t id, const char *interface,
+			    uint32_t version)
+{
+	(void)version;
+	struct interfaces *ifaces = (struct interfaces *)data;
+	if (strcmp(interface, "wl_compositor") == 0) {
+		ifaces->compositor = (struct wl_compositor *)wl_registry_bind(
+		    registry, id, &wl_compositor_interface, 3);
+	} else if (strcmp(interface, "wl_subcompositor") == 0) {
+		ifaces->subcompositor =
+		    (struct wl_subcompositor *)wl_registry_bind(
+			registry, id, &wl_subcompositor_interface, 1);
+	} else if (strcmp(interface, "wl_shm") == 0) {
+		ifaces->shm = (struct wl_shm *)wl_registry_bind(
+		    registry, id, &wl_shm_interface, 1);
+	} else if (strcmp(interface, "wl_seat") == 0) {
+		ifaces->seat = (struct wl_seat *)wl_registry_bind(
+		    registry, id, &wl_seat_interface, 5);
+	} else if (strcmp(interface, "wl_output") == 0) {
+		struct wl_output *output = (struct wl_output *)wl_registry_bind(
+		    registry, id, &wl_output_interface, 2);
+		dwl_context_output_add(ifaces->context, output, id);
+	} else if (strcmp(interface, "zaura_shell") == 0 && version >= 6) {
+		ifaces->aura = (struct zaura_shell *)wl_registry_bind(
+		    registry, id, &zaura_shell_interface, 6);
+	} else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
+		ifaces->linux_dmabuf =
+		    (struct zwp_linux_dmabuf_v1 *)wl_registry_bind(
+			registry, id, &zwp_linux_dmabuf_v1_interface, 1);
+	} else if (strcmp(interface, "zxdg_shell_v6") == 0) {
+		ifaces->xdg_shell = (struct zxdg_shell_v6 *)wl_registry_bind(
+		    registry, id, &zxdg_shell_v6_interface, 1);
+	} else if (strcmp(interface, "wp_viewporter") == 0) {
+		ifaces->viewporter = (struct wp_viewporter *)wl_registry_bind(
+		    registry, id, &wp_viewporter_interface, 1);
+	}
+}
+
+static void global_remove(void *data, struct wl_registry *registry, uint32_t id)
+{
+	(void)registry;
+
+	struct interfaces *ifaces = (struct interfaces *)data;
+	// If the ID matches any output, this will remove it. Otherwise, this is
+	// a no-op.
+	dwl_context_output_remove_destroy(ifaces->context, id);
+
+	if (ifaces->aura &&
+	    wl_proxy_get_id((struct wl_proxy *)ifaces->aura) == id) {
+		zaura_shell_destroy(ifaces->aura);
+		ifaces->aura = NULL;
+	}
+
+	// TODO(zachr): deal with the removal of some of the required
+	// interfaces.
+}
+
+static const struct wl_registry_listener registry_listener = {
+    .global = registry_global, .global_remove = global_remove};
+
+static void toplevel_configure(void *data,
+			       struct zxdg_toplevel_v6 *zxdg_toplevel_v6,
+			       int32_t width, int32_t height,
+			       struct wl_array *states)
+{
+	(void)data;
+	(void)zxdg_toplevel_v6;
+	(void)width;
+	(void)height;
+	(void)states;
+}
+
+static void toplevel_close(void *data,
+			   struct zxdg_toplevel_v6 *zxdg_toplevel_v6)
+{
+	(void)zxdg_toplevel_v6;
+	struct dwl_surface *surface = (struct dwl_surface *)data;
+	surface->close_requested = true;
+}
+
+static const struct zxdg_toplevel_v6_listener toplevel_listener = {
+    .configure = toplevel_configure, .close = toplevel_close};
+
+static void surface_enter(void *data, struct wl_surface *wl_surface,
+			  struct wl_output *wl_output)
+{
+	struct dwl_surface *surface = (struct dwl_surface *)data;
+
+	struct output *output =
+	    (struct output *)wl_output_get_user_data(wl_output);
+
+	surface->scale = (output->device_scale_factor / 1000.0) *
+			 (output->current_scale / 1000.0);
+
+	if (surface->viewport) {
+		wp_viewport_set_destination(
+		    surface->viewport, ceil(surface->width / surface->scale),
+		    ceil(surface->height / surface->scale));
+	} else {
+		wl_surface_set_buffer_scale(wl_surface, surface->scale);
+	}
+
+	wl_surface_commit(wl_surface);
+}
+
+static void surface_leave(void *data, struct wl_surface *wl_surface,
+			  struct wl_output *output)
+{
+	(void)data;
+	(void)wl_surface;
+	(void)output;
+}
+
+static const struct wl_surface_listener surface_listener = {
+    .enter = surface_enter, .leave = surface_leave};
+
+struct dwl_context *dwl_context_new()
+{
+	struct dwl_context *ctx = calloc(1, sizeof(struct dwl_context));
+	ctx->ifaces.context = ctx;
+	return ctx;
+}
+
+void dwl_context_destroy(struct dwl_context **self)
+{
+	if ((*self)->display)
+		wl_display_disconnect((*self)->display);
+	free(*self);
+	*self = NULL;
+}
+
+bool dwl_context_setup(struct dwl_context *self, const char *socket_path)
+{
+	struct wl_display *display = wl_display_connect(socket_path);
+	if (!display) {
+		syslog(LOG_ERR, "failed to connect to display");
+		return false;
+	}
+	self->display = display;
+	wl_display_set_user_data(display, self);
+
+	struct wl_registry *registry = wl_display_get_registry(display);
+	if (!registry) {
+		syslog(LOG_ERR, "failed to get registry");
+		goto fail;
+	}
+
+	struct interfaces *ifaces = &self->ifaces;
+	wl_registry_add_listener(registry, &registry_listener, ifaces);
+	wl_display_roundtrip(display);
+	dwl_context_output_get_aura(self);
+
+	if (!ifaces->shm) {
+		syslog(LOG_ERR, "missing interface shm");
+		goto fail;
+	}
+	if (!ifaces->compositor) {
+		syslog(LOG_ERR, "missing interface compositor");
+		goto fail;
+	}
+	if (!ifaces->subcompositor) {
+		syslog(LOG_ERR, "missing interface subcompositor");
+		goto fail;
+	}
+	if (!ifaces->seat) {
+		syslog(LOG_ERR, "missing interface seat");
+		goto fail;
+	}
+	if (!ifaces->linux_dmabuf) {
+		syslog(LOG_ERR, "missing interface linux_dmabuf");
+		goto fail;
+	}
+	if (!ifaces->xdg_shell) {
+		syslog(LOG_ERR, "missing interface xdg_shell");
+		goto fail;
+	}
+
+	return true;
+
+fail:
+	wl_display_disconnect(display);
+	return false;
+}
+
+int dwl_context_fd(struct dwl_context *self)
+{
+	return wl_display_get_fd(self->display);
+}
+
+void dwl_context_dispatch(struct dwl_context *self)
+{
+	wl_display_dispatch(self->display);
+	if (self->output_added) {
+		self->output_added = false;
+		dwl_context_output_get_aura(self);
+		wl_display_roundtrip(self->display);
+	}
+}
+
+static void linux_buffer_created(
+    void *data, struct zwp_linux_buffer_params_v1 *zwp_linux_buffer_params_v1,
+    struct wl_buffer *buffer)
+{
+	(void)zwp_linux_buffer_params_v1;
+	struct dwl_dmabuf *dmabuf = (struct dwl_dmabuf *)data;
+	dmabuf->buffer = buffer;
+}
+
+static void linux_buffer_failed(
+    void *data, struct zwp_linux_buffer_params_v1 *zwp_linux_buffer_params_v1)
+{
+	(void)data;
+	(void)zwp_linux_buffer_params_v1;
+}
+
+static const struct zwp_linux_buffer_params_v1_listener linux_buffer_listener =
+    {.created = linux_buffer_created, .failed = linux_buffer_failed};
+
+static void dmabuf_buffer_release(void *data, struct wl_buffer *buffer)
+{
+	struct dwl_dmabuf *dmabuf = (struct dwl_dmabuf *)data;
+	(void)buffer;
+
+	dmabuf->in_use = false;
+}
+
+static const struct wl_buffer_listener dmabuf_buffer_listener = {
+    .release = dmabuf_buffer_release};
+
+struct dwl_dmabuf *dwl_context_dmabuf_new(struct dwl_context *self, int fd,
+					  uint32_t offset, uint32_t stride,
+					  uint64_t modifiers, uint32_t width,
+					  uint32_t height, uint32_t fourcc)
+{
+	struct dwl_dmabuf *dmabuf = calloc(1, sizeof(struct dwl_dmabuf));
+	if (!dmabuf) {
+		syslog(LOG_ERR, "failed to allocate dwl_dmabuf");
+		return NULL;
+	}
+	dmabuf->width = width;
+	dmabuf->height = height;
+
+	struct zwp_linux_buffer_params_v1 *params =
+	    zwp_linux_dmabuf_v1_create_params(self->ifaces.linux_dmabuf);
+	if (!params) {
+		syslog(LOG_ERR,
+		       "failed to allocate zwp_linux_buffer_params_v1");
+		free(dmabuf);
+		return NULL;
+	}
+
+	zwp_linux_buffer_params_v1_add_listener(params, &linux_buffer_listener,
+						dmabuf);
+	zwp_linux_buffer_params_v1_add(params, fd, 0 /* plane_idx */, offset,
+				       stride, modifiers >> 32,
+				       (uint32_t)modifiers);
+	zwp_linux_buffer_params_v1_create(params, width, height, fourcc, 0);
+	wl_display_roundtrip(self->display);
+	zwp_linux_buffer_params_v1_destroy(params);
+
+	if (!dmabuf->buffer) {
+		syslog(LOG_ERR, "failed to get wl_buffer for dmabuf");
+		free(dmabuf);
+		return NULL;
+	}
+
+	wl_buffer_add_listener(dmabuf->buffer, &dmabuf_buffer_listener, dmabuf);
+
+	return dmabuf;
+}
+
+void dwl_dmabuf_destroy(struct dwl_dmabuf **self)
+{
+	wl_buffer_destroy((*self)->buffer);
+	free(*self);
+	*self = NULL;
+}
+
+static void surface_buffer_release(void *data, struct wl_buffer *buffer)
+{
+	struct dwl_surface *surface = (struct dwl_surface *)data;
+	(void)buffer;
+
+	size_t i;
+	for (i = 0; i < surface->buffer_count; i++) {
+		if (buffer == surface->buffers[i]) {
+			surface->buffer_use_bit_mask &= ~(1 << i);
+			break;
+		}
+	}
+}
+
+static const struct wl_buffer_listener surface_buffer_listener = {
+    .release = surface_buffer_release};
+
+struct dwl_surface *dwl_context_surface_new(struct dwl_context *self,
+					    struct dwl_surface *parent,
+					    int shm_fd, size_t shm_size,
+					    size_t buffer_size, uint32_t width,
+					    uint32_t height, uint32_t stride)
+{
+	if (buffer_size == 0)
+		return NULL;
+	size_t buffer_count = shm_size / buffer_size;
+	if (buffer_count == 0)
+		return NULL;
+	if (buffer_count > MAX_BUFFER_COUNT)
+		return NULL;
+
+	struct dwl_surface *disp_surface =
+	    calloc(1, sizeof(struct dwl_surface) +
+			  sizeof(struct wl_buffer *) * buffer_count);
+	if (!disp_surface)
+		return NULL;
+	disp_surface->context = self;
+	disp_surface->width = width;
+	disp_surface->height = height;
+	disp_surface->scale = DEFAULT_SCALE;
+	disp_surface->buffer_count = buffer_count;
+
+	struct wl_region *region = NULL;
+	struct wl_shm_pool *shm_pool =
+	    wl_shm_create_pool(self->ifaces.shm, shm_fd, shm_size);
+	if (!shm_pool) {
+		syslog(LOG_ERR, "failed to make shm pool");
+		goto fail;
+	}
+
+	size_t i;
+	for (i = 0; i < buffer_count; i++) {
+		struct wl_buffer *buffer = wl_shm_pool_create_buffer(
+		    shm_pool, buffer_size * i, width, height, stride,
+		    WL_SHM_FORMAT_ARGB8888);
+		if (!buffer) {
+			syslog(LOG_ERR, "failed to create buffer");
+			goto fail;
+		}
+		disp_surface->buffers[i] = buffer;
+	}
+
+	for (i = 0; i < buffer_count; i++)
+		wl_buffer_add_listener(disp_surface->buffers[i],
+				       &surface_buffer_listener, disp_surface);
+
+	disp_surface->surface =
+	    wl_compositor_create_surface(self->ifaces.compositor);
+	if (!disp_surface->surface) {
+		syslog(LOG_ERR, "failed to make surface");
+		goto fail;
+	}
+
+	wl_surface_add_listener(disp_surface->surface, &surface_listener,
+				disp_surface);
+
+	region = wl_compositor_create_region(self->ifaces.compositor);
+	if (!region) {
+		syslog(LOG_ERR, "failed to make region");
+		goto fail;
+	}
+	wl_region_add(region, 0, 0, width, height);
+	wl_surface_set_opaque_region(disp_surface->surface, region);
+
+	if (!parent) {
+		disp_surface->xdg = zxdg_shell_v6_get_xdg_surface(
+		    self->ifaces.xdg_shell, disp_surface->surface);
+		if (!disp_surface->xdg) {
+			syslog(LOG_ERR, "failed to make xdg shell surface");
+			goto fail;
+		}
+
+		disp_surface->toplevel =
+		    zxdg_surface_v6_get_toplevel(disp_surface->xdg);
+		if (!disp_surface->toplevel) {
+			syslog(LOG_ERR,
+			       "failed to make toplevel xdg shell surface");
+			goto fail;
+		}
+		zxdg_toplevel_v6_set_title(disp_surface->toplevel, "crosvm");
+		zxdg_toplevel_v6_add_listener(disp_surface->toplevel,
+					      &toplevel_listener, disp_surface);
+
+		if (self->ifaces.aura) {
+			disp_surface->aura = zaura_shell_get_aura_surface(
+			    self->ifaces.aura, disp_surface->surface);
+			if (!disp_surface->aura) {
+				syslog(LOG_ERR, "failed to make aura surface");
+				goto fail;
+			}
+			zaura_surface_set_frame(
+			    disp_surface->aura,
+			    ZAURA_SURFACE_FRAME_TYPE_NORMAL);
+		}
+	} else {
+		disp_surface->subsurface = wl_subcompositor_get_subsurface(
+		    self->ifaces.subcompositor, disp_surface->surface,
+		    parent->surface);
+		if (!disp_surface->subsurface) {
+			syslog(LOG_ERR, "failed to make subsurface");
+			goto fail;
+		}
+		wl_subsurface_set_desync(disp_surface->subsurface);
+	}
+
+	if (self->ifaces.viewporter) {
+		disp_surface->viewport = wp_viewporter_get_viewport(
+		    self->ifaces.viewporter, disp_surface->surface);
+		if (!disp_surface->viewport) {
+			syslog(LOG_ERR, "failed to make surface viewport");
+			goto fail;
+		}
+	}
+
+	wl_surface_attach(disp_surface->surface, disp_surface->buffers[0], 0,
+			  0);
+	wl_surface_damage(disp_surface->surface, 0, 0, width, height);
+	wl_region_destroy(region);
+	wl_shm_pool_destroy(shm_pool);
+
+	// Needed to get outputs before iterating them.
+	wl_display_roundtrip(self->display);
+
+	// Assuming that this surface will enter the internal output initially,
+	// trigger a surface enter for that output before doing the first
+	// surface commit. THis is to avoid unpleasant artifacts when the
+	// surface first appears.
+	struct output *output;
+	outputs_for_each(self, i, output)
+	{
+		if (output->internal) {
+			surface_enter(disp_surface, disp_surface->surface,
+				      output->output);
+		}
+	}
+
+	wl_surface_commit(disp_surface->surface);
+	wl_display_flush(self->display);
+
+	return disp_surface;
+fail:
+	if (disp_surface->viewport)
+		wp_viewport_destroy(disp_surface->viewport);
+	if (disp_surface->subsurface)
+		wl_subsurface_destroy(disp_surface->subsurface);
+	if (disp_surface->toplevel)
+		zxdg_toplevel_v6_destroy(disp_surface->toplevel);
+	if (disp_surface->xdg)
+		zxdg_surface_v6_destroy(disp_surface->xdg);
+	if (disp_surface->aura)
+		zaura_surface_destroy(disp_surface->aura);
+	if (region)
+		wl_region_destroy(region);
+	if (disp_surface->surface)
+		wl_surface_destroy(disp_surface->surface);
+	for (i = 0; i < buffer_count; i++)
+		if (disp_surface->buffers[i])
+			wl_buffer_destroy(disp_surface->buffers[i]);
+	if (shm_pool)
+		wl_shm_pool_destroy(shm_pool);
+	free(disp_surface);
+	return NULL;
+}
+
+void dwl_surface_destroy(struct dwl_surface **self)
+{
+	size_t i;
+	if ((*self)->viewport)
+		wp_viewport_destroy((*self)->viewport);
+	if ((*self)->subsurface)
+		wl_subsurface_destroy((*self)->subsurface);
+	if ((*self)->toplevel)
+		zxdg_toplevel_v6_destroy((*self)->toplevel);
+	if ((*self)->xdg)
+		zxdg_surface_v6_destroy((*self)->xdg);
+	if ((*self)->aura)
+		zaura_surface_destroy((*self)->aura);
+	if ((*self)->surface)
+		wl_surface_destroy((*self)->surface);
+	for (i = 0; i < (*self)->buffer_count; i++)
+		wl_buffer_destroy((*self)->buffers[i]);
+	wl_display_flush((*self)->context->display);
+	free(*self);
+	*self = NULL;
+}
+
+void dwl_surface_commit(struct dwl_surface *self)
+{
+	// It is possible that we are committing frames faster than the
+	// compositor can put them on the screen. This may result in dropped
+	// frames, but this is acceptable considering there is no good way to
+	// apply back pressure to the guest gpu driver right now. The intention
+	// of this module is to help bootstrap gpu support, so it does not have
+	// to have artifact free rendering.
+	wl_surface_commit(self->surface);
+	wl_display_flush(self->context->display);
+}
+
+bool dwl_surface_buffer_in_use(struct dwl_surface *self, size_t buffer_index)
+{
+	return (self->buffer_use_bit_mask & (1 << buffer_index)) != 0;
+}
+
+void dwl_surface_flip(struct dwl_surface *self, size_t buffer_index)
+{
+	if (buffer_index >= self->buffer_count)
+		return;
+	wl_surface_attach(self->surface, self->buffers[buffer_index], 0, 0);
+	wl_surface_damage(self->surface, 0, 0, self->width, self->height);
+	dwl_surface_commit(self);
+	self->buffer_use_bit_mask |= 1 << buffer_index;
+}
+
+void dwl_surface_flip_to(struct dwl_surface *self, struct dwl_dmabuf *dmabuf)
+{
+	if (self->width != dmabuf->width || self->height != dmabuf->height)
+		return;
+	wl_surface_attach(self->surface, dmabuf->buffer, 0, 0);
+	wl_surface_damage(self->surface, 0, 0, self->width, self->height);
+	dwl_surface_commit(self);
+	dmabuf->in_use = true;
+}
+
+bool dwl_surface_close_requested(const struct dwl_surface *self)
+{
+	return self->close_requested;
+}
+
+void dwl_surface_set_position(struct dwl_surface *self, uint32_t x, uint32_t y)
+{
+	if (self->subsurface) {
+		wl_subsurface_set_position(self->subsurface, x / self->scale,
+					   y / self->scale);
+		wl_surface_commit(self->surface);
+		wl_display_flush(self->context->display);
+	}
+}
diff --git a/gpu_display/src/dwl.rs b/gpu_display/src/dwl.rs
new file mode 100644
index 0000000..3f2d67d
--- /dev/null
+++ b/gpu_display/src/dwl.rs
@@ -0,0 +1,125 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+/// @page page_xdg_shell_unstable_v6 The xdg_shell_unstable_v6 protocol
+/// @section page_ifaces_xdg_shell_unstable_v6 Interfaces
+/// - @subpage page_iface_zxdg_shell_v6 - create desktop-style surfaces
+/// - @subpage page_iface_zxdg_positioner_v6 - child surface positioner
+/// - @subpage page_iface_zxdg_surface_v6 - desktop user interface surface base interface
+/// - @subpage page_iface_zxdg_toplevel_v6 - toplevel surface
+/// - @subpage page_iface_zxdg_popup_v6 - short-lived, popup surfaces for menus
+/// @section page_copyright_xdg_shell_unstable_v6 Copyright
+/// <pre>
+///
+/// Copyright © 2008-2013 Kristian Høgsberg
+/// Copyright © 2013      Rafael Antognolli
+/// Copyright © 2013      Jasper St. Pierre
+/// Copyright © 2010-2013 Intel Corporation
+///
+/// Permission is hereby granted, free of charge, to any person obtaining a
+/// copy of this software and associated documentation files (the "Software"),
+/// to deal in the Software without restriction, including without limitation
+/// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+/// and/or sell copies of the Software, and to permit persons to whom the
+/// Software is furnished to do so, subject to the following conditions:
+///
+/// The above copyright notice and this permission notice (including the next
+/// paragraph) shall be included in all copies or substantial portions of the
+/// Software.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+/// DEALINGS IN THE SOFTWARE.
+/// </pre>
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct wl_output {
+    _unused: [u8; 0],
+}
+#[repr(C)]
+pub struct dwl_context {
+    pub _bindgen_opaque_blob: [u64; 52usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct dwl_dmabuf {
+    pub _bindgen_opaque_blob: [u64; 3usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct dwl_surface {
+    pub _bindgen_opaque_blob: [u64; 12usize],
+}
+extern "C" {
+    pub fn dwl_context_new() -> *mut dwl_context;
+}
+extern "C" {
+    pub fn dwl_context_destroy(self_: *mut *mut dwl_context);
+}
+extern "C" {
+    pub fn dwl_context_setup(
+        self_: *mut dwl_context,
+        socket_path: *const ::std::os::raw::c_char,
+    ) -> bool;
+}
+extern "C" {
+    pub fn dwl_context_fd(self_: *mut dwl_context) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn dwl_context_dispatch(self_: *mut dwl_context);
+}
+extern "C" {
+    pub fn dwl_context_dmabuf_new(
+        self_: *mut dwl_context,
+        fd: ::std::os::raw::c_int,
+        offset: u32,
+        stride: u32,
+        modifiers: u64,
+        width: u32,
+        height: u32,
+        fourcc: u32,
+    ) -> *mut dwl_dmabuf;
+}
+extern "C" {
+    pub fn dwl_dmabuf_destroy(self_: *mut *mut dwl_dmabuf);
+}
+extern "C" {
+    pub fn dwl_context_surface_new(
+        self_: *mut dwl_context,
+        parent: *mut dwl_surface,
+        shm_fd: ::std::os::raw::c_int,
+        shm_size: usize,
+        buffer_size: usize,
+        width: u32,
+        height: u32,
+        stride: u32,
+    ) -> *mut dwl_surface;
+}
+extern "C" {
+    pub fn dwl_surface_destroy(self_: *mut *mut dwl_surface);
+}
+extern "C" {
+    pub fn dwl_surface_commit(self_: *mut dwl_surface);
+}
+extern "C" {
+    pub fn dwl_surface_buffer_in_use(self_: *mut dwl_surface, buffer_index: usize) -> bool;
+}
+extern "C" {
+    pub fn dwl_surface_flip(self_: *mut dwl_surface, buffer_index: usize);
+}
+extern "C" {
+    pub fn dwl_surface_flip_to(self_: *mut dwl_surface, dmabuf: *mut dwl_dmabuf);
+}
+extern "C" {
+    pub fn dwl_surface_close_requested(self_: *const dwl_surface) -> bool;
+}
+extern "C" {
+    pub fn dwl_surface_set_position(self_: *mut dwl_surface, x: u32, y: u32);
+}
diff --git a/gpu_display/src/lib.rs b/gpu_display/src/lib.rs
new file mode 100644
index 0000000..11a6703
--- /dev/null
+++ b/gpu_display/src/lib.rs
@@ -0,0 +1,399 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Crate for displaying simple surfaces and GPU buffers over wayland.
+
+mod dwl;
+
+use std::cell::Cell;
+use std::collections::HashMap;
+use std::ffi::{CStr, CString};
+use std::fmt::{self, Display};
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::path::Path;
+use std::ptr::null_mut;
+
+use data_model::{VolatileMemory, VolatileSlice};
+use sys_util::{round_up_to_page_size, Error as SysError, MemoryMapping, SharedMemory};
+
+use crate::dwl::*;
+
+const BUFFER_COUNT: usize = 2;
+const BYTES_PER_PIXEL: u32 = 4;
+
+/// An error generated by `GpuDisplay`.
+#[derive(Debug)]
+pub enum GpuDisplayError {
+    /// An internal allocation failed.
+    Allocate,
+    /// Connecting to the compositor failed.
+    Connect,
+    /// Creating shared memory failed.
+    CreateShm(SysError),
+    /// Setting the size of shared memory failed.
+    SetSize(SysError),
+    /// Failed to create a surface on the compositor.
+    CreateSurface,
+    /// Failed to import a buffer to the compositor.
+    FailedImport,
+    /// The surface ID is invalid.
+    InvalidSurfaceId,
+    /// The path is invalid.
+    InvalidPath,
+}
+
+impl Display for GpuDisplayError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::GpuDisplayError::*;
+
+        match self {
+            Allocate => write!(f, "internal allocation failed"),
+            Connect => write!(f, "failed to connect to compositor"),
+            CreateShm(e) => write!(f, "failed to create shared memory: {}", e),
+            SetSize(e) => write!(f, "failed to set size of shared memory: {}", e),
+            CreateSurface => write!(f, "failed to crate surface on the compositor"),
+            FailedImport => write!(f, "failed to import a buffer to the compositor"),
+            InvalidSurfaceId => write!(f, "invalid surface ID"),
+            InvalidPath => write!(f, "invalid path"),
+        }
+    }
+}
+
+struct DwlContext(*mut dwl_context);
+impl Drop for DwlContext {
+    fn drop(&mut self) {
+        if !self.0.is_null() {
+            // Safe given that we checked the pointer for non-null and it should always be of the
+            // correct type.
+            unsafe {
+                dwl_context_destroy(&mut self.0);
+            }
+        }
+    }
+}
+
+struct DwlDmabuf(*mut dwl_dmabuf);
+impl Drop for DwlDmabuf {
+    fn drop(&mut self) {
+        if !self.0.is_null() {
+            // Safe given that we checked the pointer for non-null and it should always be of the
+            // correct type.
+            unsafe {
+                dwl_dmabuf_destroy(&mut self.0);
+            }
+        }
+    }
+}
+
+struct DwlSurface(*mut dwl_surface);
+impl Drop for DwlSurface {
+    fn drop(&mut self) {
+        if !self.0.is_null() {
+            // Safe given that we checked the pointer for non-null and it should always be of the
+            // correct type.
+            unsafe {
+                dwl_surface_destroy(&mut self.0);
+            }
+        }
+    }
+}
+
+struct GpuDisplaySurface {
+    surface: DwlSurface,
+    buffer_size: usize,
+    buffer_index: Cell<usize>,
+    buffer_mem: MemoryMapping,
+}
+
+impl GpuDisplaySurface {
+    fn surface(&self) -> *mut dwl_surface {
+        self.surface.0
+    }
+}
+
+/// A connection to the compositor and associated collection of state.
+///
+/// The user of `GpuDisplay` can use `AsRawFd` to poll on the compositor connection's file
+/// descriptor. When the connection is readable, `dispatch_events` can be called to process it.
+pub struct GpuDisplay {
+    ctx: DwlContext,
+    dmabufs: HashMap<u32, DwlDmabuf>,
+    dmabuf_next_id: u32,
+    surfaces: HashMap<u32, GpuDisplaySurface>,
+    surface_next_id: u32,
+}
+
+impl GpuDisplay {
+    /// Opens a fresh connection to the compositor.
+    pub fn new<P: AsRef<Path>>(wayland_path: P) -> Result<GpuDisplay, GpuDisplayError> {
+        // The dwl_context_new call should always be safe to call, and we check its result.
+        let ctx = DwlContext(unsafe { dwl_context_new() });
+        if ctx.0.is_null() {
+            return Err(GpuDisplayError::Allocate);
+        }
+
+        // The dwl_context_setup call is always safe to call given that the supplied context is
+        // valid. and we check its result.
+        let cstr_path = match wayland_path.as_ref().as_os_str().to_str() {
+            Some(str) => match CString::new(str) {
+                Ok(cstr) => cstr,
+                Err(_) => return Err(GpuDisplayError::InvalidPath),
+            },
+            None => return Err(GpuDisplayError::InvalidPath),
+        };
+        let setup_success = unsafe { dwl_context_setup(ctx.0, cstr_path.as_ptr()) };
+        if !setup_success {
+            return Err(GpuDisplayError::Connect);
+        }
+
+        Ok(GpuDisplay {
+            ctx,
+            dmabufs: Default::default(),
+            dmabuf_next_id: 0,
+            surfaces: Default::default(),
+            surface_next_id: 0,
+        })
+    }
+
+    fn ctx(&self) -> *mut dwl_context {
+        self.ctx.0
+    }
+
+    fn get_surface(&self, surface_id: u32) -> Option<&GpuDisplaySurface> {
+        self.surfaces.get(&surface_id)
+    }
+
+    /// Imports a dmabuf to the compositor for use as a surface buffer and returns a handle to it.
+    pub fn import_dmabuf(
+        &mut self,
+        fd: RawFd,
+        offset: u32,
+        stride: u32,
+        modifiers: u64,
+        width: u32,
+        height: u32,
+        fourcc: u32,
+    ) -> Result<u32, GpuDisplayError> {
+        // Safe given that the context pointer is valid. Any other invalid parameters would be
+        // rejected by dwl_context_dmabuf_new safely. We check that the resulting dmabuf is valid
+        // before filing it away.
+        let dmabuf = DwlDmabuf(unsafe {
+            dwl_context_dmabuf_new(
+                self.ctx(),
+                fd,
+                offset,
+                stride,
+                modifiers,
+                width,
+                height,
+                fourcc,
+            )
+        });
+        if dmabuf.0.is_null() {
+            return Err(GpuDisplayError::FailedImport);
+        }
+
+        let next_id = self.dmabuf_next_id;
+        self.dmabufs.insert(next_id, dmabuf);
+        self.dmabuf_next_id += 1;
+        Ok(next_id)
+    }
+
+    /// Releases a previously imported dmabuf identified by the given handle.
+    pub fn release_import(&mut self, import_id: u32) {
+        self.dmabufs.remove(&import_id);
+    }
+
+    /// Dispatches internal events that were received from the compositor since the last call to
+    /// `dispatch_events`.
+    pub fn dispatch_events(&mut self) {
+        // Safe given that the context pointer is valid.
+        unsafe {
+            dwl_context_dispatch(self.ctx());
+        }
+    }
+
+    /// Creates a surface on the the compositor as either a top level window, or child of another
+    /// surface, returning a handle to the new surface.
+    pub fn create_surface(
+        &mut self,
+        parent_surface_id: Option<u32>,
+        width: u32,
+        height: u32,
+    ) -> Result<u32, GpuDisplayError> {
+        let parent_ptr = match parent_surface_id {
+            Some(id) => match self.get_surface(id).map(|p| p.surface()) {
+                Some(ptr) => ptr,
+                None => return Err(GpuDisplayError::InvalidSurfaceId),
+            },
+            None => null_mut(),
+        };
+        let row_size = width * BYTES_PER_PIXEL;
+        let fb_size = row_size * height;
+        let buffer_size = round_up_to_page_size(fb_size as usize * BUFFER_COUNT);
+        let mut buffer_shm = SharedMemory::new(Some(
+            CStr::from_bytes_with_nul(b"GpuDisplaySurface\0").unwrap(),
+        ))
+        .map_err(GpuDisplayError::CreateShm)?;
+        buffer_shm
+            .set_size(buffer_size as u64)
+            .map_err(GpuDisplayError::SetSize)?;
+        let buffer_mem = MemoryMapping::from_fd(&buffer_shm, buffer_size).unwrap();
+
+        // Safe because only a valid context, parent pointer (if not  None), and buffer FD are used.
+        // The returned surface is checked for validity before being filed away.
+        let surface = DwlSurface(unsafe {
+            dwl_context_surface_new(
+                self.ctx(),
+                parent_ptr,
+                buffer_shm.as_raw_fd(),
+                buffer_size,
+                fb_size as usize,
+                width,
+                height,
+                row_size,
+            )
+        });
+
+        if surface.0.is_null() {
+            return Err(GpuDisplayError::CreateSurface);
+        }
+
+        let next_id = self.surface_next_id;
+        self.surfaces.insert(
+            next_id,
+            GpuDisplaySurface {
+                surface,
+                buffer_size: fb_size as usize,
+                buffer_index: Cell::new(0),
+                buffer_mem,
+            },
+        );
+
+        self.surface_next_id += 1;
+        Ok(next_id)
+    }
+
+    /// Releases a previously created surface identified by the given handle.
+    pub fn release_surface(&mut self, surface_id: u32) {
+        self.surfaces.remove(&surface_id);
+    }
+
+    /// Gets a reference to an unused framebuffer for the identified surface.
+    pub fn framebuffer_memory(&self, surface_id: u32) -> Option<VolatileSlice> {
+        let surface = self.get_surface(surface_id)?;
+        let buffer_index = (surface.buffer_index.get() + 1) % BUFFER_COUNT;
+        surface
+            .buffer_mem
+            .get_slice(
+                (buffer_index * surface.buffer_size) as u64,
+                surface.buffer_size as u64,
+            )
+            .ok()
+    }
+
+    /// Commits any pending state for the identified surface.
+    pub fn commit(&self, surface_id: u32) {
+        match self.get_surface(surface_id) {
+            Some(surface) => {
+                // Safe because only a valid surface is used.
+                unsafe {
+                    dwl_surface_commit(surface.surface());
+                }
+            }
+            None => debug_assert!(false, "invalid surface_id {}", surface_id),
+        }
+    }
+
+    /// Returns true if the next buffer in the buffer queue for the given surface is currently in
+    /// use.
+    ///
+    /// If the next buffer is in use, the memory returned from `framebuffer_memory` should not be
+    /// written to.
+    pub fn next_buffer_in_use(&self, surface_id: u32) -> bool {
+        match self.get_surface(surface_id) {
+            Some(surface) => {
+                let next_buffer_index = (surface.buffer_index.get() + 1) % BUFFER_COUNT;
+                // Safe because only a valid surface and buffer index is used.
+                unsafe { dwl_surface_buffer_in_use(surface.surface(), next_buffer_index) }
+            }
+            None => {
+                debug_assert!(false, "invalid surface_id {}", surface_id);
+                false
+            }
+        }
+    }
+
+    /// Changes the visible contents of the identified surface to the contents of the framebuffer
+    /// last returned by `framebuffer_memory` for this surface.
+    pub fn flip(&self, surface_id: u32) {
+        match self.get_surface(surface_id) {
+            Some(surface) => {
+                surface
+                    .buffer_index
+                    .set((surface.buffer_index.get() + 1) % BUFFER_COUNT);
+                // Safe because only a valid surface and buffer index is used.
+                unsafe {
+                    dwl_surface_flip(surface.surface(), surface.buffer_index.get());
+                }
+            }
+            None => debug_assert!(false, "invalid surface_id {}", surface_id),
+        }
+    }
+
+    /// Changes the visible contents of the identified surface to that of the identified imported
+    /// buffer.
+    pub fn flip_to(&self, surface_id: u32, import_id: u32) {
+        match self.get_surface(surface_id) {
+            Some(surface) => {
+                match self.dmabufs.get(&import_id) {
+                    // Safe because only a valid surface and dmabuf is used.
+                    Some(dmabuf) => unsafe { dwl_surface_flip_to(surface.surface(), dmabuf.0) },
+                    None => debug_assert!(false, "invalid import_id {}", import_id),
+                }
+            }
+            None => debug_assert!(false, "invalid surface_id {}", surface_id),
+        }
+    }
+
+    /// Returns true if the identified top level surface has been told to close by the compositor,
+    /// and by extension the user.
+    pub fn close_requested(&self, surface_id: u32) -> bool {
+        match self.get_surface(surface_id) {
+            Some(surface) =>
+            // Safe because only a valid surface is used.
+            unsafe { dwl_surface_close_requested(surface.surface()) }
+            None => false,
+        }
+    }
+
+    /// Sets the position of the identified subsurface relative to its parent.
+    ///
+    /// The change in position will not be visible until `commit` is called for the parent surface.
+    pub fn set_position(&self, surface_id: u32, x: u32, y: u32) {
+        match self.get_surface(surface_id) {
+            Some(surface) => {
+                // Safe because only a valid surface is used.
+                unsafe {
+                    dwl_surface_set_position(surface.surface(), x, y);
+                }
+            }
+            None => debug_assert!(false, "invalid surface_id {}", surface_id),
+        }
+    }
+}
+
+impl Drop for GpuDisplay {
+    fn drop(&mut self) {
+        // Safe given that the context pointer is valid.
+        unsafe { dwl_context_destroy(&mut self.ctx.0) }
+    }
+}
+
+impl AsRawFd for GpuDisplay {
+    fn as_raw_fd(&self) -> RawFd {
+        // Safe given that the context pointer is valid.
+        unsafe { dwl_context_fd(self.ctx.0) }
+    }
+}
diff --git a/gpu_renderer/Cargo.toml b/gpu_renderer/Cargo.toml
new file mode 100644
index 0000000..6fcd22e
--- /dev/null
+++ b/gpu_renderer/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "gpu_renderer"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+data_model = { path = "../data_model" }
+libc = "*"
+sys_util = { path = "../sys_util" }
diff --git a/gpu_renderer/src/command_buffer.rs b/gpu_renderer/src/command_buffer.rs
new file mode 100644
index 0000000..b6c7005
--- /dev/null
+++ b/gpu_renderer/src/command_buffer.rs
@@ -0,0 +1,140 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::mem::size_of;
+use std::os::raw::c_void;
+use std::slice::{from_raw_parts, from_raw_parts_mut};
+
+use crate::generated::virgl_protocol::*;
+use crate::Resource;
+
+/// Helper struct for making a virgl command buffer.
+#[derive(Default)]
+pub struct CommandBufferBuilder {
+    cbuf: Vec<u32>,
+}
+
+impl AsRef<[u8]> for CommandBufferBuilder {
+    fn as_ref(&self) -> &[u8] {
+        // Safe because the returned slice is a trivial reinterpretation of the same number of
+        // bytes.
+        unsafe {
+            from_raw_parts(
+                self.cbuf.as_ptr() as *const u8,
+                self.cbuf.len() * size_of::<u32>(),
+            )
+        }
+    }
+}
+
+impl AsMut<[u8]> for CommandBufferBuilder {
+    fn as_mut(&mut self) -> &mut [u8] {
+        // Safe because the returned slice is a trivial reinterpretation of the same number of
+        // bytes.
+        unsafe {
+            from_raw_parts_mut(
+                self.cbuf.as_mut_ptr() as *mut u8,
+                self.cbuf.len() * size_of::<u32>(),
+            )
+        }
+    }
+}
+
+impl CommandBufferBuilder {
+    /// Constructs an empty command
+    pub fn new() -> CommandBufferBuilder {
+        Default::default()
+    }
+
+    fn push(&mut self, dw: u32) {
+        self.cbuf.push(dw);
+    }
+
+    fn push_qw(&mut self, qw: u64) {
+        self.cbuf.push(qw as u32);
+        self.cbuf.push((qw >> 32) as u32);
+    }
+
+    fn push_cmd(&mut self, cmd: u32, obj_type: u32, len: u32) {
+        self.cbuf
+            .push((cmd & 0xff) | ((obj_type & 0xff) << 8) | ((len & 0xffff) << 16));
+    }
+
+    /// Gets the command buffer as a pointer to the beginning.
+    pub fn as_mut_ptr(&mut self) -> *mut c_void {
+        self.cbuf.as_mut_ptr() as *mut c_void
+    }
+
+    /// Gets the size of the command buffer content in dwords.
+    pub fn dword_count(&self) -> usize {
+        self.cbuf.len()
+    }
+
+    /// Clears the command buffer content.
+    pub fn clear(&mut self) {
+        self.cbuf.clear();
+    }
+
+    /// Checks that the command buffer is well formed.
+    pub fn is_valid(&self) -> bool {
+        let mut i = 0;
+        while i < self.cbuf.len() {
+            i += 1 + (self.cbuf[i] >> 16) as usize;
+        }
+        i == self.cbuf.len()
+    }
+
+    /// Pushes a clear command to this command buffer.
+    pub fn e_clear(&mut self, buffers: u32, color: [f32; 4], depth: f64, stencil: u32) {
+        self.push_cmd(VIRGL_CCMD_CLEAR, 0, VIRGL_OBJ_CLEAR_SIZE);
+        self.push(buffers);
+        for c in &color {
+            self.push(c.to_bits())
+        }
+        self.push_qw(depth.to_bits());
+        self.push(stencil);
+        assert!(self.is_valid());
+    }
+
+    /// Pushes a create surface command to this command buffer.
+    pub fn e_create_surface(
+        &mut self,
+        new_id: u32,
+        res: &Resource,
+        format: u32,
+        level: u32,
+        first_layer: u32,
+        last_layer: u32,
+    ) {
+        self.push_cmd(
+            VIRGL_CCMD_CREATE_OBJECT,
+            VIRGL_OBJECT_SURFACE,
+            VIRGL_OBJ_SURFACE_SIZE,
+        );
+        self.push(new_id);
+        self.push(res.id());
+        self.push(format);
+        self.push(level);
+        self.push(first_layer | (last_layer << 16));
+        assert!(self.is_valid());
+    }
+
+    /// Pushes a set framebuffer state command to this command buffer.
+    pub fn e_set_fb_state(&mut self, surface_handles: &[u32], zbuf: Option<u32>) {
+        fn cmd_set_fb_state_size(surface_count: u32) -> u32 {
+            2 + surface_count
+        }
+        self.push_cmd(
+            VIRGL_CCMD_SET_FRAMEBUFFER_STATE,
+            0,
+            cmd_set_fb_state_size(surface_handles.len() as u32),
+        );
+        self.push(surface_handles.len() as u32);
+        self.push(zbuf.unwrap_or(0));
+        for &surface_handle in surface_handles {
+            self.push(surface_handle);
+        }
+        assert!(self.is_valid());
+    }
+}
diff --git a/gpu_renderer/src/generated/epoxy_egl.rs b/gpu_renderer/src/generated/epoxy_egl.rs
new file mode 100644
index 0000000..b998b06
--- /dev/null
+++ b/gpu_renderer/src/generated/epoxy_egl.rs
@@ -0,0 +1,31436 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+#[link(name = "epoxy")]
+extern "C" {}
+
+pub const GL_ES_VERSION_2_0: u32 = 1;
+pub const GL_ES_VERSION_3_0: u32 = 1;
+pub const GL_ES_VERSION_3_1: u32 = 1;
+pub const GL_ES_VERSION_3_2: u32 = 1;
+pub const GL_SC_VERSION_2_0: u32 = 1;
+pub const GL_VERSION_1_0: u32 = 1;
+pub const GL_VERSION_1_1: u32 = 1;
+pub const GL_VERSION_1_2: u32 = 1;
+pub const GL_VERSION_1_3: u32 = 1;
+pub const GL_VERSION_1_4: u32 = 1;
+pub const GL_VERSION_1_5: u32 = 1;
+pub const GL_VERSION_2_0: u32 = 1;
+pub const GL_VERSION_2_1: u32 = 1;
+pub const GL_VERSION_3_0: u32 = 1;
+pub const GL_VERSION_3_1: u32 = 1;
+pub const GL_VERSION_3_2: u32 = 1;
+pub const GL_VERSION_3_3: u32 = 1;
+pub const GL_VERSION_4_0: u32 = 1;
+pub const GL_VERSION_4_1: u32 = 1;
+pub const GL_VERSION_4_2: u32 = 1;
+pub const GL_VERSION_4_3: u32 = 1;
+pub const GL_VERSION_4_4: u32 = 1;
+pub const GL_VERSION_4_5: u32 = 1;
+pub const GL_VERSION_ES_CM_1_0: u32 = 1;
+pub const GL_3DFX_multisample: u32 = 1;
+pub const GL_3DFX_tbuffer: u32 = 1;
+pub const GL_3DFX_texture_compression_FXT1: u32 = 1;
+pub const GL_AMD_blend_minmax_factor: u32 = 1;
+pub const GL_AMD_compressed_3DC_texture: u32 = 1;
+pub const GL_AMD_compressed_ATC_texture: u32 = 1;
+pub const GL_AMD_conservative_depth: u32 = 1;
+pub const GL_AMD_debug_output: u32 = 1;
+pub const GL_AMD_depth_clamp_separate: u32 = 1;
+pub const GL_AMD_draw_buffers_blend: u32 = 1;
+pub const GL_AMD_framebuffer_sample_positions: u32 = 1;
+pub const GL_AMD_gcn_shader: u32 = 1;
+pub const GL_AMD_gpu_shader_half_float: u32 = 1;
+pub const GL_AMD_gpu_shader_int64: u32 = 1;
+pub const GL_AMD_interleaved_elements: u32 = 1;
+pub const GL_AMD_multi_draw_indirect: u32 = 1;
+pub const GL_AMD_name_gen_delete: u32 = 1;
+pub const GL_AMD_occlusion_query_event: u32 = 1;
+pub const GL_AMD_performance_monitor: u32 = 1;
+pub const GL_AMD_pinned_memory: u32 = 1;
+pub const GL_AMD_program_binary_Z400: u32 = 1;
+pub const GL_AMD_query_buffer_object: u32 = 1;
+pub const GL_AMD_sample_positions: u32 = 1;
+pub const GL_AMD_seamless_cubemap_per_texture: u32 = 1;
+pub const GL_AMD_shader_atomic_counter_ops: u32 = 1;
+pub const GL_AMD_shader_ballot: u32 = 1;
+pub const GL_AMD_shader_explicit_vertex_parameter: u32 = 1;
+pub const GL_AMD_shader_stencil_export: u32 = 1;
+pub const GL_AMD_shader_trinary_minmax: u32 = 1;
+pub const GL_AMD_sparse_texture: u32 = 1;
+pub const GL_AMD_stencil_operation_extended: u32 = 1;
+pub const GL_AMD_texture_texture4: u32 = 1;
+pub const GL_AMD_transform_feedback3_lines_triangles: u32 = 1;
+pub const GL_AMD_transform_feedback4: u32 = 1;
+pub const GL_AMD_vertex_shader_layer: u32 = 1;
+pub const GL_AMD_vertex_shader_tessellator: u32 = 1;
+pub const GL_AMD_vertex_shader_viewport_index: u32 = 1;
+pub const GL_ANDROID_extension_pack_es31a: u32 = 1;
+pub const GL_ANGLE_depth_texture: u32 = 1;
+pub const GL_ANGLE_framebuffer_blit: u32 = 1;
+pub const GL_ANGLE_framebuffer_multisample: u32 = 1;
+pub const GL_ANGLE_instanced_arrays: u32 = 1;
+pub const GL_ANGLE_pack_reverse_row_order: u32 = 1;
+pub const GL_ANGLE_program_binary: u32 = 1;
+pub const GL_ANGLE_texture_compression_dxt3: u32 = 1;
+pub const GL_ANGLE_texture_compression_dxt5: u32 = 1;
+pub const GL_ANGLE_texture_usage: u32 = 1;
+pub const GL_ANGLE_translated_shader_source: u32 = 1;
+pub const GL_APPLE_aux_depth_stencil: u32 = 1;
+pub const GL_APPLE_client_storage: u32 = 1;
+pub const GL_APPLE_clip_distance: u32 = 1;
+pub const GL_APPLE_color_buffer_packed_float: u32 = 1;
+pub const GL_APPLE_copy_texture_levels: u32 = 1;
+pub const GL_APPLE_element_array: u32 = 1;
+pub const GL_APPLE_fence: u32 = 1;
+pub const GL_APPLE_float_pixels: u32 = 1;
+pub const GL_APPLE_flush_buffer_range: u32 = 1;
+pub const GL_APPLE_framebuffer_multisample: u32 = 1;
+pub const GL_APPLE_object_purgeable: u32 = 1;
+pub const GL_APPLE_rgb_422: u32 = 1;
+pub const GL_APPLE_row_bytes: u32 = 1;
+pub const GL_APPLE_specular_vector: u32 = 1;
+pub const GL_APPLE_sync: u32 = 1;
+pub const GL_APPLE_texture_2D_limited_npot: u32 = 1;
+pub const GL_APPLE_texture_format_BGRA8888: u32 = 1;
+pub const GL_APPLE_texture_max_level: u32 = 1;
+pub const GL_APPLE_texture_packed_float: u32 = 1;
+pub const GL_APPLE_texture_range: u32 = 1;
+pub const GL_APPLE_transform_hint: u32 = 1;
+pub const GL_APPLE_vertex_array_object: u32 = 1;
+pub const GL_APPLE_vertex_array_range: u32 = 1;
+pub const GL_APPLE_vertex_program_evaluators: u32 = 1;
+pub const GL_APPLE_ycbcr_422: u32 = 1;
+pub const GL_ARB_ES2_compatibility: u32 = 1;
+pub const GL_ARB_ES3_1_compatibility: u32 = 1;
+pub const GL_ARB_ES3_2_compatibility: u32 = 1;
+pub const GL_ARB_ES3_compatibility: u32 = 1;
+pub const GL_ARB_arrays_of_arrays: u32 = 1;
+pub const GL_ARB_base_instance: u32 = 1;
+pub const GL_ARB_bindless_texture: u32 = 1;
+pub const GL_ARB_blend_func_extended: u32 = 1;
+pub const GL_ARB_buffer_storage: u32 = 1;
+pub const GL_ARB_cl_event: u32 = 1;
+pub const GL_ARB_clear_buffer_object: u32 = 1;
+pub const GL_ARB_clear_texture: u32 = 1;
+pub const GL_ARB_clip_control: u32 = 1;
+pub const GL_ARB_color_buffer_float: u32 = 1;
+pub const GL_ARB_compatibility: u32 = 1;
+pub const GL_ARB_compressed_texture_pixel_storage: u32 = 1;
+pub const GL_ARB_compute_shader: u32 = 1;
+pub const GL_ARB_compute_variable_group_size: u32 = 1;
+pub const GL_ARB_conditional_render_inverted: u32 = 1;
+pub const GL_ARB_conservative_depth: u32 = 1;
+pub const GL_ARB_copy_buffer: u32 = 1;
+pub const GL_ARB_copy_image: u32 = 1;
+pub const GL_ARB_cull_distance: u32 = 1;
+pub const GL_ARB_debug_output: u32 = 1;
+pub const GL_ARB_depth_buffer_float: u32 = 1;
+pub const GL_ARB_depth_clamp: u32 = 1;
+pub const GL_ARB_depth_texture: u32 = 1;
+pub const GL_ARB_derivative_control: u32 = 1;
+pub const GL_ARB_direct_state_access: u32 = 1;
+pub const GL_ARB_draw_buffers: u32 = 1;
+pub const GL_ARB_draw_buffers_blend: u32 = 1;
+pub const GL_ARB_draw_elements_base_vertex: u32 = 1;
+pub const GL_ARB_draw_indirect: u32 = 1;
+pub const GL_ARB_draw_instanced: u32 = 1;
+pub const GL_ARB_enhanced_layouts: u32 = 1;
+pub const GL_ARB_explicit_attrib_location: u32 = 1;
+pub const GL_ARB_explicit_uniform_location: u32 = 1;
+pub const GL_ARB_fragment_coord_conventions: u32 = 1;
+pub const GL_ARB_fragment_layer_viewport: u32 = 1;
+pub const GL_ARB_fragment_program: u32 = 1;
+pub const GL_ARB_fragment_program_shadow: u32 = 1;
+pub const GL_ARB_fragment_shader: u32 = 1;
+pub const GL_ARB_fragment_shader_interlock: u32 = 1;
+pub const GL_ARB_framebuffer_no_attachments: u32 = 1;
+pub const GL_ARB_framebuffer_object: u32 = 1;
+pub const GL_ARB_framebuffer_sRGB: u32 = 1;
+pub const GL_ARB_geometry_shader4: u32 = 1;
+pub const GL_ARB_get_program_binary: u32 = 1;
+pub const GL_ARB_get_texture_sub_image: u32 = 1;
+pub const GL_ARB_gpu_shader5: u32 = 1;
+pub const GL_ARB_gpu_shader_fp64: u32 = 1;
+pub const GL_ARB_gpu_shader_int64: u32 = 1;
+pub const GL_ARB_half_float_pixel: u32 = 1;
+pub const GL_ARB_half_float_vertex: u32 = 1;
+pub const GL_ARB_imaging: u32 = 1;
+pub const GL_ARB_indirect_parameters: u32 = 1;
+pub const GL_ARB_instanced_arrays: u32 = 1;
+pub const GL_ARB_internalformat_query: u32 = 1;
+pub const GL_ARB_internalformat_query2: u32 = 1;
+pub const GL_ARB_invalidate_subdata: u32 = 1;
+pub const GL_ARB_map_buffer_alignment: u32 = 1;
+pub const GL_ARB_map_buffer_range: u32 = 1;
+pub const GL_ARB_matrix_palette: u32 = 1;
+pub const GL_ARB_multi_bind: u32 = 1;
+pub const GL_ARB_multi_draw_indirect: u32 = 1;
+pub const GL_ARB_multisample: u32 = 1;
+pub const GL_ARB_multitexture: u32 = 1;
+pub const GL_ARB_occlusion_query: u32 = 1;
+pub const GL_ARB_occlusion_query2: u32 = 1;
+pub const GL_ARB_parallel_shader_compile: u32 = 1;
+pub const GL_ARB_pipeline_statistics_query: u32 = 1;
+pub const GL_ARB_pixel_buffer_object: u32 = 1;
+pub const GL_ARB_point_parameters: u32 = 1;
+pub const GL_ARB_point_sprite: u32 = 1;
+pub const GL_ARB_post_depth_coverage: u32 = 1;
+pub const GL_ARB_program_interface_query: u32 = 1;
+pub const GL_ARB_provoking_vertex: u32 = 1;
+pub const GL_ARB_query_buffer_object: u32 = 1;
+pub const GL_ARB_robust_buffer_access_behavior: u32 = 1;
+pub const GL_ARB_robustness: u32 = 1;
+pub const GL_ARB_robustness_isolation: u32 = 1;
+pub const GL_ARB_sample_locations: u32 = 1;
+pub const GL_ARB_sample_shading: u32 = 1;
+pub const GL_ARB_sampler_objects: u32 = 1;
+pub const GL_ARB_seamless_cube_map: u32 = 1;
+pub const GL_ARB_seamless_cubemap_per_texture: u32 = 1;
+pub const GL_ARB_separate_shader_objects: u32 = 1;
+pub const GL_ARB_shader_atomic_counter_ops: u32 = 1;
+pub const GL_ARB_shader_atomic_counters: u32 = 1;
+pub const GL_ARB_shader_ballot: u32 = 1;
+pub const GL_ARB_shader_bit_encoding: u32 = 1;
+pub const GL_ARB_shader_clock: u32 = 1;
+pub const GL_ARB_shader_draw_parameters: u32 = 1;
+pub const GL_ARB_shader_group_vote: u32 = 1;
+pub const GL_ARB_shader_image_load_store: u32 = 1;
+pub const GL_ARB_shader_image_size: u32 = 1;
+pub const GL_ARB_shader_objects: u32 = 1;
+pub const GL_ARB_shader_precision: u32 = 1;
+pub const GL_ARB_shader_stencil_export: u32 = 1;
+pub const GL_ARB_shader_storage_buffer_object: u32 = 1;
+pub const GL_ARB_shader_subroutine: u32 = 1;
+pub const GL_ARB_shader_texture_image_samples: u32 = 1;
+pub const GL_ARB_shader_texture_lod: u32 = 1;
+pub const GL_ARB_shader_viewport_layer_array: u32 = 1;
+pub const GL_ARB_shading_language_100: u32 = 1;
+pub const GL_ARB_shading_language_420pack: u32 = 1;
+pub const GL_ARB_shading_language_include: u32 = 1;
+pub const GL_ARB_shading_language_packing: u32 = 1;
+pub const GL_ARB_shadow: u32 = 1;
+pub const GL_ARB_shadow_ambient: u32 = 1;
+pub const GL_ARB_sparse_buffer: u32 = 1;
+pub const GL_ARB_sparse_texture: u32 = 1;
+pub const GL_ARB_sparse_texture2: u32 = 1;
+pub const GL_ARB_sparse_texture_clamp: u32 = 1;
+pub const GL_ARB_stencil_texturing: u32 = 1;
+pub const GL_ARB_sync: u32 = 1;
+pub const GL_ARB_tessellation_shader: u32 = 1;
+pub const GL_ARB_texture_barrier: u32 = 1;
+pub const GL_ARB_texture_border_clamp: u32 = 1;
+pub const GL_ARB_texture_buffer_object: u32 = 1;
+pub const GL_ARB_texture_buffer_object_rgb32: u32 = 1;
+pub const GL_ARB_texture_buffer_range: u32 = 1;
+pub const GL_ARB_texture_compression: u32 = 1;
+pub const GL_ARB_texture_compression_bptc: u32 = 1;
+pub const GL_ARB_texture_compression_rgtc: u32 = 1;
+pub const GL_ARB_texture_cube_map: u32 = 1;
+pub const GL_ARB_texture_cube_map_array: u32 = 1;
+pub const GL_ARB_texture_env_add: u32 = 1;
+pub const GL_ARB_texture_env_combine: u32 = 1;
+pub const GL_ARB_texture_env_crossbar: u32 = 1;
+pub const GL_ARB_texture_env_dot3: u32 = 1;
+pub const GL_ARB_texture_filter_minmax: u32 = 1;
+pub const GL_ARB_texture_float: u32 = 1;
+pub const GL_ARB_texture_gather: u32 = 1;
+pub const GL_ARB_texture_mirror_clamp_to_edge: u32 = 1;
+pub const GL_ARB_texture_mirrored_repeat: u32 = 1;
+pub const GL_ARB_texture_multisample: u32 = 1;
+pub const GL_ARB_texture_non_power_of_two: u32 = 1;
+pub const GL_ARB_texture_query_levels: u32 = 1;
+pub const GL_ARB_texture_query_lod: u32 = 1;
+pub const GL_ARB_texture_rectangle: u32 = 1;
+pub const GL_ARB_texture_rg: u32 = 1;
+pub const GL_ARB_texture_rgb10_a2ui: u32 = 1;
+pub const GL_ARB_texture_stencil8: u32 = 1;
+pub const GL_ARB_texture_storage: u32 = 1;
+pub const GL_ARB_texture_storage_multisample: u32 = 1;
+pub const GL_ARB_texture_swizzle: u32 = 1;
+pub const GL_ARB_texture_view: u32 = 1;
+pub const GL_ARB_timer_query: u32 = 1;
+pub const GL_ARB_transform_feedback2: u32 = 1;
+pub const GL_ARB_transform_feedback3: u32 = 1;
+pub const GL_ARB_transform_feedback_instanced: u32 = 1;
+pub const GL_ARB_transform_feedback_overflow_query: u32 = 1;
+pub const GL_ARB_transpose_matrix: u32 = 1;
+pub const GL_ARB_uniform_buffer_object: u32 = 1;
+pub const GL_ARB_vertex_array_bgra: u32 = 1;
+pub const GL_ARB_vertex_array_object: u32 = 1;
+pub const GL_ARB_vertex_attrib_64bit: u32 = 1;
+pub const GL_ARB_vertex_attrib_binding: u32 = 1;
+pub const GL_ARB_vertex_blend: u32 = 1;
+pub const GL_ARB_vertex_buffer_object: u32 = 1;
+pub const GL_ARB_vertex_program: u32 = 1;
+pub const GL_ARB_vertex_shader: u32 = 1;
+pub const GL_ARB_vertex_type_10f_11f_11f_rev: u32 = 1;
+pub const GL_ARB_vertex_type_2_10_10_10_rev: u32 = 1;
+pub const GL_ARB_viewport_array: u32 = 1;
+pub const GL_ARB_window_pos: u32 = 1;
+pub const GL_ARM_mali_program_binary: u32 = 1;
+pub const GL_ARM_mali_shader_binary: u32 = 1;
+pub const GL_ARM_rgba8: u32 = 1;
+pub const GL_ARM_shader_framebuffer_fetch: u32 = 1;
+pub const GL_ARM_shader_framebuffer_fetch_depth_stencil: u32 = 1;
+pub const GL_ATI_draw_buffers: u32 = 1;
+pub const GL_ATI_element_array: u32 = 1;
+pub const GL_ATI_envmap_bumpmap: u32 = 1;
+pub const GL_ATI_fragment_shader: u32 = 1;
+pub const GL_ATI_map_object_buffer: u32 = 1;
+pub const GL_ATI_meminfo: u32 = 1;
+pub const GL_ATI_pixel_format_float: u32 = 1;
+pub const GL_ATI_pn_triangles: u32 = 1;
+pub const GL_ATI_separate_stencil: u32 = 1;
+pub const GL_ATI_text_fragment_shader: u32 = 1;
+pub const GL_ATI_texture_env_combine3: u32 = 1;
+pub const GL_ATI_texture_float: u32 = 1;
+pub const GL_ATI_texture_mirror_once: u32 = 1;
+pub const GL_ATI_vertex_array_object: u32 = 1;
+pub const GL_ATI_vertex_attrib_array_object: u32 = 1;
+pub const GL_ATI_vertex_streams: u32 = 1;
+pub const GL_DMP_program_binary: u32 = 1;
+pub const GL_DMP_shader_binary: u32 = 1;
+pub const GL_EXT_422_pixels: u32 = 1;
+pub const GL_EXT_YUV_target: u32 = 1;
+pub const GL_EXT_abgr: u32 = 1;
+pub const GL_EXT_base_instance: u32 = 1;
+pub const GL_EXT_bgra: u32 = 1;
+pub const GL_EXT_bindable_uniform: u32 = 1;
+pub const GL_EXT_blend_color: u32 = 1;
+pub const GL_EXT_blend_equation_separate: u32 = 1;
+pub const GL_EXT_blend_func_extended: u32 = 1;
+pub const GL_EXT_blend_func_separate: u32 = 1;
+pub const GL_EXT_blend_logic_op: u32 = 1;
+pub const GL_EXT_blend_minmax: u32 = 1;
+pub const GL_EXT_blend_subtract: u32 = 1;
+pub const GL_EXT_buffer_storage: u32 = 1;
+pub const GL_EXT_clear_texture: u32 = 1;
+pub const GL_EXT_clip_cull_distance: u32 = 1;
+pub const GL_EXT_clip_volume_hint: u32 = 1;
+pub const GL_EXT_cmyka: u32 = 1;
+pub const GL_EXT_color_buffer_float: u32 = 1;
+pub const GL_EXT_color_buffer_half_float: u32 = 1;
+pub const GL_EXT_color_subtable: u32 = 1;
+pub const GL_EXT_compiled_vertex_array: u32 = 1;
+pub const GL_EXT_conservative_depth: u32 = 1;
+pub const GL_EXT_convolution: u32 = 1;
+pub const GL_EXT_coordinate_frame: u32 = 1;
+pub const GL_EXT_copy_image: u32 = 1;
+pub const GL_EXT_copy_texture: u32 = 1;
+pub const GL_EXT_cull_vertex: u32 = 1;
+pub const GL_EXT_debug_label: u32 = 1;
+pub const GL_EXT_debug_marker: u32 = 1;
+pub const GL_EXT_depth_bounds_test: u32 = 1;
+pub const GL_EXT_direct_state_access: u32 = 1;
+pub const GL_EXT_discard_framebuffer: u32 = 1;
+pub const GL_EXT_disjoint_timer_query: u32 = 1;
+pub const GL_EXT_draw_buffers: u32 = 1;
+pub const GL_EXT_draw_buffers2: u32 = 1;
+pub const GL_EXT_draw_buffers_indexed: u32 = 1;
+pub const GL_EXT_draw_elements_base_vertex: u32 = 1;
+pub const GL_EXT_draw_instanced: u32 = 1;
+pub const GL_EXT_draw_range_elements: u32 = 1;
+pub const GL_EXT_draw_transform_feedback: u32 = 1;
+pub const GL_EXT_float_blend: u32 = 1;
+pub const GL_EXT_fog_coord: u32 = 1;
+pub const GL_EXT_framebuffer_blit: u32 = 1;
+pub const GL_EXT_framebuffer_multisample: u32 = 1;
+pub const GL_EXT_framebuffer_multisample_blit_scaled: u32 = 1;
+pub const GL_EXT_framebuffer_object: u32 = 1;
+pub const GL_EXT_framebuffer_sRGB: u32 = 1;
+pub const GL_EXT_geometry_point_size: u32 = 1;
+pub const GL_EXT_geometry_shader: u32 = 1;
+pub const GL_EXT_geometry_shader4: u32 = 1;
+pub const GL_EXT_gpu_program_parameters: u32 = 1;
+pub const GL_EXT_gpu_shader4: u32 = 1;
+pub const GL_EXT_gpu_shader5: u32 = 1;
+pub const GL_EXT_histogram: u32 = 1;
+pub const GL_EXT_index_array_formats: u32 = 1;
+pub const GL_EXT_index_func: u32 = 1;
+pub const GL_EXT_index_material: u32 = 1;
+pub const GL_EXT_index_texture: u32 = 1;
+pub const GL_EXT_instanced_arrays: u32 = 1;
+pub const GL_EXT_light_texture: u32 = 1;
+pub const GL_EXT_map_buffer_range: u32 = 1;
+pub const GL_EXT_misc_attribute: u32 = 1;
+pub const GL_EXT_multi_draw_arrays: u32 = 1;
+pub const GL_EXT_multi_draw_indirect: u32 = 1;
+pub const GL_EXT_multisample: u32 = 1;
+pub const GL_EXT_multisampled_compatibility: u32 = 1;
+pub const GL_EXT_multisampled_render_to_texture: u32 = 1;
+pub const GL_EXT_multiview_draw_buffers: u32 = 1;
+pub const GL_EXT_occlusion_query_boolean: u32 = 1;
+pub const GL_EXT_packed_depth_stencil: u32 = 1;
+pub const GL_EXT_packed_float: u32 = 1;
+pub const GL_EXT_packed_pixels: u32 = 1;
+pub const GL_EXT_paletted_texture: u32 = 1;
+pub const GL_EXT_pixel_buffer_object: u32 = 1;
+pub const GL_EXT_pixel_transform: u32 = 1;
+pub const GL_EXT_pixel_transform_color_table: u32 = 1;
+pub const GL_EXT_point_parameters: u32 = 1;
+pub const GL_EXT_polygon_offset: u32 = 1;
+pub const GL_EXT_polygon_offset_clamp: u32 = 1;
+pub const GL_EXT_post_depth_coverage: u32 = 1;
+pub const GL_EXT_primitive_bounding_box: u32 = 1;
+pub const GL_EXT_protected_textures: u32 = 1;
+pub const GL_EXT_provoking_vertex: u32 = 1;
+pub const GL_EXT_pvrtc_sRGB: u32 = 1;
+pub const GL_EXT_raster_multisample: u32 = 1;
+pub const GL_EXT_read_format_bgra: u32 = 1;
+pub const GL_EXT_render_snorm: u32 = 1;
+pub const GL_EXT_rescale_normal: u32 = 1;
+pub const GL_EXT_robustness: u32 = 1;
+pub const GL_EXT_sRGB: u32 = 1;
+pub const GL_EXT_sRGB_write_control: u32 = 1;
+pub const GL_EXT_secondary_color: u32 = 1;
+pub const GL_EXT_separate_shader_objects: u32 = 1;
+pub const GL_EXT_separate_specular_color: u32 = 1;
+pub const GL_EXT_shader_framebuffer_fetch: u32 = 1;
+pub const GL_EXT_shader_group_vote: u32 = 1;
+pub const GL_EXT_shader_image_load_formatted: u32 = 1;
+pub const GL_EXT_shader_image_load_store: u32 = 1;
+pub const GL_EXT_shader_implicit_conversions: u32 = 1;
+pub const GL_EXT_shader_integer_mix: u32 = 1;
+pub const GL_EXT_shader_io_blocks: u32 = 1;
+pub const GL_EXT_shader_non_constant_global_initializers: u32 = 1;
+pub const GL_EXT_shader_pixel_local_storage: u32 = 1;
+pub const GL_EXT_shader_pixel_local_storage2: u32 = 1;
+pub const GL_EXT_shader_texture_lod: u32 = 1;
+pub const GL_EXT_shadow_funcs: u32 = 1;
+pub const GL_EXT_shadow_samplers: u32 = 1;
+pub const GL_EXT_shared_texture_palette: u32 = 1;
+pub const GL_EXT_sparse_texture: u32 = 1;
+pub const GL_EXT_sparse_texture2: u32 = 1;
+pub const GL_EXT_stencil_clear_tag: u32 = 1;
+pub const GL_EXT_stencil_two_side: u32 = 1;
+pub const GL_EXT_stencil_wrap: u32 = 1;
+pub const GL_EXT_subtexture: u32 = 1;
+pub const GL_EXT_tessellation_point_size: u32 = 1;
+pub const GL_EXT_tessellation_shader: u32 = 1;
+pub const GL_EXT_texture: u32 = 1;
+pub const GL_EXT_texture3D: u32 = 1;
+pub const GL_EXT_texture_array: u32 = 1;
+pub const GL_EXT_texture_border_clamp: u32 = 1;
+pub const GL_EXT_texture_buffer: u32 = 1;
+pub const GL_EXT_texture_buffer_object: u32 = 1;
+pub const GL_EXT_texture_compression_dxt1: u32 = 1;
+pub const GL_EXT_texture_compression_latc: u32 = 1;
+pub const GL_EXT_texture_compression_rgtc: u32 = 1;
+pub const GL_EXT_texture_compression_s3tc: u32 = 1;
+pub const GL_EXT_texture_cube_map: u32 = 1;
+pub const GL_EXT_texture_cube_map_array: u32 = 1;
+pub const GL_EXT_texture_env_add: u32 = 1;
+pub const GL_EXT_texture_env_combine: u32 = 1;
+pub const GL_EXT_texture_env_dot3: u32 = 1;
+pub const GL_EXT_texture_filter_anisotropic: u32 = 1;
+pub const GL_EXT_texture_filter_minmax: u32 = 1;
+pub const GL_EXT_texture_format_BGRA8888: u32 = 1;
+pub const GL_EXT_texture_integer: u32 = 1;
+pub const GL_EXT_texture_lod_bias: u32 = 1;
+pub const GL_EXT_texture_mirror_clamp: u32 = 1;
+pub const GL_EXT_texture_norm16: u32 = 1;
+pub const GL_EXT_texture_object: u32 = 1;
+pub const GL_EXT_texture_perturb_normal: u32 = 1;
+pub const GL_EXT_texture_rg: u32 = 1;
+pub const GL_EXT_texture_sRGB: u32 = 1;
+pub const GL_EXT_texture_sRGB_R8: u32 = 1;
+pub const GL_EXT_texture_sRGB_RG8: u32 = 1;
+pub const GL_EXT_texture_sRGB_decode: u32 = 1;
+pub const GL_EXT_texture_shared_exponent: u32 = 1;
+pub const GL_EXT_texture_snorm: u32 = 1;
+pub const GL_EXT_texture_storage: u32 = 1;
+pub const GL_EXT_texture_swizzle: u32 = 1;
+pub const GL_EXT_texture_type_2_10_10_10_REV: u32 = 1;
+pub const GL_EXT_texture_view: u32 = 1;
+pub const GL_EXT_timer_query: u32 = 1;
+pub const GL_EXT_transform_feedback: u32 = 1;
+pub const GL_EXT_unpack_subimage: u32 = 1;
+pub const GL_EXT_vertex_array: u32 = 1;
+pub const GL_EXT_vertex_array_bgra: u32 = 1;
+pub const GL_EXT_vertex_attrib_64bit: u32 = 1;
+pub const GL_EXT_vertex_shader: u32 = 1;
+pub const GL_EXT_vertex_weighting: u32 = 1;
+pub const GL_EXT_window_rectangles: u32 = 1;
+pub const GL_EXT_x11_sync_object: u32 = 1;
+pub const GL_FJ_shader_binary_GCCSO: u32 = 1;
+pub const GL_GREMEDY_frame_terminator: u32 = 1;
+pub const GL_GREMEDY_string_marker: u32 = 1;
+pub const GL_HP_convolution_border_modes: u32 = 1;
+pub const GL_HP_image_transform: u32 = 1;
+pub const GL_HP_occlusion_test: u32 = 1;
+pub const GL_HP_texture_lighting: u32 = 1;
+pub const GL_IBM_cull_vertex: u32 = 1;
+pub const GL_IBM_multimode_draw_arrays: u32 = 1;
+pub const GL_IBM_rasterpos_clip: u32 = 1;
+pub const GL_IBM_static_data: u32 = 1;
+pub const GL_IBM_texture_mirrored_repeat: u32 = 1;
+pub const GL_IBM_vertex_array_lists: u32 = 1;
+pub const GL_IMG_bindless_texture: u32 = 1;
+pub const GL_IMG_framebuffer_downsample: u32 = 1;
+pub const GL_IMG_multisampled_render_to_texture: u32 = 1;
+pub const GL_IMG_program_binary: u32 = 1;
+pub const GL_IMG_read_format: u32 = 1;
+pub const GL_IMG_shader_binary: u32 = 1;
+pub const GL_IMG_texture_compression_pvrtc: u32 = 1;
+pub const GL_IMG_texture_compression_pvrtc2: u32 = 1;
+pub const GL_IMG_texture_env_enhanced_fixed_function: u32 = 1;
+pub const GL_IMG_texture_filter_cubic: u32 = 1;
+pub const GL_IMG_user_clip_plane: u32 = 1;
+pub const GL_INGR_blend_func_separate: u32 = 1;
+pub const GL_INGR_color_clamp: u32 = 1;
+pub const GL_INGR_interlace_read: u32 = 1;
+pub const GL_INTEL_conservative_rasterization: u32 = 1;
+pub const GL_INTEL_fragment_shader_ordering: u32 = 1;
+pub const GL_INTEL_framebuffer_CMAA: u32 = 1;
+pub const GL_INTEL_map_texture: u32 = 1;
+pub const GL_INTEL_parallel_arrays: u32 = 1;
+pub const GL_INTEL_performance_query: u32 = 1;
+pub const GL_KHR_blend_equation_advanced: u32 = 1;
+pub const GL_KHR_blend_equation_advanced_coherent: u32 = 1;
+pub const GL_KHR_context_flush_control: u32 = 1;
+pub const GL_KHR_debug: u32 = 1;
+pub const GL_KHR_no_error: u32 = 1;
+pub const GL_KHR_robust_buffer_access_behavior: u32 = 1;
+pub const GL_KHR_robustness: u32 = 1;
+pub const GL_KHR_texture_compression_astc_hdr: u32 = 1;
+pub const GL_KHR_texture_compression_astc_ldr: u32 = 1;
+pub const GL_KHR_texture_compression_astc_sliced_3d: u32 = 1;
+pub const GL_MESAX_texture_stack: u32 = 1;
+pub const GL_MESA_pack_invert: u32 = 1;
+pub const GL_MESA_resize_buffers: u32 = 1;
+pub const GL_MESA_window_pos: u32 = 1;
+pub const GL_MESA_ycbcr_texture: u32 = 1;
+pub const GL_NVX_conditional_render: u32 = 1;
+pub const GL_NVX_gpu_memory_info: u32 = 1;
+pub const GL_NV_bindless_multi_draw_indirect: u32 = 1;
+pub const GL_NV_bindless_multi_draw_indirect_count: u32 = 1;
+pub const GL_NV_bindless_texture: u32 = 1;
+pub const GL_NV_blend_equation_advanced: u32 = 1;
+pub const GL_NV_blend_equation_advanced_coherent: u32 = 1;
+pub const GL_NV_blend_square: u32 = 1;
+pub const GL_NV_clip_space_w_scaling: u32 = 1;
+pub const GL_NV_command_list: u32 = 1;
+pub const GL_NV_compute_program5: u32 = 1;
+pub const GL_NV_conditional_render: u32 = 1;
+pub const GL_NV_conservative_raster: u32 = 1;
+pub const GL_NV_conservative_raster_dilate: u32 = 1;
+pub const GL_NV_conservative_raster_pre_snap_triangles: u32 = 1;
+pub const GL_NV_copy_buffer: u32 = 1;
+pub const GL_NV_copy_depth_to_color: u32 = 1;
+pub const GL_NV_copy_image: u32 = 1;
+pub const GL_NV_coverage_sample: u32 = 1;
+pub const GL_NV_deep_texture3D: u32 = 1;
+pub const GL_NV_depth_buffer_float: u32 = 1;
+pub const GL_NV_depth_clamp: u32 = 1;
+pub const GL_NV_depth_nonlinear: u32 = 1;
+pub const GL_NV_draw_buffers: u32 = 1;
+pub const GL_NV_draw_instanced: u32 = 1;
+pub const GL_NV_draw_texture: u32 = 1;
+pub const GL_NV_evaluators: u32 = 1;
+pub const GL_NV_explicit_attrib_location: u32 = 1;
+pub const GL_NV_explicit_multisample: u32 = 1;
+pub const GL_NV_fbo_color_attachments: u32 = 1;
+pub const GL_NV_fence: u32 = 1;
+pub const GL_NV_fill_rectangle: u32 = 1;
+pub const GL_NV_float_buffer: u32 = 1;
+pub const GL_NV_fog_distance: u32 = 1;
+pub const GL_NV_fragment_coverage_to_color: u32 = 1;
+pub const GL_NV_fragment_program: u32 = 1;
+pub const GL_NV_fragment_program2: u32 = 1;
+pub const GL_NV_fragment_program4: u32 = 1;
+pub const GL_NV_fragment_program_option: u32 = 1;
+pub const GL_NV_fragment_shader_interlock: u32 = 1;
+pub const GL_NV_framebuffer_blit: u32 = 1;
+pub const GL_NV_framebuffer_mixed_samples: u32 = 1;
+pub const GL_NV_framebuffer_multisample: u32 = 1;
+pub const GL_NV_framebuffer_multisample_coverage: u32 = 1;
+pub const GL_NV_generate_mipmap_sRGB: u32 = 1;
+pub const GL_NV_geometry_program4: u32 = 1;
+pub const GL_NV_geometry_shader4: u32 = 1;
+pub const GL_NV_geometry_shader_passthrough: u32 = 1;
+pub const GL_NV_gpu_program4: u32 = 1;
+pub const GL_NV_gpu_program5: u32 = 1;
+pub const GL_NV_gpu_program5_mem_extended: u32 = 1;
+pub const GL_NV_gpu_shader5: u32 = 1;
+pub const GL_NV_half_float: u32 = 1;
+pub const GL_NV_image_formats: u32 = 1;
+pub const GL_NV_instanced_arrays: u32 = 1;
+pub const GL_NV_internalformat_sample_query: u32 = 1;
+pub const GL_NV_light_max_exponent: u32 = 1;
+pub const GL_NV_multisample_coverage: u32 = 1;
+pub const GL_NV_multisample_filter_hint: u32 = 1;
+pub const GL_NV_non_square_matrices: u32 = 1;
+pub const GL_NV_occlusion_query: u32 = 1;
+pub const GL_NV_packed_depth_stencil: u32 = 1;
+pub const GL_NV_parameter_buffer_object: u32 = 1;
+pub const GL_NV_parameter_buffer_object2: u32 = 1;
+pub const GL_NV_path_rendering: u32 = 1;
+pub const GL_NV_path_rendering_shared_edge: u32 = 1;
+pub const GL_NV_pixel_data_range: u32 = 1;
+pub const GL_NV_point_sprite: u32 = 1;
+pub const GL_NV_polygon_mode: u32 = 1;
+pub const GL_NV_present_video: u32 = 1;
+pub const GL_NV_primitive_restart: u32 = 1;
+pub const GL_NV_read_buffer: u32 = 1;
+pub const GL_NV_read_buffer_front: u32 = 1;
+pub const GL_NV_read_depth: u32 = 1;
+pub const GL_NV_read_depth_stencil: u32 = 1;
+pub const GL_NV_read_stencil: u32 = 1;
+pub const GL_NV_register_combiners: u32 = 1;
+pub const GL_NV_register_combiners2: u32 = 1;
+pub const GL_NV_robustness_video_memory_purge: u32 = 1;
+pub const GL_NV_sRGB_formats: u32 = 1;
+pub const GL_NV_sample_locations: u32 = 1;
+pub const GL_NV_sample_mask_override_coverage: u32 = 1;
+pub const GL_NV_shader_atomic_counters: u32 = 1;
+pub const GL_NV_shader_atomic_float: u32 = 1;
+pub const GL_NV_shader_atomic_float64: u32 = 1;
+pub const GL_NV_shader_atomic_fp16_vector: u32 = 1;
+pub const GL_NV_shader_atomic_int64: u32 = 1;
+pub const GL_NV_shader_buffer_load: u32 = 1;
+pub const GL_NV_shader_buffer_store: u32 = 1;
+pub const GL_NV_shader_noperspective_interpolation: u32 = 1;
+pub const GL_NV_shader_storage_buffer_object: u32 = 1;
+pub const GL_NV_shader_thread_group: u32 = 1;
+pub const GL_NV_shader_thread_shuffle: u32 = 1;
+pub const GL_NV_shadow_samplers_array: u32 = 1;
+pub const GL_NV_shadow_samplers_cube: u32 = 1;
+pub const GL_NV_stereo_view_rendering: u32 = 1;
+pub const GL_NV_tessellation_program5: u32 = 1;
+pub const GL_NV_texgen_emboss: u32 = 1;
+pub const GL_NV_texgen_reflection: u32 = 1;
+pub const GL_NV_texture_barrier: u32 = 1;
+pub const GL_NV_texture_border_clamp: u32 = 1;
+pub const GL_NV_texture_compression_s3tc_update: u32 = 1;
+pub const GL_NV_texture_compression_vtc: u32 = 1;
+pub const GL_NV_texture_env_combine4: u32 = 1;
+pub const GL_NV_texture_expand_normal: u32 = 1;
+pub const GL_NV_texture_multisample: u32 = 1;
+pub const GL_NV_texture_npot_2D_mipmap: u32 = 1;
+pub const GL_NV_texture_rectangle: u32 = 1;
+pub const GL_NV_texture_shader: u32 = 1;
+pub const GL_NV_texture_shader2: u32 = 1;
+pub const GL_NV_texture_shader3: u32 = 1;
+pub const GL_NV_transform_feedback: u32 = 1;
+pub const GL_NV_transform_feedback2: u32 = 1;
+pub const GL_NV_uniform_buffer_unified_memory: u32 = 1;
+pub const GL_NV_vdpau_interop: u32 = 1;
+pub const GL_NV_vertex_array_range: u32 = 1;
+pub const GL_NV_vertex_array_range2: u32 = 1;
+pub const GL_NV_vertex_attrib_integer_64bit: u32 = 1;
+pub const GL_NV_vertex_buffer_unified_memory: u32 = 1;
+pub const GL_NV_vertex_program: u32 = 1;
+pub const GL_NV_vertex_program1_1: u32 = 1;
+pub const GL_NV_vertex_program2: u32 = 1;
+pub const GL_NV_vertex_program2_option: u32 = 1;
+pub const GL_NV_vertex_program3: u32 = 1;
+pub const GL_NV_vertex_program4: u32 = 1;
+pub const GL_NV_video_capture: u32 = 1;
+pub const GL_NV_viewport_array: u32 = 1;
+pub const GL_NV_viewport_array2: u32 = 1;
+pub const GL_NV_viewport_swizzle: u32 = 1;
+pub const GL_OES_EGL_image: u32 = 1;
+pub const GL_OES_EGL_image_external: u32 = 1;
+pub const GL_OES_EGL_image_external_essl3: u32 = 1;
+pub const GL_OES_blend_equation_separate: u32 = 1;
+pub const GL_OES_blend_func_separate: u32 = 1;
+pub const GL_OES_blend_subtract: u32 = 1;
+pub const GL_OES_byte_coordinates: u32 = 1;
+pub const GL_OES_compressed_ETC1_RGB8_sub_texture: u32 = 1;
+pub const GL_OES_compressed_ETC1_RGB8_texture: u32 = 1;
+pub const GL_OES_compressed_paletted_texture: u32 = 1;
+pub const GL_OES_copy_image: u32 = 1;
+pub const GL_OES_depth24: u32 = 1;
+pub const GL_OES_depth32: u32 = 1;
+pub const GL_OES_depth_texture: u32 = 1;
+pub const GL_OES_draw_buffers_indexed: u32 = 1;
+pub const GL_OES_draw_elements_base_vertex: u32 = 1;
+pub const GL_OES_draw_texture: u32 = 1;
+pub const GL_OES_element_index_uint: u32 = 1;
+pub const GL_OES_extended_matrix_palette: u32 = 1;
+pub const GL_OES_fbo_render_mipmap: u32 = 1;
+pub const GL_OES_fixed_point: u32 = 1;
+pub const GL_OES_fragment_precision_high: u32 = 1;
+pub const GL_OES_framebuffer_object: u32 = 1;
+pub const GL_OES_geometry_point_size: u32 = 1;
+pub const GL_OES_geometry_shader: u32 = 1;
+pub const GL_OES_get_program_binary: u32 = 1;
+pub const GL_OES_gpu_shader5: u32 = 1;
+pub const GL_OES_mapbuffer: u32 = 1;
+pub const GL_OES_matrix_get: u32 = 1;
+pub const GL_OES_matrix_palette: u32 = 1;
+pub const GL_OES_packed_depth_stencil: u32 = 1;
+pub const GL_OES_point_size_array: u32 = 1;
+pub const GL_OES_point_sprite: u32 = 1;
+pub const GL_OES_primitive_bounding_box: u32 = 1;
+pub const GL_OES_query_matrix: u32 = 1;
+pub const GL_OES_read_format: u32 = 1;
+pub const GL_OES_required_internalformat: u32 = 1;
+pub const GL_OES_rgb8_rgba8: u32 = 1;
+pub const GL_OES_sample_shading: u32 = 1;
+pub const GL_OES_sample_variables: u32 = 1;
+pub const GL_OES_shader_image_atomic: u32 = 1;
+pub const GL_OES_shader_io_blocks: u32 = 1;
+pub const GL_OES_shader_multisample_interpolation: u32 = 1;
+pub const GL_OES_single_precision: u32 = 1;
+pub const GL_OES_standard_derivatives: u32 = 1;
+pub const GL_OES_stencil1: u32 = 1;
+pub const GL_OES_stencil4: u32 = 1;
+pub const GL_OES_stencil8: u32 = 1;
+pub const GL_OES_stencil_wrap: u32 = 1;
+pub const GL_OES_surfaceless_context: u32 = 1;
+pub const GL_OES_tessellation_point_size: u32 = 1;
+pub const GL_OES_tessellation_shader: u32 = 1;
+pub const GL_OES_texture_3D: u32 = 1;
+pub const GL_OES_texture_border_clamp: u32 = 1;
+pub const GL_OES_texture_buffer: u32 = 1;
+pub const GL_OES_texture_compression_astc: u32 = 1;
+pub const GL_OES_texture_cube_map: u32 = 1;
+pub const GL_OES_texture_cube_map_array: u32 = 1;
+pub const GL_OES_texture_env_crossbar: u32 = 1;
+pub const GL_OES_texture_float: u32 = 1;
+pub const GL_OES_texture_float_linear: u32 = 1;
+pub const GL_OES_texture_half_float: u32 = 1;
+pub const GL_OES_texture_half_float_linear: u32 = 1;
+pub const GL_OES_texture_mirrored_repeat: u32 = 1;
+pub const GL_OES_texture_npot: u32 = 1;
+pub const GL_OES_texture_stencil8: u32 = 1;
+pub const GL_OES_texture_storage_multisample_2d_array: u32 = 1;
+pub const GL_OES_texture_view: u32 = 1;
+pub const GL_OES_vertex_array_object: u32 = 1;
+pub const GL_OES_vertex_half_float: u32 = 1;
+pub const GL_OES_vertex_type_10_10_10_2: u32 = 1;
+pub const GL_OES_viewport_array: u32 = 1;
+pub const GL_OML_interlace: u32 = 1;
+pub const GL_OML_resample: u32 = 1;
+pub const GL_OML_subsample: u32 = 1;
+pub const GL_OVR_multiview: u32 = 1;
+pub const GL_OVR_multiview2: u32 = 1;
+pub const GL_OVR_multiview_multisampled_render_to_texture: u32 = 1;
+pub const GL_PGI_misc_hints: u32 = 1;
+pub const GL_PGI_vertex_hints: u32 = 1;
+pub const GL_QCOM_alpha_test: u32 = 1;
+pub const GL_QCOM_binning_control: u32 = 1;
+pub const GL_QCOM_driver_control: u32 = 1;
+pub const GL_QCOM_extended_get: u32 = 1;
+pub const GL_QCOM_extended_get2: u32 = 1;
+pub const GL_QCOM_perfmon_global_mode: u32 = 1;
+pub const GL_QCOM_tiled_rendering: u32 = 1;
+pub const GL_QCOM_writeonly_rendering: u32 = 1;
+pub const GL_REND_screen_coordinates: u32 = 1;
+pub const GL_S3_s3tc: u32 = 1;
+pub const GL_SGIS_detail_texture: u32 = 1;
+pub const GL_SGIS_fog_function: u32 = 1;
+pub const GL_SGIS_generate_mipmap: u32 = 1;
+pub const GL_SGIS_multisample: u32 = 1;
+pub const GL_SGIS_pixel_texture: u32 = 1;
+pub const GL_SGIS_point_line_texgen: u32 = 1;
+pub const GL_SGIS_point_parameters: u32 = 1;
+pub const GL_SGIS_sharpen_texture: u32 = 1;
+pub const GL_SGIS_texture4D: u32 = 1;
+pub const GL_SGIS_texture_border_clamp: u32 = 1;
+pub const GL_SGIS_texture_color_mask: u32 = 1;
+pub const GL_SGIS_texture_edge_clamp: u32 = 1;
+pub const GL_SGIS_texture_filter4: u32 = 1;
+pub const GL_SGIS_texture_lod: u32 = 1;
+pub const GL_SGIS_texture_select: u32 = 1;
+pub const GL_SGIX_async: u32 = 1;
+pub const GL_SGIX_async_histogram: u32 = 1;
+pub const GL_SGIX_async_pixel: u32 = 1;
+pub const GL_SGIX_blend_alpha_minmax: u32 = 1;
+pub const GL_SGIX_calligraphic_fragment: u32 = 1;
+pub const GL_SGIX_clipmap: u32 = 1;
+pub const GL_SGIX_convolution_accuracy: u32 = 1;
+pub const GL_SGIX_depth_pass_instrument: u32 = 1;
+pub const GL_SGIX_depth_texture: u32 = 1;
+pub const GL_SGIX_flush_raster: u32 = 1;
+pub const GL_SGIX_fog_offset: u32 = 1;
+pub const GL_SGIX_fragment_lighting: u32 = 1;
+pub const GL_SGIX_framezoom: u32 = 1;
+pub const GL_SGIX_igloo_interface: u32 = 1;
+pub const GL_SGIX_instruments: u32 = 1;
+pub const GL_SGIX_interlace: u32 = 1;
+pub const GL_SGIX_ir_instrument1: u32 = 1;
+pub const GL_SGIX_list_priority: u32 = 1;
+pub const GL_SGIX_pixel_texture: u32 = 1;
+pub const GL_SGIX_pixel_tiles: u32 = 1;
+pub const GL_SGIX_polynomial_ffd: u32 = 1;
+pub const GL_SGIX_reference_plane: u32 = 1;
+pub const GL_SGIX_resample: u32 = 1;
+pub const GL_SGIX_scalebias_hint: u32 = 1;
+pub const GL_SGIX_shadow: u32 = 1;
+pub const GL_SGIX_shadow_ambient: u32 = 1;
+pub const GL_SGIX_sprite: u32 = 1;
+pub const GL_SGIX_subsample: u32 = 1;
+pub const GL_SGIX_tag_sample_buffer: u32 = 1;
+pub const GL_SGIX_texture_add_env: u32 = 1;
+pub const GL_SGIX_texture_coordinate_clamp: u32 = 1;
+pub const GL_SGIX_texture_lod_bias: u32 = 1;
+pub const GL_SGIX_texture_multi_buffer: u32 = 1;
+pub const GL_SGIX_texture_scale_bias: u32 = 1;
+pub const GL_SGIX_vertex_preclip: u32 = 1;
+pub const GL_SGIX_ycrcb: u32 = 1;
+pub const GL_SGIX_ycrcb_subsample: u32 = 1;
+pub const GL_SGIX_ycrcba: u32 = 1;
+pub const GL_SGI_color_matrix: u32 = 1;
+pub const GL_SGI_color_table: u32 = 1;
+pub const GL_SGI_texture_color_table: u32 = 1;
+pub const GL_SUNX_constant_data: u32 = 1;
+pub const GL_SUN_convolution_border_modes: u32 = 1;
+pub const GL_SUN_global_alpha: u32 = 1;
+pub const GL_SUN_mesh_array: u32 = 1;
+pub const GL_SUN_slice_accum: u32 = 1;
+pub const GL_SUN_triangle_list: u32 = 1;
+pub const GL_SUN_vertex: u32 = 1;
+pub const GL_VIV_shader_binary: u32 = 1;
+pub const GL_WIN_phong_shading: u32 = 1;
+pub const GL_WIN_specular_fog: u32 = 1;
+pub const GL_NEXT_BUFFER_NV: i32 = -2;
+pub const GL_SKIP_COMPONENTS4_NV: i32 = -3;
+pub const GL_SKIP_COMPONENTS3_NV: i32 = -4;
+pub const GL_SKIP_COMPONENTS2_NV: i32 = -5;
+pub const GL_SKIP_COMPONENTS1_NV: i32 = -6;
+pub const GL_FALSE: u32 = 0;
+pub const GL_LAYOUT_DEFAULT_INTEL: u32 = 0;
+pub const GL_NONE: u32 = 0;
+pub const GL_NONE_OES: u32 = 0;
+pub const GL_NO_ERROR: u32 = 0;
+pub const GL_ZERO: u32 = 0;
+pub const GL_CLOSE_PATH_NV: u32 = 0;
+pub const GL_POINTS: u32 = 0;
+pub const GL_TERMINATE_SEQUENCE_COMMAND_NV: u32 = 0;
+pub const GL_PERFQUERY_SINGLE_CONTEXT_INTEL: u32 = 0;
+pub const GL_2X_BIT_ATI: u32 = 1;
+pub const GL_CLIENT_PIXEL_STORE_BIT: u32 = 1;
+pub const GL_COLOR_BUFFER_BIT0_QCOM: u32 = 1;
+pub const GL_CONTEXT_CORE_PROFILE_BIT: u32 = 1;
+pub const GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT: u32 = 1;
+pub const GL_CURRENT_BIT: u32 = 1;
+pub const GL_PERFQUERY_GLOBAL_CONTEXT_INTEL: u32 = 1;
+pub const GL_QUERY_DEPTH_PASS_EVENT_BIT_AMD: u32 = 1;
+pub const GL_RED_BIT_ATI: u32 = 1;
+pub const GL_SYNC_FLUSH_COMMANDS_BIT: u32 = 1;
+pub const GL_SYNC_FLUSH_COMMANDS_BIT_APPLE: u32 = 1;
+pub const GL_TEXTURE_DEFORMATION_BIT_SGIX: u32 = 1;
+pub const GL_TEXTURE_STORAGE_SPARSE_BIT_AMD: u32 = 1;
+pub const GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT: u32 = 1;
+pub const GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT: u32 = 1;
+pub const GL_VERTEX_SHADER_BIT: u32 = 1;
+pub const GL_VERTEX_SHADER_BIT_EXT: u32 = 1;
+pub const GL_4X_BIT_ATI: u32 = 2;
+pub const GL_CLIENT_VERTEX_ARRAY_BIT: u32 = 2;
+pub const GL_COLOR_BUFFER_BIT1_QCOM: u32 = 2;
+pub const GL_COMP_BIT_ATI: u32 = 2;
+pub const GL_CONTEXT_COMPATIBILITY_PROFILE_BIT: u32 = 2;
+pub const GL_CONTEXT_FLAG_DEBUG_BIT: u32 = 2;
+pub const GL_CONTEXT_FLAG_DEBUG_BIT_KHR: u32 = 2;
+pub const GL_ELEMENT_ARRAY_BARRIER_BIT: u32 = 2;
+pub const GL_ELEMENT_ARRAY_BARRIER_BIT_EXT: u32 = 2;
+pub const GL_FRAGMENT_SHADER_BIT: u32 = 2;
+pub const GL_FRAGMENT_SHADER_BIT_EXT: u32 = 2;
+pub const GL_GEOMETRY_DEFORMATION_BIT_SGIX: u32 = 2;
+pub const GL_GREEN_BIT_ATI: u32 = 2;
+pub const GL_POINT_BIT: u32 = 2;
+pub const GL_QUERY_DEPTH_FAIL_EVENT_BIT_AMD: u32 = 2;
+pub const GL_8X_BIT_ATI: u32 = 4;
+pub const GL_BLUE_BIT_ATI: u32 = 4;
+pub const GL_COLOR_BUFFER_BIT2_QCOM: u32 = 4;
+pub const GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT: u32 = 4;
+pub const GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB: u32 = 4;
+pub const GL_GEOMETRY_SHADER_BIT: u32 = 4;
+pub const GL_GEOMETRY_SHADER_BIT_EXT: u32 = 4;
+pub const GL_GEOMETRY_SHADER_BIT_OES: u32 = 4;
+pub const GL_LINE_BIT: u32 = 4;
+pub const GL_NEGATE_BIT_ATI: u32 = 4;
+pub const GL_QUERY_STENCIL_FAIL_EVENT_BIT_AMD: u32 = 4;
+pub const GL_UNIFORM_BARRIER_BIT: u32 = 4;
+pub const GL_UNIFORM_BARRIER_BIT_EXT: u32 = 4;
+pub const GL_VERTEX23_BIT_PGI: u32 = 4;
+pub const GL_BIAS_BIT_ATI: u32 = 8;
+pub const GL_COLOR_BUFFER_BIT3_QCOM: u32 = 8;
+pub const GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR: u32 = 8;
+pub const GL_HALF_BIT_ATI: u32 = 8;
+pub const GL_POLYGON_BIT: u32 = 8;
+pub const GL_QUERY_DEPTH_BOUNDS_FAIL_EVENT_BIT_AMD: u32 = 8;
+pub const GL_TESS_CONTROL_SHADER_BIT: u32 = 8;
+pub const GL_TESS_CONTROL_SHADER_BIT_EXT: u32 = 8;
+pub const GL_TESS_CONTROL_SHADER_BIT_OES: u32 = 8;
+pub const GL_TEXTURE_FETCH_BARRIER_BIT: u32 = 8;
+pub const GL_TEXTURE_FETCH_BARRIER_BIT_EXT: u32 = 8;
+pub const GL_VERTEX4_BIT_PGI: u32 = 8;
+pub const GL_COLOR_BUFFER_BIT4_QCOM: u32 = 16;
+pub const GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT_EXT: u32 = 16;
+pub const GL_POLYGON_STIPPLE_BIT: u32 = 16;
+pub const GL_QUARTER_BIT_ATI: u32 = 16;
+pub const GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV: u32 = 16;
+pub const GL_TESS_EVALUATION_SHADER_BIT: u32 = 16;
+pub const GL_TESS_EVALUATION_SHADER_BIT_EXT: u32 = 16;
+pub const GL_TESS_EVALUATION_SHADER_BIT_OES: u32 = 16;
+pub const GL_COLOR_BUFFER_BIT5_QCOM: u32 = 32;
+pub const GL_COMPUTE_SHADER_BIT: u32 = 32;
+pub const GL_EIGHTH_BIT_ATI: u32 = 32;
+pub const GL_PIXEL_MODE_BIT: u32 = 32;
+pub const GL_SHADER_IMAGE_ACCESS_BARRIER_BIT: u32 = 32;
+pub const GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT: u32 = 32;
+pub const GL_COLOR_BUFFER_BIT6_QCOM: u32 = 64;
+pub const GL_COMMAND_BARRIER_BIT: u32 = 64;
+pub const GL_COMMAND_BARRIER_BIT_EXT: u32 = 64;
+pub const GL_LIGHTING_BIT: u32 = 64;
+pub const GL_SATURATE_BIT_ATI: u32 = 64;
+pub const GL_COLOR_BUFFER_BIT7_QCOM: u32 = 128;
+pub const GL_FOG_BIT: u32 = 128;
+pub const GL_PIXEL_BUFFER_BARRIER_BIT: u32 = 128;
+pub const GL_PIXEL_BUFFER_BARRIER_BIT_EXT: u32 = 128;
+pub const GL_DEPTH_BUFFER_BIT: u32 = 256;
+pub const GL_DEPTH_BUFFER_BIT0_QCOM: u32 = 256;
+pub const GL_TEXTURE_UPDATE_BARRIER_BIT: u32 = 256;
+pub const GL_TEXTURE_UPDATE_BARRIER_BIT_EXT: u32 = 256;
+pub const GL_ACCUM_BUFFER_BIT: u32 = 512;
+pub const GL_BUFFER_UPDATE_BARRIER_BIT: u32 = 512;
+pub const GL_BUFFER_UPDATE_BARRIER_BIT_EXT: u32 = 512;
+pub const GL_DEPTH_BUFFER_BIT1_QCOM: u32 = 512;
+pub const GL_DEPTH_BUFFER_BIT2_QCOM: u32 = 1024;
+pub const GL_FRAMEBUFFER_BARRIER_BIT: u32 = 1024;
+pub const GL_FRAMEBUFFER_BARRIER_BIT_EXT: u32 = 1024;
+pub const GL_STENCIL_BUFFER_BIT: u32 = 1024;
+pub const GL_DEPTH_BUFFER_BIT3_QCOM: u32 = 2048;
+pub const GL_TRANSFORM_FEEDBACK_BARRIER_BIT: u32 = 2048;
+pub const GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT: u32 = 2048;
+pub const GL_VIEWPORT_BIT: u32 = 2048;
+pub const GL_ATOMIC_COUNTER_BARRIER_BIT: u32 = 4096;
+pub const GL_ATOMIC_COUNTER_BARRIER_BIT_EXT: u32 = 4096;
+pub const GL_DEPTH_BUFFER_BIT4_QCOM: u32 = 4096;
+pub const GL_TRANSFORM_BIT: u32 = 4096;
+pub const GL_DEPTH_BUFFER_BIT5_QCOM: u32 = 8192;
+pub const GL_ENABLE_BIT: u32 = 8192;
+pub const GL_SHADER_STORAGE_BARRIER_BIT: u32 = 8192;
+pub const GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT: u32 = 16384;
+pub const GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT: u32 = 16384;
+pub const GL_COLOR_BUFFER_BIT: u32 = 16384;
+pub const GL_DEPTH_BUFFER_BIT6_QCOM: u32 = 16384;
+pub const GL_COVERAGE_BUFFER_BIT_NV: u32 = 32768;
+pub const GL_DEPTH_BUFFER_BIT7_QCOM: u32 = 32768;
+pub const GL_HINT_BIT: u32 = 32768;
+pub const GL_QUERY_BUFFER_BARRIER_BIT: u32 = 32768;
+pub const GL_LINES: u32 = 1;
+pub const GL_MAP_READ_BIT: u32 = 1;
+pub const GL_MAP_READ_BIT_EXT: u32 = 1;
+pub const GL_NOP_COMMAND_NV: u32 = 1;
+pub const GL_RESTART_SUN: u32 = 1;
+pub const GL_TRACE_OPERATIONS_BIT_MESA: u32 = 1;
+pub const GL_COLOR3_BIT_PGI: u32 = 65536;
+pub const GL_EVAL_BIT: u32 = 65536;
+pub const GL_FONT_X_MIN_BOUNDS_BIT_NV: u32 = 65536;
+pub const GL_STENCIL_BUFFER_BIT0_QCOM: u32 = 65536;
+pub const GL_DRAW_ELEMENTS_COMMAND_NV: u32 = 2;
+pub const GL_LINE_LOOP: u32 = 2;
+pub const GL_MAP_WRITE_BIT: u32 = 2;
+pub const GL_MAP_WRITE_BIT_EXT: u32 = 2;
+pub const GL_REPLACE_MIDDLE_SUN: u32 = 2;
+pub const GL_TRACE_PRIMITIVES_BIT_MESA: u32 = 2;
+pub const GL_COLOR4_BIT_PGI: u32 = 131072;
+pub const GL_FONT_Y_MIN_BOUNDS_BIT_NV: u32 = 131072;
+pub const GL_LIST_BIT: u32 = 131072;
+pub const GL_STENCIL_BUFFER_BIT1_QCOM: u32 = 131072;
+pub const GL_DRAW_ARRAYS_COMMAND_NV: u32 = 3;
+pub const GL_LINE_STRIP: u32 = 3;
+pub const GL_REPLACE_OLDEST_SUN: u32 = 3;
+pub const GL_DRAW_ELEMENTS_STRIP_COMMAND_NV: u32 = 4;
+pub const GL_MAP_INVALIDATE_RANGE_BIT: u32 = 4;
+pub const GL_MAP_INVALIDATE_RANGE_BIT_EXT: u32 = 4;
+pub const GL_TRACE_ARRAYS_BIT_MESA: u32 = 4;
+pub const GL_TRIANGLES: u32 = 4;
+pub const GL_EDGEFLAG_BIT_PGI: u32 = 262144;
+pub const GL_FONT_X_MAX_BOUNDS_BIT_NV: u32 = 262144;
+pub const GL_STENCIL_BUFFER_BIT2_QCOM: u32 = 262144;
+pub const GL_TEXTURE_BIT: u32 = 262144;
+pub const GL_DRAW_ARRAYS_STRIP_COMMAND_NV: u32 = 5;
+pub const GL_TRIANGLE_STRIP: u32 = 5;
+pub const GL_DRAW_ELEMENTS_INSTANCED_COMMAND_NV: u32 = 6;
+pub const GL_TRIANGLE_FAN: u32 = 6;
+pub const GL_DRAW_ARRAYS_INSTANCED_COMMAND_NV: u32 = 7;
+pub const GL_QUADS: u32 = 7;
+pub const GL_QUADS_EXT: u32 = 7;
+pub const GL_QUADS_OES: u32 = 7;
+pub const GL_ELEMENT_ADDRESS_COMMAND_NV: u32 = 8;
+pub const GL_MAP_INVALIDATE_BUFFER_BIT: u32 = 8;
+pub const GL_MAP_INVALIDATE_BUFFER_BIT_EXT: u32 = 8;
+pub const GL_QUAD_STRIP: u32 = 8;
+pub const GL_TRACE_TEXTURES_BIT_MESA: u32 = 8;
+pub const GL_FONT_Y_MAX_BOUNDS_BIT_NV: u32 = 524288;
+pub const GL_INDEX_BIT_PGI: u32 = 524288;
+pub const GL_SCISSOR_BIT: u32 = 524288;
+pub const GL_STENCIL_BUFFER_BIT3_QCOM: u32 = 524288;
+pub const GL_ATTRIBUTE_ADDRESS_COMMAND_NV: u32 = 9;
+pub const GL_POLYGON: u32 = 9;
+pub const GL_LINES_ADJACENCY: u32 = 10;
+pub const GL_LINES_ADJACENCY_ARB: u32 = 10;
+pub const GL_LINES_ADJACENCY_EXT: u32 = 10;
+pub const GL_LINES_ADJACENCY_OES: u32 = 10;
+pub const GL_UNIFORM_ADDRESS_COMMAND_NV: u32 = 10;
+pub const GL_BLEND_COLOR_COMMAND_NV: u32 = 11;
+pub const GL_LINE_STRIP_ADJACENCY: u32 = 11;
+pub const GL_LINE_STRIP_ADJACENCY_ARB: u32 = 11;
+pub const GL_LINE_STRIP_ADJACENCY_EXT: u32 = 11;
+pub const GL_LINE_STRIP_ADJACENCY_OES: u32 = 11;
+pub const GL_STENCIL_REF_COMMAND_NV: u32 = 12;
+pub const GL_TRIANGLES_ADJACENCY: u32 = 12;
+pub const GL_TRIANGLES_ADJACENCY_ARB: u32 = 12;
+pub const GL_TRIANGLES_ADJACENCY_EXT: u32 = 12;
+pub const GL_TRIANGLES_ADJACENCY_OES: u32 = 12;
+pub const GL_LINE_WIDTH_COMMAND_NV: u32 = 13;
+pub const GL_TRIANGLE_STRIP_ADJACENCY: u32 = 13;
+pub const GL_TRIANGLE_STRIP_ADJACENCY_ARB: u32 = 13;
+pub const GL_TRIANGLE_STRIP_ADJACENCY_EXT: u32 = 13;
+pub const GL_TRIANGLE_STRIP_ADJACENCY_OES: u32 = 13;
+pub const GL_PATCHES: u32 = 14;
+pub const GL_PATCHES_EXT: u32 = 14;
+pub const GL_PATCHES_OES: u32 = 14;
+pub const GL_POLYGON_OFFSET_COMMAND_NV: u32 = 14;
+pub const GL_ALPHA_REF_COMMAND_NV: u32 = 15;
+pub const GL_ALL_ATTRIB_BITS: u32 = 1048575;
+pub const GL_MAP_FLUSH_EXPLICIT_BIT: u32 = 16;
+pub const GL_MAP_FLUSH_EXPLICIT_BIT_EXT: u32 = 16;
+pub const GL_TRACE_PIXELS_BIT_MESA: u32 = 16;
+pub const GL_VIEWPORT_COMMAND_NV: u32 = 16;
+pub const GL_FONT_UNITS_PER_EM_BIT_NV: u32 = 1048576;
+pub const GL_MAT_AMBIENT_BIT_PGI: u32 = 1048576;
+pub const GL_STENCIL_BUFFER_BIT4_QCOM: u32 = 1048576;
+pub const GL_SCISSOR_COMMAND_NV: u32 = 17;
+pub const GL_FRONT_FACE_COMMAND_NV: u32 = 18;
+pub const GL_MAP_UNSYNCHRONIZED_BIT: u32 = 32;
+pub const GL_MAP_UNSYNCHRONIZED_BIT_EXT: u32 = 32;
+pub const GL_TRACE_ERRORS_BIT_MESA: u32 = 32;
+pub const GL_FONT_ASCENDER_BIT_NV: u32 = 2097152;
+pub const GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI: u32 = 2097152;
+pub const GL_STENCIL_BUFFER_BIT5_QCOM: u32 = 2097152;
+pub const GL_MAP_PERSISTENT_BIT: u32 = 64;
+pub const GL_MAP_PERSISTENT_BIT_EXT: u32 = 64;
+pub const GL_FONT_DESCENDER_BIT_NV: u32 = 4194304;
+pub const GL_MAT_DIFFUSE_BIT_PGI: u32 = 4194304;
+pub const GL_STENCIL_BUFFER_BIT6_QCOM: u32 = 4194304;
+pub const GL_MAP_COHERENT_BIT: u32 = 128;
+pub const GL_MAP_COHERENT_BIT_EXT: u32 = 128;
+pub const GL_FONT_HEIGHT_BIT_NV: u32 = 8388608;
+pub const GL_MAT_EMISSION_BIT_PGI: u32 = 8388608;
+pub const GL_STENCIL_BUFFER_BIT7_QCOM: u32 = 8388608;
+pub const GL_BOLD_BIT_NV: u32 = 1;
+pub const GL_GLYPH_WIDTH_BIT_NV: u32 = 1;
+pub const GL_ACCUM: u32 = 256;
+pub const GL_DYNAMIC_STORAGE_BIT: u32 = 256;
+pub const GL_DYNAMIC_STORAGE_BIT_EXT: u32 = 256;
+pub const GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV: u32 = 16777216;
+pub const GL_MAT_COLOR_INDEXES_BIT_PGI: u32 = 16777216;
+pub const GL_MULTISAMPLE_BUFFER_BIT0_QCOM: u32 = 16777216;
+pub const GL_LOAD: u32 = 257;
+pub const GL_RETURN: u32 = 258;
+pub const GL_MULT: u32 = 259;
+pub const GL_ADD: u32 = 260;
+pub const GL_GLYPH_HEIGHT_BIT_NV: u32 = 2;
+pub const GL_ITALIC_BIT_NV: u32 = 2;
+pub const GL_MOVE_TO_NV: u32 = 2;
+pub const GL_CLIENT_STORAGE_BIT: u32 = 512;
+pub const GL_CLIENT_STORAGE_BIT_EXT: u32 = 512;
+pub const GL_NEVER: u32 = 512;
+pub const GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV: u32 = 33554432;
+pub const GL_MAT_SHININESS_BIT_PGI: u32 = 33554432;
+pub const GL_MULTISAMPLE_BUFFER_BIT1_QCOM: u32 = 33554432;
+pub const GL_LESS: u32 = 513;
+pub const GL_EQUAL: u32 = 514;
+pub const GL_LEQUAL: u32 = 515;
+pub const GL_GREATER: u32 = 516;
+pub const GL_NOTEQUAL: u32 = 517;
+pub const GL_GEQUAL: u32 = 518;
+pub const GL_ALWAYS: u32 = 519;
+pub const GL_RELATIVE_MOVE_TO_NV: u32 = 3;
+pub const GL_SRC_COLOR: u32 = 768;
+pub const GL_ONE_MINUS_SRC_COLOR: u32 = 769;
+pub const GL_SRC_ALPHA: u32 = 770;
+pub const GL_ONE_MINUS_SRC_ALPHA: u32 = 771;
+pub const GL_DST_ALPHA: u32 = 772;
+pub const GL_ONE_MINUS_DST_ALPHA: u32 = 773;
+pub const GL_DST_COLOR: u32 = 774;
+pub const GL_ONE_MINUS_DST_COLOR: u32 = 775;
+pub const GL_SRC_ALPHA_SATURATE: u32 = 776;
+pub const GL_SRC_ALPHA_SATURATE_EXT: u32 = 776;
+pub const GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV: u32 = 4;
+pub const GL_LINE_TO_NV: u32 = 4;
+pub const GL_FRONT_LEFT: u32 = 1024;
+pub const GL_SPARSE_STORAGE_BIT_ARB: u32 = 1024;
+pub const GL_FONT_UNDERLINE_POSITION_BIT_NV: u32 = 67108864;
+pub const GL_MAT_SPECULAR_BIT_PGI: u32 = 67108864;
+pub const GL_MULTISAMPLE_BUFFER_BIT2_QCOM: u32 = 67108864;
+pub const GL_FRONT_RIGHT: u32 = 1025;
+pub const GL_BACK_LEFT: u32 = 1026;
+pub const GL_BACK_RIGHT: u32 = 1027;
+pub const GL_FRONT: u32 = 1028;
+pub const GL_BACK: u32 = 1029;
+pub const GL_LEFT: u32 = 1030;
+pub const GL_RIGHT: u32 = 1031;
+pub const GL_FRONT_AND_BACK: u32 = 1032;
+pub const GL_AUX0: u32 = 1033;
+pub const GL_AUX1: u32 = 1034;
+pub const GL_AUX2: u32 = 1035;
+pub const GL_AUX3: u32 = 1036;
+pub const GL_RELATIVE_LINE_TO_NV: u32 = 5;
+pub const GL_INVALID_ENUM: u32 = 1280;
+pub const GL_INVALID_VALUE: u32 = 1281;
+pub const GL_INVALID_OPERATION: u32 = 1282;
+pub const GL_STACK_OVERFLOW: u32 = 1283;
+pub const GL_STACK_OVERFLOW_KHR: u32 = 1283;
+pub const GL_STACK_UNDERFLOW: u32 = 1284;
+pub const GL_STACK_UNDERFLOW_KHR: u32 = 1284;
+pub const GL_OUT_OF_MEMORY: u32 = 1285;
+pub const GL_INVALID_FRAMEBUFFER_OPERATION: u32 = 1286;
+pub const GL_INVALID_FRAMEBUFFER_OPERATION_EXT: u32 = 1286;
+pub const GL_INVALID_FRAMEBUFFER_OPERATION_OES: u32 = 1286;
+pub const GL_CONTEXT_LOST: u32 = 1287;
+pub const GL_CONTEXT_LOST_KHR: u32 = 1287;
+pub const GL_HORIZONTAL_LINE_TO_NV: u32 = 6;
+pub const GL_2D: u32 = 1536;
+pub const GL_3D: u32 = 1537;
+pub const GL_3D_COLOR: u32 = 1538;
+pub const GL_3D_COLOR_TEXTURE: u32 = 1539;
+pub const GL_4D_COLOR_TEXTURE: u32 = 1540;
+pub const GL_RELATIVE_HORIZONTAL_LINE_TO_NV: u32 = 7;
+pub const GL_PASS_THROUGH_TOKEN: u32 = 1792;
+pub const GL_POINT_TOKEN: u32 = 1793;
+pub const GL_LINE_TOKEN: u32 = 1794;
+pub const GL_POLYGON_TOKEN: u32 = 1795;
+pub const GL_BITMAP_TOKEN: u32 = 1796;
+pub const GL_DRAW_PIXEL_TOKEN: u32 = 1797;
+pub const GL_COPY_PIXEL_TOKEN: u32 = 1798;
+pub const GL_LINE_RESET_TOKEN: u32 = 1799;
+pub const GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV: u32 = 8;
+pub const GL_VERTICAL_LINE_TO_NV: u32 = 8;
+pub const GL_EXP: u32 = 2048;
+pub const GL_FONT_UNDERLINE_THICKNESS_BIT_NV: u32 = 134217728;
+pub const GL_MULTISAMPLE_BUFFER_BIT3_QCOM: u32 = 134217728;
+pub const GL_NORMAL_BIT_PGI: u32 = 134217728;
+pub const GL_EXP2: u32 = 2049;
+pub const GL_RELATIVE_VERTICAL_LINE_TO_NV: u32 = 9;
+pub const GL_CW: u32 = 2304;
+pub const GL_CCW: u32 = 2305;
+pub const GL_QUADRATIC_CURVE_TO_NV: u32 = 10;
+pub const GL_COEFF: u32 = 2560;
+pub const GL_ORDER: u32 = 2561;
+pub const GL_DOMAIN: u32 = 2562;
+pub const GL_RELATIVE_QUADRATIC_CURVE_TO_NV: u32 = 11;
+pub const GL_CURRENT_COLOR: u32 = 2816;
+pub const GL_CURRENT_INDEX: u32 = 2817;
+pub const GL_CURRENT_NORMAL: u32 = 2818;
+pub const GL_CURRENT_TEXTURE_COORDS: u32 = 2819;
+pub const GL_CURRENT_RASTER_COLOR: u32 = 2820;
+pub const GL_CURRENT_RASTER_INDEX: u32 = 2821;
+pub const GL_CURRENT_RASTER_TEXTURE_COORDS: u32 = 2822;
+pub const GL_CURRENT_RASTER_POSITION: u32 = 2823;
+pub const GL_CURRENT_RASTER_POSITION_VALID: u32 = 2824;
+pub const GL_CURRENT_RASTER_DISTANCE: u32 = 2825;
+pub const GL_POINT_SMOOTH: u32 = 2832;
+pub const GL_POINT_SIZE: u32 = 2833;
+pub const GL_POINT_SIZE_RANGE: u32 = 2834;
+pub const GL_SMOOTH_POINT_SIZE_RANGE: u32 = 2834;
+pub const GL_POINT_SIZE_GRANULARITY: u32 = 2835;
+pub const GL_SMOOTH_POINT_SIZE_GRANULARITY: u32 = 2835;
+pub const GL_LINE_SMOOTH: u32 = 2848;
+pub const GL_LINE_WIDTH: u32 = 2849;
+pub const GL_LINE_WIDTH_RANGE: u32 = 2850;
+pub const GL_SMOOTH_LINE_WIDTH_RANGE: u32 = 2850;
+pub const GL_LINE_WIDTH_GRANULARITY: u32 = 2851;
+pub const GL_SMOOTH_LINE_WIDTH_GRANULARITY: u32 = 2851;
+pub const GL_LINE_STIPPLE: u32 = 2852;
+pub const GL_LINE_STIPPLE_PATTERN: u32 = 2853;
+pub const GL_LINE_STIPPLE_REPEAT: u32 = 2854;
+pub const GL_LIST_MODE: u32 = 2864;
+pub const GL_MAX_LIST_NESTING: u32 = 2865;
+pub const GL_LIST_BASE: u32 = 2866;
+pub const GL_LIST_INDEX: u32 = 2867;
+pub const GL_POLYGON_MODE: u32 = 2880;
+pub const GL_POLYGON_MODE_NV: u32 = 2880;
+pub const GL_POLYGON_SMOOTH: u32 = 2881;
+pub const GL_POLYGON_STIPPLE: u32 = 2882;
+pub const GL_EDGE_FLAG: u32 = 2883;
+pub const GL_CULL_FACE: u32 = 2884;
+pub const GL_CULL_FACE_MODE: u32 = 2885;
+pub const GL_FRONT_FACE: u32 = 2886;
+pub const GL_LIGHTING: u32 = 2896;
+pub const GL_LIGHT_MODEL_LOCAL_VIEWER: u32 = 2897;
+pub const GL_LIGHT_MODEL_TWO_SIDE: u32 = 2898;
+pub const GL_LIGHT_MODEL_AMBIENT: u32 = 2899;
+pub const GL_SHADE_MODEL: u32 = 2900;
+pub const GL_COLOR_MATERIAL_FACE: u32 = 2901;
+pub const GL_COLOR_MATERIAL_PARAMETER: u32 = 2902;
+pub const GL_COLOR_MATERIAL: u32 = 2903;
+pub const GL_FOG: u32 = 2912;
+pub const GL_FOG_INDEX: u32 = 2913;
+pub const GL_FOG_DENSITY: u32 = 2914;
+pub const GL_FOG_START: u32 = 2915;
+pub const GL_FOG_END: u32 = 2916;
+pub const GL_FOG_MODE: u32 = 2917;
+pub const GL_FOG_COLOR: u32 = 2918;
+pub const GL_DEPTH_RANGE: u32 = 2928;
+pub const GL_DEPTH_TEST: u32 = 2929;
+pub const GL_DEPTH_WRITEMASK: u32 = 2930;
+pub const GL_DEPTH_CLEAR_VALUE: u32 = 2931;
+pub const GL_DEPTH_FUNC: u32 = 2932;
+pub const GL_ACCUM_CLEAR_VALUE: u32 = 2944;
+pub const GL_STENCIL_TEST: u32 = 2960;
+pub const GL_STENCIL_CLEAR_VALUE: u32 = 2961;
+pub const GL_STENCIL_FUNC: u32 = 2962;
+pub const GL_STENCIL_VALUE_MASK: u32 = 2963;
+pub const GL_STENCIL_FAIL: u32 = 2964;
+pub const GL_STENCIL_PASS_DEPTH_FAIL: u32 = 2965;
+pub const GL_STENCIL_PASS_DEPTH_PASS: u32 = 2966;
+pub const GL_STENCIL_REF: u32 = 2967;
+pub const GL_STENCIL_WRITEMASK: u32 = 2968;
+pub const GL_MATRIX_MODE: u32 = 2976;
+pub const GL_NORMALIZE: u32 = 2977;
+pub const GL_VIEWPORT: u32 = 2978;
+pub const GL_MODELVIEW0_STACK_DEPTH_EXT: u32 = 2979;
+pub const GL_MODELVIEW_STACK_DEPTH: u32 = 2979;
+pub const GL_PATH_MODELVIEW_STACK_DEPTH_NV: u32 = 2979;
+pub const GL_PATH_PROJECTION_STACK_DEPTH_NV: u32 = 2980;
+pub const GL_PROJECTION_STACK_DEPTH: u32 = 2980;
+pub const GL_TEXTURE_STACK_DEPTH: u32 = 2981;
+pub const GL_MODELVIEW0_MATRIX_EXT: u32 = 2982;
+pub const GL_MODELVIEW_MATRIX: u32 = 2982;
+pub const GL_PATH_MODELVIEW_MATRIX_NV: u32 = 2982;
+pub const GL_PATH_PROJECTION_MATRIX_NV: u32 = 2983;
+pub const GL_PROJECTION_MATRIX: u32 = 2983;
+pub const GL_TEXTURE_MATRIX: u32 = 2984;
+pub const GL_ATTRIB_STACK_DEPTH: u32 = 2992;
+pub const GL_CLIENT_ATTRIB_STACK_DEPTH: u32 = 2993;
+pub const GL_ALPHA_TEST: u32 = 3008;
+pub const GL_ALPHA_TEST_QCOM: u32 = 3008;
+pub const GL_ALPHA_TEST_FUNC: u32 = 3009;
+pub const GL_ALPHA_TEST_FUNC_QCOM: u32 = 3009;
+pub const GL_ALPHA_TEST_REF: u32 = 3010;
+pub const GL_ALPHA_TEST_REF_QCOM: u32 = 3010;
+pub const GL_DITHER: u32 = 3024;
+pub const GL_BLEND_DST: u32 = 3040;
+pub const GL_BLEND_SRC: u32 = 3041;
+pub const GL_BLEND: u32 = 3042;
+pub const GL_LOGIC_OP_MODE: u32 = 3056;
+pub const GL_INDEX_LOGIC_OP: u32 = 3057;
+pub const GL_LOGIC_OP: u32 = 3057;
+pub const GL_COLOR_LOGIC_OP: u32 = 3058;
+pub const GL_CUBIC_CURVE_TO_NV: u32 = 12;
+pub const GL_AUX_BUFFERS: u32 = 3072;
+pub const GL_DRAW_BUFFER: u32 = 3073;
+pub const GL_DRAW_BUFFER_EXT: u32 = 3073;
+pub const GL_READ_BUFFER: u32 = 3074;
+pub const GL_READ_BUFFER_EXT: u32 = 3074;
+pub const GL_READ_BUFFER_NV: u32 = 3074;
+pub const GL_SCISSOR_BOX: u32 = 3088;
+pub const GL_SCISSOR_TEST: u32 = 3089;
+pub const GL_INDEX_CLEAR_VALUE: u32 = 3104;
+pub const GL_INDEX_WRITEMASK: u32 = 3105;
+pub const GL_COLOR_CLEAR_VALUE: u32 = 3106;
+pub const GL_COLOR_WRITEMASK: u32 = 3107;
+pub const GL_INDEX_MODE: u32 = 3120;
+pub const GL_RGBA_MODE: u32 = 3121;
+pub const GL_DOUBLEBUFFER: u32 = 3122;
+pub const GL_STEREO: u32 = 3123;
+pub const GL_RENDER_MODE: u32 = 3136;
+pub const GL_PERSPECTIVE_CORRECTION_HINT: u32 = 3152;
+pub const GL_POINT_SMOOTH_HINT: u32 = 3153;
+pub const GL_LINE_SMOOTH_HINT: u32 = 3154;
+pub const GL_POLYGON_SMOOTH_HINT: u32 = 3155;
+pub const GL_FOG_HINT: u32 = 3156;
+pub const GL_TEXTURE_GEN_S: u32 = 3168;
+pub const GL_TEXTURE_GEN_T: u32 = 3169;
+pub const GL_TEXTURE_GEN_R: u32 = 3170;
+pub const GL_TEXTURE_GEN_Q: u32 = 3171;
+pub const GL_PIXEL_MAP_I_TO_I: u32 = 3184;
+pub const GL_PIXEL_MAP_S_TO_S: u32 = 3185;
+pub const GL_PIXEL_MAP_I_TO_R: u32 = 3186;
+pub const GL_PIXEL_MAP_I_TO_G: u32 = 3187;
+pub const GL_PIXEL_MAP_I_TO_B: u32 = 3188;
+pub const GL_PIXEL_MAP_I_TO_A: u32 = 3189;
+pub const GL_PIXEL_MAP_R_TO_R: u32 = 3190;
+pub const GL_PIXEL_MAP_G_TO_G: u32 = 3191;
+pub const GL_PIXEL_MAP_B_TO_B: u32 = 3192;
+pub const GL_PIXEL_MAP_A_TO_A: u32 = 3193;
+pub const GL_PIXEL_MAP_I_TO_I_SIZE: u32 = 3248;
+pub const GL_PIXEL_MAP_S_TO_S_SIZE: u32 = 3249;
+pub const GL_PIXEL_MAP_I_TO_R_SIZE: u32 = 3250;
+pub const GL_PIXEL_MAP_I_TO_G_SIZE: u32 = 3251;
+pub const GL_PIXEL_MAP_I_TO_B_SIZE: u32 = 3252;
+pub const GL_PIXEL_MAP_I_TO_A_SIZE: u32 = 3253;
+pub const GL_PIXEL_MAP_R_TO_R_SIZE: u32 = 3254;
+pub const GL_PIXEL_MAP_G_TO_G_SIZE: u32 = 3255;
+pub const GL_PIXEL_MAP_B_TO_B_SIZE: u32 = 3256;
+pub const GL_PIXEL_MAP_A_TO_A_SIZE: u32 = 3257;
+pub const GL_UNPACK_SWAP_BYTES: u32 = 3312;
+pub const GL_UNPACK_LSB_FIRST: u32 = 3313;
+pub const GL_UNPACK_ROW_LENGTH: u32 = 3314;
+pub const GL_UNPACK_ROW_LENGTH_EXT: u32 = 3314;
+pub const GL_UNPACK_SKIP_ROWS: u32 = 3315;
+pub const GL_UNPACK_SKIP_ROWS_EXT: u32 = 3315;
+pub const GL_UNPACK_SKIP_PIXELS: u32 = 3316;
+pub const GL_UNPACK_SKIP_PIXELS_EXT: u32 = 3316;
+pub const GL_UNPACK_ALIGNMENT: u32 = 3317;
+pub const GL_RELATIVE_CUBIC_CURVE_TO_NV: u32 = 13;
+pub const GL_PACK_SWAP_BYTES: u32 = 3328;
+pub const GL_PACK_LSB_FIRST: u32 = 3329;
+pub const GL_PACK_ROW_LENGTH: u32 = 3330;
+pub const GL_PACK_SKIP_ROWS: u32 = 3331;
+pub const GL_PACK_SKIP_PIXELS: u32 = 3332;
+pub const GL_PACK_ALIGNMENT: u32 = 3333;
+pub const GL_MAP_COLOR: u32 = 3344;
+pub const GL_MAP_STENCIL: u32 = 3345;
+pub const GL_INDEX_SHIFT: u32 = 3346;
+pub const GL_INDEX_OFFSET: u32 = 3347;
+pub const GL_RED_SCALE: u32 = 3348;
+pub const GL_RED_BIAS: u32 = 3349;
+pub const GL_ZOOM_X: u32 = 3350;
+pub const GL_ZOOM_Y: u32 = 3351;
+pub const GL_GREEN_SCALE: u32 = 3352;
+pub const GL_GREEN_BIAS: u32 = 3353;
+pub const GL_BLUE_SCALE: u32 = 3354;
+pub const GL_BLUE_BIAS: u32 = 3355;
+pub const GL_ALPHA_SCALE: u32 = 3356;
+pub const GL_ALPHA_BIAS: u32 = 3357;
+pub const GL_DEPTH_SCALE: u32 = 3358;
+pub const GL_DEPTH_BIAS: u32 = 3359;
+pub const GL_MAX_EVAL_ORDER: u32 = 3376;
+pub const GL_MAX_LIGHTS: u32 = 3377;
+pub const GL_MAX_CLIP_DISTANCES: u32 = 3378;
+pub const GL_MAX_CLIP_DISTANCES_APPLE: u32 = 3378;
+pub const GL_MAX_CLIP_DISTANCES_EXT: u32 = 3378;
+pub const GL_MAX_CLIP_PLANES: u32 = 3378;
+pub const GL_MAX_CLIP_PLANES_IMG: u32 = 3378;
+pub const GL_MAX_TEXTURE_SIZE: u32 = 3379;
+pub const GL_MAX_PIXEL_MAP_TABLE: u32 = 3380;
+pub const GL_MAX_ATTRIB_STACK_DEPTH: u32 = 3381;
+pub const GL_MAX_MODELVIEW_STACK_DEPTH: u32 = 3382;
+pub const GL_PATH_MAX_MODELVIEW_STACK_DEPTH_NV: u32 = 3382;
+pub const GL_MAX_NAME_STACK_DEPTH: u32 = 3383;
+pub const GL_MAX_PROJECTION_STACK_DEPTH: u32 = 3384;
+pub const GL_PATH_MAX_PROJECTION_STACK_DEPTH_NV: u32 = 3384;
+pub const GL_MAX_TEXTURE_STACK_DEPTH: u32 = 3385;
+pub const GL_MAX_VIEWPORT_DIMS: u32 = 3386;
+pub const GL_MAX_CLIENT_ATTRIB_STACK_DEPTH: u32 = 3387;
+pub const GL_SUBPIXEL_BITS: u32 = 3408;
+pub const GL_INDEX_BITS: u32 = 3409;
+pub const GL_RED_BITS: u32 = 3410;
+pub const GL_GREEN_BITS: u32 = 3411;
+pub const GL_BLUE_BITS: u32 = 3412;
+pub const GL_ALPHA_BITS: u32 = 3413;
+pub const GL_DEPTH_BITS: u32 = 3414;
+pub const GL_STENCIL_BITS: u32 = 3415;
+pub const GL_ACCUM_RED_BITS: u32 = 3416;
+pub const GL_ACCUM_GREEN_BITS: u32 = 3417;
+pub const GL_ACCUM_BLUE_BITS: u32 = 3418;
+pub const GL_ACCUM_ALPHA_BITS: u32 = 3419;
+pub const GL_NAME_STACK_DEPTH: u32 = 3440;
+pub const GL_AUTO_NORMAL: u32 = 3456;
+pub const GL_MAP1_COLOR_4: u32 = 3472;
+pub const GL_MAP1_INDEX: u32 = 3473;
+pub const GL_MAP1_NORMAL: u32 = 3474;
+pub const GL_MAP1_TEXTURE_COORD_1: u32 = 3475;
+pub const GL_MAP1_TEXTURE_COORD_2: u32 = 3476;
+pub const GL_MAP1_TEXTURE_COORD_3: u32 = 3477;
+pub const GL_MAP1_TEXTURE_COORD_4: u32 = 3478;
+pub const GL_MAP1_VERTEX_3: u32 = 3479;
+pub const GL_MAP1_VERTEX_4: u32 = 3480;
+pub const GL_MAP2_COLOR_4: u32 = 3504;
+pub const GL_MAP2_INDEX: u32 = 3505;
+pub const GL_MAP2_NORMAL: u32 = 3506;
+pub const GL_MAP2_TEXTURE_COORD_1: u32 = 3507;
+pub const GL_MAP2_TEXTURE_COORD_2: u32 = 3508;
+pub const GL_MAP2_TEXTURE_COORD_3: u32 = 3509;
+pub const GL_MAP2_TEXTURE_COORD_4: u32 = 3510;
+pub const GL_MAP2_VERTEX_3: u32 = 3511;
+pub const GL_MAP2_VERTEX_4: u32 = 3512;
+pub const GL_MAP1_GRID_DOMAIN: u32 = 3536;
+pub const GL_MAP1_GRID_SEGMENTS: u32 = 3537;
+pub const GL_MAP2_GRID_DOMAIN: u32 = 3538;
+pub const GL_MAP2_GRID_SEGMENTS: u32 = 3539;
+pub const GL_TEXTURE_1D: u32 = 3552;
+pub const GL_TEXTURE_2D: u32 = 3553;
+pub const GL_FEEDBACK_BUFFER_POINTER: u32 = 3568;
+pub const GL_FEEDBACK_BUFFER_SIZE: u32 = 3569;
+pub const GL_FEEDBACK_BUFFER_TYPE: u32 = 3570;
+pub const GL_SELECTION_BUFFER_POINTER: u32 = 3571;
+pub const GL_SELECTION_BUFFER_SIZE: u32 = 3572;
+pub const GL_SMOOTH_QUADRATIC_CURVE_TO_NV: u32 = 14;
+pub const GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV: u32 = 15;
+pub const GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV: u32 = 16;
+pub const GL_SMOOTH_CUBIC_CURVE_TO_NV: u32 = 16;
+pub const GL_GLYPH_HAS_KERNING_BIT_NV: u32 = 256;
+pub const GL_TEXTURE_WIDTH: u32 = 4096;
+pub const GL_FONT_HAS_KERNING_BIT_NV: u32 = 268435456;
+pub const GL_MULTISAMPLE_BUFFER_BIT4_QCOM: u32 = 268435456;
+pub const GL_TEXCOORD1_BIT_PGI: u32 = 268435456;
+pub const GL_TEXTURE_HEIGHT: u32 = 4097;
+pub const GL_TEXTURE_COMPONENTS: u32 = 4099;
+pub const GL_TEXTURE_INTERNAL_FORMAT: u32 = 4099;
+pub const GL_TEXTURE_BORDER_COLOR: u32 = 4100;
+pub const GL_TEXTURE_BORDER_COLOR_EXT: u32 = 4100;
+pub const GL_TEXTURE_BORDER_COLOR_NV: u32 = 4100;
+pub const GL_TEXTURE_BORDER_COLOR_OES: u32 = 4100;
+pub const GL_TEXTURE_BORDER: u32 = 4101;
+pub const GL_TEXTURE_TARGET: u32 = 4102;
+pub const GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV: u32 = 17;
+pub const GL_DONT_CARE: u32 = 4352;
+pub const GL_FASTEST: u32 = 4353;
+pub const GL_NICEST: u32 = 4354;
+pub const GL_SMALL_CCW_ARC_TO_NV: u32 = 18;
+pub const GL_AMBIENT: u32 = 4608;
+pub const GL_DIFFUSE: u32 = 4609;
+pub const GL_SPECULAR: u32 = 4610;
+pub const GL_POSITION: u32 = 4611;
+pub const GL_SPOT_DIRECTION: u32 = 4612;
+pub const GL_SPOT_EXPONENT: u32 = 4613;
+pub const GL_SPOT_CUTOFF: u32 = 4614;
+pub const GL_CONSTANT_ATTENUATION: u32 = 4615;
+pub const GL_LINEAR_ATTENUATION: u32 = 4616;
+pub const GL_QUADRATIC_ATTENUATION: u32 = 4617;
+pub const GL_RELATIVE_SMALL_CCW_ARC_TO_NV: u32 = 19;
+pub const GL_COMPILE: u32 = 4864;
+pub const GL_COMPILE_AND_EXECUTE: u32 = 4865;
+pub const GL_SMALL_CW_ARC_TO_NV: u32 = 20;
+pub const GL_BYTE: u32 = 5120;
+pub const GL_UNSIGNED_BYTE: u32 = 5121;
+pub const GL_SHORT: u32 = 5122;
+pub const GL_UNSIGNED_SHORT: u32 = 5123;
+pub const GL_INT: u32 = 5124;
+pub const GL_UNSIGNED_INT: u32 = 5125;
+pub const GL_FLOAT: u32 = 5126;
+pub const GL_2_BYTES: u32 = 5127;
+pub const GL_2_BYTES_NV: u32 = 5127;
+pub const GL_3_BYTES: u32 = 5128;
+pub const GL_3_BYTES_NV: u32 = 5128;
+pub const GL_4_BYTES: u32 = 5129;
+pub const GL_4_BYTES_NV: u32 = 5129;
+pub const GL_DOUBLE: u32 = 5130;
+pub const GL_DOUBLE_EXT: u32 = 5130;
+pub const GL_HALF_APPLE: u32 = 5131;
+pub const GL_HALF_FLOAT: u32 = 5131;
+pub const GL_HALF_FLOAT_ARB: u32 = 5131;
+pub const GL_HALF_FLOAT_NV: u32 = 5131;
+pub const GL_FIXED: u32 = 5132;
+pub const GL_FIXED_OES: u32 = 5132;
+pub const GL_INT64_ARB: u32 = 5134;
+pub const GL_INT64_NV: u32 = 5134;
+pub const GL_UNSIGNED_INT64_ARB: u32 = 5135;
+pub const GL_UNSIGNED_INT64_NV: u32 = 5135;
+pub const GL_RELATIVE_SMALL_CW_ARC_TO_NV: u32 = 21;
+pub const GL_CLEAR: u32 = 5376;
+pub const GL_AND: u32 = 5377;
+pub const GL_AND_REVERSE: u32 = 5378;
+pub const GL_COPY: u32 = 5379;
+pub const GL_AND_INVERTED: u32 = 5380;
+pub const GL_NOOP: u32 = 5381;
+pub const GL_XOR: u32 = 5382;
+pub const GL_XOR_NV: u32 = 5382;
+pub const GL_OR: u32 = 5383;
+pub const GL_NOR: u32 = 5384;
+pub const GL_EQUIV: u32 = 5385;
+pub const GL_INVERT: u32 = 5386;
+pub const GL_OR_REVERSE: u32 = 5387;
+pub const GL_COPY_INVERTED: u32 = 5388;
+pub const GL_OR_INVERTED: u32 = 5389;
+pub const GL_NAND: u32 = 5390;
+pub const GL_SET: u32 = 5391;
+pub const GL_LARGE_CCW_ARC_TO_NV: u32 = 22;
+pub const GL_EMISSION: u32 = 5632;
+pub const GL_SHININESS: u32 = 5633;
+pub const GL_AMBIENT_AND_DIFFUSE: u32 = 5634;
+pub const GL_COLOR_INDEXES: u32 = 5635;
+pub const GL_RELATIVE_LARGE_CCW_ARC_TO_NV: u32 = 23;
+pub const GL_MODELVIEW: u32 = 5888;
+pub const GL_MODELVIEW0_ARB: u32 = 5888;
+pub const GL_MODELVIEW0_EXT: u32 = 5888;
+pub const GL_PATH_MODELVIEW_NV: u32 = 5888;
+pub const GL_PATH_PROJECTION_NV: u32 = 5889;
+pub const GL_PROJECTION: u32 = 5889;
+pub const GL_TEXTURE: u32 = 5890;
+pub const GL_LARGE_CW_ARC_TO_NV: u32 = 24;
+pub const GL_COLOR: u32 = 6144;
+pub const GL_COLOR_EXT: u32 = 6144;
+pub const GL_DEPTH: u32 = 6145;
+pub const GL_DEPTH_EXT: u32 = 6145;
+pub const GL_STENCIL: u32 = 6146;
+pub const GL_STENCIL_EXT: u32 = 6146;
+pub const GL_RELATIVE_LARGE_CW_ARC_TO_NV: u32 = 25;
+pub const GL_COLOR_INDEX: u32 = 6400;
+pub const GL_STENCIL_INDEX: u32 = 6401;
+pub const GL_STENCIL_INDEX_OES: u32 = 6401;
+pub const GL_DEPTH_COMPONENT: u32 = 6402;
+pub const GL_RED: u32 = 6403;
+pub const GL_RED_EXT: u32 = 6403;
+pub const GL_RED_NV: u32 = 6403;
+pub const GL_GREEN: u32 = 6404;
+pub const GL_GREEN_NV: u32 = 6404;
+pub const GL_BLUE: u32 = 6405;
+pub const GL_BLUE_NV: u32 = 6405;
+pub const GL_ALPHA: u32 = 6406;
+pub const GL_RGB: u32 = 6407;
+pub const GL_RGBA: u32 = 6408;
+pub const GL_LUMINANCE: u32 = 6409;
+pub const GL_LUMINANCE_ALPHA: u32 = 6410;
+pub const GL_RASTER_POSITION_UNCLIPPED_IBM: u32 = 103010;
+pub const GL_CONIC_CURVE_TO_NV: u32 = 26;
+pub const GL_BITMAP: u32 = 6656;
+pub const GL_PREFER_DOUBLEBUFFER_HINT_PGI: u32 = 107000;
+pub const GL_CONSERVE_MEMORY_HINT_PGI: u32 = 107005;
+pub const GL_RECLAIM_MEMORY_HINT_PGI: u32 = 107006;
+pub const GL_NATIVE_GRAPHICS_HANDLE_PGI: u32 = 107010;
+pub const GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI: u32 = 107011;
+pub const GL_NATIVE_GRAPHICS_END_HINT_PGI: u32 = 107012;
+pub const GL_ALWAYS_FAST_HINT_PGI: u32 = 107020;
+pub const GL_ALWAYS_SOFT_HINT_PGI: u32 = 107021;
+pub const GL_ALLOW_DRAW_OBJ_HINT_PGI: u32 = 107022;
+pub const GL_ALLOW_DRAW_WIN_HINT_PGI: u32 = 107023;
+pub const GL_ALLOW_DRAW_FRG_HINT_PGI: u32 = 107024;
+pub const GL_ALLOW_DRAW_MEM_HINT_PGI: u32 = 107025;
+pub const GL_STRICT_DEPTHFUNC_HINT_PGI: u32 = 107030;
+pub const GL_STRICT_LIGHTING_HINT_PGI: u32 = 107031;
+pub const GL_STRICT_SCISSOR_HINT_PGI: u32 = 107032;
+pub const GL_FULL_STIPPLE_HINT_PGI: u32 = 107033;
+pub const GL_CLIP_NEAR_HINT_PGI: u32 = 107040;
+pub const GL_CLIP_FAR_HINT_PGI: u32 = 107041;
+pub const GL_WIDE_LINE_HINT_PGI: u32 = 107042;
+pub const GL_BACK_NORMALS_HINT_PGI: u32 = 107043;
+pub const GL_VERTEX_DATA_HINT_PGI: u32 = 107050;
+pub const GL_VERTEX_CONSISTENT_HINT_PGI: u32 = 107051;
+pub const GL_MATERIAL_SIDE_HINT_PGI: u32 = 107052;
+pub const GL_MAX_VERTEX_HINT_PGI: u32 = 107053;
+pub const GL_RELATIVE_CONIC_CURVE_TO_NV: u32 = 27;
+pub const GL_POINT: u32 = 6912;
+pub const GL_POINT_NV: u32 = 6912;
+pub const GL_LINE: u32 = 6913;
+pub const GL_LINE_NV: u32 = 6913;
+pub const GL_FILL: u32 = 6914;
+pub const GL_FILL_NV: u32 = 6914;
+pub const GL_RENDER: u32 = 7168;
+pub const GL_FEEDBACK: u32 = 7169;
+pub const GL_SELECT: u32 = 7170;
+pub const GL_FLAT: u32 = 7424;
+pub const GL_SMOOTH: u32 = 7425;
+pub const GL_KEEP: u32 = 7680;
+pub const GL_REPLACE: u32 = 7681;
+pub const GL_INCR: u32 = 7682;
+pub const GL_DECR: u32 = 7683;
+pub const GL_VENDOR: u32 = 7936;
+pub const GL_RENDERER: u32 = 7937;
+pub const GL_VERSION: u32 = 7938;
+pub const GL_EXTENSIONS: u32 = 7939;
+pub const GL_GLYPH_VERTICAL_BEARING_X_BIT_NV: u32 = 32;
+pub const GL_S: u32 = 8192;
+pub const GL_FONT_NUM_GLYPH_INDICES_BIT_NV: u32 = 536870912;
+pub const GL_MULTISAMPLE_BIT: u32 = 536870912;
+pub const GL_MULTISAMPLE_BIT_3DFX: u32 = 536870912;
+pub const GL_MULTISAMPLE_BIT_ARB: u32 = 536870912;
+pub const GL_MULTISAMPLE_BIT_EXT: u32 = 536870912;
+pub const GL_MULTISAMPLE_BUFFER_BIT5_QCOM: u32 = 536870912;
+pub const GL_TEXCOORD2_BIT_PGI: u32 = 536870912;
+pub const GL_T: u32 = 8193;
+pub const GL_R: u32 = 8194;
+pub const GL_Q: u32 = 8195;
+pub const GL_MODULATE: u32 = 8448;
+pub const GL_DECAL: u32 = 8449;
+pub const GL_TEXTURE_ENV_MODE: u32 = 8704;
+pub const GL_TEXTURE_ENV_COLOR: u32 = 8705;
+pub const GL_TEXTURE_ENV: u32 = 8960;
+pub const GL_EYE_LINEAR: u32 = 9216;
+pub const GL_EYE_LINEAR_NV: u32 = 9216;
+pub const GL_OBJECT_LINEAR: u32 = 9217;
+pub const GL_OBJECT_LINEAR_NV: u32 = 9217;
+pub const GL_SPHERE_MAP: u32 = 9218;
+pub const GL_TEXTURE_GEN_MODE: u32 = 9472;
+pub const GL_TEXTURE_GEN_MODE_OES: u32 = 9472;
+pub const GL_OBJECT_PLANE: u32 = 9473;
+pub const GL_EYE_PLANE: u32 = 9474;
+pub const GL_NEAREST: u32 = 9728;
+pub const GL_LINEAR: u32 = 9729;
+pub const GL_NEAREST_MIPMAP_NEAREST: u32 = 9984;
+pub const GL_LINEAR_MIPMAP_NEAREST: u32 = 9985;
+pub const GL_NEAREST_MIPMAP_LINEAR: u32 = 9986;
+pub const GL_LINEAR_MIPMAP_LINEAR: u32 = 9987;
+pub const GL_TEXTURE_MAG_FILTER: u32 = 10240;
+pub const GL_TEXTURE_MIN_FILTER: u32 = 10241;
+pub const GL_TEXTURE_WRAP_S: u32 = 10242;
+pub const GL_TEXTURE_WRAP_T: u32 = 10243;
+pub const GL_CLAMP: u32 = 10496;
+pub const GL_REPEAT: u32 = 10497;
+pub const GL_POLYGON_OFFSET_UNITS: u32 = 10752;
+pub const GL_POLYGON_OFFSET_POINT: u32 = 10753;
+pub const GL_POLYGON_OFFSET_POINT_NV: u32 = 10753;
+pub const GL_POLYGON_OFFSET_LINE: u32 = 10754;
+pub const GL_POLYGON_OFFSET_LINE_NV: u32 = 10754;
+pub const GL_R3_G3_B2: u32 = 10768;
+pub const GL_V2F: u32 = 10784;
+pub const GL_V3F: u32 = 10785;
+pub const GL_C4UB_V2F: u32 = 10786;
+pub const GL_C4UB_V3F: u32 = 10787;
+pub const GL_C3F_V3F: u32 = 10788;
+pub const GL_N3F_V3F: u32 = 10789;
+pub const GL_C4F_N3F_V3F: u32 = 10790;
+pub const GL_T2F_V3F: u32 = 10791;
+pub const GL_T4F_V4F: u32 = 10792;
+pub const GL_T2F_C4UB_V3F: u32 = 10793;
+pub const GL_T2F_C3F_V3F: u32 = 10794;
+pub const GL_T2F_N3F_V3F: u32 = 10795;
+pub const GL_T2F_C4F_N3F_V3F: u32 = 10796;
+pub const GL_T4F_C4F_N3F_V4F: u32 = 10797;
+pub const GL_CLIP_DISTANCE0: u32 = 12288;
+pub const GL_CLIP_DISTANCE0_APPLE: u32 = 12288;
+pub const GL_CLIP_DISTANCE0_EXT: u32 = 12288;
+pub const GL_CLIP_PLANE0: u32 = 12288;
+pub const GL_CLIP_PLANE0_IMG: u32 = 12288;
+pub const GL_CLIP_DISTANCE1: u32 = 12289;
+pub const GL_CLIP_DISTANCE1_APPLE: u32 = 12289;
+pub const GL_CLIP_DISTANCE1_EXT: u32 = 12289;
+pub const GL_CLIP_PLANE1: u32 = 12289;
+pub const GL_CLIP_PLANE1_IMG: u32 = 12289;
+pub const GL_CLIP_DISTANCE2: u32 = 12290;
+pub const GL_CLIP_DISTANCE2_APPLE: u32 = 12290;
+pub const GL_CLIP_DISTANCE2_EXT: u32 = 12290;
+pub const GL_CLIP_PLANE2: u32 = 12290;
+pub const GL_CLIP_PLANE2_IMG: u32 = 12290;
+pub const GL_CLIP_DISTANCE3: u32 = 12291;
+pub const GL_CLIP_DISTANCE3_APPLE: u32 = 12291;
+pub const GL_CLIP_DISTANCE3_EXT: u32 = 12291;
+pub const GL_CLIP_PLANE3: u32 = 12291;
+pub const GL_CLIP_PLANE3_IMG: u32 = 12291;
+pub const GL_CLIP_DISTANCE4: u32 = 12292;
+pub const GL_CLIP_DISTANCE4_APPLE: u32 = 12292;
+pub const GL_CLIP_DISTANCE4_EXT: u32 = 12292;
+pub const GL_CLIP_PLANE4: u32 = 12292;
+pub const GL_CLIP_PLANE4_IMG: u32 = 12292;
+pub const GL_CLIP_DISTANCE5: u32 = 12293;
+pub const GL_CLIP_DISTANCE5_APPLE: u32 = 12293;
+pub const GL_CLIP_DISTANCE5_EXT: u32 = 12293;
+pub const GL_CLIP_PLANE5: u32 = 12293;
+pub const GL_CLIP_PLANE5_IMG: u32 = 12293;
+pub const GL_CLIP_DISTANCE6: u32 = 12294;
+pub const GL_CLIP_DISTANCE6_APPLE: u32 = 12294;
+pub const GL_CLIP_DISTANCE6_EXT: u32 = 12294;
+pub const GL_CLIP_DISTANCE7: u32 = 12295;
+pub const GL_CLIP_DISTANCE7_APPLE: u32 = 12295;
+pub const GL_CLIP_DISTANCE7_EXT: u32 = 12295;
+pub const GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV: u32 = 64;
+pub const GL_LIGHT0: u32 = 16384;
+pub const GL_MULTISAMPLE_BUFFER_BIT6_QCOM: u32 = 1073741824;
+pub const GL_TEXCOORD3_BIT_PGI: u32 = 1073741824;
+pub const GL_LIGHT1: u32 = 16385;
+pub const GL_LIGHT2: u32 = 16386;
+pub const GL_LIGHT3: u32 = 16387;
+pub const GL_LIGHT4: u32 = 16388;
+pub const GL_LIGHT5: u32 = 16389;
+pub const GL_LIGHT6: u32 = 16390;
+pub const GL_LIGHT7: u32 = 16391;
+pub const GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV: u32 = 128;
+pub const GL_ABGR_EXT: u32 = 32768;
+pub const GL_MULTISAMPLE_BUFFER_BIT7_QCOM: u32 = 2147483648;
+pub const GL_TEXCOORD4_BIT_PGI: u32 = 2147483648;
+pub const GL_CONSTANT_COLOR: u32 = 32769;
+pub const GL_CONSTANT_COLOR_EXT: u32 = 32769;
+pub const GL_ONE_MINUS_CONSTANT_COLOR: u32 = 32770;
+pub const GL_ONE_MINUS_CONSTANT_COLOR_EXT: u32 = 32770;
+pub const GL_CONSTANT_ALPHA: u32 = 32771;
+pub const GL_CONSTANT_ALPHA_EXT: u32 = 32771;
+pub const GL_ONE_MINUS_CONSTANT_ALPHA: u32 = 32772;
+pub const GL_ONE_MINUS_CONSTANT_ALPHA_EXT: u32 = 32772;
+pub const GL_BLEND_COLOR: u32 = 32773;
+pub const GL_BLEND_COLOR_EXT: u32 = 32773;
+pub const GL_FUNC_ADD: u32 = 32774;
+pub const GL_FUNC_ADD_EXT: u32 = 32774;
+pub const GL_FUNC_ADD_OES: u32 = 32774;
+pub const GL_MIN: u32 = 32775;
+pub const GL_MIN_EXT: u32 = 32775;
+pub const GL_MAX: u32 = 32776;
+pub const GL_MAX_EXT: u32 = 32776;
+pub const GL_BLEND_EQUATION: u32 = 32777;
+pub const GL_BLEND_EQUATION_EXT: u32 = 32777;
+pub const GL_BLEND_EQUATION_OES: u32 = 32777;
+pub const GL_BLEND_EQUATION_RGB: u32 = 32777;
+pub const GL_BLEND_EQUATION_RGB_EXT: u32 = 32777;
+pub const GL_BLEND_EQUATION_RGB_OES: u32 = 32777;
+pub const GL_FUNC_SUBTRACT: u32 = 32778;
+pub const GL_FUNC_SUBTRACT_EXT: u32 = 32778;
+pub const GL_FUNC_SUBTRACT_OES: u32 = 32778;
+pub const GL_FUNC_REVERSE_SUBTRACT: u32 = 32779;
+pub const GL_FUNC_REVERSE_SUBTRACT_EXT: u32 = 32779;
+pub const GL_FUNC_REVERSE_SUBTRACT_OES: u32 = 32779;
+pub const GL_CMYK_EXT: u32 = 32780;
+pub const GL_CMYKA_EXT: u32 = 32781;
+pub const GL_PACK_CMYK_HINT_EXT: u32 = 32782;
+pub const GL_UNPACK_CMYK_HINT_EXT: u32 = 32783;
+pub const GL_CONVOLUTION_1D: u32 = 32784;
+pub const GL_CONVOLUTION_1D_EXT: u32 = 32784;
+pub const GL_CONVOLUTION_2D: u32 = 32785;
+pub const GL_CONVOLUTION_2D_EXT: u32 = 32785;
+pub const GL_SEPARABLE_2D: u32 = 32786;
+pub const GL_SEPARABLE_2D_EXT: u32 = 32786;
+pub const GL_CONVOLUTION_BORDER_MODE: u32 = 32787;
+pub const GL_CONVOLUTION_BORDER_MODE_EXT: u32 = 32787;
+pub const GL_CONVOLUTION_FILTER_SCALE: u32 = 32788;
+pub const GL_CONVOLUTION_FILTER_SCALE_EXT: u32 = 32788;
+pub const GL_CONVOLUTION_FILTER_BIAS: u32 = 32789;
+pub const GL_CONVOLUTION_FILTER_BIAS_EXT: u32 = 32789;
+pub const GL_REDUCE: u32 = 32790;
+pub const GL_REDUCE_EXT: u32 = 32790;
+pub const GL_CONVOLUTION_FORMAT: u32 = 32791;
+pub const GL_CONVOLUTION_FORMAT_EXT: u32 = 32791;
+pub const GL_CONVOLUTION_WIDTH: u32 = 32792;
+pub const GL_CONVOLUTION_WIDTH_EXT: u32 = 32792;
+pub const GL_CONVOLUTION_HEIGHT: u32 = 32793;
+pub const GL_CONVOLUTION_HEIGHT_EXT: u32 = 32793;
+pub const GL_MAX_CONVOLUTION_WIDTH: u32 = 32794;
+pub const GL_MAX_CONVOLUTION_WIDTH_EXT: u32 = 32794;
+pub const GL_MAX_CONVOLUTION_HEIGHT: u32 = 32795;
+pub const GL_MAX_CONVOLUTION_HEIGHT_EXT: u32 = 32795;
+pub const GL_POST_CONVOLUTION_RED_SCALE: u32 = 32796;
+pub const GL_POST_CONVOLUTION_RED_SCALE_EXT: u32 = 32796;
+pub const GL_POST_CONVOLUTION_GREEN_SCALE: u32 = 32797;
+pub const GL_POST_CONVOLUTION_GREEN_SCALE_EXT: u32 = 32797;
+pub const GL_POST_CONVOLUTION_BLUE_SCALE: u32 = 32798;
+pub const GL_POST_CONVOLUTION_BLUE_SCALE_EXT: u32 = 32798;
+pub const GL_POST_CONVOLUTION_ALPHA_SCALE: u32 = 32799;
+pub const GL_POST_CONVOLUTION_ALPHA_SCALE_EXT: u32 = 32799;
+pub const GL_POST_CONVOLUTION_RED_BIAS: u32 = 32800;
+pub const GL_POST_CONVOLUTION_RED_BIAS_EXT: u32 = 32800;
+pub const GL_POST_CONVOLUTION_GREEN_BIAS: u32 = 32801;
+pub const GL_POST_CONVOLUTION_GREEN_BIAS_EXT: u32 = 32801;
+pub const GL_POST_CONVOLUTION_BLUE_BIAS: u32 = 32802;
+pub const GL_POST_CONVOLUTION_BLUE_BIAS_EXT: u32 = 32802;
+pub const GL_POST_CONVOLUTION_ALPHA_BIAS: u32 = 32803;
+pub const GL_POST_CONVOLUTION_ALPHA_BIAS_EXT: u32 = 32803;
+pub const GL_HISTOGRAM: u32 = 32804;
+pub const GL_HISTOGRAM_EXT: u32 = 32804;
+pub const GL_PROXY_HISTOGRAM: u32 = 32805;
+pub const GL_PROXY_HISTOGRAM_EXT: u32 = 32805;
+pub const GL_HISTOGRAM_WIDTH: u32 = 32806;
+pub const GL_HISTOGRAM_WIDTH_EXT: u32 = 32806;
+pub const GL_HISTOGRAM_FORMAT: u32 = 32807;
+pub const GL_HISTOGRAM_FORMAT_EXT: u32 = 32807;
+pub const GL_HISTOGRAM_RED_SIZE: u32 = 32808;
+pub const GL_HISTOGRAM_RED_SIZE_EXT: u32 = 32808;
+pub const GL_HISTOGRAM_GREEN_SIZE: u32 = 32809;
+pub const GL_HISTOGRAM_GREEN_SIZE_EXT: u32 = 32809;
+pub const GL_HISTOGRAM_BLUE_SIZE: u32 = 32810;
+pub const GL_HISTOGRAM_BLUE_SIZE_EXT: u32 = 32810;
+pub const GL_HISTOGRAM_ALPHA_SIZE: u32 = 32811;
+pub const GL_HISTOGRAM_ALPHA_SIZE_EXT: u32 = 32811;
+pub const GL_HISTOGRAM_LUMINANCE_SIZE: u32 = 32812;
+pub const GL_HISTOGRAM_LUMINANCE_SIZE_EXT: u32 = 32812;
+pub const GL_HISTOGRAM_SINK: u32 = 32813;
+pub const GL_HISTOGRAM_SINK_EXT: u32 = 32813;
+pub const GL_MINMAX: u32 = 32814;
+pub const GL_MINMAX_EXT: u32 = 32814;
+pub const GL_MINMAX_FORMAT: u32 = 32815;
+pub const GL_MINMAX_FORMAT_EXT: u32 = 32815;
+pub const GL_MINMAX_SINK: u32 = 32816;
+pub const GL_MINMAX_SINK_EXT: u32 = 32816;
+pub const GL_TABLE_TOO_LARGE: u32 = 32817;
+pub const GL_TABLE_TOO_LARGE_EXT: u32 = 32817;
+pub const GL_UNSIGNED_BYTE_3_3_2: u32 = 32818;
+pub const GL_UNSIGNED_BYTE_3_3_2_EXT: u32 = 32818;
+pub const GL_UNSIGNED_SHORT_4_4_4_4: u32 = 32819;
+pub const GL_UNSIGNED_SHORT_4_4_4_4_EXT: u32 = 32819;
+pub const GL_UNSIGNED_SHORT_5_5_5_1: u32 = 32820;
+pub const GL_UNSIGNED_SHORT_5_5_5_1_EXT: u32 = 32820;
+pub const GL_UNSIGNED_INT_8_8_8_8: u32 = 32821;
+pub const GL_UNSIGNED_INT_8_8_8_8_EXT: u32 = 32821;
+pub const GL_UNSIGNED_INT_10_10_10_2: u32 = 32822;
+pub const GL_UNSIGNED_INT_10_10_10_2_EXT: u32 = 32822;
+pub const GL_POLYGON_OFFSET_EXT: u32 = 32823;
+pub const GL_POLYGON_OFFSET_FILL: u32 = 32823;
+pub const GL_POLYGON_OFFSET_FACTOR: u32 = 32824;
+pub const GL_POLYGON_OFFSET_FACTOR_EXT: u32 = 32824;
+pub const GL_POLYGON_OFFSET_BIAS_EXT: u32 = 32825;
+pub const GL_RESCALE_NORMAL: u32 = 32826;
+pub const GL_RESCALE_NORMAL_EXT: u32 = 32826;
+pub const GL_ALPHA4: u32 = 32827;
+pub const GL_ALPHA4_EXT: u32 = 32827;
+pub const GL_ALPHA8: u32 = 32828;
+pub const GL_ALPHA8_EXT: u32 = 32828;
+pub const GL_ALPHA8_OES: u32 = 32828;
+pub const GL_ALPHA12: u32 = 32829;
+pub const GL_ALPHA12_EXT: u32 = 32829;
+pub const GL_ALPHA16: u32 = 32830;
+pub const GL_ALPHA16_EXT: u32 = 32830;
+pub const GL_LUMINANCE4: u32 = 32831;
+pub const GL_LUMINANCE4_EXT: u32 = 32831;
+pub const GL_LUMINANCE8: u32 = 32832;
+pub const GL_LUMINANCE8_EXT: u32 = 32832;
+pub const GL_LUMINANCE8_OES: u32 = 32832;
+pub const GL_LUMINANCE12: u32 = 32833;
+pub const GL_LUMINANCE12_EXT: u32 = 32833;
+pub const GL_LUMINANCE16: u32 = 32834;
+pub const GL_LUMINANCE16_EXT: u32 = 32834;
+pub const GL_LUMINANCE4_ALPHA4: u32 = 32835;
+pub const GL_LUMINANCE4_ALPHA4_EXT: u32 = 32835;
+pub const GL_LUMINANCE4_ALPHA4_OES: u32 = 32835;
+pub const GL_LUMINANCE6_ALPHA2: u32 = 32836;
+pub const GL_LUMINANCE6_ALPHA2_EXT: u32 = 32836;
+pub const GL_LUMINANCE8_ALPHA8: u32 = 32837;
+pub const GL_LUMINANCE8_ALPHA8_EXT: u32 = 32837;
+pub const GL_LUMINANCE8_ALPHA8_OES: u32 = 32837;
+pub const GL_LUMINANCE12_ALPHA4: u32 = 32838;
+pub const GL_LUMINANCE12_ALPHA4_EXT: u32 = 32838;
+pub const GL_LUMINANCE12_ALPHA12: u32 = 32839;
+pub const GL_LUMINANCE12_ALPHA12_EXT: u32 = 32839;
+pub const GL_LUMINANCE16_ALPHA16: u32 = 32840;
+pub const GL_LUMINANCE16_ALPHA16_EXT: u32 = 32840;
+pub const GL_INTENSITY: u32 = 32841;
+pub const GL_INTENSITY_EXT: u32 = 32841;
+pub const GL_INTENSITY4: u32 = 32842;
+pub const GL_INTENSITY4_EXT: u32 = 32842;
+pub const GL_INTENSITY8: u32 = 32843;
+pub const GL_INTENSITY8_EXT: u32 = 32843;
+pub const GL_INTENSITY12: u32 = 32844;
+pub const GL_INTENSITY12_EXT: u32 = 32844;
+pub const GL_INTENSITY16: u32 = 32845;
+pub const GL_INTENSITY16_EXT: u32 = 32845;
+pub const GL_RGB2_EXT: u32 = 32846;
+pub const GL_RGB4: u32 = 32847;
+pub const GL_RGB4_EXT: u32 = 32847;
+pub const GL_RGB5: u32 = 32848;
+pub const GL_RGB5_EXT: u32 = 32848;
+pub const GL_RGB8: u32 = 32849;
+pub const GL_RGB8_EXT: u32 = 32849;
+pub const GL_RGB8_OES: u32 = 32849;
+pub const GL_RGB10: u32 = 32850;
+pub const GL_RGB10_EXT: u32 = 32850;
+pub const GL_RGB12: u32 = 32851;
+pub const GL_RGB12_EXT: u32 = 32851;
+pub const GL_RGB16: u32 = 32852;
+pub const GL_RGB16_EXT: u32 = 32852;
+pub const GL_RGBA2: u32 = 32853;
+pub const GL_RGBA2_EXT: u32 = 32853;
+pub const GL_RGBA4: u32 = 32854;
+pub const GL_RGBA4_EXT: u32 = 32854;
+pub const GL_RGBA4_OES: u32 = 32854;
+pub const GL_RGB5_A1: u32 = 32855;
+pub const GL_RGB5_A1_EXT: u32 = 32855;
+pub const GL_RGB5_A1_OES: u32 = 32855;
+pub const GL_RGBA8: u32 = 32856;
+pub const GL_RGBA8_EXT: u32 = 32856;
+pub const GL_RGBA8_OES: u32 = 32856;
+pub const GL_RGB10_A2: u32 = 32857;
+pub const GL_RGB10_A2_EXT: u32 = 32857;
+pub const GL_RGBA12: u32 = 32858;
+pub const GL_RGBA12_EXT: u32 = 32858;
+pub const GL_RGBA16: u32 = 32859;
+pub const GL_RGBA16_EXT: u32 = 32859;
+pub const GL_TEXTURE_RED_SIZE: u32 = 32860;
+pub const GL_TEXTURE_RED_SIZE_EXT: u32 = 32860;
+pub const GL_TEXTURE_GREEN_SIZE: u32 = 32861;
+pub const GL_TEXTURE_GREEN_SIZE_EXT: u32 = 32861;
+pub const GL_TEXTURE_BLUE_SIZE: u32 = 32862;
+pub const GL_TEXTURE_BLUE_SIZE_EXT: u32 = 32862;
+pub const GL_TEXTURE_ALPHA_SIZE: u32 = 32863;
+pub const GL_TEXTURE_ALPHA_SIZE_EXT: u32 = 32863;
+pub const GL_TEXTURE_LUMINANCE_SIZE: u32 = 32864;
+pub const GL_TEXTURE_LUMINANCE_SIZE_EXT: u32 = 32864;
+pub const GL_TEXTURE_INTENSITY_SIZE: u32 = 32865;
+pub const GL_TEXTURE_INTENSITY_SIZE_EXT: u32 = 32865;
+pub const GL_REPLACE_EXT: u32 = 32866;
+pub const GL_PROXY_TEXTURE_1D: u32 = 32867;
+pub const GL_PROXY_TEXTURE_1D_EXT: u32 = 32867;
+pub const GL_PROXY_TEXTURE_2D: u32 = 32868;
+pub const GL_PROXY_TEXTURE_2D_EXT: u32 = 32868;
+pub const GL_TEXTURE_TOO_LARGE_EXT: u32 = 32869;
+pub const GL_TEXTURE_PRIORITY: u32 = 32870;
+pub const GL_TEXTURE_PRIORITY_EXT: u32 = 32870;
+pub const GL_TEXTURE_RESIDENT: u32 = 32871;
+pub const GL_TEXTURE_RESIDENT_EXT: u32 = 32871;
+pub const GL_TEXTURE_1D_BINDING_EXT: u32 = 32872;
+pub const GL_TEXTURE_BINDING_1D: u32 = 32872;
+pub const GL_TEXTURE_2D_BINDING_EXT: u32 = 32873;
+pub const GL_TEXTURE_BINDING_2D: u32 = 32873;
+pub const GL_TEXTURE_3D_BINDING_EXT: u32 = 32874;
+pub const GL_TEXTURE_3D_BINDING_OES: u32 = 32874;
+pub const GL_TEXTURE_BINDING_3D: u32 = 32874;
+pub const GL_TEXTURE_BINDING_3D_OES: u32 = 32874;
+pub const GL_PACK_SKIP_IMAGES: u32 = 32875;
+pub const GL_PACK_SKIP_IMAGES_EXT: u32 = 32875;
+pub const GL_PACK_IMAGE_HEIGHT: u32 = 32876;
+pub const GL_PACK_IMAGE_HEIGHT_EXT: u32 = 32876;
+pub const GL_UNPACK_SKIP_IMAGES: u32 = 32877;
+pub const GL_UNPACK_SKIP_IMAGES_EXT: u32 = 32877;
+pub const GL_UNPACK_IMAGE_HEIGHT: u32 = 32878;
+pub const GL_UNPACK_IMAGE_HEIGHT_EXT: u32 = 32878;
+pub const GL_TEXTURE_3D: u32 = 32879;
+pub const GL_TEXTURE_3D_EXT: u32 = 32879;
+pub const GL_TEXTURE_3D_OES: u32 = 32879;
+pub const GL_PROXY_TEXTURE_3D: u32 = 32880;
+pub const GL_PROXY_TEXTURE_3D_EXT: u32 = 32880;
+pub const GL_TEXTURE_DEPTH: u32 = 32881;
+pub const GL_TEXTURE_DEPTH_EXT: u32 = 32881;
+pub const GL_TEXTURE_WRAP_R: u32 = 32882;
+pub const GL_TEXTURE_WRAP_R_EXT: u32 = 32882;
+pub const GL_TEXTURE_WRAP_R_OES: u32 = 32882;
+pub const GL_MAX_3D_TEXTURE_SIZE: u32 = 32883;
+pub const GL_MAX_3D_TEXTURE_SIZE_EXT: u32 = 32883;
+pub const GL_MAX_3D_TEXTURE_SIZE_OES: u32 = 32883;
+pub const GL_VERTEX_ARRAY: u32 = 32884;
+pub const GL_VERTEX_ARRAY_EXT: u32 = 32884;
+pub const GL_VERTEX_ARRAY_KHR: u32 = 32884;
+pub const GL_NORMAL_ARRAY: u32 = 32885;
+pub const GL_NORMAL_ARRAY_EXT: u32 = 32885;
+pub const GL_COLOR_ARRAY: u32 = 32886;
+pub const GL_COLOR_ARRAY_EXT: u32 = 32886;
+pub const GL_INDEX_ARRAY: u32 = 32887;
+pub const GL_INDEX_ARRAY_EXT: u32 = 32887;
+pub const GL_TEXTURE_COORD_ARRAY: u32 = 32888;
+pub const GL_TEXTURE_COORD_ARRAY_EXT: u32 = 32888;
+pub const GL_EDGE_FLAG_ARRAY: u32 = 32889;
+pub const GL_EDGE_FLAG_ARRAY_EXT: u32 = 32889;
+pub const GL_VERTEX_ARRAY_SIZE: u32 = 32890;
+pub const GL_VERTEX_ARRAY_SIZE_EXT: u32 = 32890;
+pub const GL_VERTEX_ARRAY_TYPE: u32 = 32891;
+pub const GL_VERTEX_ARRAY_TYPE_EXT: u32 = 32891;
+pub const GL_VERTEX_ARRAY_STRIDE: u32 = 32892;
+pub const GL_VERTEX_ARRAY_STRIDE_EXT: u32 = 32892;
+pub const GL_VERTEX_ARRAY_COUNT_EXT: u32 = 32893;
+pub const GL_NORMAL_ARRAY_TYPE: u32 = 32894;
+pub const GL_NORMAL_ARRAY_TYPE_EXT: u32 = 32894;
+pub const GL_NORMAL_ARRAY_STRIDE: u32 = 32895;
+pub const GL_NORMAL_ARRAY_STRIDE_EXT: u32 = 32895;
+pub const GL_NORMAL_ARRAY_COUNT_EXT: u32 = 32896;
+pub const GL_COLOR_ARRAY_SIZE: u32 = 32897;
+pub const GL_COLOR_ARRAY_SIZE_EXT: u32 = 32897;
+pub const GL_COLOR_ARRAY_TYPE: u32 = 32898;
+pub const GL_COLOR_ARRAY_TYPE_EXT: u32 = 32898;
+pub const GL_COLOR_ARRAY_STRIDE: u32 = 32899;
+pub const GL_COLOR_ARRAY_STRIDE_EXT: u32 = 32899;
+pub const GL_COLOR_ARRAY_COUNT_EXT: u32 = 32900;
+pub const GL_INDEX_ARRAY_TYPE: u32 = 32901;
+pub const GL_INDEX_ARRAY_TYPE_EXT: u32 = 32901;
+pub const GL_INDEX_ARRAY_STRIDE: u32 = 32902;
+pub const GL_INDEX_ARRAY_STRIDE_EXT: u32 = 32902;
+pub const GL_INDEX_ARRAY_COUNT_EXT: u32 = 32903;
+pub const GL_TEXTURE_COORD_ARRAY_SIZE: u32 = 32904;
+pub const GL_TEXTURE_COORD_ARRAY_SIZE_EXT: u32 = 32904;
+pub const GL_TEXTURE_COORD_ARRAY_TYPE: u32 = 32905;
+pub const GL_TEXTURE_COORD_ARRAY_TYPE_EXT: u32 = 32905;
+pub const GL_TEXTURE_COORD_ARRAY_STRIDE: u32 = 32906;
+pub const GL_TEXTURE_COORD_ARRAY_STRIDE_EXT: u32 = 32906;
+pub const GL_TEXTURE_COORD_ARRAY_COUNT_EXT: u32 = 32907;
+pub const GL_EDGE_FLAG_ARRAY_STRIDE: u32 = 32908;
+pub const GL_EDGE_FLAG_ARRAY_STRIDE_EXT: u32 = 32908;
+pub const GL_EDGE_FLAG_ARRAY_COUNT_EXT: u32 = 32909;
+pub const GL_VERTEX_ARRAY_POINTER: u32 = 32910;
+pub const GL_VERTEX_ARRAY_POINTER_EXT: u32 = 32910;
+pub const GL_NORMAL_ARRAY_POINTER: u32 = 32911;
+pub const GL_NORMAL_ARRAY_POINTER_EXT: u32 = 32911;
+pub const GL_COLOR_ARRAY_POINTER: u32 = 32912;
+pub const GL_COLOR_ARRAY_POINTER_EXT: u32 = 32912;
+pub const GL_INDEX_ARRAY_POINTER: u32 = 32913;
+pub const GL_INDEX_ARRAY_POINTER_EXT: u32 = 32913;
+pub const GL_TEXTURE_COORD_ARRAY_POINTER: u32 = 32914;
+pub const GL_TEXTURE_COORD_ARRAY_POINTER_EXT: u32 = 32914;
+pub const GL_EDGE_FLAG_ARRAY_POINTER: u32 = 32915;
+pub const GL_EDGE_FLAG_ARRAY_POINTER_EXT: u32 = 32915;
+pub const GL_INTERLACE_SGIX: u32 = 32916;
+pub const GL_DETAIL_TEXTURE_2D_SGIS: u32 = 32917;
+pub const GL_DETAIL_TEXTURE_2D_BINDING_SGIS: u32 = 32918;
+pub const GL_LINEAR_DETAIL_SGIS: u32 = 32919;
+pub const GL_LINEAR_DETAIL_ALPHA_SGIS: u32 = 32920;
+pub const GL_LINEAR_DETAIL_COLOR_SGIS: u32 = 32921;
+pub const GL_DETAIL_TEXTURE_LEVEL_SGIS: u32 = 32922;
+pub const GL_DETAIL_TEXTURE_MODE_SGIS: u32 = 32923;
+pub const GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS: u32 = 32924;
+pub const GL_MULTISAMPLE: u32 = 32925;
+pub const GL_MULTISAMPLE_ARB: u32 = 32925;
+pub const GL_MULTISAMPLE_EXT: u32 = 32925;
+pub const GL_MULTISAMPLE_SGIS: u32 = 32925;
+pub const GL_SAMPLE_ALPHA_TO_COVERAGE: u32 = 32926;
+pub const GL_SAMPLE_ALPHA_TO_COVERAGE_ARB: u32 = 32926;
+pub const GL_SAMPLE_ALPHA_TO_MASK_EXT: u32 = 32926;
+pub const GL_SAMPLE_ALPHA_TO_MASK_SGIS: u32 = 32926;
+pub const GL_SAMPLE_ALPHA_TO_ONE: u32 = 32927;
+pub const GL_SAMPLE_ALPHA_TO_ONE_ARB: u32 = 32927;
+pub const GL_SAMPLE_ALPHA_TO_ONE_EXT: u32 = 32927;
+pub const GL_SAMPLE_ALPHA_TO_ONE_SGIS: u32 = 32927;
+pub const GL_SAMPLE_COVERAGE: u32 = 32928;
+pub const GL_SAMPLE_COVERAGE_ARB: u32 = 32928;
+pub const GL_SAMPLE_MASK_EXT: u32 = 32928;
+pub const GL_SAMPLE_MASK_SGIS: u32 = 32928;
+pub const GL_1PASS_EXT: u32 = 32929;
+pub const GL_1PASS_SGIS: u32 = 32929;
+pub const GL_2PASS_0_EXT: u32 = 32930;
+pub const GL_2PASS_0_SGIS: u32 = 32930;
+pub const GL_2PASS_1_EXT: u32 = 32931;
+pub const GL_2PASS_1_SGIS: u32 = 32931;
+pub const GL_4PASS_0_EXT: u32 = 32932;
+pub const GL_4PASS_0_SGIS: u32 = 32932;
+pub const GL_4PASS_1_EXT: u32 = 32933;
+pub const GL_4PASS_1_SGIS: u32 = 32933;
+pub const GL_4PASS_2_EXT: u32 = 32934;
+pub const GL_4PASS_2_SGIS: u32 = 32934;
+pub const GL_4PASS_3_EXT: u32 = 32935;
+pub const GL_4PASS_3_SGIS: u32 = 32935;
+pub const GL_SAMPLE_BUFFERS: u32 = 32936;
+pub const GL_SAMPLE_BUFFERS_ARB: u32 = 32936;
+pub const GL_SAMPLE_BUFFERS_EXT: u32 = 32936;
+pub const GL_SAMPLE_BUFFERS_SGIS: u32 = 32936;
+pub const GL_SAMPLES: u32 = 32937;
+pub const GL_SAMPLES_ARB: u32 = 32937;
+pub const GL_SAMPLES_EXT: u32 = 32937;
+pub const GL_SAMPLES_SGIS: u32 = 32937;
+pub const GL_SAMPLE_COVERAGE_VALUE: u32 = 32938;
+pub const GL_SAMPLE_COVERAGE_VALUE_ARB: u32 = 32938;
+pub const GL_SAMPLE_MASK_VALUE_EXT: u32 = 32938;
+pub const GL_SAMPLE_MASK_VALUE_SGIS: u32 = 32938;
+pub const GL_SAMPLE_COVERAGE_INVERT: u32 = 32939;
+pub const GL_SAMPLE_COVERAGE_INVERT_ARB: u32 = 32939;
+pub const GL_SAMPLE_MASK_INVERT_EXT: u32 = 32939;
+pub const GL_SAMPLE_MASK_INVERT_SGIS: u32 = 32939;
+pub const GL_SAMPLE_PATTERN_EXT: u32 = 32940;
+pub const GL_SAMPLE_PATTERN_SGIS: u32 = 32940;
+pub const GL_LINEAR_SHARPEN_SGIS: u32 = 32941;
+pub const GL_LINEAR_SHARPEN_ALPHA_SGIS: u32 = 32942;
+pub const GL_LINEAR_SHARPEN_COLOR_SGIS: u32 = 32943;
+pub const GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS: u32 = 32944;
+pub const GL_COLOR_MATRIX: u32 = 32945;
+pub const GL_COLOR_MATRIX_SGI: u32 = 32945;
+pub const GL_COLOR_MATRIX_STACK_DEPTH: u32 = 32946;
+pub const GL_COLOR_MATRIX_STACK_DEPTH_SGI: u32 = 32946;
+pub const GL_MAX_COLOR_MATRIX_STACK_DEPTH: u32 = 32947;
+pub const GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI: u32 = 32947;
+pub const GL_POST_COLOR_MATRIX_RED_SCALE: u32 = 32948;
+pub const GL_POST_COLOR_MATRIX_RED_SCALE_SGI: u32 = 32948;
+pub const GL_POST_COLOR_MATRIX_GREEN_SCALE: u32 = 32949;
+pub const GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI: u32 = 32949;
+pub const GL_POST_COLOR_MATRIX_BLUE_SCALE: u32 = 32950;
+pub const GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI: u32 = 32950;
+pub const GL_POST_COLOR_MATRIX_ALPHA_SCALE: u32 = 32951;
+pub const GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI: u32 = 32951;
+pub const GL_POST_COLOR_MATRIX_RED_BIAS: u32 = 32952;
+pub const GL_POST_COLOR_MATRIX_RED_BIAS_SGI: u32 = 32952;
+pub const GL_POST_COLOR_MATRIX_GREEN_BIAS: u32 = 32953;
+pub const GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI: u32 = 32953;
+pub const GL_POST_COLOR_MATRIX_BLUE_BIAS: u32 = 32954;
+pub const GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI: u32 = 32954;
+pub const GL_POST_COLOR_MATRIX_ALPHA_BIAS: u32 = 32955;
+pub const GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI: u32 = 32955;
+pub const GL_TEXTURE_COLOR_TABLE_SGI: u32 = 32956;
+pub const GL_PROXY_TEXTURE_COLOR_TABLE_SGI: u32 = 32957;
+pub const GL_TEXTURE_ENV_BIAS_SGIX: u32 = 32958;
+pub const GL_SHADOW_AMBIENT_SGIX: u32 = 32959;
+pub const GL_TEXTURE_COMPARE_FAIL_VALUE_ARB: u32 = 32959;
+pub const GL_BLEND_DST_RGB: u32 = 32968;
+pub const GL_BLEND_DST_RGB_EXT: u32 = 32968;
+pub const GL_BLEND_DST_RGB_OES: u32 = 32968;
+pub const GL_BLEND_SRC_RGB: u32 = 32969;
+pub const GL_BLEND_SRC_RGB_EXT: u32 = 32969;
+pub const GL_BLEND_SRC_RGB_OES: u32 = 32969;
+pub const GL_BLEND_DST_ALPHA: u32 = 32970;
+pub const GL_BLEND_DST_ALPHA_EXT: u32 = 32970;
+pub const GL_BLEND_DST_ALPHA_OES: u32 = 32970;
+pub const GL_BLEND_SRC_ALPHA: u32 = 32971;
+pub const GL_BLEND_SRC_ALPHA_EXT: u32 = 32971;
+pub const GL_BLEND_SRC_ALPHA_OES: u32 = 32971;
+pub const GL_422_EXT: u32 = 32972;
+pub const GL_422_REV_EXT: u32 = 32973;
+pub const GL_422_AVERAGE_EXT: u32 = 32974;
+pub const GL_422_REV_AVERAGE_EXT: u32 = 32975;
+pub const GL_COLOR_TABLE: u32 = 32976;
+pub const GL_COLOR_TABLE_SGI: u32 = 32976;
+pub const GL_POST_CONVOLUTION_COLOR_TABLE: u32 = 32977;
+pub const GL_POST_CONVOLUTION_COLOR_TABLE_SGI: u32 = 32977;
+pub const GL_POST_COLOR_MATRIX_COLOR_TABLE: u32 = 32978;
+pub const GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI: u32 = 32978;
+pub const GL_PROXY_COLOR_TABLE: u32 = 32979;
+pub const GL_PROXY_COLOR_TABLE_SGI: u32 = 32979;
+pub const GL_PROXY_POST_CONVOLUTION_COLOR_TABLE: u32 = 32980;
+pub const GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI: u32 = 32980;
+pub const GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE: u32 = 32981;
+pub const GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI: u32 = 32981;
+pub const GL_COLOR_TABLE_SCALE: u32 = 32982;
+pub const GL_COLOR_TABLE_SCALE_SGI: u32 = 32982;
+pub const GL_COLOR_TABLE_BIAS: u32 = 32983;
+pub const GL_COLOR_TABLE_BIAS_SGI: u32 = 32983;
+pub const GL_COLOR_TABLE_FORMAT: u32 = 32984;
+pub const GL_COLOR_TABLE_FORMAT_SGI: u32 = 32984;
+pub const GL_COLOR_TABLE_WIDTH: u32 = 32985;
+pub const GL_COLOR_TABLE_WIDTH_SGI: u32 = 32985;
+pub const GL_COLOR_TABLE_RED_SIZE: u32 = 32986;
+pub const GL_COLOR_TABLE_RED_SIZE_SGI: u32 = 32986;
+pub const GL_COLOR_TABLE_GREEN_SIZE: u32 = 32987;
+pub const GL_COLOR_TABLE_GREEN_SIZE_SGI: u32 = 32987;
+pub const GL_COLOR_TABLE_BLUE_SIZE: u32 = 32988;
+pub const GL_COLOR_TABLE_BLUE_SIZE_SGI: u32 = 32988;
+pub const GL_COLOR_TABLE_ALPHA_SIZE: u32 = 32989;
+pub const GL_COLOR_TABLE_ALPHA_SIZE_SGI: u32 = 32989;
+pub const GL_COLOR_TABLE_LUMINANCE_SIZE: u32 = 32990;
+pub const GL_COLOR_TABLE_LUMINANCE_SIZE_SGI: u32 = 32990;
+pub const GL_COLOR_TABLE_INTENSITY_SIZE: u32 = 32991;
+pub const GL_COLOR_TABLE_INTENSITY_SIZE_SGI: u32 = 32991;
+pub const GL_BGR: u32 = 32992;
+pub const GL_BGR_EXT: u32 = 32992;
+pub const GL_BGRA: u32 = 32993;
+pub const GL_BGRA_EXT: u32 = 32993;
+pub const GL_BGRA_IMG: u32 = 32993;
+pub const GL_COLOR_INDEX1_EXT: u32 = 32994;
+pub const GL_COLOR_INDEX2_EXT: u32 = 32995;
+pub const GL_COLOR_INDEX4_EXT: u32 = 32996;
+pub const GL_COLOR_INDEX8_EXT: u32 = 32997;
+pub const GL_COLOR_INDEX12_EXT: u32 = 32998;
+pub const GL_COLOR_INDEX16_EXT: u32 = 32999;
+pub const GL_MAX_ELEMENTS_VERTICES: u32 = 33000;
+pub const GL_MAX_ELEMENTS_VERTICES_EXT: u32 = 33000;
+pub const GL_MAX_ELEMENTS_INDICES: u32 = 33001;
+pub const GL_MAX_ELEMENTS_INDICES_EXT: u32 = 33001;
+pub const GL_PHONG_WIN: u32 = 33002;
+pub const GL_PHONG_HINT_WIN: u32 = 33003;
+pub const GL_FOG_SPECULAR_TEXTURE_WIN: u32 = 33004;
+pub const GL_TEXTURE_INDEX_SIZE_EXT: u32 = 33005;
+pub const GL_PARAMETER_BUFFER_ARB: u32 = 33006;
+pub const GL_PARAMETER_BUFFER_BINDING_ARB: u32 = 33007;
+pub const GL_CLIP_VOLUME_CLIPPING_HINT_EXT: u32 = 33008;
+pub const GL_DUAL_ALPHA4_SGIS: u32 = 33040;
+pub const GL_DUAL_ALPHA8_SGIS: u32 = 33041;
+pub const GL_DUAL_ALPHA12_SGIS: u32 = 33042;
+pub const GL_DUAL_ALPHA16_SGIS: u32 = 33043;
+pub const GL_DUAL_LUMINANCE4_SGIS: u32 = 33044;
+pub const GL_DUAL_LUMINANCE8_SGIS: u32 = 33045;
+pub const GL_DUAL_LUMINANCE12_SGIS: u32 = 33046;
+pub const GL_DUAL_LUMINANCE16_SGIS: u32 = 33047;
+pub const GL_DUAL_INTENSITY4_SGIS: u32 = 33048;
+pub const GL_DUAL_INTENSITY8_SGIS: u32 = 33049;
+pub const GL_DUAL_INTENSITY12_SGIS: u32 = 33050;
+pub const GL_DUAL_INTENSITY16_SGIS: u32 = 33051;
+pub const GL_DUAL_LUMINANCE_ALPHA4_SGIS: u32 = 33052;
+pub const GL_DUAL_LUMINANCE_ALPHA8_SGIS: u32 = 33053;
+pub const GL_QUAD_ALPHA4_SGIS: u32 = 33054;
+pub const GL_QUAD_ALPHA8_SGIS: u32 = 33055;
+pub const GL_QUAD_LUMINANCE4_SGIS: u32 = 33056;
+pub const GL_QUAD_LUMINANCE8_SGIS: u32 = 33057;
+pub const GL_QUAD_INTENSITY4_SGIS: u32 = 33058;
+pub const GL_QUAD_INTENSITY8_SGIS: u32 = 33059;
+pub const GL_DUAL_TEXTURE_SELECT_SGIS: u32 = 33060;
+pub const GL_QUAD_TEXTURE_SELECT_SGIS: u32 = 33061;
+pub const GL_POINT_SIZE_MIN: u32 = 33062;
+pub const GL_POINT_SIZE_MIN_ARB: u32 = 33062;
+pub const GL_POINT_SIZE_MIN_EXT: u32 = 33062;
+pub const GL_POINT_SIZE_MIN_SGIS: u32 = 33062;
+pub const GL_POINT_SIZE_MAX: u32 = 33063;
+pub const GL_POINT_SIZE_MAX_ARB: u32 = 33063;
+pub const GL_POINT_SIZE_MAX_EXT: u32 = 33063;
+pub const GL_POINT_SIZE_MAX_SGIS: u32 = 33063;
+pub const GL_POINT_FADE_THRESHOLD_SIZE: u32 = 33064;
+pub const GL_POINT_FADE_THRESHOLD_SIZE_ARB: u32 = 33064;
+pub const GL_POINT_FADE_THRESHOLD_SIZE_EXT: u32 = 33064;
+pub const GL_POINT_FADE_THRESHOLD_SIZE_SGIS: u32 = 33064;
+pub const GL_DISTANCE_ATTENUATION_EXT: u32 = 33065;
+pub const GL_DISTANCE_ATTENUATION_SGIS: u32 = 33065;
+pub const GL_POINT_DISTANCE_ATTENUATION: u32 = 33065;
+pub const GL_POINT_DISTANCE_ATTENUATION_ARB: u32 = 33065;
+pub const GL_FOG_FUNC_SGIS: u32 = 33066;
+pub const GL_FOG_FUNC_POINTS_SGIS: u32 = 33067;
+pub const GL_MAX_FOG_FUNC_POINTS_SGIS: u32 = 33068;
+pub const GL_CLAMP_TO_BORDER: u32 = 33069;
+pub const GL_CLAMP_TO_BORDER_ARB: u32 = 33069;
+pub const GL_CLAMP_TO_BORDER_EXT: u32 = 33069;
+pub const GL_CLAMP_TO_BORDER_NV: u32 = 33069;
+pub const GL_CLAMP_TO_BORDER_OES: u32 = 33069;
+pub const GL_CLAMP_TO_BORDER_SGIS: u32 = 33069;
+pub const GL_TEXTURE_MULTI_BUFFER_HINT_SGIX: u32 = 33070;
+pub const GL_CLAMP_TO_EDGE: u32 = 33071;
+pub const GL_CLAMP_TO_EDGE_SGIS: u32 = 33071;
+pub const GL_PACK_SKIP_VOLUMES_SGIS: u32 = 33072;
+pub const GL_PACK_IMAGE_DEPTH_SGIS: u32 = 33073;
+pub const GL_UNPACK_SKIP_VOLUMES_SGIS: u32 = 33074;
+pub const GL_UNPACK_IMAGE_DEPTH_SGIS: u32 = 33075;
+pub const GL_TEXTURE_4D_SGIS: u32 = 33076;
+pub const GL_PROXY_TEXTURE_4D_SGIS: u32 = 33077;
+pub const GL_TEXTURE_4DSIZE_SGIS: u32 = 33078;
+pub const GL_TEXTURE_WRAP_Q_SGIS: u32 = 33079;
+pub const GL_MAX_4D_TEXTURE_SIZE_SGIS: u32 = 33080;
+pub const GL_PIXEL_TEX_GEN_SGIX: u32 = 33081;
+pub const GL_TEXTURE_MIN_LOD: u32 = 33082;
+pub const GL_TEXTURE_MIN_LOD_SGIS: u32 = 33082;
+pub const GL_TEXTURE_MAX_LOD: u32 = 33083;
+pub const GL_TEXTURE_MAX_LOD_SGIS: u32 = 33083;
+pub const GL_TEXTURE_BASE_LEVEL: u32 = 33084;
+pub const GL_TEXTURE_BASE_LEVEL_SGIS: u32 = 33084;
+pub const GL_TEXTURE_MAX_LEVEL: u32 = 33085;
+pub const GL_TEXTURE_MAX_LEVEL_APPLE: u32 = 33085;
+pub const GL_TEXTURE_MAX_LEVEL_SGIS: u32 = 33085;
+pub const GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX: u32 = 33086;
+pub const GL_PIXEL_TILE_CACHE_INCREMENT_SGIX: u32 = 33087;
+pub const GL_PIXEL_TILE_WIDTH_SGIX: u32 = 33088;
+pub const GL_PIXEL_TILE_HEIGHT_SGIX: u32 = 33089;
+pub const GL_PIXEL_TILE_GRID_WIDTH_SGIX: u32 = 33090;
+pub const GL_PIXEL_TILE_GRID_HEIGHT_SGIX: u32 = 33091;
+pub const GL_PIXEL_TILE_GRID_DEPTH_SGIX: u32 = 33092;
+pub const GL_PIXEL_TILE_CACHE_SIZE_SGIX: u32 = 33093;
+pub const GL_FILTER4_SGIS: u32 = 33094;
+pub const GL_TEXTURE_FILTER4_SIZE_SGIS: u32 = 33095;
+pub const GL_SPRITE_SGIX: u32 = 33096;
+pub const GL_SPRITE_MODE_SGIX: u32 = 33097;
+pub const GL_SPRITE_AXIS_SGIX: u32 = 33098;
+pub const GL_SPRITE_TRANSLATION_SGIX: u32 = 33099;
+pub const GL_SPRITE_AXIAL_SGIX: u32 = 33100;
+pub const GL_SPRITE_OBJECT_ALIGNED_SGIX: u32 = 33101;
+pub const GL_SPRITE_EYE_ALIGNED_SGIX: u32 = 33102;
+pub const GL_TEXTURE_4D_BINDING_SGIS: u32 = 33103;
+pub const GL_IGNORE_BORDER_HP: u32 = 33104;
+pub const GL_CONSTANT_BORDER: u32 = 33105;
+pub const GL_CONSTANT_BORDER_HP: u32 = 33105;
+pub const GL_REPLICATE_BORDER: u32 = 33107;
+pub const GL_REPLICATE_BORDER_HP: u32 = 33107;
+pub const GL_CONVOLUTION_BORDER_COLOR: u32 = 33108;
+pub const GL_CONVOLUTION_BORDER_COLOR_HP: u32 = 33108;
+pub const GL_IMAGE_SCALE_X_HP: u32 = 33109;
+pub const GL_IMAGE_SCALE_Y_HP: u32 = 33110;
+pub const GL_IMAGE_TRANSLATE_X_HP: u32 = 33111;
+pub const GL_IMAGE_TRANSLATE_Y_HP: u32 = 33112;
+pub const GL_IMAGE_ROTATE_ANGLE_HP: u32 = 33113;
+pub const GL_IMAGE_ROTATE_ORIGIN_X_HP: u32 = 33114;
+pub const GL_IMAGE_ROTATE_ORIGIN_Y_HP: u32 = 33115;
+pub const GL_IMAGE_MAG_FILTER_HP: u32 = 33116;
+pub const GL_IMAGE_MIN_FILTER_HP: u32 = 33117;
+pub const GL_IMAGE_CUBIC_WEIGHT_HP: u32 = 33118;
+pub const GL_CUBIC_HP: u32 = 33119;
+pub const GL_AVERAGE_HP: u32 = 33120;
+pub const GL_IMAGE_TRANSFORM_2D_HP: u32 = 33121;
+pub const GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP: u32 = 33122;
+pub const GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP: u32 = 33123;
+pub const GL_OCCLUSION_TEST_HP: u32 = 33125;
+pub const GL_OCCLUSION_TEST_RESULT_HP: u32 = 33126;
+pub const GL_TEXTURE_LIGHTING_MODE_HP: u32 = 33127;
+pub const GL_TEXTURE_POST_SPECULAR_HP: u32 = 33128;
+pub const GL_TEXTURE_PRE_SPECULAR_HP: u32 = 33129;
+pub const GL_LINEAR_CLIPMAP_LINEAR_SGIX: u32 = 33136;
+pub const GL_TEXTURE_CLIPMAP_CENTER_SGIX: u32 = 33137;
+pub const GL_TEXTURE_CLIPMAP_FRAME_SGIX: u32 = 33138;
+pub const GL_TEXTURE_CLIPMAP_OFFSET_SGIX: u32 = 33139;
+pub const GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX: u32 = 33140;
+pub const GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX: u32 = 33141;
+pub const GL_TEXTURE_CLIPMAP_DEPTH_SGIX: u32 = 33142;
+pub const GL_MAX_CLIPMAP_DEPTH_SGIX: u32 = 33143;
+pub const GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX: u32 = 33144;
+pub const GL_POST_TEXTURE_FILTER_BIAS_SGIX: u32 = 33145;
+pub const GL_POST_TEXTURE_FILTER_SCALE_SGIX: u32 = 33146;
+pub const GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX: u32 = 33147;
+pub const GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX: u32 = 33148;
+pub const GL_REFERENCE_PLANE_SGIX: u32 = 33149;
+pub const GL_REFERENCE_PLANE_EQUATION_SGIX: u32 = 33150;
+pub const GL_IR_INSTRUMENT1_SGIX: u32 = 33151;
+pub const GL_INSTRUMENT_BUFFER_POINTER_SGIX: u32 = 33152;
+pub const GL_INSTRUMENT_MEASUREMENTS_SGIX: u32 = 33153;
+pub const GL_LIST_PRIORITY_SGIX: u32 = 33154;
+pub const GL_CALLIGRAPHIC_FRAGMENT_SGIX: u32 = 33155;
+pub const GL_PIXEL_TEX_GEN_Q_CEILING_SGIX: u32 = 33156;
+pub const GL_PIXEL_TEX_GEN_Q_ROUND_SGIX: u32 = 33157;
+pub const GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX: u32 = 33158;
+pub const GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX: u32 = 33159;
+pub const GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX: u32 = 33160;
+pub const GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX: u32 = 33161;
+pub const GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX: u32 = 33162;
+pub const GL_FRAMEZOOM_SGIX: u32 = 33163;
+pub const GL_FRAMEZOOM_FACTOR_SGIX: u32 = 33164;
+pub const GL_MAX_FRAMEZOOM_FACTOR_SGIX: u32 = 33165;
+pub const GL_TEXTURE_LOD_BIAS_S_SGIX: u32 = 33166;
+pub const GL_TEXTURE_LOD_BIAS_T_SGIX: u32 = 33167;
+pub const GL_TEXTURE_LOD_BIAS_R_SGIX: u32 = 33168;
+pub const GL_GENERATE_MIPMAP: u32 = 33169;
+pub const GL_GENERATE_MIPMAP_SGIS: u32 = 33169;
+pub const GL_GENERATE_MIPMAP_HINT: u32 = 33170;
+pub const GL_GENERATE_MIPMAP_HINT_SGIS: u32 = 33170;
+pub const GL_GEOMETRY_DEFORMATION_SGIX: u32 = 33172;
+pub const GL_TEXTURE_DEFORMATION_SGIX: u32 = 33173;
+pub const GL_DEFORMATIONS_MASK_SGIX: u32 = 33174;
+pub const GL_MAX_DEFORMATION_ORDER_SGIX: u32 = 33175;
+pub const GL_FOG_OFFSET_SGIX: u32 = 33176;
+pub const GL_FOG_OFFSET_VALUE_SGIX: u32 = 33177;
+pub const GL_TEXTURE_COMPARE_SGIX: u32 = 33178;
+pub const GL_TEXTURE_COMPARE_OPERATOR_SGIX: u32 = 33179;
+pub const GL_TEXTURE_LEQUAL_R_SGIX: u32 = 33180;
+pub const GL_TEXTURE_GEQUAL_R_SGIX: u32 = 33181;
+pub const GL_DEPTH_COMPONENT16: u32 = 33189;
+pub const GL_DEPTH_COMPONENT16_ARB: u32 = 33189;
+pub const GL_DEPTH_COMPONENT16_OES: u32 = 33189;
+pub const GL_DEPTH_COMPONENT16_SGIX: u32 = 33189;
+pub const GL_DEPTH_COMPONENT24: u32 = 33190;
+pub const GL_DEPTH_COMPONENT24_ARB: u32 = 33190;
+pub const GL_DEPTH_COMPONENT24_OES: u32 = 33190;
+pub const GL_DEPTH_COMPONENT24_SGIX: u32 = 33190;
+pub const GL_DEPTH_COMPONENT32: u32 = 33191;
+pub const GL_DEPTH_COMPONENT32_ARB: u32 = 33191;
+pub const GL_DEPTH_COMPONENT32_OES: u32 = 33191;
+pub const GL_DEPTH_COMPONENT32_SGIX: u32 = 33191;
+pub const GL_ARRAY_ELEMENT_LOCK_FIRST_EXT: u32 = 33192;
+pub const GL_ARRAY_ELEMENT_LOCK_COUNT_EXT: u32 = 33193;
+pub const GL_CULL_VERTEX_EXT: u32 = 33194;
+pub const GL_CULL_VERTEX_EYE_POSITION_EXT: u32 = 33195;
+pub const GL_CULL_VERTEX_OBJECT_POSITION_EXT: u32 = 33196;
+pub const GL_IUI_V2F_EXT: u32 = 33197;
+pub const GL_IUI_V3F_EXT: u32 = 33198;
+pub const GL_IUI_N3F_V2F_EXT: u32 = 33199;
+pub const GL_IUI_N3F_V3F_EXT: u32 = 33200;
+pub const GL_T2F_IUI_V2F_EXT: u32 = 33201;
+pub const GL_T2F_IUI_V3F_EXT: u32 = 33202;
+pub const GL_T2F_IUI_N3F_V2F_EXT: u32 = 33203;
+pub const GL_T2F_IUI_N3F_V3F_EXT: u32 = 33204;
+pub const GL_INDEX_TEST_EXT: u32 = 33205;
+pub const GL_INDEX_TEST_FUNC_EXT: u32 = 33206;
+pub const GL_INDEX_TEST_REF_EXT: u32 = 33207;
+pub const GL_INDEX_MATERIAL_EXT: u32 = 33208;
+pub const GL_INDEX_MATERIAL_PARAMETER_EXT: u32 = 33209;
+pub const GL_INDEX_MATERIAL_FACE_EXT: u32 = 33210;
+pub const GL_YCRCB_422_SGIX: u32 = 33211;
+pub const GL_YCRCB_444_SGIX: u32 = 33212;
+pub const GL_WRAP_BORDER_SUN: u32 = 33236;
+pub const GL_UNPACK_CONSTANT_DATA_SUNX: u32 = 33237;
+pub const GL_TEXTURE_CONSTANT_DATA_SUNX: u32 = 33238;
+pub const GL_TRIANGLE_LIST_SUN: u32 = 33239;
+pub const GL_REPLACEMENT_CODE_SUN: u32 = 33240;
+pub const GL_GLOBAL_ALPHA_SUN: u32 = 33241;
+pub const GL_GLOBAL_ALPHA_FACTOR_SUN: u32 = 33242;
+pub const GL_TEXTURE_COLOR_WRITEMASK_SGIS: u32 = 33263;
+pub const GL_EYE_DISTANCE_TO_POINT_SGIS: u32 = 33264;
+pub const GL_OBJECT_DISTANCE_TO_POINT_SGIS: u32 = 33265;
+pub const GL_EYE_DISTANCE_TO_LINE_SGIS: u32 = 33266;
+pub const GL_OBJECT_DISTANCE_TO_LINE_SGIS: u32 = 33267;
+pub const GL_EYE_POINT_SGIS: u32 = 33268;
+pub const GL_OBJECT_POINT_SGIS: u32 = 33269;
+pub const GL_EYE_LINE_SGIS: u32 = 33270;
+pub const GL_OBJECT_LINE_SGIS: u32 = 33271;
+pub const GL_LIGHT_MODEL_COLOR_CONTROL: u32 = 33272;
+pub const GL_LIGHT_MODEL_COLOR_CONTROL_EXT: u32 = 33272;
+pub const GL_SINGLE_COLOR: u32 = 33273;
+pub const GL_SINGLE_COLOR_EXT: u32 = 33273;
+pub const GL_SEPARATE_SPECULAR_COLOR: u32 = 33274;
+pub const GL_SEPARATE_SPECULAR_COLOR_EXT: u32 = 33274;
+pub const GL_SHARED_TEXTURE_PALETTE_EXT: u32 = 33275;
+pub const GL_TEXT_FRAGMENT_SHADER_ATI: u32 = 33280;
+pub const GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: u32 = 33296;
+pub const GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: u32 = 33296;
+pub const GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: u32 = 33297;
+pub const GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT: u32 = 33297;
+pub const GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: u32 = 33298;
+pub const GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: u32 = 33299;
+pub const GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: u32 = 33300;
+pub const GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: u32 = 33301;
+pub const GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: u32 = 33302;
+pub const GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: u32 = 33303;
+pub const GL_FRAMEBUFFER_DEFAULT: u32 = 33304;
+pub const GL_FRAMEBUFFER_UNDEFINED: u32 = 33305;
+pub const GL_FRAMEBUFFER_UNDEFINED_OES: u32 = 33305;
+pub const GL_DEPTH_STENCIL_ATTACHMENT: u32 = 33306;
+pub const GL_MAJOR_VERSION: u32 = 33307;
+pub const GL_MINOR_VERSION: u32 = 33308;
+pub const GL_NUM_EXTENSIONS: u32 = 33309;
+pub const GL_CONTEXT_FLAGS: u32 = 33310;
+pub const GL_BUFFER_IMMUTABLE_STORAGE: u32 = 33311;
+pub const GL_BUFFER_IMMUTABLE_STORAGE_EXT: u32 = 33311;
+pub const GL_BUFFER_STORAGE_FLAGS: u32 = 33312;
+pub const GL_BUFFER_STORAGE_FLAGS_EXT: u32 = 33312;
+pub const GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED: u32 = 33313;
+pub const GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED_OES: u32 = 33313;
+pub const GL_INDEX: u32 = 33314;
+pub const GL_COMPRESSED_RED: u32 = 33317;
+pub const GL_COMPRESSED_RG: u32 = 33318;
+pub const GL_RG: u32 = 33319;
+pub const GL_RG_EXT: u32 = 33319;
+pub const GL_RG_INTEGER: u32 = 33320;
+pub const GL_R8: u32 = 33321;
+pub const GL_R8_EXT: u32 = 33321;
+pub const GL_R16: u32 = 33322;
+pub const GL_R16_EXT: u32 = 33322;
+pub const GL_RG8: u32 = 33323;
+pub const GL_RG8_EXT: u32 = 33323;
+pub const GL_RG16: u32 = 33324;
+pub const GL_RG16_EXT: u32 = 33324;
+pub const GL_R16F: u32 = 33325;
+pub const GL_R16F_EXT: u32 = 33325;
+pub const GL_R32F: u32 = 33326;
+pub const GL_R32F_EXT: u32 = 33326;
+pub const GL_RG16F: u32 = 33327;
+pub const GL_RG16F_EXT: u32 = 33327;
+pub const GL_RG32F: u32 = 33328;
+pub const GL_RG32F_EXT: u32 = 33328;
+pub const GL_R8I: u32 = 33329;
+pub const GL_R8UI: u32 = 33330;
+pub const GL_R16I: u32 = 33331;
+pub const GL_R16UI: u32 = 33332;
+pub const GL_R32I: u32 = 33333;
+pub const GL_R32UI: u32 = 33334;
+pub const GL_RG8I: u32 = 33335;
+pub const GL_RG8UI: u32 = 33336;
+pub const GL_RG16I: u32 = 33337;
+pub const GL_RG16UI: u32 = 33338;
+pub const GL_RG32I: u32 = 33339;
+pub const GL_RG32UI: u32 = 33340;
+pub const GL_SYNC_CL_EVENT_ARB: u32 = 33344;
+pub const GL_SYNC_CL_EVENT_COMPLETE_ARB: u32 = 33345;
+pub const GL_DEBUG_OUTPUT_SYNCHRONOUS: u32 = 33346;
+pub const GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB: u32 = 33346;
+pub const GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR: u32 = 33346;
+pub const GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH: u32 = 33347;
+pub const GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB: u32 = 33347;
+pub const GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR: u32 = 33347;
+pub const GL_DEBUG_CALLBACK_FUNCTION: u32 = 33348;
+pub const GL_DEBUG_CALLBACK_FUNCTION_ARB: u32 = 33348;
+pub const GL_DEBUG_CALLBACK_FUNCTION_KHR: u32 = 33348;
+pub const GL_DEBUG_CALLBACK_USER_PARAM: u32 = 33349;
+pub const GL_DEBUG_CALLBACK_USER_PARAM_ARB: u32 = 33349;
+pub const GL_DEBUG_CALLBACK_USER_PARAM_KHR: u32 = 33349;
+pub const GL_DEBUG_SOURCE_API: u32 = 33350;
+pub const GL_DEBUG_SOURCE_API_ARB: u32 = 33350;
+pub const GL_DEBUG_SOURCE_API_KHR: u32 = 33350;
+pub const GL_DEBUG_SOURCE_WINDOW_SYSTEM: u32 = 33351;
+pub const GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: u32 = 33351;
+pub const GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR: u32 = 33351;
+pub const GL_DEBUG_SOURCE_SHADER_COMPILER: u32 = 33352;
+pub const GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: u32 = 33352;
+pub const GL_DEBUG_SOURCE_SHADER_COMPILER_KHR: u32 = 33352;
+pub const GL_DEBUG_SOURCE_THIRD_PARTY: u32 = 33353;
+pub const GL_DEBUG_SOURCE_THIRD_PARTY_ARB: u32 = 33353;
+pub const GL_DEBUG_SOURCE_THIRD_PARTY_KHR: u32 = 33353;
+pub const GL_DEBUG_SOURCE_APPLICATION: u32 = 33354;
+pub const GL_DEBUG_SOURCE_APPLICATION_ARB: u32 = 33354;
+pub const GL_DEBUG_SOURCE_APPLICATION_KHR: u32 = 33354;
+pub const GL_DEBUG_SOURCE_OTHER: u32 = 33355;
+pub const GL_DEBUG_SOURCE_OTHER_ARB: u32 = 33355;
+pub const GL_DEBUG_SOURCE_OTHER_KHR: u32 = 33355;
+pub const GL_DEBUG_TYPE_ERROR: u32 = 33356;
+pub const GL_DEBUG_TYPE_ERROR_ARB: u32 = 33356;
+pub const GL_DEBUG_TYPE_ERROR_KHR: u32 = 33356;
+pub const GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: u32 = 33357;
+pub const GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: u32 = 33357;
+pub const GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR: u32 = 33357;
+pub const GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: u32 = 33358;
+pub const GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: u32 = 33358;
+pub const GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR: u32 = 33358;
+pub const GL_DEBUG_TYPE_PORTABILITY: u32 = 33359;
+pub const GL_DEBUG_TYPE_PORTABILITY_ARB: u32 = 33359;
+pub const GL_DEBUG_TYPE_PORTABILITY_KHR: u32 = 33359;
+pub const GL_DEBUG_TYPE_PERFORMANCE: u32 = 33360;
+pub const GL_DEBUG_TYPE_PERFORMANCE_ARB: u32 = 33360;
+pub const GL_DEBUG_TYPE_PERFORMANCE_KHR: u32 = 33360;
+pub const GL_DEBUG_TYPE_OTHER: u32 = 33361;
+pub const GL_DEBUG_TYPE_OTHER_ARB: u32 = 33361;
+pub const GL_DEBUG_TYPE_OTHER_KHR: u32 = 33361;
+pub const GL_LOSE_CONTEXT_ON_RESET: u32 = 33362;
+pub const GL_LOSE_CONTEXT_ON_RESET_ARB: u32 = 33362;
+pub const GL_LOSE_CONTEXT_ON_RESET_EXT: u32 = 33362;
+pub const GL_LOSE_CONTEXT_ON_RESET_KHR: u32 = 33362;
+pub const GL_GUILTY_CONTEXT_RESET: u32 = 33363;
+pub const GL_GUILTY_CONTEXT_RESET_ARB: u32 = 33363;
+pub const GL_GUILTY_CONTEXT_RESET_EXT: u32 = 33363;
+pub const GL_GUILTY_CONTEXT_RESET_KHR: u32 = 33363;
+pub const GL_INNOCENT_CONTEXT_RESET: u32 = 33364;
+pub const GL_INNOCENT_CONTEXT_RESET_ARB: u32 = 33364;
+pub const GL_INNOCENT_CONTEXT_RESET_EXT: u32 = 33364;
+pub const GL_INNOCENT_CONTEXT_RESET_KHR: u32 = 33364;
+pub const GL_UNKNOWN_CONTEXT_RESET: u32 = 33365;
+pub const GL_UNKNOWN_CONTEXT_RESET_ARB: u32 = 33365;
+pub const GL_UNKNOWN_CONTEXT_RESET_EXT: u32 = 33365;
+pub const GL_UNKNOWN_CONTEXT_RESET_KHR: u32 = 33365;
+pub const GL_RESET_NOTIFICATION_STRATEGY: u32 = 33366;
+pub const GL_RESET_NOTIFICATION_STRATEGY_ARB: u32 = 33366;
+pub const GL_RESET_NOTIFICATION_STRATEGY_EXT: u32 = 33366;
+pub const GL_RESET_NOTIFICATION_STRATEGY_KHR: u32 = 33366;
+pub const GL_PROGRAM_BINARY_RETRIEVABLE_HINT: u32 = 33367;
+pub const GL_PROGRAM_SEPARABLE: u32 = 33368;
+pub const GL_PROGRAM_SEPARABLE_EXT: u32 = 33368;
+pub const GL_ACTIVE_PROGRAM: u32 = 33369;
+pub const GL_PROGRAM_PIPELINE_BINDING: u32 = 33370;
+pub const GL_PROGRAM_PIPELINE_BINDING_EXT: u32 = 33370;
+pub const GL_MAX_VIEWPORTS: u32 = 33371;
+pub const GL_MAX_VIEWPORTS_NV: u32 = 33371;
+pub const GL_MAX_VIEWPORTS_OES: u32 = 33371;
+pub const GL_VIEWPORT_SUBPIXEL_BITS: u32 = 33372;
+pub const GL_VIEWPORT_SUBPIXEL_BITS_EXT: u32 = 33372;
+pub const GL_VIEWPORT_SUBPIXEL_BITS_NV: u32 = 33372;
+pub const GL_VIEWPORT_SUBPIXEL_BITS_OES: u32 = 33372;
+pub const GL_VIEWPORT_BOUNDS_RANGE: u32 = 33373;
+pub const GL_VIEWPORT_BOUNDS_RANGE_EXT: u32 = 33373;
+pub const GL_VIEWPORT_BOUNDS_RANGE_NV: u32 = 33373;
+pub const GL_VIEWPORT_BOUNDS_RANGE_OES: u32 = 33373;
+pub const GL_LAYER_PROVOKING_VERTEX: u32 = 33374;
+pub const GL_LAYER_PROVOKING_VERTEX_EXT: u32 = 33374;
+pub const GL_LAYER_PROVOKING_VERTEX_OES: u32 = 33374;
+pub const GL_VIEWPORT_INDEX_PROVOKING_VERTEX: u32 = 33375;
+pub const GL_VIEWPORT_INDEX_PROVOKING_VERTEX_EXT: u32 = 33375;
+pub const GL_VIEWPORT_INDEX_PROVOKING_VERTEX_NV: u32 = 33375;
+pub const GL_VIEWPORT_INDEX_PROVOKING_VERTEX_OES: u32 = 33375;
+pub const GL_UNDEFINED_VERTEX: u32 = 33376;
+pub const GL_UNDEFINED_VERTEX_EXT: u32 = 33376;
+pub const GL_UNDEFINED_VERTEX_OES: u32 = 33376;
+pub const GL_NO_RESET_NOTIFICATION: u32 = 33377;
+pub const GL_NO_RESET_NOTIFICATION_ARB: u32 = 33377;
+pub const GL_NO_RESET_NOTIFICATION_EXT: u32 = 33377;
+pub const GL_NO_RESET_NOTIFICATION_KHR: u32 = 33377;
+pub const GL_MAX_COMPUTE_SHARED_MEMORY_SIZE: u32 = 33378;
+pub const GL_MAX_COMPUTE_UNIFORM_COMPONENTS: u32 = 33379;
+pub const GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS: u32 = 33380;
+pub const GL_MAX_COMPUTE_ATOMIC_COUNTERS: u32 = 33381;
+pub const GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS: u32 = 33382;
+pub const GL_COMPUTE_WORK_GROUP_SIZE: u32 = 33383;
+pub const GL_DEBUG_TYPE_MARKER: u32 = 33384;
+pub const GL_DEBUG_TYPE_MARKER_KHR: u32 = 33384;
+pub const GL_DEBUG_TYPE_PUSH_GROUP: u32 = 33385;
+pub const GL_DEBUG_TYPE_PUSH_GROUP_KHR: u32 = 33385;
+pub const GL_DEBUG_TYPE_POP_GROUP: u32 = 33386;
+pub const GL_DEBUG_TYPE_POP_GROUP_KHR: u32 = 33386;
+pub const GL_DEBUG_SEVERITY_NOTIFICATION: u32 = 33387;
+pub const GL_DEBUG_SEVERITY_NOTIFICATION_KHR: u32 = 33387;
+pub const GL_MAX_DEBUG_GROUP_STACK_DEPTH: u32 = 33388;
+pub const GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR: u32 = 33388;
+pub const GL_DEBUG_GROUP_STACK_DEPTH: u32 = 33389;
+pub const GL_DEBUG_GROUP_STACK_DEPTH_KHR: u32 = 33389;
+pub const GL_MAX_UNIFORM_LOCATIONS: u32 = 33390;
+pub const GL_INTERNALFORMAT_SUPPORTED: u32 = 33391;
+pub const GL_INTERNALFORMAT_PREFERRED: u32 = 33392;
+pub const GL_INTERNALFORMAT_RED_SIZE: u32 = 33393;
+pub const GL_INTERNALFORMAT_GREEN_SIZE: u32 = 33394;
+pub const GL_INTERNALFORMAT_BLUE_SIZE: u32 = 33395;
+pub const GL_INTERNALFORMAT_ALPHA_SIZE: u32 = 33396;
+pub const GL_INTERNALFORMAT_DEPTH_SIZE: u32 = 33397;
+pub const GL_INTERNALFORMAT_STENCIL_SIZE: u32 = 33398;
+pub const GL_INTERNALFORMAT_SHARED_SIZE: u32 = 33399;
+pub const GL_INTERNALFORMAT_RED_TYPE: u32 = 33400;
+pub const GL_INTERNALFORMAT_GREEN_TYPE: u32 = 33401;
+pub const GL_INTERNALFORMAT_BLUE_TYPE: u32 = 33402;
+pub const GL_INTERNALFORMAT_ALPHA_TYPE: u32 = 33403;
+pub const GL_INTERNALFORMAT_DEPTH_TYPE: u32 = 33404;
+pub const GL_INTERNALFORMAT_STENCIL_TYPE: u32 = 33405;
+pub const GL_MAX_WIDTH: u32 = 33406;
+pub const GL_MAX_HEIGHT: u32 = 33407;
+pub const GL_MAX_DEPTH: u32 = 33408;
+pub const GL_MAX_LAYERS: u32 = 33409;
+pub const GL_MAX_COMBINED_DIMENSIONS: u32 = 33410;
+pub const GL_COLOR_COMPONENTS: u32 = 33411;
+pub const GL_DEPTH_COMPONENTS: u32 = 33412;
+pub const GL_STENCIL_COMPONENTS: u32 = 33413;
+pub const GL_COLOR_RENDERABLE: u32 = 33414;
+pub const GL_DEPTH_RENDERABLE: u32 = 33415;
+pub const GL_STENCIL_RENDERABLE: u32 = 33416;
+pub const GL_FRAMEBUFFER_RENDERABLE: u32 = 33417;
+pub const GL_FRAMEBUFFER_RENDERABLE_LAYERED: u32 = 33418;
+pub const GL_FRAMEBUFFER_BLEND: u32 = 33419;
+pub const GL_READ_PIXELS: u32 = 33420;
+pub const GL_READ_PIXELS_FORMAT: u32 = 33421;
+pub const GL_READ_PIXELS_TYPE: u32 = 33422;
+pub const GL_TEXTURE_IMAGE_FORMAT: u32 = 33423;
+pub const GL_TEXTURE_IMAGE_TYPE: u32 = 33424;
+pub const GL_GET_TEXTURE_IMAGE_FORMAT: u32 = 33425;
+pub const GL_GET_TEXTURE_IMAGE_TYPE: u32 = 33426;
+pub const GL_MIPMAP: u32 = 33427;
+pub const GL_MANUAL_GENERATE_MIPMAP: u32 = 33428;
+pub const GL_AUTO_GENERATE_MIPMAP: u32 = 33429;
+pub const GL_COLOR_ENCODING: u32 = 33430;
+pub const GL_SRGB_READ: u32 = 33431;
+pub const GL_SRGB_WRITE: u32 = 33432;
+pub const GL_SRGB_DECODE_ARB: u32 = 33433;
+pub const GL_FILTER: u32 = 33434;
+pub const GL_VERTEX_TEXTURE: u32 = 33435;
+pub const GL_TESS_CONTROL_TEXTURE: u32 = 33436;
+pub const GL_TESS_EVALUATION_TEXTURE: u32 = 33437;
+pub const GL_GEOMETRY_TEXTURE: u32 = 33438;
+pub const GL_FRAGMENT_TEXTURE: u32 = 33439;
+pub const GL_COMPUTE_TEXTURE: u32 = 33440;
+pub const GL_TEXTURE_SHADOW: u32 = 33441;
+pub const GL_TEXTURE_GATHER: u32 = 33442;
+pub const GL_TEXTURE_GATHER_SHADOW: u32 = 33443;
+pub const GL_SHADER_IMAGE_LOAD: u32 = 33444;
+pub const GL_SHADER_IMAGE_STORE: u32 = 33445;
+pub const GL_SHADER_IMAGE_ATOMIC: u32 = 33446;
+pub const GL_IMAGE_TEXEL_SIZE: u32 = 33447;
+pub const GL_IMAGE_COMPATIBILITY_CLASS: u32 = 33448;
+pub const GL_IMAGE_PIXEL_FORMAT: u32 = 33449;
+pub const GL_IMAGE_PIXEL_TYPE: u32 = 33450;
+pub const GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST: u32 = 33452;
+pub const GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST: u32 = 33453;
+pub const GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE: u32 = 33454;
+pub const GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE: u32 = 33455;
+pub const GL_TEXTURE_COMPRESSED_BLOCK_WIDTH: u32 = 33457;
+pub const GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT: u32 = 33458;
+pub const GL_TEXTURE_COMPRESSED_BLOCK_SIZE: u32 = 33459;
+pub const GL_CLEAR_BUFFER: u32 = 33460;
+pub const GL_TEXTURE_VIEW: u32 = 33461;
+pub const GL_VIEW_COMPATIBILITY_CLASS: u32 = 33462;
+pub const GL_FULL_SUPPORT: u32 = 33463;
+pub const GL_CAVEAT_SUPPORT: u32 = 33464;
+pub const GL_IMAGE_CLASS_4_X_32: u32 = 33465;
+pub const GL_IMAGE_CLASS_2_X_32: u32 = 33466;
+pub const GL_IMAGE_CLASS_1_X_32: u32 = 33467;
+pub const GL_IMAGE_CLASS_4_X_16: u32 = 33468;
+pub const GL_IMAGE_CLASS_2_X_16: u32 = 33469;
+pub const GL_IMAGE_CLASS_1_X_16: u32 = 33470;
+pub const GL_IMAGE_CLASS_4_X_8: u32 = 33471;
+pub const GL_IMAGE_CLASS_2_X_8: u32 = 33472;
+pub const GL_IMAGE_CLASS_1_X_8: u32 = 33473;
+pub const GL_IMAGE_CLASS_11_11_10: u32 = 33474;
+pub const GL_IMAGE_CLASS_10_10_10_2: u32 = 33475;
+pub const GL_VIEW_CLASS_128_BITS: u32 = 33476;
+pub const GL_VIEW_CLASS_96_BITS: u32 = 33477;
+pub const GL_VIEW_CLASS_64_BITS: u32 = 33478;
+pub const GL_VIEW_CLASS_48_BITS: u32 = 33479;
+pub const GL_VIEW_CLASS_32_BITS: u32 = 33480;
+pub const GL_VIEW_CLASS_24_BITS: u32 = 33481;
+pub const GL_VIEW_CLASS_16_BITS: u32 = 33482;
+pub const GL_VIEW_CLASS_8_BITS: u32 = 33483;
+pub const GL_VIEW_CLASS_S3TC_DXT1_RGB: u32 = 33484;
+pub const GL_VIEW_CLASS_S3TC_DXT1_RGBA: u32 = 33485;
+pub const GL_VIEW_CLASS_S3TC_DXT3_RGBA: u32 = 33486;
+pub const GL_VIEW_CLASS_S3TC_DXT5_RGBA: u32 = 33487;
+pub const GL_VIEW_CLASS_RGTC1_RED: u32 = 33488;
+pub const GL_VIEW_CLASS_RGTC2_RG: u32 = 33489;
+pub const GL_VIEW_CLASS_BPTC_UNORM: u32 = 33490;
+pub const GL_VIEW_CLASS_BPTC_FLOAT: u32 = 33491;
+pub const GL_VERTEX_ATTRIB_BINDING: u32 = 33492;
+pub const GL_VERTEX_ATTRIB_RELATIVE_OFFSET: u32 = 33493;
+pub const GL_VERTEX_BINDING_DIVISOR: u32 = 33494;
+pub const GL_VERTEX_BINDING_OFFSET: u32 = 33495;
+pub const GL_VERTEX_BINDING_STRIDE: u32 = 33496;
+pub const GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET: u32 = 33497;
+pub const GL_MAX_VERTEX_ATTRIB_BINDINGS: u32 = 33498;
+pub const GL_TEXTURE_VIEW_MIN_LEVEL: u32 = 33499;
+pub const GL_TEXTURE_VIEW_MIN_LEVEL_EXT: u32 = 33499;
+pub const GL_TEXTURE_VIEW_MIN_LEVEL_OES: u32 = 33499;
+pub const GL_TEXTURE_VIEW_NUM_LEVELS: u32 = 33500;
+pub const GL_TEXTURE_VIEW_NUM_LEVELS_EXT: u32 = 33500;
+pub const GL_TEXTURE_VIEW_NUM_LEVELS_OES: u32 = 33500;
+pub const GL_TEXTURE_VIEW_MIN_LAYER: u32 = 33501;
+pub const GL_TEXTURE_VIEW_MIN_LAYER_EXT: u32 = 33501;
+pub const GL_TEXTURE_VIEW_MIN_LAYER_OES: u32 = 33501;
+pub const GL_TEXTURE_VIEW_NUM_LAYERS: u32 = 33502;
+pub const GL_TEXTURE_VIEW_NUM_LAYERS_EXT: u32 = 33502;
+pub const GL_TEXTURE_VIEW_NUM_LAYERS_OES: u32 = 33502;
+pub const GL_TEXTURE_IMMUTABLE_LEVELS: u32 = 33503;
+pub const GL_BUFFER: u32 = 33504;
+pub const GL_BUFFER_KHR: u32 = 33504;
+pub const GL_SHADER: u32 = 33505;
+pub const GL_SHADER_KHR: u32 = 33505;
+pub const GL_PROGRAM: u32 = 33506;
+pub const GL_PROGRAM_KHR: u32 = 33506;
+pub const GL_QUERY: u32 = 33507;
+pub const GL_QUERY_KHR: u32 = 33507;
+pub const GL_PROGRAM_PIPELINE: u32 = 33508;
+pub const GL_PROGRAM_PIPELINE_KHR: u32 = 33508;
+pub const GL_MAX_VERTEX_ATTRIB_STRIDE: u32 = 33509;
+pub const GL_SAMPLER: u32 = 33510;
+pub const GL_SAMPLER_KHR: u32 = 33510;
+pub const GL_DISPLAY_LIST: u32 = 33511;
+pub const GL_MAX_LABEL_LENGTH: u32 = 33512;
+pub const GL_MAX_LABEL_LENGTH_KHR: u32 = 33512;
+pub const GL_NUM_SHADING_LANGUAGE_VERSIONS: u32 = 33513;
+pub const GL_QUERY_TARGET: u32 = 33514;
+pub const GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB: u32 = 33516;
+pub const GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB: u32 = 33517;
+pub const GL_VERTICES_SUBMITTED_ARB: u32 = 33518;
+pub const GL_PRIMITIVES_SUBMITTED_ARB: u32 = 33519;
+pub const GL_VERTEX_SHADER_INVOCATIONS_ARB: u32 = 33520;
+pub const GL_TESS_CONTROL_SHADER_PATCHES_ARB: u32 = 33521;
+pub const GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB: u32 = 33522;
+pub const GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB: u32 = 33523;
+pub const GL_FRAGMENT_SHADER_INVOCATIONS_ARB: u32 = 33524;
+pub const GL_COMPUTE_SHADER_INVOCATIONS_ARB: u32 = 33525;
+pub const GL_CLIPPING_INPUT_PRIMITIVES_ARB: u32 = 33526;
+pub const GL_CLIPPING_OUTPUT_PRIMITIVES_ARB: u32 = 33527;
+pub const GL_SPARSE_BUFFER_PAGE_SIZE_ARB: u32 = 33528;
+pub const GL_MAX_CULL_DISTANCES: u32 = 33529;
+pub const GL_MAX_CULL_DISTANCES_EXT: u32 = 33529;
+pub const GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES: u32 = 33530;
+pub const GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT: u32 = 33530;
+pub const GL_CONTEXT_RELEASE_BEHAVIOR: u32 = 33531;
+pub const GL_CONTEXT_RELEASE_BEHAVIOR_KHR: u32 = 33531;
+pub const GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH: u32 = 33532;
+pub const GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR: u32 = 33532;
+pub const GL_DEPTH_PASS_INSTRUMENT_SGIX: u32 = 33552;
+pub const GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX: u32 = 33553;
+pub const GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX: u32 = 33554;
+pub const GL_FRAGMENTS_INSTRUMENT_SGIX: u32 = 33555;
+pub const GL_FRAGMENTS_INSTRUMENT_COUNTERS_SGIX: u32 = 33556;
+pub const GL_FRAGMENTS_INSTRUMENT_MAX_SGIX: u32 = 33557;
+pub const GL_CONVOLUTION_HINT_SGIX: u32 = 33558;
+pub const GL_YCRCB_SGIX: u32 = 33560;
+pub const GL_YCRCBA_SGIX: u32 = 33561;
+pub const GL_UNPACK_COMPRESSED_SIZE_SGIX: u32 = 33562;
+pub const GL_PACK_MAX_COMPRESSED_SIZE_SGIX: u32 = 33563;
+pub const GL_PACK_COMPRESSED_SIZE_SGIX: u32 = 33564;
+pub const GL_SLIM8U_SGIX: u32 = 33565;
+pub const GL_SLIM10U_SGIX: u32 = 33566;
+pub const GL_SLIM12S_SGIX: u32 = 33567;
+pub const GL_ALPHA_MIN_SGIX: u32 = 33568;
+pub const GL_ALPHA_MAX_SGIX: u32 = 33569;
+pub const GL_SCALEBIAS_HINT_SGIX: u32 = 33570;
+pub const GL_ASYNC_MARKER_SGIX: u32 = 33577;
+pub const GL_PIXEL_TEX_GEN_MODE_SGIX: u32 = 33579;
+pub const GL_ASYNC_HISTOGRAM_SGIX: u32 = 33580;
+pub const GL_MAX_ASYNC_HISTOGRAM_SGIX: u32 = 33581;
+pub const GL_PIXEL_TRANSFORM_2D_EXT: u32 = 33584;
+pub const GL_PIXEL_MAG_FILTER_EXT: u32 = 33585;
+pub const GL_PIXEL_MIN_FILTER_EXT: u32 = 33586;
+pub const GL_PIXEL_CUBIC_WEIGHT_EXT: u32 = 33587;
+pub const GL_CUBIC_EXT: u32 = 33588;
+pub const GL_AVERAGE_EXT: u32 = 33589;
+pub const GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT: u32 = 33590;
+pub const GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT: u32 = 33591;
+pub const GL_PIXEL_TRANSFORM_2D_MATRIX_EXT: u32 = 33592;
+pub const GL_FRAGMENT_MATERIAL_EXT: u32 = 33609;
+pub const GL_FRAGMENT_NORMAL_EXT: u32 = 33610;
+pub const GL_FRAGMENT_COLOR_EXT: u32 = 33612;
+pub const GL_ATTENUATION_EXT: u32 = 33613;
+pub const GL_SHADOW_ATTENUATION_EXT: u32 = 33614;
+pub const GL_TEXTURE_APPLICATION_MODE_EXT: u32 = 33615;
+pub const GL_TEXTURE_LIGHT_EXT: u32 = 33616;
+pub const GL_TEXTURE_MATERIAL_FACE_EXT: u32 = 33617;
+pub const GL_TEXTURE_MATERIAL_PARAMETER_EXT: u32 = 33618;
+pub const GL_PIXEL_TEXTURE_SGIS: u32 = 33619;
+pub const GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS: u32 = 33620;
+pub const GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS: u32 = 33621;
+pub const GL_PIXEL_GROUP_COLOR_SGIS: u32 = 33622;
+pub const GL_LINE_QUALITY_HINT_SGIX: u32 = 33627;
+pub const GL_ASYNC_TEX_IMAGE_SGIX: u32 = 33628;
+pub const GL_ASYNC_DRAW_PIXELS_SGIX: u32 = 33629;
+pub const GL_ASYNC_READ_PIXELS_SGIX: u32 = 33630;
+pub const GL_MAX_ASYNC_TEX_IMAGE_SGIX: u32 = 33631;
+pub const GL_MAX_ASYNC_DRAW_PIXELS_SGIX: u32 = 33632;
+pub const GL_MAX_ASYNC_READ_PIXELS_SGIX: u32 = 33633;
+pub const GL_UNSIGNED_BYTE_2_3_3_REV: u32 = 33634;
+pub const GL_UNSIGNED_BYTE_2_3_3_REV_EXT: u32 = 33634;
+pub const GL_UNSIGNED_SHORT_5_6_5: u32 = 33635;
+pub const GL_UNSIGNED_SHORT_5_6_5_EXT: u32 = 33635;
+pub const GL_UNSIGNED_SHORT_5_6_5_REV: u32 = 33636;
+pub const GL_UNSIGNED_SHORT_5_6_5_REV_EXT: u32 = 33636;
+pub const GL_UNSIGNED_SHORT_4_4_4_4_REV: u32 = 33637;
+pub const GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: u32 = 33637;
+pub const GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG: u32 = 33637;
+pub const GL_UNSIGNED_SHORT_1_5_5_5_REV: u32 = 33638;
+pub const GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: u32 = 33638;
+pub const GL_UNSIGNED_INT_8_8_8_8_REV: u32 = 33639;
+pub const GL_UNSIGNED_INT_8_8_8_8_REV_EXT: u32 = 33639;
+pub const GL_UNSIGNED_INT_2_10_10_10_REV: u32 = 33640;
+pub const GL_UNSIGNED_INT_2_10_10_10_REV_EXT: u32 = 33640;
+pub const GL_TEXTURE_MAX_CLAMP_S_SGIX: u32 = 33641;
+pub const GL_TEXTURE_MAX_CLAMP_T_SGIX: u32 = 33642;
+pub const GL_TEXTURE_MAX_CLAMP_R_SGIX: u32 = 33643;
+pub const GL_MIRRORED_REPEAT: u32 = 33648;
+pub const GL_MIRRORED_REPEAT_ARB: u32 = 33648;
+pub const GL_MIRRORED_REPEAT_IBM: u32 = 33648;
+pub const GL_MIRRORED_REPEAT_OES: u32 = 33648;
+pub const GL_RGB_S3TC: u32 = 33696;
+pub const GL_RGB4_S3TC: u32 = 33697;
+pub const GL_RGBA_S3TC: u32 = 33698;
+pub const GL_RGBA4_S3TC: u32 = 33699;
+pub const GL_RGBA_DXT5_S3TC: u32 = 33700;
+pub const GL_RGBA4_DXT5_S3TC: u32 = 33701;
+pub const GL_VERTEX_PRECLIP_SGIX: u32 = 33774;
+pub const GL_VERTEX_PRECLIP_HINT_SGIX: u32 = 33775;
+pub const GL_COMPRESSED_RGB_S3TC_DXT1_EXT: u32 = 33776;
+pub const GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: u32 = 33777;
+pub const GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: u32 = 33778;
+pub const GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: u32 = 33778;
+pub const GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: u32 = 33779;
+pub const GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: u32 = 33779;
+pub const GL_PARALLEL_ARRAYS_INTEL: u32 = 33780;
+pub const GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL: u32 = 33781;
+pub const GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL: u32 = 33782;
+pub const GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL: u32 = 33783;
+pub const GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL: u32 = 33784;
+pub const GL_PERFQUERY_DONOT_FLUSH_INTEL: u32 = 33785;
+pub const GL_PERFQUERY_FLUSH_INTEL: u32 = 33786;
+pub const GL_PERFQUERY_WAIT_INTEL: u32 = 33787;
+pub const GL_CONSERVATIVE_RASTERIZATION_INTEL: u32 = 33790;
+pub const GL_TEXTURE_MEMORY_LAYOUT_INTEL: u32 = 33791;
+pub const GL_FRAGMENT_LIGHTING_SGIX: u32 = 33792;
+pub const GL_FRAGMENT_COLOR_MATERIAL_SGIX: u32 = 33793;
+pub const GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX: u32 = 33794;
+pub const GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX: u32 = 33795;
+pub const GL_MAX_FRAGMENT_LIGHTS_SGIX: u32 = 33796;
+pub const GL_MAX_ACTIVE_LIGHTS_SGIX: u32 = 33797;
+pub const GL_CURRENT_RASTER_NORMAL_SGIX: u32 = 33798;
+pub const GL_LIGHT_ENV_MODE_SGIX: u32 = 33799;
+pub const GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX: u32 = 33800;
+pub const GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX: u32 = 33801;
+pub const GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX: u32 = 33802;
+pub const GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX: u32 = 33803;
+pub const GL_FRAGMENT_LIGHT0_SGIX: u32 = 33804;
+pub const GL_FRAGMENT_LIGHT1_SGIX: u32 = 33805;
+pub const GL_FRAGMENT_LIGHT2_SGIX: u32 = 33806;
+pub const GL_FRAGMENT_LIGHT3_SGIX: u32 = 33807;
+pub const GL_FRAGMENT_LIGHT4_SGIX: u32 = 33808;
+pub const GL_FRAGMENT_LIGHT5_SGIX: u32 = 33809;
+pub const GL_FRAGMENT_LIGHT6_SGIX: u32 = 33810;
+pub const GL_FRAGMENT_LIGHT7_SGIX: u32 = 33811;
+pub const GL_PACK_RESAMPLE_SGIX: u32 = 33838;
+pub const GL_UNPACK_RESAMPLE_SGIX: u32 = 33839;
+pub const GL_RESAMPLE_DECIMATE_SGIX: u32 = 33840;
+pub const GL_RESAMPLE_REPLICATE_SGIX: u32 = 33843;
+pub const GL_RESAMPLE_ZERO_FILL_SGIX: u32 = 33844;
+pub const GL_TANGENT_ARRAY_EXT: u32 = 33849;
+pub const GL_BINORMAL_ARRAY_EXT: u32 = 33850;
+pub const GL_CURRENT_TANGENT_EXT: u32 = 33851;
+pub const GL_CURRENT_BINORMAL_EXT: u32 = 33852;
+pub const GL_TANGENT_ARRAY_TYPE_EXT: u32 = 33854;
+pub const GL_TANGENT_ARRAY_STRIDE_EXT: u32 = 33855;
+pub const GL_BINORMAL_ARRAY_TYPE_EXT: u32 = 33856;
+pub const GL_BINORMAL_ARRAY_STRIDE_EXT: u32 = 33857;
+pub const GL_TANGENT_ARRAY_POINTER_EXT: u32 = 33858;
+pub const GL_BINORMAL_ARRAY_POINTER_EXT: u32 = 33859;
+pub const GL_MAP1_TANGENT_EXT: u32 = 33860;
+pub const GL_MAP2_TANGENT_EXT: u32 = 33861;
+pub const GL_MAP1_BINORMAL_EXT: u32 = 33862;
+pub const GL_MAP2_BINORMAL_EXT: u32 = 33863;
+pub const GL_NEAREST_CLIPMAP_NEAREST_SGIX: u32 = 33869;
+pub const GL_NEAREST_CLIPMAP_LINEAR_SGIX: u32 = 33870;
+pub const GL_LINEAR_CLIPMAP_NEAREST_SGIX: u32 = 33871;
+pub const GL_FOG_COORDINATE_SOURCE: u32 = 33872;
+pub const GL_FOG_COORDINATE_SOURCE_EXT: u32 = 33872;
+pub const GL_FOG_COORD_SRC: u32 = 33872;
+pub const GL_FOG_COORD: u32 = 33873;
+pub const GL_FOG_COORDINATE: u32 = 33873;
+pub const GL_FOG_COORDINATE_EXT: u32 = 33873;
+pub const GL_FRAGMENT_DEPTH: u32 = 33874;
+pub const GL_FRAGMENT_DEPTH_EXT: u32 = 33874;
+pub const GL_CURRENT_FOG_COORD: u32 = 33875;
+pub const GL_CURRENT_FOG_COORDINATE: u32 = 33875;
+pub const GL_CURRENT_FOG_COORDINATE_EXT: u32 = 33875;
+pub const GL_FOG_COORDINATE_ARRAY_TYPE: u32 = 33876;
+pub const GL_FOG_COORDINATE_ARRAY_TYPE_EXT: u32 = 33876;
+pub const GL_FOG_COORD_ARRAY_TYPE: u32 = 33876;
+pub const GL_FOG_COORDINATE_ARRAY_STRIDE: u32 = 33877;
+pub const GL_FOG_COORDINATE_ARRAY_STRIDE_EXT: u32 = 33877;
+pub const GL_FOG_COORD_ARRAY_STRIDE: u32 = 33877;
+pub const GL_FOG_COORDINATE_ARRAY_POINTER: u32 = 33878;
+pub const GL_FOG_COORDINATE_ARRAY_POINTER_EXT: u32 = 33878;
+pub const GL_FOG_COORD_ARRAY_POINTER: u32 = 33878;
+pub const GL_FOG_COORDINATE_ARRAY: u32 = 33879;
+pub const GL_FOG_COORDINATE_ARRAY_EXT: u32 = 33879;
+pub const GL_FOG_COORD_ARRAY: u32 = 33879;
+pub const GL_COLOR_SUM: u32 = 33880;
+pub const GL_COLOR_SUM_ARB: u32 = 33880;
+pub const GL_COLOR_SUM_EXT: u32 = 33880;
+pub const GL_CURRENT_SECONDARY_COLOR: u32 = 33881;
+pub const GL_CURRENT_SECONDARY_COLOR_EXT: u32 = 33881;
+pub const GL_SECONDARY_COLOR_ARRAY_SIZE: u32 = 33882;
+pub const GL_SECONDARY_COLOR_ARRAY_SIZE_EXT: u32 = 33882;
+pub const GL_SECONDARY_COLOR_ARRAY_TYPE: u32 = 33883;
+pub const GL_SECONDARY_COLOR_ARRAY_TYPE_EXT: u32 = 33883;
+pub const GL_SECONDARY_COLOR_ARRAY_STRIDE: u32 = 33884;
+pub const GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT: u32 = 33884;
+pub const GL_SECONDARY_COLOR_ARRAY_POINTER: u32 = 33885;
+pub const GL_SECONDARY_COLOR_ARRAY_POINTER_EXT: u32 = 33885;
+pub const GL_SECONDARY_COLOR_ARRAY: u32 = 33886;
+pub const GL_SECONDARY_COLOR_ARRAY_EXT: u32 = 33886;
+pub const GL_CURRENT_RASTER_SECONDARY_COLOR: u32 = 33887;
+pub const GL_ALIASED_POINT_SIZE_RANGE: u32 = 33901;
+pub const GL_ALIASED_LINE_WIDTH_RANGE: u32 = 33902;
+pub const GL_SCREEN_COORDINATES_REND: u32 = 33936;
+pub const GL_INVERTED_SCREEN_W_REND: u32 = 33937;
+pub const GL_TEXTURE0: u32 = 33984;
+pub const GL_TEXTURE0_ARB: u32 = 33984;
+pub const GL_TEXTURE1: u32 = 33985;
+pub const GL_TEXTURE1_ARB: u32 = 33985;
+pub const GL_TEXTURE2: u32 = 33986;
+pub const GL_TEXTURE2_ARB: u32 = 33986;
+pub const GL_TEXTURE3: u32 = 33987;
+pub const GL_TEXTURE3_ARB: u32 = 33987;
+pub const GL_TEXTURE4: u32 = 33988;
+pub const GL_TEXTURE4_ARB: u32 = 33988;
+pub const GL_TEXTURE5: u32 = 33989;
+pub const GL_TEXTURE5_ARB: u32 = 33989;
+pub const GL_TEXTURE6: u32 = 33990;
+pub const GL_TEXTURE6_ARB: u32 = 33990;
+pub const GL_TEXTURE7: u32 = 33991;
+pub const GL_TEXTURE7_ARB: u32 = 33991;
+pub const GL_TEXTURE8: u32 = 33992;
+pub const GL_TEXTURE8_ARB: u32 = 33992;
+pub const GL_TEXTURE9: u32 = 33993;
+pub const GL_TEXTURE9_ARB: u32 = 33993;
+pub const GL_TEXTURE10: u32 = 33994;
+pub const GL_TEXTURE10_ARB: u32 = 33994;
+pub const GL_TEXTURE11: u32 = 33995;
+pub const GL_TEXTURE11_ARB: u32 = 33995;
+pub const GL_TEXTURE12: u32 = 33996;
+pub const GL_TEXTURE12_ARB: u32 = 33996;
+pub const GL_TEXTURE13: u32 = 33997;
+pub const GL_TEXTURE13_ARB: u32 = 33997;
+pub const GL_TEXTURE14: u32 = 33998;
+pub const GL_TEXTURE14_ARB: u32 = 33998;
+pub const GL_TEXTURE15: u32 = 33999;
+pub const GL_TEXTURE15_ARB: u32 = 33999;
+pub const GL_TEXTURE16: u32 = 34000;
+pub const GL_TEXTURE16_ARB: u32 = 34000;
+pub const GL_TEXTURE17: u32 = 34001;
+pub const GL_TEXTURE17_ARB: u32 = 34001;
+pub const GL_TEXTURE18: u32 = 34002;
+pub const GL_TEXTURE18_ARB: u32 = 34002;
+pub const GL_TEXTURE19: u32 = 34003;
+pub const GL_TEXTURE19_ARB: u32 = 34003;
+pub const GL_TEXTURE20: u32 = 34004;
+pub const GL_TEXTURE20_ARB: u32 = 34004;
+pub const GL_TEXTURE21: u32 = 34005;
+pub const GL_TEXTURE21_ARB: u32 = 34005;
+pub const GL_TEXTURE22: u32 = 34006;
+pub const GL_TEXTURE22_ARB: u32 = 34006;
+pub const GL_TEXTURE23: u32 = 34007;
+pub const GL_TEXTURE23_ARB: u32 = 34007;
+pub const GL_TEXTURE24: u32 = 34008;
+pub const GL_TEXTURE24_ARB: u32 = 34008;
+pub const GL_TEXTURE25: u32 = 34009;
+pub const GL_TEXTURE25_ARB: u32 = 34009;
+pub const GL_TEXTURE26: u32 = 34010;
+pub const GL_TEXTURE26_ARB: u32 = 34010;
+pub const GL_TEXTURE27: u32 = 34011;
+pub const GL_TEXTURE27_ARB: u32 = 34011;
+pub const GL_TEXTURE28: u32 = 34012;
+pub const GL_TEXTURE28_ARB: u32 = 34012;
+pub const GL_TEXTURE29: u32 = 34013;
+pub const GL_TEXTURE29_ARB: u32 = 34013;
+pub const GL_TEXTURE30: u32 = 34014;
+pub const GL_TEXTURE30_ARB: u32 = 34014;
+pub const GL_TEXTURE31: u32 = 34015;
+pub const GL_TEXTURE31_ARB: u32 = 34015;
+pub const GL_ACTIVE_TEXTURE: u32 = 34016;
+pub const GL_ACTIVE_TEXTURE_ARB: u32 = 34016;
+pub const GL_CLIENT_ACTIVE_TEXTURE: u32 = 34017;
+pub const GL_CLIENT_ACTIVE_TEXTURE_ARB: u32 = 34017;
+pub const GL_MAX_TEXTURE_UNITS: u32 = 34018;
+pub const GL_MAX_TEXTURE_UNITS_ARB: u32 = 34018;
+pub const GL_PATH_TRANSPOSE_MODELVIEW_MATRIX_NV: u32 = 34019;
+pub const GL_TRANSPOSE_MODELVIEW_MATRIX: u32 = 34019;
+pub const GL_TRANSPOSE_MODELVIEW_MATRIX_ARB: u32 = 34019;
+pub const GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV: u32 = 34020;
+pub const GL_TRANSPOSE_PROJECTION_MATRIX: u32 = 34020;
+pub const GL_TRANSPOSE_PROJECTION_MATRIX_ARB: u32 = 34020;
+pub const GL_TRANSPOSE_TEXTURE_MATRIX: u32 = 34021;
+pub const GL_TRANSPOSE_TEXTURE_MATRIX_ARB: u32 = 34021;
+pub const GL_TRANSPOSE_COLOR_MATRIX: u32 = 34022;
+pub const GL_TRANSPOSE_COLOR_MATRIX_ARB: u32 = 34022;
+pub const GL_SUBTRACT: u32 = 34023;
+pub const GL_SUBTRACT_ARB: u32 = 34023;
+pub const GL_MAX_RENDERBUFFER_SIZE: u32 = 34024;
+pub const GL_MAX_RENDERBUFFER_SIZE_EXT: u32 = 34024;
+pub const GL_MAX_RENDERBUFFER_SIZE_OES: u32 = 34024;
+pub const GL_COMPRESSED_ALPHA: u32 = 34025;
+pub const GL_COMPRESSED_ALPHA_ARB: u32 = 34025;
+pub const GL_COMPRESSED_LUMINANCE: u32 = 34026;
+pub const GL_COMPRESSED_LUMINANCE_ARB: u32 = 34026;
+pub const GL_COMPRESSED_LUMINANCE_ALPHA: u32 = 34027;
+pub const GL_COMPRESSED_LUMINANCE_ALPHA_ARB: u32 = 34027;
+pub const GL_COMPRESSED_INTENSITY: u32 = 34028;
+pub const GL_COMPRESSED_INTENSITY_ARB: u32 = 34028;
+pub const GL_COMPRESSED_RGB: u32 = 34029;
+pub const GL_COMPRESSED_RGB_ARB: u32 = 34029;
+pub const GL_COMPRESSED_RGBA: u32 = 34030;
+pub const GL_COMPRESSED_RGBA_ARB: u32 = 34030;
+pub const GL_TEXTURE_COMPRESSION_HINT: u32 = 34031;
+pub const GL_TEXTURE_COMPRESSION_HINT_ARB: u32 = 34031;
+pub const GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER: u32 = 34032;
+pub const GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER: u32 = 34033;
+pub const GL_ALL_COMPLETED_NV: u32 = 34034;
+pub const GL_FENCE_STATUS_NV: u32 = 34035;
+pub const GL_FENCE_CONDITION_NV: u32 = 34036;
+pub const GL_TEXTURE_RECTANGLE: u32 = 34037;
+pub const GL_TEXTURE_RECTANGLE_ARB: u32 = 34037;
+pub const GL_TEXTURE_RECTANGLE_NV: u32 = 34037;
+pub const GL_TEXTURE_BINDING_RECTANGLE: u32 = 34038;
+pub const GL_TEXTURE_BINDING_RECTANGLE_ARB: u32 = 34038;
+pub const GL_TEXTURE_BINDING_RECTANGLE_NV: u32 = 34038;
+pub const GL_PROXY_TEXTURE_RECTANGLE: u32 = 34039;
+pub const GL_PROXY_TEXTURE_RECTANGLE_ARB: u32 = 34039;
+pub const GL_PROXY_TEXTURE_RECTANGLE_NV: u32 = 34039;
+pub const GL_MAX_RECTANGLE_TEXTURE_SIZE: u32 = 34040;
+pub const GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB: u32 = 34040;
+pub const GL_MAX_RECTANGLE_TEXTURE_SIZE_NV: u32 = 34040;
+pub const GL_DEPTH_STENCIL: u32 = 34041;
+pub const GL_DEPTH_STENCIL_EXT: u32 = 34041;
+pub const GL_DEPTH_STENCIL_NV: u32 = 34041;
+pub const GL_DEPTH_STENCIL_OES: u32 = 34041;
+pub const GL_UNSIGNED_INT_24_8: u32 = 34042;
+pub const GL_UNSIGNED_INT_24_8_EXT: u32 = 34042;
+pub const GL_UNSIGNED_INT_24_8_NV: u32 = 34042;
+pub const GL_UNSIGNED_INT_24_8_OES: u32 = 34042;
+pub const GL_MAX_TEXTURE_LOD_BIAS: u32 = 34045;
+pub const GL_MAX_TEXTURE_LOD_BIAS_EXT: u32 = 34045;
+pub const GL_TEXTURE_MAX_ANISOTROPY_EXT: u32 = 34046;
+pub const GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: u32 = 34047;
+pub const GL_TEXTURE_FILTER_CONTROL: u32 = 34048;
+pub const GL_TEXTURE_FILTER_CONTROL_EXT: u32 = 34048;
+pub const GL_TEXTURE_LOD_BIAS: u32 = 34049;
+pub const GL_TEXTURE_LOD_BIAS_EXT: u32 = 34049;
+pub const GL_MODELVIEW1_STACK_DEPTH_EXT: u32 = 34050;
+pub const GL_COMBINE4_NV: u32 = 34051;
+pub const GL_MAX_SHININESS_NV: u32 = 34052;
+pub const GL_MAX_SPOT_EXPONENT_NV: u32 = 34053;
+pub const GL_MODELVIEW1_MATRIX_EXT: u32 = 34054;
+pub const GL_INCR_WRAP: u32 = 34055;
+pub const GL_INCR_WRAP_EXT: u32 = 34055;
+pub const GL_INCR_WRAP_OES: u32 = 34055;
+pub const GL_DECR_WRAP: u32 = 34056;
+pub const GL_DECR_WRAP_EXT: u32 = 34056;
+pub const GL_DECR_WRAP_OES: u32 = 34056;
+pub const GL_VERTEX_WEIGHTING_EXT: u32 = 34057;
+pub const GL_MODELVIEW1_ARB: u32 = 34058;
+pub const GL_MODELVIEW1_EXT: u32 = 34058;
+pub const GL_CURRENT_VERTEX_WEIGHT_EXT: u32 = 34059;
+pub const GL_VERTEX_WEIGHT_ARRAY_EXT: u32 = 34060;
+pub const GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT: u32 = 34061;
+pub const GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT: u32 = 34062;
+pub const GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT: u32 = 34063;
+pub const GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT: u32 = 34064;
+pub const GL_NORMAL_MAP: u32 = 34065;
+pub const GL_NORMAL_MAP_ARB: u32 = 34065;
+pub const GL_NORMAL_MAP_EXT: u32 = 34065;
+pub const GL_NORMAL_MAP_NV: u32 = 34065;
+pub const GL_NORMAL_MAP_OES: u32 = 34065;
+pub const GL_REFLECTION_MAP: u32 = 34066;
+pub const GL_REFLECTION_MAP_ARB: u32 = 34066;
+pub const GL_REFLECTION_MAP_EXT: u32 = 34066;
+pub const GL_REFLECTION_MAP_NV: u32 = 34066;
+pub const GL_REFLECTION_MAP_OES: u32 = 34066;
+pub const GL_TEXTURE_CUBE_MAP: u32 = 34067;
+pub const GL_TEXTURE_CUBE_MAP_ARB: u32 = 34067;
+pub const GL_TEXTURE_CUBE_MAP_EXT: u32 = 34067;
+pub const GL_TEXTURE_CUBE_MAP_OES: u32 = 34067;
+pub const GL_TEXTURE_BINDING_CUBE_MAP: u32 = 34068;
+pub const GL_TEXTURE_BINDING_CUBE_MAP_ARB: u32 = 34068;
+pub const GL_TEXTURE_BINDING_CUBE_MAP_EXT: u32 = 34068;
+pub const GL_TEXTURE_BINDING_CUBE_MAP_OES: u32 = 34068;
+pub const GL_TEXTURE_CUBE_MAP_POSITIVE_X: u32 = 34069;
+pub const GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: u32 = 34069;
+pub const GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT: u32 = 34069;
+pub const GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES: u32 = 34069;
+pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_X: u32 = 34070;
+pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: u32 = 34070;
+pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT: u32 = 34070;
+pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES: u32 = 34070;
+pub const GL_TEXTURE_CUBE_MAP_POSITIVE_Y: u32 = 34071;
+pub const GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: u32 = 34071;
+pub const GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT: u32 = 34071;
+pub const GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES: u32 = 34071;
+pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: u32 = 34072;
+pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: u32 = 34072;
+pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT: u32 = 34072;
+pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES: u32 = 34072;
+pub const GL_TEXTURE_CUBE_MAP_POSITIVE_Z: u32 = 34073;
+pub const GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: u32 = 34073;
+pub const GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT: u32 = 34073;
+pub const GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES: u32 = 34073;
+pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: u32 = 34074;
+pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: u32 = 34074;
+pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT: u32 = 34074;
+pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES: u32 = 34074;
+pub const GL_PROXY_TEXTURE_CUBE_MAP: u32 = 34075;
+pub const GL_PROXY_TEXTURE_CUBE_MAP_ARB: u32 = 34075;
+pub const GL_PROXY_TEXTURE_CUBE_MAP_EXT: u32 = 34075;
+pub const GL_MAX_CUBE_MAP_TEXTURE_SIZE: u32 = 34076;
+pub const GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB: u32 = 34076;
+pub const GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT: u32 = 34076;
+pub const GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES: u32 = 34076;
+pub const GL_VERTEX_ARRAY_RANGE_APPLE: u32 = 34077;
+pub const GL_VERTEX_ARRAY_RANGE_NV: u32 = 34077;
+pub const GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE: u32 = 34078;
+pub const GL_VERTEX_ARRAY_RANGE_LENGTH_NV: u32 = 34078;
+pub const GL_VERTEX_ARRAY_RANGE_VALID_NV: u32 = 34079;
+pub const GL_VERTEX_ARRAY_STORAGE_HINT_APPLE: u32 = 34079;
+pub const GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV: u32 = 34080;
+pub const GL_VERTEX_ARRAY_RANGE_POINTER_APPLE: u32 = 34081;
+pub const GL_VERTEX_ARRAY_RANGE_POINTER_NV: u32 = 34081;
+pub const GL_REGISTER_COMBINERS_NV: u32 = 34082;
+pub const GL_VARIABLE_A_NV: u32 = 34083;
+pub const GL_VARIABLE_B_NV: u32 = 34084;
+pub const GL_VARIABLE_C_NV: u32 = 34085;
+pub const GL_VARIABLE_D_NV: u32 = 34086;
+pub const GL_VARIABLE_E_NV: u32 = 34087;
+pub const GL_VARIABLE_F_NV: u32 = 34088;
+pub const GL_VARIABLE_G_NV: u32 = 34089;
+pub const GL_CONSTANT_COLOR0_NV: u32 = 34090;
+pub const GL_CONSTANT_COLOR1_NV: u32 = 34091;
+pub const GL_PRIMARY_COLOR_NV: u32 = 34092;
+pub const GL_SECONDARY_COLOR_NV: u32 = 34093;
+pub const GL_SPARE0_NV: u32 = 34094;
+pub const GL_SPARE1_NV: u32 = 34095;
+pub const GL_DISCARD_NV: u32 = 34096;
+pub const GL_E_TIMES_F_NV: u32 = 34097;
+pub const GL_SPARE0_PLUS_SECONDARY_COLOR_NV: u32 = 34098;
+pub const GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV: u32 = 34099;
+pub const GL_MULTISAMPLE_FILTER_HINT_NV: u32 = 34100;
+pub const GL_PER_STAGE_CONSTANTS_NV: u32 = 34101;
+pub const GL_UNSIGNED_IDENTITY_NV: u32 = 34102;
+pub const GL_UNSIGNED_INVERT_NV: u32 = 34103;
+pub const GL_EXPAND_NORMAL_NV: u32 = 34104;
+pub const GL_EXPAND_NEGATE_NV: u32 = 34105;
+pub const GL_HALF_BIAS_NORMAL_NV: u32 = 34106;
+pub const GL_HALF_BIAS_NEGATE_NV: u32 = 34107;
+pub const GL_SIGNED_IDENTITY_NV: u32 = 34108;
+pub const GL_SIGNED_NEGATE_NV: u32 = 34109;
+pub const GL_SCALE_BY_TWO_NV: u32 = 34110;
+pub const GL_SCALE_BY_FOUR_NV: u32 = 34111;
+pub const GL_SCALE_BY_ONE_HALF_NV: u32 = 34112;
+pub const GL_BIAS_BY_NEGATIVE_ONE_HALF_NV: u32 = 34113;
+pub const GL_COMBINER_INPUT_NV: u32 = 34114;
+pub const GL_COMBINER_MAPPING_NV: u32 = 34115;
+pub const GL_COMBINER_COMPONENT_USAGE_NV: u32 = 34116;
+pub const GL_COMBINER_AB_DOT_PRODUCT_NV: u32 = 34117;
+pub const GL_COMBINER_CD_DOT_PRODUCT_NV: u32 = 34118;
+pub const GL_COMBINER_MUX_SUM_NV: u32 = 34119;
+pub const GL_COMBINER_SCALE_NV: u32 = 34120;
+pub const GL_COMBINER_BIAS_NV: u32 = 34121;
+pub const GL_COMBINER_AB_OUTPUT_NV: u32 = 34122;
+pub const GL_COMBINER_CD_OUTPUT_NV: u32 = 34123;
+pub const GL_COMBINER_SUM_OUTPUT_NV: u32 = 34124;
+pub const GL_MAX_GENERAL_COMBINERS_NV: u32 = 34125;
+pub const GL_NUM_GENERAL_COMBINERS_NV: u32 = 34126;
+pub const GL_COLOR_SUM_CLAMP_NV: u32 = 34127;
+pub const GL_COMBINER0_NV: u32 = 34128;
+pub const GL_COMBINER1_NV: u32 = 34129;
+pub const GL_COMBINER2_NV: u32 = 34130;
+pub const GL_COMBINER3_NV: u32 = 34131;
+pub const GL_COMBINER4_NV: u32 = 34132;
+pub const GL_COMBINER5_NV: u32 = 34133;
+pub const GL_COMBINER6_NV: u32 = 34134;
+pub const GL_COMBINER7_NV: u32 = 34135;
+pub const GL_PRIMITIVE_RESTART_NV: u32 = 34136;
+pub const GL_PRIMITIVE_RESTART_INDEX_NV: u32 = 34137;
+pub const GL_FOG_DISTANCE_MODE_NV: u32 = 34138;
+pub const GL_EYE_RADIAL_NV: u32 = 34139;
+pub const GL_EYE_PLANE_ABSOLUTE_NV: u32 = 34140;
+pub const GL_EMBOSS_LIGHT_NV: u32 = 34141;
+pub const GL_EMBOSS_CONSTANT_NV: u32 = 34142;
+pub const GL_EMBOSS_MAP_NV: u32 = 34143;
+pub const GL_RED_MIN_CLAMP_INGR: u32 = 34144;
+pub const GL_GREEN_MIN_CLAMP_INGR: u32 = 34145;
+pub const GL_BLUE_MIN_CLAMP_INGR: u32 = 34146;
+pub const GL_ALPHA_MIN_CLAMP_INGR: u32 = 34147;
+pub const GL_RED_MAX_CLAMP_INGR: u32 = 34148;
+pub const GL_GREEN_MAX_CLAMP_INGR: u32 = 34149;
+pub const GL_BLUE_MAX_CLAMP_INGR: u32 = 34150;
+pub const GL_ALPHA_MAX_CLAMP_INGR: u32 = 34151;
+pub const GL_INTERLACE_READ_INGR: u32 = 34152;
+pub const GL_COMBINE: u32 = 34160;
+pub const GL_COMBINE_ARB: u32 = 34160;
+pub const GL_COMBINE_EXT: u32 = 34160;
+pub const GL_COMBINE_RGB: u32 = 34161;
+pub const GL_COMBINE_RGB_ARB: u32 = 34161;
+pub const GL_COMBINE_RGB_EXT: u32 = 34161;
+pub const GL_COMBINE_ALPHA: u32 = 34162;
+pub const GL_COMBINE_ALPHA_ARB: u32 = 34162;
+pub const GL_COMBINE_ALPHA_EXT: u32 = 34162;
+pub const GL_RGB_SCALE: u32 = 34163;
+pub const GL_RGB_SCALE_ARB: u32 = 34163;
+pub const GL_RGB_SCALE_EXT: u32 = 34163;
+pub const GL_ADD_SIGNED: u32 = 34164;
+pub const GL_ADD_SIGNED_ARB: u32 = 34164;
+pub const GL_ADD_SIGNED_EXT: u32 = 34164;
+pub const GL_INTERPOLATE: u32 = 34165;
+pub const GL_INTERPOLATE_ARB: u32 = 34165;
+pub const GL_INTERPOLATE_EXT: u32 = 34165;
+pub const GL_CONSTANT: u32 = 34166;
+pub const GL_CONSTANT_ARB: u32 = 34166;
+pub const GL_CONSTANT_EXT: u32 = 34166;
+pub const GL_CONSTANT_NV: u32 = 34166;
+pub const GL_PRIMARY_COLOR: u32 = 34167;
+pub const GL_PRIMARY_COLOR_ARB: u32 = 34167;
+pub const GL_PRIMARY_COLOR_EXT: u32 = 34167;
+pub const GL_PREVIOUS: u32 = 34168;
+pub const GL_PREVIOUS_ARB: u32 = 34168;
+pub const GL_PREVIOUS_EXT: u32 = 34168;
+pub const GL_SOURCE0_RGB: u32 = 34176;
+pub const GL_SOURCE0_RGB_ARB: u32 = 34176;
+pub const GL_SOURCE0_RGB_EXT: u32 = 34176;
+pub const GL_SRC0_RGB: u32 = 34176;
+pub const GL_SOURCE1_RGB: u32 = 34177;
+pub const GL_SOURCE1_RGB_ARB: u32 = 34177;
+pub const GL_SOURCE1_RGB_EXT: u32 = 34177;
+pub const GL_SRC1_RGB: u32 = 34177;
+pub const GL_SOURCE2_RGB: u32 = 34178;
+pub const GL_SOURCE2_RGB_ARB: u32 = 34178;
+pub const GL_SOURCE2_RGB_EXT: u32 = 34178;
+pub const GL_SRC2_RGB: u32 = 34178;
+pub const GL_SOURCE3_RGB_NV: u32 = 34179;
+pub const GL_SOURCE0_ALPHA: u32 = 34184;
+pub const GL_SOURCE0_ALPHA_ARB: u32 = 34184;
+pub const GL_SOURCE0_ALPHA_EXT: u32 = 34184;
+pub const GL_SRC0_ALPHA: u32 = 34184;
+pub const GL_SOURCE1_ALPHA: u32 = 34185;
+pub const GL_SOURCE1_ALPHA_ARB: u32 = 34185;
+pub const GL_SOURCE1_ALPHA_EXT: u32 = 34185;
+pub const GL_SRC1_ALPHA: u32 = 34185;
+pub const GL_SRC1_ALPHA_EXT: u32 = 34185;
+pub const GL_SOURCE2_ALPHA: u32 = 34186;
+pub const GL_SOURCE2_ALPHA_ARB: u32 = 34186;
+pub const GL_SOURCE2_ALPHA_EXT: u32 = 34186;
+pub const GL_SRC2_ALPHA: u32 = 34186;
+pub const GL_SOURCE3_ALPHA_NV: u32 = 34187;
+pub const GL_OPERAND0_RGB: u32 = 34192;
+pub const GL_OPERAND0_RGB_ARB: u32 = 34192;
+pub const GL_OPERAND0_RGB_EXT: u32 = 34192;
+pub const GL_OPERAND1_RGB: u32 = 34193;
+pub const GL_OPERAND1_RGB_ARB: u32 = 34193;
+pub const GL_OPERAND1_RGB_EXT: u32 = 34193;
+pub const GL_OPERAND2_RGB: u32 = 34194;
+pub const GL_OPERAND2_RGB_ARB: u32 = 34194;
+pub const GL_OPERAND2_RGB_EXT: u32 = 34194;
+pub const GL_OPERAND3_RGB_NV: u32 = 34195;
+pub const GL_OPERAND0_ALPHA: u32 = 34200;
+pub const GL_OPERAND0_ALPHA_ARB: u32 = 34200;
+pub const GL_OPERAND0_ALPHA_EXT: u32 = 34200;
+pub const GL_OPERAND1_ALPHA: u32 = 34201;
+pub const GL_OPERAND1_ALPHA_ARB: u32 = 34201;
+pub const GL_OPERAND1_ALPHA_EXT: u32 = 34201;
+pub const GL_OPERAND2_ALPHA: u32 = 34202;
+pub const GL_OPERAND2_ALPHA_ARB: u32 = 34202;
+pub const GL_OPERAND2_ALPHA_EXT: u32 = 34202;
+pub const GL_OPERAND3_ALPHA_NV: u32 = 34203;
+pub const GL_PACK_SUBSAMPLE_RATE_SGIX: u32 = 34208;
+pub const GL_UNPACK_SUBSAMPLE_RATE_SGIX: u32 = 34209;
+pub const GL_PIXEL_SUBSAMPLE_4444_SGIX: u32 = 34210;
+pub const GL_PIXEL_SUBSAMPLE_2424_SGIX: u32 = 34211;
+pub const GL_PIXEL_SUBSAMPLE_4242_SGIX: u32 = 34212;
+pub const GL_PERTURB_EXT: u32 = 34222;
+pub const GL_TEXTURE_NORMAL_EXT: u32 = 34223;
+pub const GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE: u32 = 34224;
+pub const GL_TRANSFORM_HINT_APPLE: u32 = 34225;
+pub const GL_UNPACK_CLIENT_STORAGE_APPLE: u32 = 34226;
+pub const GL_BUFFER_OBJECT_APPLE: u32 = 34227;
+pub const GL_STORAGE_CLIENT_APPLE: u32 = 34228;
+pub const GL_VERTEX_ARRAY_BINDING: u32 = 34229;
+pub const GL_VERTEX_ARRAY_BINDING_APPLE: u32 = 34229;
+pub const GL_VERTEX_ARRAY_BINDING_OES: u32 = 34229;
+pub const GL_TEXTURE_RANGE_LENGTH_APPLE: u32 = 34231;
+pub const GL_TEXTURE_RANGE_POINTER_APPLE: u32 = 34232;
+pub const GL_YCBCR_422_APPLE: u32 = 34233;
+pub const GL_UNSIGNED_SHORT_8_8_APPLE: u32 = 34234;
+pub const GL_UNSIGNED_SHORT_8_8_MESA: u32 = 34234;
+pub const GL_UNSIGNED_SHORT_8_8_REV_APPLE: u32 = 34235;
+pub const GL_UNSIGNED_SHORT_8_8_REV_MESA: u32 = 34235;
+pub const GL_TEXTURE_STORAGE_HINT_APPLE: u32 = 34236;
+pub const GL_STORAGE_PRIVATE_APPLE: u32 = 34237;
+pub const GL_STORAGE_CACHED_APPLE: u32 = 34238;
+pub const GL_STORAGE_SHARED_APPLE: u32 = 34239;
+pub const GL_REPLACEMENT_CODE_ARRAY_SUN: u32 = 34240;
+pub const GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN: u32 = 34241;
+pub const GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN: u32 = 34242;
+pub const GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN: u32 = 34243;
+pub const GL_R1UI_V3F_SUN: u32 = 34244;
+pub const GL_R1UI_C4UB_V3F_SUN: u32 = 34245;
+pub const GL_R1UI_C3F_V3F_SUN: u32 = 34246;
+pub const GL_R1UI_N3F_V3F_SUN: u32 = 34247;
+pub const GL_R1UI_C4F_N3F_V3F_SUN: u32 = 34248;
+pub const GL_R1UI_T2F_V3F_SUN: u32 = 34249;
+pub const GL_R1UI_T2F_N3F_V3F_SUN: u32 = 34250;
+pub const GL_R1UI_T2F_C4F_N3F_V3F_SUN: u32 = 34251;
+pub const GL_SLICE_ACCUM_SUN: u32 = 34252;
+pub const GL_QUAD_MESH_SUN: u32 = 34324;
+pub const GL_TRIANGLE_MESH_SUN: u32 = 34325;
+pub const GL_VERTEX_PROGRAM_ARB: u32 = 34336;
+pub const GL_VERTEX_PROGRAM_NV: u32 = 34336;
+pub const GL_VERTEX_STATE_PROGRAM_NV: u32 = 34337;
+pub const GL_VERTEX_ATTRIB_ARRAY_ENABLED: u32 = 34338;
+pub const GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB: u32 = 34338;
+pub const GL_ATTRIB_ARRAY_SIZE_NV: u32 = 34339;
+pub const GL_VERTEX_ATTRIB_ARRAY_SIZE: u32 = 34339;
+pub const GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB: u32 = 34339;
+pub const GL_ATTRIB_ARRAY_STRIDE_NV: u32 = 34340;
+pub const GL_VERTEX_ATTRIB_ARRAY_STRIDE: u32 = 34340;
+pub const GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB: u32 = 34340;
+pub const GL_ATTRIB_ARRAY_TYPE_NV: u32 = 34341;
+pub const GL_VERTEX_ATTRIB_ARRAY_TYPE: u32 = 34341;
+pub const GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB: u32 = 34341;
+pub const GL_CURRENT_ATTRIB_NV: u32 = 34342;
+pub const GL_CURRENT_VERTEX_ATTRIB: u32 = 34342;
+pub const GL_CURRENT_VERTEX_ATTRIB_ARB: u32 = 34342;
+pub const GL_PROGRAM_LENGTH_ARB: u32 = 34343;
+pub const GL_PROGRAM_LENGTH_NV: u32 = 34343;
+pub const GL_PROGRAM_STRING_ARB: u32 = 34344;
+pub const GL_PROGRAM_STRING_NV: u32 = 34344;
+pub const GL_MODELVIEW_PROJECTION_NV: u32 = 34345;
+pub const GL_IDENTITY_NV: u32 = 34346;
+pub const GL_INVERSE_NV: u32 = 34347;
+pub const GL_TRANSPOSE_NV: u32 = 34348;
+pub const GL_INVERSE_TRANSPOSE_NV: u32 = 34349;
+pub const GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB: u32 = 34350;
+pub const GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV: u32 = 34350;
+pub const GL_MAX_PROGRAM_MATRICES_ARB: u32 = 34351;
+pub const GL_MAX_TRACK_MATRICES_NV: u32 = 34351;
+pub const GL_MATRIX0_NV: u32 = 34352;
+pub const GL_MATRIX1_NV: u32 = 34353;
+pub const GL_MATRIX2_NV: u32 = 34354;
+pub const GL_MATRIX3_NV: u32 = 34355;
+pub const GL_MATRIX4_NV: u32 = 34356;
+pub const GL_MATRIX5_NV: u32 = 34357;
+pub const GL_MATRIX6_NV: u32 = 34358;
+pub const GL_MATRIX7_NV: u32 = 34359;
+pub const GL_CURRENT_MATRIX_STACK_DEPTH_ARB: u32 = 34368;
+pub const GL_CURRENT_MATRIX_STACK_DEPTH_NV: u32 = 34368;
+pub const GL_CURRENT_MATRIX_ARB: u32 = 34369;
+pub const GL_CURRENT_MATRIX_NV: u32 = 34369;
+pub const GL_PROGRAM_POINT_SIZE: u32 = 34370;
+pub const GL_PROGRAM_POINT_SIZE_ARB: u32 = 34370;
+pub const GL_PROGRAM_POINT_SIZE_EXT: u32 = 34370;
+pub const GL_VERTEX_PROGRAM_POINT_SIZE: u32 = 34370;
+pub const GL_VERTEX_PROGRAM_POINT_SIZE_ARB: u32 = 34370;
+pub const GL_VERTEX_PROGRAM_POINT_SIZE_NV: u32 = 34370;
+pub const GL_VERTEX_PROGRAM_TWO_SIDE: u32 = 34371;
+pub const GL_VERTEX_PROGRAM_TWO_SIDE_ARB: u32 = 34371;
+pub const GL_VERTEX_PROGRAM_TWO_SIDE_NV: u32 = 34371;
+pub const GL_PROGRAM_PARAMETER_NV: u32 = 34372;
+pub const GL_ATTRIB_ARRAY_POINTER_NV: u32 = 34373;
+pub const GL_VERTEX_ATTRIB_ARRAY_POINTER: u32 = 34373;
+pub const GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB: u32 = 34373;
+pub const GL_PROGRAM_TARGET_NV: u32 = 34374;
+pub const GL_PROGRAM_RESIDENT_NV: u32 = 34375;
+pub const GL_TRACK_MATRIX_NV: u32 = 34376;
+pub const GL_TRACK_MATRIX_TRANSFORM_NV: u32 = 34377;
+pub const GL_VERTEX_PROGRAM_BINDING_NV: u32 = 34378;
+pub const GL_PROGRAM_ERROR_POSITION_ARB: u32 = 34379;
+pub const GL_PROGRAM_ERROR_POSITION_NV: u32 = 34379;
+pub const GL_OFFSET_TEXTURE_RECTANGLE_NV: u32 = 34380;
+pub const GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV: u32 = 34381;
+pub const GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV: u32 = 34382;
+pub const GL_DEPTH_CLAMP: u32 = 34383;
+pub const GL_DEPTH_CLAMP_NV: u32 = 34383;
+pub const GL_VERTEX_ATTRIB_ARRAY0_NV: u32 = 34384;
+pub const GL_VERTEX_ATTRIB_ARRAY1_NV: u32 = 34385;
+pub const GL_VERTEX_ATTRIB_ARRAY2_NV: u32 = 34386;
+pub const GL_VERTEX_ATTRIB_ARRAY3_NV: u32 = 34387;
+pub const GL_VERTEX_ATTRIB_ARRAY4_NV: u32 = 34388;
+pub const GL_VERTEX_ATTRIB_ARRAY5_NV: u32 = 34389;
+pub const GL_VERTEX_ATTRIB_ARRAY6_NV: u32 = 34390;
+pub const GL_VERTEX_ATTRIB_ARRAY7_NV: u32 = 34391;
+pub const GL_VERTEX_ATTRIB_ARRAY8_NV: u32 = 34392;
+pub const GL_VERTEX_ATTRIB_ARRAY9_NV: u32 = 34393;
+pub const GL_VERTEX_ATTRIB_ARRAY10_NV: u32 = 34394;
+pub const GL_VERTEX_ATTRIB_ARRAY11_NV: u32 = 34395;
+pub const GL_VERTEX_ATTRIB_ARRAY12_NV: u32 = 34396;
+pub const GL_VERTEX_ATTRIB_ARRAY13_NV: u32 = 34397;
+pub const GL_VERTEX_ATTRIB_ARRAY14_NV: u32 = 34398;
+pub const GL_VERTEX_ATTRIB_ARRAY15_NV: u32 = 34399;
+pub const GL_MAP1_VERTEX_ATTRIB0_4_NV: u32 = 34400;
+pub const GL_MAP1_VERTEX_ATTRIB1_4_NV: u32 = 34401;
+pub const GL_MAP1_VERTEX_ATTRIB2_4_NV: u32 = 34402;
+pub const GL_MAP1_VERTEX_ATTRIB3_4_NV: u32 = 34403;
+pub const GL_MAP1_VERTEX_ATTRIB4_4_NV: u32 = 34404;
+pub const GL_MAP1_VERTEX_ATTRIB5_4_NV: u32 = 34405;
+pub const GL_MAP1_VERTEX_ATTRIB6_4_NV: u32 = 34406;
+pub const GL_MAP1_VERTEX_ATTRIB7_4_NV: u32 = 34407;
+pub const GL_MAP1_VERTEX_ATTRIB8_4_NV: u32 = 34408;
+pub const GL_MAP1_VERTEX_ATTRIB9_4_NV: u32 = 34409;
+pub const GL_MAP1_VERTEX_ATTRIB10_4_NV: u32 = 34410;
+pub const GL_MAP1_VERTEX_ATTRIB11_4_NV: u32 = 34411;
+pub const GL_MAP1_VERTEX_ATTRIB12_4_NV: u32 = 34412;
+pub const GL_MAP1_VERTEX_ATTRIB13_4_NV: u32 = 34413;
+pub const GL_MAP1_VERTEX_ATTRIB14_4_NV: u32 = 34414;
+pub const GL_MAP1_VERTEX_ATTRIB15_4_NV: u32 = 34415;
+pub const GL_MAP2_VERTEX_ATTRIB0_4_NV: u32 = 34416;
+pub const GL_MAP2_VERTEX_ATTRIB1_4_NV: u32 = 34417;
+pub const GL_MAP2_VERTEX_ATTRIB2_4_NV: u32 = 34418;
+pub const GL_MAP2_VERTEX_ATTRIB3_4_NV: u32 = 34419;
+pub const GL_MAP2_VERTEX_ATTRIB4_4_NV: u32 = 34420;
+pub const GL_MAP2_VERTEX_ATTRIB5_4_NV: u32 = 34421;
+pub const GL_MAP2_VERTEX_ATTRIB6_4_NV: u32 = 34422;
+pub const GL_MAP2_VERTEX_ATTRIB7_4_NV: u32 = 34423;
+pub const GL_PROGRAM_BINDING_ARB: u32 = 34423;
+pub const GL_MAP2_VERTEX_ATTRIB8_4_NV: u32 = 34424;
+pub const GL_MAP2_VERTEX_ATTRIB9_4_NV: u32 = 34425;
+pub const GL_MAP2_VERTEX_ATTRIB10_4_NV: u32 = 34426;
+pub const GL_MAP2_VERTEX_ATTRIB11_4_NV: u32 = 34427;
+pub const GL_MAP2_VERTEX_ATTRIB12_4_NV: u32 = 34428;
+pub const GL_MAP2_VERTEX_ATTRIB13_4_NV: u32 = 34429;
+pub const GL_MAP2_VERTEX_ATTRIB14_4_NV: u32 = 34430;
+pub const GL_MAP2_VERTEX_ATTRIB15_4_NV: u32 = 34431;
+pub const GL_TEXTURE_COMPRESSED_IMAGE_SIZE: u32 = 34464;
+pub const GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB: u32 = 34464;
+pub const GL_TEXTURE_COMPRESSED: u32 = 34465;
+pub const GL_TEXTURE_COMPRESSED_ARB: u32 = 34465;
+pub const GL_NUM_COMPRESSED_TEXTURE_FORMATS: u32 = 34466;
+pub const GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB: u32 = 34466;
+pub const GL_COMPRESSED_TEXTURE_FORMATS: u32 = 34467;
+pub const GL_COMPRESSED_TEXTURE_FORMATS_ARB: u32 = 34467;
+pub const GL_MAX_VERTEX_UNITS_ARB: u32 = 34468;
+pub const GL_MAX_VERTEX_UNITS_OES: u32 = 34468;
+pub const GL_ACTIVE_VERTEX_UNITS_ARB: u32 = 34469;
+pub const GL_WEIGHT_SUM_UNITY_ARB: u32 = 34470;
+pub const GL_VERTEX_BLEND_ARB: u32 = 34471;
+pub const GL_CURRENT_WEIGHT_ARB: u32 = 34472;
+pub const GL_WEIGHT_ARRAY_TYPE_ARB: u32 = 34473;
+pub const GL_WEIGHT_ARRAY_TYPE_OES: u32 = 34473;
+pub const GL_WEIGHT_ARRAY_STRIDE_ARB: u32 = 34474;
+pub const GL_WEIGHT_ARRAY_STRIDE_OES: u32 = 34474;
+pub const GL_WEIGHT_ARRAY_SIZE_ARB: u32 = 34475;
+pub const GL_WEIGHT_ARRAY_SIZE_OES: u32 = 34475;
+pub const GL_WEIGHT_ARRAY_POINTER_ARB: u32 = 34476;
+pub const GL_WEIGHT_ARRAY_POINTER_OES: u32 = 34476;
+pub const GL_WEIGHT_ARRAY_ARB: u32 = 34477;
+pub const GL_WEIGHT_ARRAY_OES: u32 = 34477;
+pub const GL_DOT3_RGB: u32 = 34478;
+pub const GL_DOT3_RGB_ARB: u32 = 34478;
+pub const GL_DOT3_RGBA: u32 = 34479;
+pub const GL_DOT3_RGBA_ARB: u32 = 34479;
+pub const GL_DOT3_RGBA_IMG: u32 = 34479;
+pub const GL_COMPRESSED_RGB_FXT1_3DFX: u32 = 34480;
+pub const GL_COMPRESSED_RGBA_FXT1_3DFX: u32 = 34481;
+pub const GL_MULTISAMPLE_3DFX: u32 = 34482;
+pub const GL_SAMPLE_BUFFERS_3DFX: u32 = 34483;
+pub const GL_SAMPLES_3DFX: u32 = 34484;
+pub const GL_EVAL_2D_NV: u32 = 34496;
+pub const GL_EVAL_TRIANGULAR_2D_NV: u32 = 34497;
+pub const GL_MAP_TESSELLATION_NV: u32 = 34498;
+pub const GL_MAP_ATTRIB_U_ORDER_NV: u32 = 34499;
+pub const GL_MAP_ATTRIB_V_ORDER_NV: u32 = 34500;
+pub const GL_EVAL_FRACTIONAL_TESSELLATION_NV: u32 = 34501;
+pub const GL_EVAL_VERTEX_ATTRIB0_NV: u32 = 34502;
+pub const GL_EVAL_VERTEX_ATTRIB1_NV: u32 = 34503;
+pub const GL_EVAL_VERTEX_ATTRIB2_NV: u32 = 34504;
+pub const GL_EVAL_VERTEX_ATTRIB3_NV: u32 = 34505;
+pub const GL_EVAL_VERTEX_ATTRIB4_NV: u32 = 34506;
+pub const GL_EVAL_VERTEX_ATTRIB5_NV: u32 = 34507;
+pub const GL_EVAL_VERTEX_ATTRIB6_NV: u32 = 34508;
+pub const GL_EVAL_VERTEX_ATTRIB7_NV: u32 = 34509;
+pub const GL_EVAL_VERTEX_ATTRIB8_NV: u32 = 34510;
+pub const GL_EVAL_VERTEX_ATTRIB9_NV: u32 = 34511;
+pub const GL_EVAL_VERTEX_ATTRIB10_NV: u32 = 34512;
+pub const GL_EVAL_VERTEX_ATTRIB11_NV: u32 = 34513;
+pub const GL_EVAL_VERTEX_ATTRIB12_NV: u32 = 34514;
+pub const GL_EVAL_VERTEX_ATTRIB13_NV: u32 = 34515;
+pub const GL_EVAL_VERTEX_ATTRIB14_NV: u32 = 34516;
+pub const GL_EVAL_VERTEX_ATTRIB15_NV: u32 = 34517;
+pub const GL_MAX_MAP_TESSELLATION_NV: u32 = 34518;
+pub const GL_MAX_RATIONAL_EVAL_ORDER_NV: u32 = 34519;
+pub const GL_MAX_PROGRAM_PATCH_ATTRIBS_NV: u32 = 34520;
+pub const GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV: u32 = 34521;
+pub const GL_UNSIGNED_INT_S8_S8_8_8_NV: u32 = 34522;
+pub const GL_UNSIGNED_INT_8_8_S8_S8_REV_NV: u32 = 34523;
+pub const GL_DSDT_MAG_INTENSITY_NV: u32 = 34524;
+pub const GL_SHADER_CONSISTENT_NV: u32 = 34525;
+pub const GL_TEXTURE_SHADER_NV: u32 = 34526;
+pub const GL_SHADER_OPERATION_NV: u32 = 34527;
+pub const GL_CULL_MODES_NV: u32 = 34528;
+pub const GL_OFFSET_TEXTURE_2D_MATRIX_NV: u32 = 34529;
+pub const GL_OFFSET_TEXTURE_MATRIX_NV: u32 = 34529;
+pub const GL_OFFSET_TEXTURE_2D_SCALE_NV: u32 = 34530;
+pub const GL_OFFSET_TEXTURE_SCALE_NV: u32 = 34530;
+pub const GL_OFFSET_TEXTURE_2D_BIAS_NV: u32 = 34531;
+pub const GL_OFFSET_TEXTURE_BIAS_NV: u32 = 34531;
+pub const GL_PREVIOUS_TEXTURE_INPUT_NV: u32 = 34532;
+pub const GL_CONST_EYE_NV: u32 = 34533;
+pub const GL_PASS_THROUGH_NV: u32 = 34534;
+pub const GL_CULL_FRAGMENT_NV: u32 = 34535;
+pub const GL_OFFSET_TEXTURE_2D_NV: u32 = 34536;
+pub const GL_DEPENDENT_AR_TEXTURE_2D_NV: u32 = 34537;
+pub const GL_DEPENDENT_GB_TEXTURE_2D_NV: u32 = 34538;
+pub const GL_SURFACE_STATE_NV: u32 = 34539;
+pub const GL_DOT_PRODUCT_NV: u32 = 34540;
+pub const GL_DOT_PRODUCT_DEPTH_REPLACE_NV: u32 = 34541;
+pub const GL_DOT_PRODUCT_TEXTURE_2D_NV: u32 = 34542;
+pub const GL_DOT_PRODUCT_TEXTURE_3D_NV: u32 = 34543;
+pub const GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV: u32 = 34544;
+pub const GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV: u32 = 34545;
+pub const GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV: u32 = 34546;
+pub const GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV: u32 = 34547;
+pub const GL_HILO_NV: u32 = 34548;
+pub const GL_DSDT_NV: u32 = 34549;
+pub const GL_DSDT_MAG_NV: u32 = 34550;
+pub const GL_DSDT_MAG_VIB_NV: u32 = 34551;
+pub const GL_HILO16_NV: u32 = 34552;
+pub const GL_SIGNED_HILO_NV: u32 = 34553;
+pub const GL_SIGNED_HILO16_NV: u32 = 34554;
+pub const GL_SIGNED_RGBA_NV: u32 = 34555;
+pub const GL_SIGNED_RGBA8_NV: u32 = 34556;
+pub const GL_SURFACE_REGISTERED_NV: u32 = 34557;
+pub const GL_SIGNED_RGB_NV: u32 = 34558;
+pub const GL_SIGNED_RGB8_NV: u32 = 34559;
+pub const GL_SURFACE_MAPPED_NV: u32 = 34560;
+pub const GL_SIGNED_LUMINANCE_NV: u32 = 34561;
+pub const GL_SIGNED_LUMINANCE8_NV: u32 = 34562;
+pub const GL_SIGNED_LUMINANCE_ALPHA_NV: u32 = 34563;
+pub const GL_SIGNED_LUMINANCE8_ALPHA8_NV: u32 = 34564;
+pub const GL_SIGNED_ALPHA_NV: u32 = 34565;
+pub const GL_SIGNED_ALPHA8_NV: u32 = 34566;
+pub const GL_SIGNED_INTENSITY_NV: u32 = 34567;
+pub const GL_SIGNED_INTENSITY8_NV: u32 = 34568;
+pub const GL_DSDT8_NV: u32 = 34569;
+pub const GL_DSDT8_MAG8_NV: u32 = 34570;
+pub const GL_DSDT8_MAG8_INTENSITY8_NV: u32 = 34571;
+pub const GL_SIGNED_RGB_UNSIGNED_ALPHA_NV: u32 = 34572;
+pub const GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV: u32 = 34573;
+pub const GL_HI_SCALE_NV: u32 = 34574;
+pub const GL_LO_SCALE_NV: u32 = 34575;
+pub const GL_DS_SCALE_NV: u32 = 34576;
+pub const GL_DT_SCALE_NV: u32 = 34577;
+pub const GL_MAGNITUDE_SCALE_NV: u32 = 34578;
+pub const GL_VIBRANCE_SCALE_NV: u32 = 34579;
+pub const GL_HI_BIAS_NV: u32 = 34580;
+pub const GL_LO_BIAS_NV: u32 = 34581;
+pub const GL_DS_BIAS_NV: u32 = 34582;
+pub const GL_DT_BIAS_NV: u32 = 34583;
+pub const GL_MAGNITUDE_BIAS_NV: u32 = 34584;
+pub const GL_VIBRANCE_BIAS_NV: u32 = 34585;
+pub const GL_TEXTURE_BORDER_VALUES_NV: u32 = 34586;
+pub const GL_TEXTURE_HI_SIZE_NV: u32 = 34587;
+pub const GL_TEXTURE_LO_SIZE_NV: u32 = 34588;
+pub const GL_TEXTURE_DS_SIZE_NV: u32 = 34589;
+pub const GL_TEXTURE_DT_SIZE_NV: u32 = 34590;
+pub const GL_TEXTURE_MAG_SIZE_NV: u32 = 34591;
+pub const GL_MODELVIEW2_ARB: u32 = 34594;
+pub const GL_MODELVIEW3_ARB: u32 = 34595;
+pub const GL_MODELVIEW4_ARB: u32 = 34596;
+pub const GL_MODELVIEW5_ARB: u32 = 34597;
+pub const GL_MODELVIEW6_ARB: u32 = 34598;
+pub const GL_MODELVIEW7_ARB: u32 = 34599;
+pub const GL_MODELVIEW8_ARB: u32 = 34600;
+pub const GL_MODELVIEW9_ARB: u32 = 34601;
+pub const GL_MODELVIEW10_ARB: u32 = 34602;
+pub const GL_MODELVIEW11_ARB: u32 = 34603;
+pub const GL_MODELVIEW12_ARB: u32 = 34604;
+pub const GL_MODELVIEW13_ARB: u32 = 34605;
+pub const GL_MODELVIEW14_ARB: u32 = 34606;
+pub const GL_MODELVIEW15_ARB: u32 = 34607;
+pub const GL_MODELVIEW16_ARB: u32 = 34608;
+pub const GL_MODELVIEW17_ARB: u32 = 34609;
+pub const GL_MODELVIEW18_ARB: u32 = 34610;
+pub const GL_MODELVIEW19_ARB: u32 = 34611;
+pub const GL_MODELVIEW20_ARB: u32 = 34612;
+pub const GL_MODELVIEW21_ARB: u32 = 34613;
+pub const GL_MODELVIEW22_ARB: u32 = 34614;
+pub const GL_MODELVIEW23_ARB: u32 = 34615;
+pub const GL_MODELVIEW24_ARB: u32 = 34616;
+pub const GL_MODELVIEW25_ARB: u32 = 34617;
+pub const GL_MODELVIEW26_ARB: u32 = 34618;
+pub const GL_MODELVIEW27_ARB: u32 = 34619;
+pub const GL_MODELVIEW28_ARB: u32 = 34620;
+pub const GL_MODELVIEW29_ARB: u32 = 34621;
+pub const GL_MODELVIEW30_ARB: u32 = 34622;
+pub const GL_MODELVIEW31_ARB: u32 = 34623;
+pub const GL_DOT3_RGB_EXT: u32 = 34624;
+pub const GL_Z400_BINARY_AMD: u32 = 34624;
+pub const GL_DOT3_RGBA_EXT: u32 = 34625;
+pub const GL_PROGRAM_BINARY_LENGTH: u32 = 34625;
+pub const GL_PROGRAM_BINARY_LENGTH_OES: u32 = 34625;
+pub const GL_MIRROR_CLAMP_ATI: u32 = 34626;
+pub const GL_MIRROR_CLAMP_EXT: u32 = 34626;
+pub const GL_MIRROR_CLAMP_TO_EDGE: u32 = 34627;
+pub const GL_MIRROR_CLAMP_TO_EDGE_ATI: u32 = 34627;
+pub const GL_MIRROR_CLAMP_TO_EDGE_EXT: u32 = 34627;
+pub const GL_MODULATE_ADD_ATI: u32 = 34628;
+pub const GL_MODULATE_SIGNED_ADD_ATI: u32 = 34629;
+pub const GL_MODULATE_SUBTRACT_ATI: u32 = 34630;
+pub const GL_SET_AMD: u32 = 34634;
+pub const GL_REPLACE_VALUE_AMD: u32 = 34635;
+pub const GL_STENCIL_OP_VALUE_AMD: u32 = 34636;
+pub const GL_STENCIL_BACK_OP_VALUE_AMD: u32 = 34637;
+pub const GL_VERTEX_ATTRIB_ARRAY_LONG: u32 = 34638;
+pub const GL_OCCLUSION_QUERY_EVENT_MASK_AMD: u32 = 34639;
+pub const GL_DEPTH_STENCIL_MESA: u32 = 34640;
+pub const GL_UNSIGNED_INT_24_8_MESA: u32 = 34641;
+pub const GL_UNSIGNED_INT_8_24_REV_MESA: u32 = 34642;
+pub const GL_UNSIGNED_SHORT_15_1_MESA: u32 = 34643;
+pub const GL_UNSIGNED_SHORT_1_15_REV_MESA: u32 = 34644;
+pub const GL_TRACE_MASK_MESA: u32 = 34645;
+pub const GL_TRACE_NAME_MESA: u32 = 34646;
+pub const GL_YCBCR_MESA: u32 = 34647;
+pub const GL_PACK_INVERT_MESA: u32 = 34648;
+pub const GL_DEBUG_OBJECT_MESA: u32 = 34649;
+pub const GL_TEXTURE_1D_STACK_MESAX: u32 = 34649;
+pub const GL_DEBUG_PRINT_MESA: u32 = 34650;
+pub const GL_TEXTURE_2D_STACK_MESAX: u32 = 34650;
+pub const GL_DEBUG_ASSERT_MESA: u32 = 34651;
+pub const GL_PROXY_TEXTURE_1D_STACK_MESAX: u32 = 34651;
+pub const GL_PROXY_TEXTURE_2D_STACK_MESAX: u32 = 34652;
+pub const GL_TEXTURE_1D_STACK_BINDING_MESAX: u32 = 34653;
+pub const GL_TEXTURE_2D_STACK_BINDING_MESAX: u32 = 34654;
+pub const GL_STATIC_ATI: u32 = 34656;
+pub const GL_DYNAMIC_ATI: u32 = 34657;
+pub const GL_PRESERVE_ATI: u32 = 34658;
+pub const GL_DISCARD_ATI: u32 = 34659;
+pub const GL_BUFFER_SIZE: u32 = 34660;
+pub const GL_BUFFER_SIZE_ARB: u32 = 34660;
+pub const GL_OBJECT_BUFFER_SIZE_ATI: u32 = 34660;
+pub const GL_BUFFER_USAGE: u32 = 34661;
+pub const GL_BUFFER_USAGE_ARB: u32 = 34661;
+pub const GL_OBJECT_BUFFER_USAGE_ATI: u32 = 34661;
+pub const GL_ARRAY_OBJECT_BUFFER_ATI: u32 = 34662;
+pub const GL_ARRAY_OBJECT_OFFSET_ATI: u32 = 34663;
+pub const GL_ELEMENT_ARRAY_ATI: u32 = 34664;
+pub const GL_ELEMENT_ARRAY_TYPE_ATI: u32 = 34665;
+pub const GL_ELEMENT_ARRAY_POINTER_ATI: u32 = 34666;
+pub const GL_MAX_VERTEX_STREAMS_ATI: u32 = 34667;
+pub const GL_VERTEX_STREAM0_ATI: u32 = 34668;
+pub const GL_VERTEX_STREAM1_ATI: u32 = 34669;
+pub const GL_VERTEX_STREAM2_ATI: u32 = 34670;
+pub const GL_VERTEX_STREAM3_ATI: u32 = 34671;
+pub const GL_VERTEX_STREAM4_ATI: u32 = 34672;
+pub const GL_VERTEX_STREAM5_ATI: u32 = 34673;
+pub const GL_VERTEX_STREAM6_ATI: u32 = 34674;
+pub const GL_VERTEX_STREAM7_ATI: u32 = 34675;
+pub const GL_VERTEX_SOURCE_ATI: u32 = 34676;
+pub const GL_BUMP_ROT_MATRIX_ATI: u32 = 34677;
+pub const GL_BUMP_ROT_MATRIX_SIZE_ATI: u32 = 34678;
+pub const GL_BUMP_NUM_TEX_UNITS_ATI: u32 = 34679;
+pub const GL_BUMP_TEX_UNITS_ATI: u32 = 34680;
+pub const GL_DUDV_ATI: u32 = 34681;
+pub const GL_DU8DV8_ATI: u32 = 34682;
+pub const GL_BUMP_ENVMAP_ATI: u32 = 34683;
+pub const GL_BUMP_TARGET_ATI: u32 = 34684;
+pub const GL_VERTEX_SHADER_EXT: u32 = 34688;
+pub const GL_VERTEX_SHADER_BINDING_EXT: u32 = 34689;
+pub const GL_OP_INDEX_EXT: u32 = 34690;
+pub const GL_OP_NEGATE_EXT: u32 = 34691;
+pub const GL_OP_DOT3_EXT: u32 = 34692;
+pub const GL_OP_DOT4_EXT: u32 = 34693;
+pub const GL_OP_MUL_EXT: u32 = 34694;
+pub const GL_OP_ADD_EXT: u32 = 34695;
+pub const GL_OP_MADD_EXT: u32 = 34696;
+pub const GL_OP_FRAC_EXT: u32 = 34697;
+pub const GL_OP_MAX_EXT: u32 = 34698;
+pub const GL_OP_MIN_EXT: u32 = 34699;
+pub const GL_OP_SET_GE_EXT: u32 = 34700;
+pub const GL_OP_SET_LT_EXT: u32 = 34701;
+pub const GL_OP_CLAMP_EXT: u32 = 34702;
+pub const GL_OP_FLOOR_EXT: u32 = 34703;
+pub const GL_OP_ROUND_EXT: u32 = 34704;
+pub const GL_OP_EXP_BASE_2_EXT: u32 = 34705;
+pub const GL_OP_LOG_BASE_2_EXT: u32 = 34706;
+pub const GL_OP_POWER_EXT: u32 = 34707;
+pub const GL_OP_RECIP_EXT: u32 = 34708;
+pub const GL_OP_RECIP_SQRT_EXT: u32 = 34709;
+pub const GL_OP_SUB_EXT: u32 = 34710;
+pub const GL_OP_CROSS_PRODUCT_EXT: u32 = 34711;
+pub const GL_OP_MULTIPLY_MATRIX_EXT: u32 = 34712;
+pub const GL_OP_MOV_EXT: u32 = 34713;
+pub const GL_OUTPUT_VERTEX_EXT: u32 = 34714;
+pub const GL_OUTPUT_COLOR0_EXT: u32 = 34715;
+pub const GL_OUTPUT_COLOR1_EXT: u32 = 34716;
+pub const GL_OUTPUT_TEXTURE_COORD0_EXT: u32 = 34717;
+pub const GL_OUTPUT_TEXTURE_COORD1_EXT: u32 = 34718;
+pub const GL_OUTPUT_TEXTURE_COORD2_EXT: u32 = 34719;
+pub const GL_OUTPUT_TEXTURE_COORD3_EXT: u32 = 34720;
+pub const GL_OUTPUT_TEXTURE_COORD4_EXT: u32 = 34721;
+pub const GL_OUTPUT_TEXTURE_COORD5_EXT: u32 = 34722;
+pub const GL_OUTPUT_TEXTURE_COORD6_EXT: u32 = 34723;
+pub const GL_OUTPUT_TEXTURE_COORD7_EXT: u32 = 34724;
+pub const GL_OUTPUT_TEXTURE_COORD8_EXT: u32 = 34725;
+pub const GL_OUTPUT_TEXTURE_COORD9_EXT: u32 = 34726;
+pub const GL_OUTPUT_TEXTURE_COORD10_EXT: u32 = 34727;
+pub const GL_OUTPUT_TEXTURE_COORD11_EXT: u32 = 34728;
+pub const GL_OUTPUT_TEXTURE_COORD12_EXT: u32 = 34729;
+pub const GL_OUTPUT_TEXTURE_COORD13_EXT: u32 = 34730;
+pub const GL_OUTPUT_TEXTURE_COORD14_EXT: u32 = 34731;
+pub const GL_OUTPUT_TEXTURE_COORD15_EXT: u32 = 34732;
+pub const GL_OUTPUT_TEXTURE_COORD16_EXT: u32 = 34733;
+pub const GL_OUTPUT_TEXTURE_COORD17_EXT: u32 = 34734;
+pub const GL_OUTPUT_TEXTURE_COORD18_EXT: u32 = 34735;
+pub const GL_OUTPUT_TEXTURE_COORD19_EXT: u32 = 34736;
+pub const GL_OUTPUT_TEXTURE_COORD20_EXT: u32 = 34737;
+pub const GL_OUTPUT_TEXTURE_COORD21_EXT: u32 = 34738;
+pub const GL_OUTPUT_TEXTURE_COORD22_EXT: u32 = 34739;
+pub const GL_OUTPUT_TEXTURE_COORD23_EXT: u32 = 34740;
+pub const GL_OUTPUT_TEXTURE_COORD24_EXT: u32 = 34741;
+pub const GL_OUTPUT_TEXTURE_COORD25_EXT: u32 = 34742;
+pub const GL_OUTPUT_TEXTURE_COORD26_EXT: u32 = 34743;
+pub const GL_OUTPUT_TEXTURE_COORD27_EXT: u32 = 34744;
+pub const GL_OUTPUT_TEXTURE_COORD28_EXT: u32 = 34745;
+pub const GL_OUTPUT_TEXTURE_COORD29_EXT: u32 = 34746;
+pub const GL_OUTPUT_TEXTURE_COORD30_EXT: u32 = 34747;
+pub const GL_OUTPUT_TEXTURE_COORD31_EXT: u32 = 34748;
+pub const GL_OUTPUT_FOG_EXT: u32 = 34749;
+pub const GL_SCALAR_EXT: u32 = 34750;
+pub const GL_VECTOR_EXT: u32 = 34751;
+pub const GL_MATRIX_EXT: u32 = 34752;
+pub const GL_VARIANT_EXT: u32 = 34753;
+pub const GL_INVARIANT_EXT: u32 = 34754;
+pub const GL_LOCAL_CONSTANT_EXT: u32 = 34755;
+pub const GL_LOCAL_EXT: u32 = 34756;
+pub const GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT: u32 = 34757;
+pub const GL_MAX_VERTEX_SHADER_VARIANTS_EXT: u32 = 34758;
+pub const GL_MAX_VERTEX_SHADER_INVARIANTS_EXT: u32 = 34759;
+pub const GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT: u32 = 34760;
+pub const GL_MAX_VERTEX_SHADER_LOCALS_EXT: u32 = 34761;
+pub const GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT: u32 = 34762;
+pub const GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT: u32 = 34763;
+pub const GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT: u32 = 34764;
+pub const GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT: u32 = 34765;
+pub const GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT: u32 = 34766;
+pub const GL_VERTEX_SHADER_INSTRUCTIONS_EXT: u32 = 34767;
+pub const GL_VERTEX_SHADER_VARIANTS_EXT: u32 = 34768;
+pub const GL_VERTEX_SHADER_INVARIANTS_EXT: u32 = 34769;
+pub const GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT: u32 = 34770;
+pub const GL_VERTEX_SHADER_LOCALS_EXT: u32 = 34771;
+pub const GL_VERTEX_SHADER_OPTIMIZED_EXT: u32 = 34772;
+pub const GL_X_EXT: u32 = 34773;
+pub const GL_Y_EXT: u32 = 34774;
+pub const GL_Z_EXT: u32 = 34775;
+pub const GL_W_EXT: u32 = 34776;
+pub const GL_NEGATIVE_X_EXT: u32 = 34777;
+pub const GL_NEGATIVE_Y_EXT: u32 = 34778;
+pub const GL_NEGATIVE_Z_EXT: u32 = 34779;
+pub const GL_NEGATIVE_W_EXT: u32 = 34780;
+pub const GL_ZERO_EXT: u32 = 34781;
+pub const GL_ONE_EXT: u32 = 34782;
+pub const GL_NEGATIVE_ONE_EXT: u32 = 34783;
+pub const GL_NORMALIZED_RANGE_EXT: u32 = 34784;
+pub const GL_FULL_RANGE_EXT: u32 = 34785;
+pub const GL_CURRENT_VERTEX_EXT: u32 = 34786;
+pub const GL_MVP_MATRIX_EXT: u32 = 34787;
+pub const GL_VARIANT_VALUE_EXT: u32 = 34788;
+pub const GL_VARIANT_DATATYPE_EXT: u32 = 34789;
+pub const GL_VARIANT_ARRAY_STRIDE_EXT: u32 = 34790;
+pub const GL_VARIANT_ARRAY_TYPE_EXT: u32 = 34791;
+pub const GL_VARIANT_ARRAY_EXT: u32 = 34792;
+pub const GL_VARIANT_ARRAY_POINTER_EXT: u32 = 34793;
+pub const GL_INVARIANT_VALUE_EXT: u32 = 34794;
+pub const GL_INVARIANT_DATATYPE_EXT: u32 = 34795;
+pub const GL_LOCAL_CONSTANT_VALUE_EXT: u32 = 34796;
+pub const GL_LOCAL_CONSTANT_DATATYPE_EXT: u32 = 34797;
+pub const GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: u32 = 34798;
+pub const GL_PN_TRIANGLES_ATI: u32 = 34800;
+pub const GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI: u32 = 34801;
+pub const GL_PN_TRIANGLES_POINT_MODE_ATI: u32 = 34802;
+pub const GL_PN_TRIANGLES_NORMAL_MODE_ATI: u32 = 34803;
+pub const GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI: u32 = 34804;
+pub const GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI: u32 = 34805;
+pub const GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI: u32 = 34806;
+pub const GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI: u32 = 34807;
+pub const GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI: u32 = 34808;
+pub const GL_3DC_X_AMD: u32 = 34809;
+pub const GL_3DC_XY_AMD: u32 = 34810;
+pub const GL_VBO_FREE_MEMORY_ATI: u32 = 34811;
+pub const GL_TEXTURE_FREE_MEMORY_ATI: u32 = 34812;
+pub const GL_RENDERBUFFER_FREE_MEMORY_ATI: u32 = 34813;
+pub const GL_NUM_PROGRAM_BINARY_FORMATS: u32 = 34814;
+pub const GL_NUM_PROGRAM_BINARY_FORMATS_OES: u32 = 34814;
+pub const GL_PROGRAM_BINARY_FORMATS: u32 = 34815;
+pub const GL_PROGRAM_BINARY_FORMATS_OES: u32 = 34815;
+pub const GL_STENCIL_BACK_FUNC: u32 = 34816;
+pub const GL_STENCIL_BACK_FUNC_ATI: u32 = 34816;
+pub const GL_STENCIL_BACK_FAIL: u32 = 34817;
+pub const GL_STENCIL_BACK_FAIL_ATI: u32 = 34817;
+pub const GL_STENCIL_BACK_PASS_DEPTH_FAIL: u32 = 34818;
+pub const GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI: u32 = 34818;
+pub const GL_STENCIL_BACK_PASS_DEPTH_PASS: u32 = 34819;
+pub const GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI: u32 = 34819;
+pub const GL_FRAGMENT_PROGRAM_ARB: u32 = 34820;
+pub const GL_PROGRAM_ALU_INSTRUCTIONS_ARB: u32 = 34821;
+pub const GL_PROGRAM_TEX_INSTRUCTIONS_ARB: u32 = 34822;
+pub const GL_PROGRAM_TEX_INDIRECTIONS_ARB: u32 = 34823;
+pub const GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB: u32 = 34824;
+pub const GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB: u32 = 34825;
+pub const GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB: u32 = 34826;
+pub const GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB: u32 = 34827;
+pub const GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB: u32 = 34828;
+pub const GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB: u32 = 34829;
+pub const GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB: u32 = 34830;
+pub const GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB: u32 = 34831;
+pub const GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB: u32 = 34832;
+pub const GL_RGBA32F: u32 = 34836;
+pub const GL_RGBA32F_ARB: u32 = 34836;
+pub const GL_RGBA32F_EXT: u32 = 34836;
+pub const GL_RGBA_FLOAT32_APPLE: u32 = 34836;
+pub const GL_RGBA_FLOAT32_ATI: u32 = 34836;
+pub const GL_RGB32F: u32 = 34837;
+pub const GL_RGB32F_ARB: u32 = 34837;
+pub const GL_RGB32F_EXT: u32 = 34837;
+pub const GL_RGB_FLOAT32_APPLE: u32 = 34837;
+pub const GL_RGB_FLOAT32_ATI: u32 = 34837;
+pub const GL_ALPHA32F_ARB: u32 = 34838;
+pub const GL_ALPHA32F_EXT: u32 = 34838;
+pub const GL_ALPHA_FLOAT32_APPLE: u32 = 34838;
+pub const GL_ALPHA_FLOAT32_ATI: u32 = 34838;
+pub const GL_INTENSITY32F_ARB: u32 = 34839;
+pub const GL_INTENSITY_FLOAT32_APPLE: u32 = 34839;
+pub const GL_INTENSITY_FLOAT32_ATI: u32 = 34839;
+pub const GL_LUMINANCE32F_ARB: u32 = 34840;
+pub const GL_LUMINANCE32F_EXT: u32 = 34840;
+pub const GL_LUMINANCE_FLOAT32_APPLE: u32 = 34840;
+pub const GL_LUMINANCE_FLOAT32_ATI: u32 = 34840;
+pub const GL_LUMINANCE_ALPHA32F_ARB: u32 = 34841;
+pub const GL_LUMINANCE_ALPHA32F_EXT: u32 = 34841;
+pub const GL_LUMINANCE_ALPHA_FLOAT32_APPLE: u32 = 34841;
+pub const GL_LUMINANCE_ALPHA_FLOAT32_ATI: u32 = 34841;
+pub const GL_RGBA16F: u32 = 34842;
+pub const GL_RGBA16F_ARB: u32 = 34842;
+pub const GL_RGBA16F_EXT: u32 = 34842;
+pub const GL_RGBA_FLOAT16_APPLE: u32 = 34842;
+pub const GL_RGBA_FLOAT16_ATI: u32 = 34842;
+pub const GL_RGB16F: u32 = 34843;
+pub const GL_RGB16F_ARB: u32 = 34843;
+pub const GL_RGB16F_EXT: u32 = 34843;
+pub const GL_RGB_FLOAT16_APPLE: u32 = 34843;
+pub const GL_RGB_FLOAT16_ATI: u32 = 34843;
+pub const GL_ALPHA16F_ARB: u32 = 34844;
+pub const GL_ALPHA16F_EXT: u32 = 34844;
+pub const GL_ALPHA_FLOAT16_APPLE: u32 = 34844;
+pub const GL_ALPHA_FLOAT16_ATI: u32 = 34844;
+pub const GL_INTENSITY16F_ARB: u32 = 34845;
+pub const GL_INTENSITY_FLOAT16_APPLE: u32 = 34845;
+pub const GL_INTENSITY_FLOAT16_ATI: u32 = 34845;
+pub const GL_LUMINANCE16F_ARB: u32 = 34846;
+pub const GL_LUMINANCE16F_EXT: u32 = 34846;
+pub const GL_LUMINANCE_FLOAT16_APPLE: u32 = 34846;
+pub const GL_LUMINANCE_FLOAT16_ATI: u32 = 34846;
+pub const GL_LUMINANCE_ALPHA16F_ARB: u32 = 34847;
+pub const GL_LUMINANCE_ALPHA16F_EXT: u32 = 34847;
+pub const GL_LUMINANCE_ALPHA_FLOAT16_APPLE: u32 = 34847;
+pub const GL_LUMINANCE_ALPHA_FLOAT16_ATI: u32 = 34847;
+pub const GL_RGBA_FLOAT_MODE_ARB: u32 = 34848;
+pub const GL_RGBA_FLOAT_MODE_ATI: u32 = 34848;
+pub const GL_WRITEONLY_RENDERING_QCOM: u32 = 34851;
+pub const GL_MAX_DRAW_BUFFERS: u32 = 34852;
+pub const GL_MAX_DRAW_BUFFERS_ARB: u32 = 34852;
+pub const GL_MAX_DRAW_BUFFERS_ATI: u32 = 34852;
+pub const GL_MAX_DRAW_BUFFERS_EXT: u32 = 34852;
+pub const GL_MAX_DRAW_BUFFERS_NV: u32 = 34852;
+pub const GL_DRAW_BUFFER0: u32 = 34853;
+pub const GL_DRAW_BUFFER0_ARB: u32 = 34853;
+pub const GL_DRAW_BUFFER0_ATI: u32 = 34853;
+pub const GL_DRAW_BUFFER0_EXT: u32 = 34853;
+pub const GL_DRAW_BUFFER0_NV: u32 = 34853;
+pub const GL_DRAW_BUFFER1: u32 = 34854;
+pub const GL_DRAW_BUFFER1_ARB: u32 = 34854;
+pub const GL_DRAW_BUFFER1_ATI: u32 = 34854;
+pub const GL_DRAW_BUFFER1_EXT: u32 = 34854;
+pub const GL_DRAW_BUFFER1_NV: u32 = 34854;
+pub const GL_DRAW_BUFFER2: u32 = 34855;
+pub const GL_DRAW_BUFFER2_ARB: u32 = 34855;
+pub const GL_DRAW_BUFFER2_ATI: u32 = 34855;
+pub const GL_DRAW_BUFFER2_EXT: u32 = 34855;
+pub const GL_DRAW_BUFFER2_NV: u32 = 34855;
+pub const GL_DRAW_BUFFER3: u32 = 34856;
+pub const GL_DRAW_BUFFER3_ARB: u32 = 34856;
+pub const GL_DRAW_BUFFER3_ATI: u32 = 34856;
+pub const GL_DRAW_BUFFER3_EXT: u32 = 34856;
+pub const GL_DRAW_BUFFER3_NV: u32 = 34856;
+pub const GL_DRAW_BUFFER4: u32 = 34857;
+pub const GL_DRAW_BUFFER4_ARB: u32 = 34857;
+pub const GL_DRAW_BUFFER4_ATI: u32 = 34857;
+pub const GL_DRAW_BUFFER4_EXT: u32 = 34857;
+pub const GL_DRAW_BUFFER4_NV: u32 = 34857;
+pub const GL_DRAW_BUFFER5: u32 = 34858;
+pub const GL_DRAW_BUFFER5_ARB: u32 = 34858;
+pub const GL_DRAW_BUFFER5_ATI: u32 = 34858;
+pub const GL_DRAW_BUFFER5_EXT: u32 = 34858;
+pub const GL_DRAW_BUFFER5_NV: u32 = 34858;
+pub const GL_DRAW_BUFFER6: u32 = 34859;
+pub const GL_DRAW_BUFFER6_ARB: u32 = 34859;
+pub const GL_DRAW_BUFFER6_ATI: u32 = 34859;
+pub const GL_DRAW_BUFFER6_EXT: u32 = 34859;
+pub const GL_DRAW_BUFFER6_NV: u32 = 34859;
+pub const GL_DRAW_BUFFER7: u32 = 34860;
+pub const GL_DRAW_BUFFER7_ARB: u32 = 34860;
+pub const GL_DRAW_BUFFER7_ATI: u32 = 34860;
+pub const GL_DRAW_BUFFER7_EXT: u32 = 34860;
+pub const GL_DRAW_BUFFER7_NV: u32 = 34860;
+pub const GL_DRAW_BUFFER8: u32 = 34861;
+pub const GL_DRAW_BUFFER8_ARB: u32 = 34861;
+pub const GL_DRAW_BUFFER8_ATI: u32 = 34861;
+pub const GL_DRAW_BUFFER8_EXT: u32 = 34861;
+pub const GL_DRAW_BUFFER8_NV: u32 = 34861;
+pub const GL_DRAW_BUFFER9: u32 = 34862;
+pub const GL_DRAW_BUFFER9_ARB: u32 = 34862;
+pub const GL_DRAW_BUFFER9_ATI: u32 = 34862;
+pub const GL_DRAW_BUFFER9_EXT: u32 = 34862;
+pub const GL_DRAW_BUFFER9_NV: u32 = 34862;
+pub const GL_DRAW_BUFFER10: u32 = 34863;
+pub const GL_DRAW_BUFFER10_ARB: u32 = 34863;
+pub const GL_DRAW_BUFFER10_ATI: u32 = 34863;
+pub const GL_DRAW_BUFFER10_EXT: u32 = 34863;
+pub const GL_DRAW_BUFFER10_NV: u32 = 34863;
+pub const GL_DRAW_BUFFER11: u32 = 34864;
+pub const GL_DRAW_BUFFER11_ARB: u32 = 34864;
+pub const GL_DRAW_BUFFER11_ATI: u32 = 34864;
+pub const GL_DRAW_BUFFER11_EXT: u32 = 34864;
+pub const GL_DRAW_BUFFER11_NV: u32 = 34864;
+pub const GL_DRAW_BUFFER12: u32 = 34865;
+pub const GL_DRAW_BUFFER12_ARB: u32 = 34865;
+pub const GL_DRAW_BUFFER12_ATI: u32 = 34865;
+pub const GL_DRAW_BUFFER12_EXT: u32 = 34865;
+pub const GL_DRAW_BUFFER12_NV: u32 = 34865;
+pub const GL_DRAW_BUFFER13: u32 = 34866;
+pub const GL_DRAW_BUFFER13_ARB: u32 = 34866;
+pub const GL_DRAW_BUFFER13_ATI: u32 = 34866;
+pub const GL_DRAW_BUFFER13_EXT: u32 = 34866;
+pub const GL_DRAW_BUFFER13_NV: u32 = 34866;
+pub const GL_DRAW_BUFFER14: u32 = 34867;
+pub const GL_DRAW_BUFFER14_ARB: u32 = 34867;
+pub const GL_DRAW_BUFFER14_ATI: u32 = 34867;
+pub const GL_DRAW_BUFFER14_EXT: u32 = 34867;
+pub const GL_DRAW_BUFFER14_NV: u32 = 34867;
+pub const GL_DRAW_BUFFER15: u32 = 34868;
+pub const GL_DRAW_BUFFER15_ARB: u32 = 34868;
+pub const GL_DRAW_BUFFER15_ATI: u32 = 34868;
+pub const GL_DRAW_BUFFER15_EXT: u32 = 34868;
+pub const GL_DRAW_BUFFER15_NV: u32 = 34868;
+pub const GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI: u32 = 34869;
+pub const GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI: u32 = 34871;
+pub const GL_BLEND_EQUATION_ALPHA: u32 = 34877;
+pub const GL_BLEND_EQUATION_ALPHA_EXT: u32 = 34877;
+pub const GL_BLEND_EQUATION_ALPHA_OES: u32 = 34877;
+pub const GL_SUBSAMPLE_DISTANCE_AMD: u32 = 34879;
+pub const GL_MATRIX_PALETTE_ARB: u32 = 34880;
+pub const GL_MATRIX_PALETTE_OES: u32 = 34880;
+pub const GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB: u32 = 34881;
+pub const GL_MAX_PALETTE_MATRICES_ARB: u32 = 34882;
+pub const GL_MAX_PALETTE_MATRICES_OES: u32 = 34882;
+pub const GL_CURRENT_PALETTE_MATRIX_ARB: u32 = 34883;
+pub const GL_CURRENT_PALETTE_MATRIX_OES: u32 = 34883;
+pub const GL_MATRIX_INDEX_ARRAY_ARB: u32 = 34884;
+pub const GL_MATRIX_INDEX_ARRAY_OES: u32 = 34884;
+pub const GL_CURRENT_MATRIX_INDEX_ARB: u32 = 34885;
+pub const GL_MATRIX_INDEX_ARRAY_SIZE_ARB: u32 = 34886;
+pub const GL_MATRIX_INDEX_ARRAY_SIZE_OES: u32 = 34886;
+pub const GL_MATRIX_INDEX_ARRAY_TYPE_ARB: u32 = 34887;
+pub const GL_MATRIX_INDEX_ARRAY_TYPE_OES: u32 = 34887;
+pub const GL_MATRIX_INDEX_ARRAY_STRIDE_ARB: u32 = 34888;
+pub const GL_MATRIX_INDEX_ARRAY_STRIDE_OES: u32 = 34888;
+pub const GL_MATRIX_INDEX_ARRAY_POINTER_ARB: u32 = 34889;
+pub const GL_MATRIX_INDEX_ARRAY_POINTER_OES: u32 = 34889;
+pub const GL_TEXTURE_DEPTH_SIZE: u32 = 34890;
+pub const GL_TEXTURE_DEPTH_SIZE_ARB: u32 = 34890;
+pub const GL_DEPTH_TEXTURE_MODE: u32 = 34891;
+pub const GL_DEPTH_TEXTURE_MODE_ARB: u32 = 34891;
+pub const GL_TEXTURE_COMPARE_MODE: u32 = 34892;
+pub const GL_TEXTURE_COMPARE_MODE_ARB: u32 = 34892;
+pub const GL_TEXTURE_COMPARE_MODE_EXT: u32 = 34892;
+pub const GL_TEXTURE_COMPARE_FUNC: u32 = 34893;
+pub const GL_TEXTURE_COMPARE_FUNC_ARB: u32 = 34893;
+pub const GL_TEXTURE_COMPARE_FUNC_EXT: u32 = 34893;
+pub const GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT: u32 = 34894;
+pub const GL_COMPARE_REF_TO_TEXTURE: u32 = 34894;
+pub const GL_COMPARE_REF_TO_TEXTURE_EXT: u32 = 34894;
+pub const GL_COMPARE_R_TO_TEXTURE: u32 = 34894;
+pub const GL_COMPARE_R_TO_TEXTURE_ARB: u32 = 34894;
+pub const GL_TEXTURE_CUBE_MAP_SEAMLESS: u32 = 34895;
+pub const GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV: u32 = 34896;
+pub const GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV: u32 = 34897;
+pub const GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV: u32 = 34898;
+pub const GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV: u32 = 34899;
+pub const GL_OFFSET_HILO_TEXTURE_2D_NV: u32 = 34900;
+pub const GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV: u32 = 34901;
+pub const GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV: u32 = 34902;
+pub const GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV: u32 = 34903;
+pub const GL_DEPENDENT_HILO_TEXTURE_2D_NV: u32 = 34904;
+pub const GL_DEPENDENT_RGB_TEXTURE_3D_NV: u32 = 34905;
+pub const GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV: u32 = 34906;
+pub const GL_DOT_PRODUCT_PASS_THROUGH_NV: u32 = 34907;
+pub const GL_DOT_PRODUCT_TEXTURE_1D_NV: u32 = 34908;
+pub const GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV: u32 = 34909;
+pub const GL_HILO8_NV: u32 = 34910;
+pub const GL_SIGNED_HILO8_NV: u32 = 34911;
+pub const GL_FORCE_BLUE_TO_ONE_NV: u32 = 34912;
+pub const GL_POINT_SPRITE: u32 = 34913;
+pub const GL_POINT_SPRITE_ARB: u32 = 34913;
+pub const GL_POINT_SPRITE_NV: u32 = 34913;
+pub const GL_POINT_SPRITE_OES: u32 = 34913;
+pub const GL_COORD_REPLACE: u32 = 34914;
+pub const GL_COORD_REPLACE_ARB: u32 = 34914;
+pub const GL_COORD_REPLACE_NV: u32 = 34914;
+pub const GL_COORD_REPLACE_OES: u32 = 34914;
+pub const GL_POINT_SPRITE_R_MODE_NV: u32 = 34915;
+pub const GL_PIXEL_COUNTER_BITS_NV: u32 = 34916;
+pub const GL_QUERY_COUNTER_BITS: u32 = 34916;
+pub const GL_QUERY_COUNTER_BITS_ARB: u32 = 34916;
+pub const GL_QUERY_COUNTER_BITS_EXT: u32 = 34916;
+pub const GL_CURRENT_OCCLUSION_QUERY_ID_NV: u32 = 34917;
+pub const GL_CURRENT_QUERY: u32 = 34917;
+pub const GL_CURRENT_QUERY_ARB: u32 = 34917;
+pub const GL_CURRENT_QUERY_EXT: u32 = 34917;
+pub const GL_PIXEL_COUNT_NV: u32 = 34918;
+pub const GL_QUERY_RESULT: u32 = 34918;
+pub const GL_QUERY_RESULT_ARB: u32 = 34918;
+pub const GL_QUERY_RESULT_EXT: u32 = 34918;
+pub const GL_PIXEL_COUNT_AVAILABLE_NV: u32 = 34919;
+pub const GL_QUERY_RESULT_AVAILABLE: u32 = 34919;
+pub const GL_QUERY_RESULT_AVAILABLE_ARB: u32 = 34919;
+pub const GL_QUERY_RESULT_AVAILABLE_EXT: u32 = 34919;
+pub const GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV: u32 = 34920;
+pub const GL_MAX_VERTEX_ATTRIBS: u32 = 34921;
+pub const GL_MAX_VERTEX_ATTRIBS_ARB: u32 = 34921;
+pub const GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: u32 = 34922;
+pub const GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB: u32 = 34922;
+pub const GL_MAX_TESS_CONTROL_INPUT_COMPONENTS: u32 = 34924;
+pub const GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT: u32 = 34924;
+pub const GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_OES: u32 = 34924;
+pub const GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS: u32 = 34925;
+pub const GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT: u32 = 34925;
+pub const GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_OES: u32 = 34925;
+pub const GL_DEPTH_STENCIL_TO_RGBA_NV: u32 = 34926;
+pub const GL_DEPTH_STENCIL_TO_BGRA_NV: u32 = 34927;
+pub const GL_FRAGMENT_PROGRAM_NV: u32 = 34928;
+pub const GL_MAX_TEXTURE_COORDS: u32 = 34929;
+pub const GL_MAX_TEXTURE_COORDS_ARB: u32 = 34929;
+pub const GL_MAX_TEXTURE_COORDS_NV: u32 = 34929;
+pub const GL_MAX_TEXTURE_IMAGE_UNITS: u32 = 34930;
+pub const GL_MAX_TEXTURE_IMAGE_UNITS_ARB: u32 = 34930;
+pub const GL_MAX_TEXTURE_IMAGE_UNITS_NV: u32 = 34930;
+pub const GL_FRAGMENT_PROGRAM_BINDING_NV: u32 = 34931;
+pub const GL_PROGRAM_ERROR_STRING_ARB: u32 = 34932;
+pub const GL_PROGRAM_ERROR_STRING_NV: u32 = 34932;
+pub const GL_PROGRAM_FORMAT_ASCII_ARB: u32 = 34933;
+pub const GL_PROGRAM_FORMAT_ARB: u32 = 34934;
+pub const GL_WRITE_PIXEL_DATA_RANGE_NV: u32 = 34936;
+pub const GL_READ_PIXEL_DATA_RANGE_NV: u32 = 34937;
+pub const GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV: u32 = 34938;
+pub const GL_READ_PIXEL_DATA_RANGE_LENGTH_NV: u32 = 34939;
+pub const GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV: u32 = 34940;
+pub const GL_READ_PIXEL_DATA_RANGE_POINTER_NV: u32 = 34941;
+pub const GL_GEOMETRY_SHADER_INVOCATIONS: u32 = 34943;
+pub const GL_GEOMETRY_SHADER_INVOCATIONS_EXT: u32 = 34943;
+pub const GL_GEOMETRY_SHADER_INVOCATIONS_OES: u32 = 34943;
+pub const GL_FLOAT_R_NV: u32 = 34944;
+pub const GL_FLOAT_RG_NV: u32 = 34945;
+pub const GL_FLOAT_RGB_NV: u32 = 34946;
+pub const GL_FLOAT_RGBA_NV: u32 = 34947;
+pub const GL_FLOAT_R16_NV: u32 = 34948;
+pub const GL_FLOAT_R32_NV: u32 = 34949;
+pub const GL_FLOAT_RG16_NV: u32 = 34950;
+pub const GL_FLOAT_RG32_NV: u32 = 34951;
+pub const GL_FLOAT_RGB16_NV: u32 = 34952;
+pub const GL_FLOAT_RGB32_NV: u32 = 34953;
+pub const GL_FLOAT_RGBA16_NV: u32 = 34954;
+pub const GL_FLOAT_RGBA32_NV: u32 = 34955;
+pub const GL_TEXTURE_FLOAT_COMPONENTS_NV: u32 = 34956;
+pub const GL_FLOAT_CLEAR_COLOR_VALUE_NV: u32 = 34957;
+pub const GL_FLOAT_RGBA_MODE_NV: u32 = 34958;
+pub const GL_TEXTURE_UNSIGNED_REMAP_MODE_NV: u32 = 34959;
+pub const GL_DEPTH_BOUNDS_TEST_EXT: u32 = 34960;
+pub const GL_DEPTH_BOUNDS_EXT: u32 = 34961;
+pub const GL_ARRAY_BUFFER: u32 = 34962;
+pub const GL_ARRAY_BUFFER_ARB: u32 = 34962;
+pub const GL_ELEMENT_ARRAY_BUFFER: u32 = 34963;
+pub const GL_ELEMENT_ARRAY_BUFFER_ARB: u32 = 34963;
+pub const GL_ARRAY_BUFFER_BINDING: u32 = 34964;
+pub const GL_ARRAY_BUFFER_BINDING_ARB: u32 = 34964;
+pub const GL_ELEMENT_ARRAY_BUFFER_BINDING: u32 = 34965;
+pub const GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB: u32 = 34965;
+pub const GL_VERTEX_ARRAY_BUFFER_BINDING: u32 = 34966;
+pub const GL_VERTEX_ARRAY_BUFFER_BINDING_ARB: u32 = 34966;
+pub const GL_NORMAL_ARRAY_BUFFER_BINDING: u32 = 34967;
+pub const GL_NORMAL_ARRAY_BUFFER_BINDING_ARB: u32 = 34967;
+pub const GL_COLOR_ARRAY_BUFFER_BINDING: u32 = 34968;
+pub const GL_COLOR_ARRAY_BUFFER_BINDING_ARB: u32 = 34968;
+pub const GL_INDEX_ARRAY_BUFFER_BINDING: u32 = 34969;
+pub const GL_INDEX_ARRAY_BUFFER_BINDING_ARB: u32 = 34969;
+pub const GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING: u32 = 34970;
+pub const GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB: u32 = 34970;
+pub const GL_EDGE_FLAG_ARRAY_BUFFER_BINDING: u32 = 34971;
+pub const GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB: u32 = 34971;
+pub const GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING: u32 = 34972;
+pub const GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB: u32 = 34972;
+pub const GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING: u32 = 34973;
+pub const GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB: u32 = 34973;
+pub const GL_FOG_COORD_ARRAY_BUFFER_BINDING: u32 = 34973;
+pub const GL_WEIGHT_ARRAY_BUFFER_BINDING: u32 = 34974;
+pub const GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB: u32 = 34974;
+pub const GL_WEIGHT_ARRAY_BUFFER_BINDING_OES: u32 = 34974;
+pub const GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: u32 = 34975;
+pub const GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB: u32 = 34975;
+pub const GL_PROGRAM_INSTRUCTIONS_ARB: u32 = 34976;
+pub const GL_MAX_PROGRAM_INSTRUCTIONS_ARB: u32 = 34977;
+pub const GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB: u32 = 34978;
+pub const GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB: u32 = 34979;
+pub const GL_PROGRAM_TEMPORARIES_ARB: u32 = 34980;
+pub const GL_MAX_PROGRAM_TEMPORARIES_ARB: u32 = 34981;
+pub const GL_PROGRAM_NATIVE_TEMPORARIES_ARB: u32 = 34982;
+pub const GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB: u32 = 34983;
+pub const GL_PROGRAM_PARAMETERS_ARB: u32 = 34984;
+pub const GL_MAX_PROGRAM_PARAMETERS_ARB: u32 = 34985;
+pub const GL_PROGRAM_NATIVE_PARAMETERS_ARB: u32 = 34986;
+pub const GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB: u32 = 34987;
+pub const GL_PROGRAM_ATTRIBS_ARB: u32 = 34988;
+pub const GL_MAX_PROGRAM_ATTRIBS_ARB: u32 = 34989;
+pub const GL_PROGRAM_NATIVE_ATTRIBS_ARB: u32 = 34990;
+pub const GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB: u32 = 34991;
+pub const GL_PROGRAM_ADDRESS_REGISTERS_ARB: u32 = 34992;
+pub const GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB: u32 = 34993;
+pub const GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB: u32 = 34994;
+pub const GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB: u32 = 34995;
+pub const GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB: u32 = 34996;
+pub const GL_MAX_PROGRAM_ENV_PARAMETERS_ARB: u32 = 34997;
+pub const GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB: u32 = 34998;
+pub const GL_TRANSPOSE_CURRENT_MATRIX_ARB: u32 = 34999;
+pub const GL_READ_ONLY: u32 = 35000;
+pub const GL_READ_ONLY_ARB: u32 = 35000;
+pub const GL_WRITE_ONLY: u32 = 35001;
+pub const GL_WRITE_ONLY_ARB: u32 = 35001;
+pub const GL_WRITE_ONLY_OES: u32 = 35001;
+pub const GL_READ_WRITE: u32 = 35002;
+pub const GL_READ_WRITE_ARB: u32 = 35002;
+pub const GL_BUFFER_ACCESS: u32 = 35003;
+pub const GL_BUFFER_ACCESS_ARB: u32 = 35003;
+pub const GL_BUFFER_ACCESS_OES: u32 = 35003;
+pub const GL_BUFFER_MAPPED: u32 = 35004;
+pub const GL_BUFFER_MAPPED_ARB: u32 = 35004;
+pub const GL_BUFFER_MAPPED_OES: u32 = 35004;
+pub const GL_BUFFER_MAP_POINTER: u32 = 35005;
+pub const GL_BUFFER_MAP_POINTER_ARB: u32 = 35005;
+pub const GL_BUFFER_MAP_POINTER_OES: u32 = 35005;
+pub const GL_WRITE_DISCARD_NV: u32 = 35006;
+pub const GL_TIME_ELAPSED: u32 = 35007;
+pub const GL_TIME_ELAPSED_EXT: u32 = 35007;
+pub const GL_MATRIX0_ARB: u32 = 35008;
+pub const GL_MATRIX1_ARB: u32 = 35009;
+pub const GL_MATRIX2_ARB: u32 = 35010;
+pub const GL_MATRIX3_ARB: u32 = 35011;
+pub const GL_MATRIX4_ARB: u32 = 35012;
+pub const GL_MATRIX5_ARB: u32 = 35013;
+pub const GL_MATRIX6_ARB: u32 = 35014;
+pub const GL_MATRIX7_ARB: u32 = 35015;
+pub const GL_MATRIX8_ARB: u32 = 35016;
+pub const GL_MATRIX9_ARB: u32 = 35017;
+pub const GL_MATRIX10_ARB: u32 = 35018;
+pub const GL_MATRIX11_ARB: u32 = 35019;
+pub const GL_MATRIX12_ARB: u32 = 35020;
+pub const GL_MATRIX13_ARB: u32 = 35021;
+pub const GL_MATRIX14_ARB: u32 = 35022;
+pub const GL_MATRIX15_ARB: u32 = 35023;
+pub const GL_MATRIX16_ARB: u32 = 35024;
+pub const GL_MATRIX17_ARB: u32 = 35025;
+pub const GL_MATRIX18_ARB: u32 = 35026;
+pub const GL_MATRIX19_ARB: u32 = 35027;
+pub const GL_MATRIX20_ARB: u32 = 35028;
+pub const GL_MATRIX21_ARB: u32 = 35029;
+pub const GL_MATRIX22_ARB: u32 = 35030;
+pub const GL_MATRIX23_ARB: u32 = 35031;
+pub const GL_MATRIX24_ARB: u32 = 35032;
+pub const GL_MATRIX25_ARB: u32 = 35033;
+pub const GL_MATRIX26_ARB: u32 = 35034;
+pub const GL_MATRIX27_ARB: u32 = 35035;
+pub const GL_MATRIX28_ARB: u32 = 35036;
+pub const GL_MATRIX29_ARB: u32 = 35037;
+pub const GL_MATRIX30_ARB: u32 = 35038;
+pub const GL_MATRIX31_ARB: u32 = 35039;
+pub const GL_STREAM_DRAW: u32 = 35040;
+pub const GL_STREAM_DRAW_ARB: u32 = 35040;
+pub const GL_STREAM_READ: u32 = 35041;
+pub const GL_STREAM_READ_ARB: u32 = 35041;
+pub const GL_STREAM_COPY: u32 = 35042;
+pub const GL_STREAM_COPY_ARB: u32 = 35042;
+pub const GL_STATIC_DRAW: u32 = 35044;
+pub const GL_STATIC_DRAW_ARB: u32 = 35044;
+pub const GL_STATIC_READ: u32 = 35045;
+pub const GL_STATIC_READ_ARB: u32 = 35045;
+pub const GL_STATIC_COPY: u32 = 35046;
+pub const GL_STATIC_COPY_ARB: u32 = 35046;
+pub const GL_DYNAMIC_DRAW: u32 = 35048;
+pub const GL_DYNAMIC_DRAW_ARB: u32 = 35048;
+pub const GL_DYNAMIC_READ: u32 = 35049;
+pub const GL_DYNAMIC_READ_ARB: u32 = 35049;
+pub const GL_DYNAMIC_COPY: u32 = 35050;
+pub const GL_DYNAMIC_COPY_ARB: u32 = 35050;
+pub const GL_PIXEL_PACK_BUFFER: u32 = 35051;
+pub const GL_PIXEL_PACK_BUFFER_ARB: u32 = 35051;
+pub const GL_PIXEL_PACK_BUFFER_EXT: u32 = 35051;
+pub const GL_PIXEL_UNPACK_BUFFER: u32 = 35052;
+pub const GL_PIXEL_UNPACK_BUFFER_ARB: u32 = 35052;
+pub const GL_PIXEL_UNPACK_BUFFER_EXT: u32 = 35052;
+pub const GL_PIXEL_PACK_BUFFER_BINDING: u32 = 35053;
+pub const GL_PIXEL_PACK_BUFFER_BINDING_ARB: u32 = 35053;
+pub const GL_PIXEL_PACK_BUFFER_BINDING_EXT: u32 = 35053;
+pub const GL_ETC1_SRGB8_NV: u32 = 35054;
+pub const GL_PIXEL_UNPACK_BUFFER_BINDING: u32 = 35055;
+pub const GL_PIXEL_UNPACK_BUFFER_BINDING_ARB: u32 = 35055;
+pub const GL_PIXEL_UNPACK_BUFFER_BINDING_EXT: u32 = 35055;
+pub const GL_DEPTH24_STENCIL8: u32 = 35056;
+pub const GL_DEPTH24_STENCIL8_EXT: u32 = 35056;
+pub const GL_DEPTH24_STENCIL8_OES: u32 = 35056;
+pub const GL_TEXTURE_STENCIL_SIZE: u32 = 35057;
+pub const GL_TEXTURE_STENCIL_SIZE_EXT: u32 = 35057;
+pub const GL_STENCIL_TAG_BITS_EXT: u32 = 35058;
+pub const GL_STENCIL_CLEAR_TAG_VALUE_EXT: u32 = 35059;
+pub const GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV: u32 = 35060;
+pub const GL_MAX_PROGRAM_CALL_DEPTH_NV: u32 = 35061;
+pub const GL_MAX_PROGRAM_IF_DEPTH_NV: u32 = 35062;
+pub const GL_MAX_PROGRAM_LOOP_DEPTH_NV: u32 = 35063;
+pub const GL_MAX_PROGRAM_LOOP_COUNT_NV: u32 = 35064;
+pub const GL_SRC1_COLOR: u32 = 35065;
+pub const GL_SRC1_COLOR_EXT: u32 = 35065;
+pub const GL_ONE_MINUS_SRC1_COLOR: u32 = 35066;
+pub const GL_ONE_MINUS_SRC1_COLOR_EXT: u32 = 35066;
+pub const GL_ONE_MINUS_SRC1_ALPHA: u32 = 35067;
+pub const GL_ONE_MINUS_SRC1_ALPHA_EXT: u32 = 35067;
+pub const GL_MAX_DUAL_SOURCE_DRAW_BUFFERS: u32 = 35068;
+pub const GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT: u32 = 35068;
+pub const GL_VERTEX_ATTRIB_ARRAY_INTEGER: u32 = 35069;
+pub const GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT: u32 = 35069;
+pub const GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV: u32 = 35069;
+pub const GL_VERTEX_ATTRIB_ARRAY_DIVISOR: u32 = 35070;
+pub const GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: u32 = 35070;
+pub const GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB: u32 = 35070;
+pub const GL_VERTEX_ATTRIB_ARRAY_DIVISOR_EXT: u32 = 35070;
+pub const GL_VERTEX_ATTRIB_ARRAY_DIVISOR_NV: u32 = 35070;
+pub const GL_MAX_ARRAY_TEXTURE_LAYERS: u32 = 35071;
+pub const GL_MAX_ARRAY_TEXTURE_LAYERS_EXT: u32 = 35071;
+pub const GL_MIN_PROGRAM_TEXEL_OFFSET: u32 = 35076;
+pub const GL_MIN_PROGRAM_TEXEL_OFFSET_EXT: u32 = 35076;
+pub const GL_MIN_PROGRAM_TEXEL_OFFSET_NV: u32 = 35076;
+pub const GL_MAX_PROGRAM_TEXEL_OFFSET: u32 = 35077;
+pub const GL_MAX_PROGRAM_TEXEL_OFFSET_EXT: u32 = 35077;
+pub const GL_MAX_PROGRAM_TEXEL_OFFSET_NV: u32 = 35077;
+pub const GL_PROGRAM_ATTRIB_COMPONENTS_NV: u32 = 35078;
+pub const GL_PROGRAM_RESULT_COMPONENTS_NV: u32 = 35079;
+pub const GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV: u32 = 35080;
+pub const GL_MAX_PROGRAM_RESULT_COMPONENTS_NV: u32 = 35081;
+pub const GL_STENCIL_TEST_TWO_SIDE_EXT: u32 = 35088;
+pub const GL_ACTIVE_STENCIL_FACE_EXT: u32 = 35089;
+pub const GL_MIRROR_CLAMP_TO_BORDER_EXT: u32 = 35090;
+pub const GL_SAMPLES_PASSED: u32 = 35092;
+pub const GL_SAMPLES_PASSED_ARB: u32 = 35092;
+pub const GL_GEOMETRY_LINKED_VERTICES_OUT_EXT: u32 = 35094;
+pub const GL_GEOMETRY_LINKED_VERTICES_OUT_OES: u32 = 35094;
+pub const GL_GEOMETRY_VERTICES_OUT: u32 = 35094;
+pub const GL_GEOMETRY_INPUT_TYPE: u32 = 35095;
+pub const GL_GEOMETRY_LINKED_INPUT_TYPE_EXT: u32 = 35095;
+pub const GL_GEOMETRY_LINKED_INPUT_TYPE_OES: u32 = 35095;
+pub const GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT: u32 = 35096;
+pub const GL_GEOMETRY_LINKED_OUTPUT_TYPE_OES: u32 = 35096;
+pub const GL_GEOMETRY_OUTPUT_TYPE: u32 = 35096;
+pub const GL_SAMPLER_BINDING: u32 = 35097;
+pub const GL_CLAMP_VERTEX_COLOR: u32 = 35098;
+pub const GL_CLAMP_VERTEX_COLOR_ARB: u32 = 35098;
+pub const GL_CLAMP_FRAGMENT_COLOR: u32 = 35099;
+pub const GL_CLAMP_FRAGMENT_COLOR_ARB: u32 = 35099;
+pub const GL_CLAMP_READ_COLOR: u32 = 35100;
+pub const GL_CLAMP_READ_COLOR_ARB: u32 = 35100;
+pub const GL_FIXED_ONLY: u32 = 35101;
+pub const GL_FIXED_ONLY_ARB: u32 = 35101;
+pub const GL_TESS_CONTROL_PROGRAM_NV: u32 = 35102;
+pub const GL_TESS_EVALUATION_PROGRAM_NV: u32 = 35103;
+pub const GL_FRAGMENT_SHADER_ATI: u32 = 35104;
+pub const GL_REG_0_ATI: u32 = 35105;
+pub const GL_REG_1_ATI: u32 = 35106;
+pub const GL_REG_2_ATI: u32 = 35107;
+pub const GL_REG_3_ATI: u32 = 35108;
+pub const GL_REG_4_ATI: u32 = 35109;
+pub const GL_REG_5_ATI: u32 = 35110;
+pub const GL_REG_6_ATI: u32 = 35111;
+pub const GL_REG_7_ATI: u32 = 35112;
+pub const GL_REG_8_ATI: u32 = 35113;
+pub const GL_REG_9_ATI: u32 = 35114;
+pub const GL_REG_10_ATI: u32 = 35115;
+pub const GL_REG_11_ATI: u32 = 35116;
+pub const GL_REG_12_ATI: u32 = 35117;
+pub const GL_REG_13_ATI: u32 = 35118;
+pub const GL_REG_14_ATI: u32 = 35119;
+pub const GL_REG_15_ATI: u32 = 35120;
+pub const GL_REG_16_ATI: u32 = 35121;
+pub const GL_REG_17_ATI: u32 = 35122;
+pub const GL_REG_18_ATI: u32 = 35123;
+pub const GL_REG_19_ATI: u32 = 35124;
+pub const GL_REG_20_ATI: u32 = 35125;
+pub const GL_REG_21_ATI: u32 = 35126;
+pub const GL_REG_22_ATI: u32 = 35127;
+pub const GL_REG_23_ATI: u32 = 35128;
+pub const GL_REG_24_ATI: u32 = 35129;
+pub const GL_REG_25_ATI: u32 = 35130;
+pub const GL_REG_26_ATI: u32 = 35131;
+pub const GL_REG_27_ATI: u32 = 35132;
+pub const GL_REG_28_ATI: u32 = 35133;
+pub const GL_REG_29_ATI: u32 = 35134;
+pub const GL_REG_30_ATI: u32 = 35135;
+pub const GL_REG_31_ATI: u32 = 35136;
+pub const GL_CON_0_ATI: u32 = 35137;
+pub const GL_CON_1_ATI: u32 = 35138;
+pub const GL_CON_2_ATI: u32 = 35139;
+pub const GL_CON_3_ATI: u32 = 35140;
+pub const GL_CON_4_ATI: u32 = 35141;
+pub const GL_CON_5_ATI: u32 = 35142;
+pub const GL_CON_6_ATI: u32 = 35143;
+pub const GL_CON_7_ATI: u32 = 35144;
+pub const GL_CON_8_ATI: u32 = 35145;
+pub const GL_CON_9_ATI: u32 = 35146;
+pub const GL_CON_10_ATI: u32 = 35147;
+pub const GL_CON_11_ATI: u32 = 35148;
+pub const GL_CON_12_ATI: u32 = 35149;
+pub const GL_CON_13_ATI: u32 = 35150;
+pub const GL_CON_14_ATI: u32 = 35151;
+pub const GL_CON_15_ATI: u32 = 35152;
+pub const GL_CON_16_ATI: u32 = 35153;
+pub const GL_CON_17_ATI: u32 = 35154;
+pub const GL_CON_18_ATI: u32 = 35155;
+pub const GL_CON_19_ATI: u32 = 35156;
+pub const GL_CON_20_ATI: u32 = 35157;
+pub const GL_CON_21_ATI: u32 = 35158;
+pub const GL_CON_22_ATI: u32 = 35159;
+pub const GL_CON_23_ATI: u32 = 35160;
+pub const GL_CON_24_ATI: u32 = 35161;
+pub const GL_CON_25_ATI: u32 = 35162;
+pub const GL_CON_26_ATI: u32 = 35163;
+pub const GL_CON_27_ATI: u32 = 35164;
+pub const GL_CON_28_ATI: u32 = 35165;
+pub const GL_CON_29_ATI: u32 = 35166;
+pub const GL_CON_30_ATI: u32 = 35167;
+pub const GL_CON_31_ATI: u32 = 35168;
+pub const GL_MOV_ATI: u32 = 35169;
+pub const GL_ADD_ATI: u32 = 35171;
+pub const GL_MUL_ATI: u32 = 35172;
+pub const GL_SUB_ATI: u32 = 35173;
+pub const GL_DOT3_ATI: u32 = 35174;
+pub const GL_DOT4_ATI: u32 = 35175;
+pub const GL_MAD_ATI: u32 = 35176;
+pub const GL_LERP_ATI: u32 = 35177;
+pub const GL_CND_ATI: u32 = 35178;
+pub const GL_CND0_ATI: u32 = 35179;
+pub const GL_DOT2_ADD_ATI: u32 = 35180;
+pub const GL_SECONDARY_INTERPOLATOR_ATI: u32 = 35181;
+pub const GL_NUM_FRAGMENT_REGISTERS_ATI: u32 = 35182;
+pub const GL_NUM_FRAGMENT_CONSTANTS_ATI: u32 = 35183;
+pub const GL_NUM_PASSES_ATI: u32 = 35184;
+pub const GL_NUM_INSTRUCTIONS_PER_PASS_ATI: u32 = 35185;
+pub const GL_NUM_INSTRUCTIONS_TOTAL_ATI: u32 = 35186;
+pub const GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI: u32 = 35187;
+pub const GL_NUM_LOOPBACK_COMPONENTS_ATI: u32 = 35188;
+pub const GL_COLOR_ALPHA_PAIRING_ATI: u32 = 35189;
+pub const GL_SWIZZLE_STR_ATI: u32 = 35190;
+pub const GL_SWIZZLE_STQ_ATI: u32 = 35191;
+pub const GL_SWIZZLE_STR_DR_ATI: u32 = 35192;
+pub const GL_SWIZZLE_STQ_DQ_ATI: u32 = 35193;
+pub const GL_SWIZZLE_STRQ_ATI: u32 = 35194;
+pub const GL_SWIZZLE_STRQ_DQ_ATI: u32 = 35195;
+pub const GL_INTERLACE_OML: u32 = 35200;
+pub const GL_INTERLACE_READ_OML: u32 = 35201;
+pub const GL_FORMAT_SUBSAMPLE_24_24_OML: u32 = 35202;
+pub const GL_FORMAT_SUBSAMPLE_244_244_OML: u32 = 35203;
+pub const GL_PACK_RESAMPLE_OML: u32 = 35204;
+pub const GL_UNPACK_RESAMPLE_OML: u32 = 35205;
+pub const GL_RESAMPLE_REPLICATE_OML: u32 = 35206;
+pub const GL_RESAMPLE_ZERO_FILL_OML: u32 = 35207;
+pub const GL_RESAMPLE_AVERAGE_OML: u32 = 35208;
+pub const GL_RESAMPLE_DECIMATE_OML: u32 = 35209;
+pub const GL_POINT_SIZE_ARRAY_TYPE_OES: u32 = 35210;
+pub const GL_POINT_SIZE_ARRAY_STRIDE_OES: u32 = 35211;
+pub const GL_POINT_SIZE_ARRAY_POINTER_OES: u32 = 35212;
+pub const GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES: u32 = 35213;
+pub const GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES: u32 = 35214;
+pub const GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES: u32 = 35215;
+pub const GL_VERTEX_ATTRIB_MAP1_APPLE: u32 = 35328;
+pub const GL_VERTEX_ATTRIB_MAP2_APPLE: u32 = 35329;
+pub const GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE: u32 = 35330;
+pub const GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE: u32 = 35331;
+pub const GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE: u32 = 35332;
+pub const GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE: u32 = 35333;
+pub const GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE: u32 = 35334;
+pub const GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE: u32 = 35335;
+pub const GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE: u32 = 35336;
+pub const GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE: u32 = 35337;
+pub const GL_DRAW_PIXELS_APPLE: u32 = 35338;
+pub const GL_FENCE_APPLE: u32 = 35339;
+pub const GL_ELEMENT_ARRAY_APPLE: u32 = 35340;
+pub const GL_ELEMENT_ARRAY_TYPE_APPLE: u32 = 35341;
+pub const GL_ELEMENT_ARRAY_POINTER_APPLE: u32 = 35342;
+pub const GL_COLOR_FLOAT_APPLE: u32 = 35343;
+pub const GL_UNIFORM_BUFFER: u32 = 35345;
+pub const GL_BUFFER_SERIALIZED_MODIFY_APPLE: u32 = 35346;
+pub const GL_BUFFER_FLUSHING_UNMAP_APPLE: u32 = 35347;
+pub const GL_AUX_DEPTH_STENCIL_APPLE: u32 = 35348;
+pub const GL_PACK_ROW_BYTES_APPLE: u32 = 35349;
+pub const GL_UNPACK_ROW_BYTES_APPLE: u32 = 35350;
+pub const GL_RELEASED_APPLE: u32 = 35353;
+pub const GL_VOLATILE_APPLE: u32 = 35354;
+pub const GL_RETAINED_APPLE: u32 = 35355;
+pub const GL_UNDEFINED_APPLE: u32 = 35356;
+pub const GL_PURGEABLE_APPLE: u32 = 35357;
+pub const GL_RGB_422_APPLE: u32 = 35359;
+pub const GL_UNIFORM_BUFFER_BINDING: u32 = 35368;
+pub const GL_UNIFORM_BUFFER_START: u32 = 35369;
+pub const GL_UNIFORM_BUFFER_SIZE: u32 = 35370;
+pub const GL_MAX_VERTEX_UNIFORM_BLOCKS: u32 = 35371;
+pub const GL_MAX_GEOMETRY_UNIFORM_BLOCKS: u32 = 35372;
+pub const GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT: u32 = 35372;
+pub const GL_MAX_GEOMETRY_UNIFORM_BLOCKS_OES: u32 = 35372;
+pub const GL_MAX_FRAGMENT_UNIFORM_BLOCKS: u32 = 35373;
+pub const GL_MAX_COMBINED_UNIFORM_BLOCKS: u32 = 35374;
+pub const GL_MAX_UNIFORM_BUFFER_BINDINGS: u32 = 35375;
+pub const GL_MAX_UNIFORM_BLOCK_SIZE: u32 = 35376;
+pub const GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: u32 = 35377;
+pub const GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS: u32 = 35378;
+pub const GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_EXT: u32 = 35378;
+pub const GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_OES: u32 = 35378;
+pub const GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: u32 = 35379;
+pub const GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: u32 = 35380;
+pub const GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: u32 = 35381;
+pub const GL_ACTIVE_UNIFORM_BLOCKS: u32 = 35382;
+pub const GL_UNIFORM_TYPE: u32 = 35383;
+pub const GL_UNIFORM_SIZE: u32 = 35384;
+pub const GL_UNIFORM_NAME_LENGTH: u32 = 35385;
+pub const GL_UNIFORM_BLOCK_INDEX: u32 = 35386;
+pub const GL_UNIFORM_OFFSET: u32 = 35387;
+pub const GL_UNIFORM_ARRAY_STRIDE: u32 = 35388;
+pub const GL_UNIFORM_MATRIX_STRIDE: u32 = 35389;
+pub const GL_UNIFORM_IS_ROW_MAJOR: u32 = 35390;
+pub const GL_UNIFORM_BLOCK_BINDING: u32 = 35391;
+pub const GL_UNIFORM_BLOCK_DATA_SIZE: u32 = 35392;
+pub const GL_UNIFORM_BLOCK_NAME_LENGTH: u32 = 35393;
+pub const GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: u32 = 35394;
+pub const GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: u32 = 35395;
+pub const GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: u32 = 35396;
+pub const GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER: u32 = 35397;
+pub const GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: u32 = 35398;
+pub const GL_TEXTURE_SRGB_DECODE_EXT: u32 = 35400;
+pub const GL_DECODE_EXT: u32 = 35401;
+pub const GL_SKIP_DECODE_EXT: u32 = 35402;
+pub const GL_PROGRAM_PIPELINE_OBJECT_EXT: u32 = 35407;
+pub const GL_RGB_RAW_422_APPLE: u32 = 35409;
+pub const GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT: u32 = 35410;
+pub const GL_SYNC_OBJECT_APPLE: u32 = 35411;
+pub const GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT: u32 = 35412;
+pub const GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT: u32 = 35413;
+pub const GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT: u32 = 35414;
+pub const GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT: u32 = 35415;
+pub const GL_FRAGMENT_SHADER: u32 = 35632;
+pub const GL_FRAGMENT_SHADER_ARB: u32 = 35632;
+pub const GL_VERTEX_SHADER: u32 = 35633;
+pub const GL_VERTEX_SHADER_ARB: u32 = 35633;
+pub const GL_PROGRAM_OBJECT_ARB: u32 = 35648;
+pub const GL_PROGRAM_OBJECT_EXT: u32 = 35648;
+pub const GL_SHADER_OBJECT_ARB: u32 = 35656;
+pub const GL_SHADER_OBJECT_EXT: u32 = 35656;
+pub const GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: u32 = 35657;
+pub const GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB: u32 = 35657;
+pub const GL_MAX_VERTEX_UNIFORM_COMPONENTS: u32 = 35658;
+pub const GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB: u32 = 35658;
+pub const GL_MAX_VARYING_COMPONENTS: u32 = 35659;
+pub const GL_MAX_VARYING_COMPONENTS_EXT: u32 = 35659;
+pub const GL_MAX_VARYING_FLOATS: u32 = 35659;
+pub const GL_MAX_VARYING_FLOATS_ARB: u32 = 35659;
+pub const GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: u32 = 35660;
+pub const GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB: u32 = 35660;
+pub const GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: u32 = 35661;
+pub const GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB: u32 = 35661;
+pub const GL_OBJECT_TYPE_ARB: u32 = 35662;
+pub const GL_OBJECT_SUBTYPE_ARB: u32 = 35663;
+pub const GL_SHADER_TYPE: u32 = 35663;
+pub const GL_FLOAT_VEC2: u32 = 35664;
+pub const GL_FLOAT_VEC2_ARB: u32 = 35664;
+pub const GL_FLOAT_VEC3: u32 = 35665;
+pub const GL_FLOAT_VEC3_ARB: u32 = 35665;
+pub const GL_FLOAT_VEC4: u32 = 35666;
+pub const GL_FLOAT_VEC4_ARB: u32 = 35666;
+pub const GL_INT_VEC2: u32 = 35667;
+pub const GL_INT_VEC2_ARB: u32 = 35667;
+pub const GL_INT_VEC3: u32 = 35668;
+pub const GL_INT_VEC3_ARB: u32 = 35668;
+pub const GL_INT_VEC4: u32 = 35669;
+pub const GL_INT_VEC4_ARB: u32 = 35669;
+pub const GL_BOOL: u32 = 35670;
+pub const GL_BOOL_ARB: u32 = 35670;
+pub const GL_BOOL_VEC2: u32 = 35671;
+pub const GL_BOOL_VEC2_ARB: u32 = 35671;
+pub const GL_BOOL_VEC3: u32 = 35672;
+pub const GL_BOOL_VEC3_ARB: u32 = 35672;
+pub const GL_BOOL_VEC4: u32 = 35673;
+pub const GL_BOOL_VEC4_ARB: u32 = 35673;
+pub const GL_FLOAT_MAT2: u32 = 35674;
+pub const GL_FLOAT_MAT2_ARB: u32 = 35674;
+pub const GL_FLOAT_MAT3: u32 = 35675;
+pub const GL_FLOAT_MAT3_ARB: u32 = 35675;
+pub const GL_FLOAT_MAT4: u32 = 35676;
+pub const GL_FLOAT_MAT4_ARB: u32 = 35676;
+pub const GL_SAMPLER_1D: u32 = 35677;
+pub const GL_SAMPLER_1D_ARB: u32 = 35677;
+pub const GL_SAMPLER_2D: u32 = 35678;
+pub const GL_SAMPLER_2D_ARB: u32 = 35678;
+pub const GL_SAMPLER_3D: u32 = 35679;
+pub const GL_SAMPLER_3D_ARB: u32 = 35679;
+pub const GL_SAMPLER_3D_OES: u32 = 35679;
+pub const GL_SAMPLER_CUBE: u32 = 35680;
+pub const GL_SAMPLER_CUBE_ARB: u32 = 35680;
+pub const GL_SAMPLER_1D_SHADOW: u32 = 35681;
+pub const GL_SAMPLER_1D_SHADOW_ARB: u32 = 35681;
+pub const GL_SAMPLER_2D_SHADOW: u32 = 35682;
+pub const GL_SAMPLER_2D_SHADOW_ARB: u32 = 35682;
+pub const GL_SAMPLER_2D_SHADOW_EXT: u32 = 35682;
+pub const GL_SAMPLER_2D_RECT: u32 = 35683;
+pub const GL_SAMPLER_2D_RECT_ARB: u32 = 35683;
+pub const GL_SAMPLER_2D_RECT_SHADOW: u32 = 35684;
+pub const GL_SAMPLER_2D_RECT_SHADOW_ARB: u32 = 35684;
+pub const GL_FLOAT_MAT2x3: u32 = 35685;
+pub const GL_FLOAT_MAT2x3_NV: u32 = 35685;
+pub const GL_FLOAT_MAT2x4: u32 = 35686;
+pub const GL_FLOAT_MAT2x4_NV: u32 = 35686;
+pub const GL_FLOAT_MAT3x2: u32 = 35687;
+pub const GL_FLOAT_MAT3x2_NV: u32 = 35687;
+pub const GL_FLOAT_MAT3x4: u32 = 35688;
+pub const GL_FLOAT_MAT3x4_NV: u32 = 35688;
+pub const GL_FLOAT_MAT4x2: u32 = 35689;
+pub const GL_FLOAT_MAT4x2_NV: u32 = 35689;
+pub const GL_FLOAT_MAT4x3: u32 = 35690;
+pub const GL_FLOAT_MAT4x3_NV: u32 = 35690;
+pub const GL_DELETE_STATUS: u32 = 35712;
+pub const GL_OBJECT_DELETE_STATUS_ARB: u32 = 35712;
+pub const GL_COMPILE_STATUS: u32 = 35713;
+pub const GL_OBJECT_COMPILE_STATUS_ARB: u32 = 35713;
+pub const GL_LINK_STATUS: u32 = 35714;
+pub const GL_OBJECT_LINK_STATUS_ARB: u32 = 35714;
+pub const GL_OBJECT_VALIDATE_STATUS_ARB: u32 = 35715;
+pub const GL_VALIDATE_STATUS: u32 = 35715;
+pub const GL_INFO_LOG_LENGTH: u32 = 35716;
+pub const GL_OBJECT_INFO_LOG_LENGTH_ARB: u32 = 35716;
+pub const GL_ATTACHED_SHADERS: u32 = 35717;
+pub const GL_OBJECT_ATTACHED_OBJECTS_ARB: u32 = 35717;
+pub const GL_ACTIVE_UNIFORMS: u32 = 35718;
+pub const GL_OBJECT_ACTIVE_UNIFORMS_ARB: u32 = 35718;
+pub const GL_ACTIVE_UNIFORM_MAX_LENGTH: u32 = 35719;
+pub const GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB: u32 = 35719;
+pub const GL_OBJECT_SHADER_SOURCE_LENGTH_ARB: u32 = 35720;
+pub const GL_SHADER_SOURCE_LENGTH: u32 = 35720;
+pub const GL_ACTIVE_ATTRIBUTES: u32 = 35721;
+pub const GL_OBJECT_ACTIVE_ATTRIBUTES_ARB: u32 = 35721;
+pub const GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: u32 = 35722;
+pub const GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB: u32 = 35722;
+pub const GL_FRAGMENT_SHADER_DERIVATIVE_HINT: u32 = 35723;
+pub const GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB: u32 = 35723;
+pub const GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: u32 = 35723;
+pub const GL_SHADING_LANGUAGE_VERSION: u32 = 35724;
+pub const GL_SHADING_LANGUAGE_VERSION_ARB: u32 = 35724;
+pub const GL_ACTIVE_PROGRAM_EXT: u32 = 35725;
+pub const GL_CURRENT_PROGRAM: u32 = 35725;
+pub const GL_PALETTE4_RGB8_OES: u32 = 35728;
+pub const GL_PALETTE4_RGBA8_OES: u32 = 35729;
+pub const GL_PALETTE4_R5_G6_B5_OES: u32 = 35730;
+pub const GL_PALETTE4_RGBA4_OES: u32 = 35731;
+pub const GL_PALETTE4_RGB5_A1_OES: u32 = 35732;
+pub const GL_PALETTE8_RGB8_OES: u32 = 35733;
+pub const GL_PALETTE8_RGBA8_OES: u32 = 35734;
+pub const GL_PALETTE8_R5_G6_B5_OES: u32 = 35735;
+pub const GL_PALETTE8_RGBA4_OES: u32 = 35736;
+pub const GL_PALETTE8_RGB5_A1_OES: u32 = 35737;
+pub const GL_IMPLEMENTATION_COLOR_READ_TYPE: u32 = 35738;
+pub const GL_IMPLEMENTATION_COLOR_READ_TYPE_OES: u32 = 35738;
+pub const GL_IMPLEMENTATION_COLOR_READ_FORMAT: u32 = 35739;
+pub const GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES: u32 = 35739;
+pub const GL_POINT_SIZE_ARRAY_OES: u32 = 35740;
+pub const GL_TEXTURE_CROP_RECT_OES: u32 = 35741;
+pub const GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES: u32 = 35742;
+pub const GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES: u32 = 35743;
+pub const GL_FRAGMENT_PROGRAM_POSITION_MESA: u32 = 35760;
+pub const GL_FRAGMENT_PROGRAM_CALLBACK_MESA: u32 = 35761;
+pub const GL_FRAGMENT_PROGRAM_CALLBACK_FUNC_MESA: u32 = 35762;
+pub const GL_FRAGMENT_PROGRAM_CALLBACK_DATA_MESA: u32 = 35763;
+pub const GL_VERTEX_PROGRAM_POSITION_MESA: u32 = 35764;
+pub const GL_VERTEX_PROGRAM_CALLBACK_MESA: u32 = 35765;
+pub const GL_VERTEX_PROGRAM_CALLBACK_FUNC_MESA: u32 = 35766;
+pub const GL_VERTEX_PROGRAM_CALLBACK_DATA_MESA: u32 = 35767;
+pub const GL_COUNTER_TYPE_AMD: u32 = 35776;
+pub const GL_COUNTER_RANGE_AMD: u32 = 35777;
+pub const GL_UNSIGNED_INT64_AMD: u32 = 35778;
+pub const GL_PERCENTAGE_AMD: u32 = 35779;
+pub const GL_PERFMON_RESULT_AVAILABLE_AMD: u32 = 35780;
+pub const GL_PERFMON_RESULT_SIZE_AMD: u32 = 35781;
+pub const GL_PERFMON_RESULT_AMD: u32 = 35782;
+pub const GL_TEXTURE_WIDTH_QCOM: u32 = 35794;
+pub const GL_TEXTURE_HEIGHT_QCOM: u32 = 35795;
+pub const GL_TEXTURE_DEPTH_QCOM: u32 = 35796;
+pub const GL_TEXTURE_INTERNAL_FORMAT_QCOM: u32 = 35797;
+pub const GL_TEXTURE_FORMAT_QCOM: u32 = 35798;
+pub const GL_TEXTURE_TYPE_QCOM: u32 = 35799;
+pub const GL_TEXTURE_IMAGE_VALID_QCOM: u32 = 35800;
+pub const GL_TEXTURE_NUM_LEVELS_QCOM: u32 = 35801;
+pub const GL_TEXTURE_TARGET_QCOM: u32 = 35802;
+pub const GL_TEXTURE_OBJECT_VALID_QCOM: u32 = 35803;
+pub const GL_STATE_RESTORE: u32 = 35804;
+pub const GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT: u32 = 35815;
+pub const GL_TEXTURE_PROTECTED_EXT: u32 = 35834;
+pub const GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: u32 = 35840;
+pub const GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: u32 = 35841;
+pub const GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: u32 = 35842;
+pub const GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: u32 = 35843;
+pub const GL_MODULATE_COLOR_IMG: u32 = 35844;
+pub const GL_RECIP_ADD_SIGNED_ALPHA_IMG: u32 = 35845;
+pub const GL_TEXTURE_ALPHA_MODULATE_IMG: u32 = 35846;
+pub const GL_FACTOR_ALPHA_MODULATE_IMG: u32 = 35847;
+pub const GL_FRAGMENT_ALPHA_MODULATE_IMG: u32 = 35848;
+pub const GL_ADD_BLEND_IMG: u32 = 35849;
+pub const GL_SGX_BINARY_IMG: u32 = 35850;
+pub const GL_TEXTURE_RED_TYPE: u32 = 35856;
+pub const GL_TEXTURE_RED_TYPE_ARB: u32 = 35856;
+pub const GL_TEXTURE_GREEN_TYPE: u32 = 35857;
+pub const GL_TEXTURE_GREEN_TYPE_ARB: u32 = 35857;
+pub const GL_TEXTURE_BLUE_TYPE: u32 = 35858;
+pub const GL_TEXTURE_BLUE_TYPE_ARB: u32 = 35858;
+pub const GL_TEXTURE_ALPHA_TYPE: u32 = 35859;
+pub const GL_TEXTURE_ALPHA_TYPE_ARB: u32 = 35859;
+pub const GL_TEXTURE_LUMINANCE_TYPE: u32 = 35860;
+pub const GL_TEXTURE_LUMINANCE_TYPE_ARB: u32 = 35860;
+pub const GL_TEXTURE_INTENSITY_TYPE: u32 = 35861;
+pub const GL_TEXTURE_INTENSITY_TYPE_ARB: u32 = 35861;
+pub const GL_TEXTURE_DEPTH_TYPE: u32 = 35862;
+pub const GL_TEXTURE_DEPTH_TYPE_ARB: u32 = 35862;
+pub const GL_UNSIGNED_NORMALIZED: u32 = 35863;
+pub const GL_UNSIGNED_NORMALIZED_ARB: u32 = 35863;
+pub const GL_UNSIGNED_NORMALIZED_EXT: u32 = 35863;
+pub const GL_TEXTURE_1D_ARRAY: u32 = 35864;
+pub const GL_TEXTURE_1D_ARRAY_EXT: u32 = 35864;
+pub const GL_PROXY_TEXTURE_1D_ARRAY: u32 = 35865;
+pub const GL_PROXY_TEXTURE_1D_ARRAY_EXT: u32 = 35865;
+pub const GL_TEXTURE_2D_ARRAY: u32 = 35866;
+pub const GL_TEXTURE_2D_ARRAY_EXT: u32 = 35866;
+pub const GL_PROXY_TEXTURE_2D_ARRAY: u32 = 35867;
+pub const GL_PROXY_TEXTURE_2D_ARRAY_EXT: u32 = 35867;
+pub const GL_TEXTURE_BINDING_1D_ARRAY: u32 = 35868;
+pub const GL_TEXTURE_BINDING_1D_ARRAY_EXT: u32 = 35868;
+pub const GL_TEXTURE_BINDING_2D_ARRAY: u32 = 35869;
+pub const GL_TEXTURE_BINDING_2D_ARRAY_EXT: u32 = 35869;
+pub const GL_GEOMETRY_PROGRAM_NV: u32 = 35878;
+pub const GL_MAX_PROGRAM_OUTPUT_VERTICES_NV: u32 = 35879;
+pub const GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV: u32 = 35880;
+pub const GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS: u32 = 35881;
+pub const GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB: u32 = 35881;
+pub const GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT: u32 = 35881;
+pub const GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_OES: u32 = 35881;
+pub const GL_TEXTURE_BUFFER: u32 = 35882;
+pub const GL_TEXTURE_BUFFER_ARB: u32 = 35882;
+pub const GL_TEXTURE_BUFFER_BINDING: u32 = 35882;
+pub const GL_TEXTURE_BUFFER_BINDING_EXT: u32 = 35882;
+pub const GL_TEXTURE_BUFFER_BINDING_OES: u32 = 35882;
+pub const GL_TEXTURE_BUFFER_EXT: u32 = 35882;
+pub const GL_TEXTURE_BUFFER_OES: u32 = 35882;
+pub const GL_MAX_TEXTURE_BUFFER_SIZE: u32 = 35883;
+pub const GL_MAX_TEXTURE_BUFFER_SIZE_ARB: u32 = 35883;
+pub const GL_MAX_TEXTURE_BUFFER_SIZE_EXT: u32 = 35883;
+pub const GL_MAX_TEXTURE_BUFFER_SIZE_OES: u32 = 35883;
+pub const GL_TEXTURE_BINDING_BUFFER: u32 = 35884;
+pub const GL_TEXTURE_BINDING_BUFFER_ARB: u32 = 35884;
+pub const GL_TEXTURE_BINDING_BUFFER_EXT: u32 = 35884;
+pub const GL_TEXTURE_BINDING_BUFFER_OES: u32 = 35884;
+pub const GL_TEXTURE_BUFFER_DATA_STORE_BINDING: u32 = 35885;
+pub const GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB: u32 = 35885;
+pub const GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT: u32 = 35885;
+pub const GL_TEXTURE_BUFFER_DATA_STORE_BINDING_OES: u32 = 35885;
+pub const GL_TEXTURE_BUFFER_FORMAT_ARB: u32 = 35886;
+pub const GL_TEXTURE_BUFFER_FORMAT_EXT: u32 = 35886;
+pub const GL_ANY_SAMPLES_PASSED: u32 = 35887;
+pub const GL_ANY_SAMPLES_PASSED_EXT: u32 = 35887;
+pub const GL_SAMPLE_SHADING: u32 = 35894;
+pub const GL_SAMPLE_SHADING_ARB: u32 = 35894;
+pub const GL_SAMPLE_SHADING_OES: u32 = 35894;
+pub const GL_MIN_SAMPLE_SHADING_VALUE: u32 = 35895;
+pub const GL_MIN_SAMPLE_SHADING_VALUE_ARB: u32 = 35895;
+pub const GL_MIN_SAMPLE_SHADING_VALUE_OES: u32 = 35895;
+pub const GL_R11F_G11F_B10F: u32 = 35898;
+pub const GL_R11F_G11F_B10F_APPLE: u32 = 35898;
+pub const GL_R11F_G11F_B10F_EXT: u32 = 35898;
+pub const GL_UNSIGNED_INT_10F_11F_11F_REV: u32 = 35899;
+pub const GL_UNSIGNED_INT_10F_11F_11F_REV_APPLE: u32 = 35899;
+pub const GL_UNSIGNED_INT_10F_11F_11F_REV_EXT: u32 = 35899;
+pub const GL_RGBA_SIGNED_COMPONENTS_EXT: u32 = 35900;
+pub const GL_RGB9_E5: u32 = 35901;
+pub const GL_RGB9_E5_APPLE: u32 = 35901;
+pub const GL_RGB9_E5_EXT: u32 = 35901;
+pub const GL_UNSIGNED_INT_5_9_9_9_REV: u32 = 35902;
+pub const GL_UNSIGNED_INT_5_9_9_9_REV_APPLE: u32 = 35902;
+pub const GL_UNSIGNED_INT_5_9_9_9_REV_EXT: u32 = 35902;
+pub const GL_TEXTURE_SHARED_SIZE: u32 = 35903;
+pub const GL_TEXTURE_SHARED_SIZE_EXT: u32 = 35903;
+pub const GL_SRGB: u32 = 35904;
+pub const GL_SRGB_EXT: u32 = 35904;
+pub const GL_SRGB8: u32 = 35905;
+pub const GL_SRGB8_EXT: u32 = 35905;
+pub const GL_SRGB8_NV: u32 = 35905;
+pub const GL_SRGB_ALPHA: u32 = 35906;
+pub const GL_SRGB_ALPHA_EXT: u32 = 35906;
+pub const GL_SRGB8_ALPHA8: u32 = 35907;
+pub const GL_SRGB8_ALPHA8_EXT: u32 = 35907;
+pub const GL_SLUMINANCE_ALPHA: u32 = 35908;
+pub const GL_SLUMINANCE_ALPHA_EXT: u32 = 35908;
+pub const GL_SLUMINANCE_ALPHA_NV: u32 = 35908;
+pub const GL_SLUMINANCE8_ALPHA8: u32 = 35909;
+pub const GL_SLUMINANCE8_ALPHA8_EXT: u32 = 35909;
+pub const GL_SLUMINANCE8_ALPHA8_NV: u32 = 35909;
+pub const GL_SLUMINANCE: u32 = 35910;
+pub const GL_SLUMINANCE_EXT: u32 = 35910;
+pub const GL_SLUMINANCE_NV: u32 = 35910;
+pub const GL_SLUMINANCE8: u32 = 35911;
+pub const GL_SLUMINANCE8_EXT: u32 = 35911;
+pub const GL_SLUMINANCE8_NV: u32 = 35911;
+pub const GL_COMPRESSED_SRGB: u32 = 35912;
+pub const GL_COMPRESSED_SRGB_EXT: u32 = 35912;
+pub const GL_COMPRESSED_SRGB_ALPHA: u32 = 35913;
+pub const GL_COMPRESSED_SRGB_ALPHA_EXT: u32 = 35913;
+pub const GL_COMPRESSED_SLUMINANCE: u32 = 35914;
+pub const GL_COMPRESSED_SLUMINANCE_EXT: u32 = 35914;
+pub const GL_COMPRESSED_SLUMINANCE_ALPHA: u32 = 35915;
+pub const GL_COMPRESSED_SLUMINANCE_ALPHA_EXT: u32 = 35915;
+pub const GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: u32 = 35916;
+pub const GL_COMPRESSED_SRGB_S3TC_DXT1_NV: u32 = 35916;
+pub const GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: u32 = 35917;
+pub const GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV: u32 = 35917;
+pub const GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: u32 = 35918;
+pub const GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV: u32 = 35918;
+pub const GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: u32 = 35919;
+pub const GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV: u32 = 35919;
+pub const GL_COMPRESSED_LUMINANCE_LATC1_EXT: u32 = 35952;
+pub const GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT: u32 = 35953;
+pub const GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: u32 = 35954;
+pub const GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT: u32 = 35955;
+pub const GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV: u32 = 35956;
+pub const GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV: u32 = 35957;
+pub const GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: u32 = 35958;
+pub const GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT: u32 = 35958;
+pub const GL_BACK_PRIMARY_COLOR_NV: u32 = 35959;
+pub const GL_BACK_SECONDARY_COLOR_NV: u32 = 35960;
+pub const GL_TEXTURE_COORD_NV: u32 = 35961;
+pub const GL_CLIP_DISTANCE_NV: u32 = 35962;
+pub const GL_VERTEX_ID_NV: u32 = 35963;
+pub const GL_PRIMITIVE_ID_NV: u32 = 35964;
+pub const GL_GENERIC_ATTRIB_NV: u32 = 35965;
+pub const GL_TRANSFORM_FEEDBACK_ATTRIBS_NV: u32 = 35966;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_MODE: u32 = 35967;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT: u32 = 35967;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV: u32 = 35967;
+pub const GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: u32 = 35968;
+pub const GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT: u32 = 35968;
+pub const GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV: u32 = 35968;
+pub const GL_ACTIVE_VARYINGS_NV: u32 = 35969;
+pub const GL_ACTIVE_VARYING_MAX_LENGTH_NV: u32 = 35970;
+pub const GL_TRANSFORM_FEEDBACK_VARYINGS: u32 = 35971;
+pub const GL_TRANSFORM_FEEDBACK_VARYINGS_EXT: u32 = 35971;
+pub const GL_TRANSFORM_FEEDBACK_VARYINGS_NV: u32 = 35971;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_START: u32 = 35972;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT: u32 = 35972;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_START_NV: u32 = 35972;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: u32 = 35973;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT: u32 = 35973;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV: u32 = 35973;
+pub const GL_TRANSFORM_FEEDBACK_RECORD_NV: u32 = 35974;
+pub const GL_PRIMITIVES_GENERATED: u32 = 35975;
+pub const GL_PRIMITIVES_GENERATED_EXT: u32 = 35975;
+pub const GL_PRIMITIVES_GENERATED_NV: u32 = 35975;
+pub const GL_PRIMITIVES_GENERATED_OES: u32 = 35975;
+pub const GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: u32 = 35976;
+pub const GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT: u32 = 35976;
+pub const GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV: u32 = 35976;
+pub const GL_RASTERIZER_DISCARD: u32 = 35977;
+pub const GL_RASTERIZER_DISCARD_EXT: u32 = 35977;
+pub const GL_RASTERIZER_DISCARD_NV: u32 = 35977;
+pub const GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: u32 = 35978;
+pub const GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT: u32 = 35978;
+pub const GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV: u32 = 35978;
+pub const GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: u32 = 35979;
+pub const GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT: u32 = 35979;
+pub const GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV: u32 = 35979;
+pub const GL_INTERLEAVED_ATTRIBS: u32 = 35980;
+pub const GL_INTERLEAVED_ATTRIBS_EXT: u32 = 35980;
+pub const GL_INTERLEAVED_ATTRIBS_NV: u32 = 35980;
+pub const GL_SEPARATE_ATTRIBS: u32 = 35981;
+pub const GL_SEPARATE_ATTRIBS_EXT: u32 = 35981;
+pub const GL_SEPARATE_ATTRIBS_NV: u32 = 35981;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER: u32 = 35982;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_EXT: u32 = 35982;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_NV: u32 = 35982;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: u32 = 35983;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT: u32 = 35983;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV: u32 = 35983;
+pub const GL_ATC_RGB_AMD: u32 = 35986;
+pub const GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: u32 = 35987;
+pub const GL_POINT_SPRITE_COORD_ORIGIN: u32 = 36000;
+pub const GL_LOWER_LEFT: u32 = 36001;
+pub const GL_UPPER_LEFT: u32 = 36002;
+pub const GL_STENCIL_BACK_REF: u32 = 36003;
+pub const GL_STENCIL_BACK_VALUE_MASK: u32 = 36004;
+pub const GL_STENCIL_BACK_WRITEMASK: u32 = 36005;
+pub const GL_DRAW_FRAMEBUFFER_BINDING: u32 = 36006;
+pub const GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: u32 = 36006;
+pub const GL_DRAW_FRAMEBUFFER_BINDING_APPLE: u32 = 36006;
+pub const GL_DRAW_FRAMEBUFFER_BINDING_EXT: u32 = 36006;
+pub const GL_DRAW_FRAMEBUFFER_BINDING_NV: u32 = 36006;
+pub const GL_FRAMEBUFFER_BINDING: u32 = 36006;
+pub const GL_FRAMEBUFFER_BINDING_ANGLE: u32 = 36006;
+pub const GL_FRAMEBUFFER_BINDING_EXT: u32 = 36006;
+pub const GL_FRAMEBUFFER_BINDING_OES: u32 = 36006;
+pub const GL_RENDERBUFFER_BINDING: u32 = 36007;
+pub const GL_RENDERBUFFER_BINDING_ANGLE: u32 = 36007;
+pub const GL_RENDERBUFFER_BINDING_EXT: u32 = 36007;
+pub const GL_RENDERBUFFER_BINDING_OES: u32 = 36007;
+pub const GL_READ_FRAMEBUFFER: u32 = 36008;
+pub const GL_READ_FRAMEBUFFER_ANGLE: u32 = 36008;
+pub const GL_READ_FRAMEBUFFER_APPLE: u32 = 36008;
+pub const GL_READ_FRAMEBUFFER_EXT: u32 = 36008;
+pub const GL_READ_FRAMEBUFFER_NV: u32 = 36008;
+pub const GL_DRAW_FRAMEBUFFER: u32 = 36009;
+pub const GL_DRAW_FRAMEBUFFER_ANGLE: u32 = 36009;
+pub const GL_DRAW_FRAMEBUFFER_APPLE: u32 = 36009;
+pub const GL_DRAW_FRAMEBUFFER_EXT: u32 = 36009;
+pub const GL_DRAW_FRAMEBUFFER_NV: u32 = 36009;
+pub const GL_READ_FRAMEBUFFER_BINDING: u32 = 36010;
+pub const GL_READ_FRAMEBUFFER_BINDING_ANGLE: u32 = 36010;
+pub const GL_READ_FRAMEBUFFER_BINDING_APPLE: u32 = 36010;
+pub const GL_READ_FRAMEBUFFER_BINDING_EXT: u32 = 36010;
+pub const GL_READ_FRAMEBUFFER_BINDING_NV: u32 = 36010;
+pub const GL_RENDERBUFFER_COVERAGE_SAMPLES_NV: u32 = 36011;
+pub const GL_RENDERBUFFER_SAMPLES: u32 = 36011;
+pub const GL_RENDERBUFFER_SAMPLES_ANGLE: u32 = 36011;
+pub const GL_RENDERBUFFER_SAMPLES_APPLE: u32 = 36011;
+pub const GL_RENDERBUFFER_SAMPLES_EXT: u32 = 36011;
+pub const GL_RENDERBUFFER_SAMPLES_NV: u32 = 36011;
+pub const GL_DEPTH_COMPONENT32F: u32 = 36012;
+pub const GL_DEPTH32F_STENCIL8: u32 = 36013;
+pub const GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: u32 = 36048;
+pub const GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: u32 = 36048;
+pub const GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES: u32 = 36048;
+pub const GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: u32 = 36049;
+pub const GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: u32 = 36049;
+pub const GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES: u32 = 36049;
+pub const GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: u32 = 36050;
+pub const GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: u32 = 36050;
+pub const GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES: u32 = 36050;
+pub const GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: u32 = 36051;
+pub const GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: u32 = 36051;
+pub const GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES: u32 = 36051;
+pub const GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: u32 = 36052;
+pub const GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES: u32 = 36052;
+pub const GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: u32 = 36052;
+pub const GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT: u32 = 36052;
+pub const GL_FRAMEBUFFER_COMPLETE: u32 = 36053;
+pub const GL_FRAMEBUFFER_COMPLETE_EXT: u32 = 36053;
+pub const GL_FRAMEBUFFER_COMPLETE_OES: u32 = 36053;
+pub const GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: u32 = 36054;
+pub const GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: u32 = 36054;
+pub const GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES: u32 = 36054;
+pub const GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: u32 = 36055;
+pub const GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: u32 = 36055;
+pub const GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES: u32 = 36055;
+pub const GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: u32 = 36057;
+pub const GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: u32 = 36057;
+pub const GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES: u32 = 36057;
+pub const GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: u32 = 36058;
+pub const GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES: u32 = 36058;
+pub const GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: u32 = 36059;
+pub const GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: u32 = 36059;
+pub const GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_OES: u32 = 36059;
+pub const GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: u32 = 36060;
+pub const GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: u32 = 36060;
+pub const GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_OES: u32 = 36060;
+pub const GL_FRAMEBUFFER_UNSUPPORTED: u32 = 36061;
+pub const GL_FRAMEBUFFER_UNSUPPORTED_EXT: u32 = 36061;
+pub const GL_FRAMEBUFFER_UNSUPPORTED_OES: u32 = 36061;
+pub const GL_MAX_COLOR_ATTACHMENTS: u32 = 36063;
+pub const GL_MAX_COLOR_ATTACHMENTS_EXT: u32 = 36063;
+pub const GL_MAX_COLOR_ATTACHMENTS_NV: u32 = 36063;
+pub const GL_COLOR_ATTACHMENT0: u32 = 36064;
+pub const GL_COLOR_ATTACHMENT0_EXT: u32 = 36064;
+pub const GL_COLOR_ATTACHMENT0_NV: u32 = 36064;
+pub const GL_COLOR_ATTACHMENT0_OES: u32 = 36064;
+pub const GL_COLOR_ATTACHMENT1: u32 = 36065;
+pub const GL_COLOR_ATTACHMENT1_EXT: u32 = 36065;
+pub const GL_COLOR_ATTACHMENT1_NV: u32 = 36065;
+pub const GL_COLOR_ATTACHMENT2: u32 = 36066;
+pub const GL_COLOR_ATTACHMENT2_EXT: u32 = 36066;
+pub const GL_COLOR_ATTACHMENT2_NV: u32 = 36066;
+pub const GL_COLOR_ATTACHMENT3: u32 = 36067;
+pub const GL_COLOR_ATTACHMENT3_EXT: u32 = 36067;
+pub const GL_COLOR_ATTACHMENT3_NV: u32 = 36067;
+pub const GL_COLOR_ATTACHMENT4: u32 = 36068;
+pub const GL_COLOR_ATTACHMENT4_EXT: u32 = 36068;
+pub const GL_COLOR_ATTACHMENT4_NV: u32 = 36068;
+pub const GL_COLOR_ATTACHMENT5: u32 = 36069;
+pub const GL_COLOR_ATTACHMENT5_EXT: u32 = 36069;
+pub const GL_COLOR_ATTACHMENT5_NV: u32 = 36069;
+pub const GL_COLOR_ATTACHMENT6: u32 = 36070;
+pub const GL_COLOR_ATTACHMENT6_EXT: u32 = 36070;
+pub const GL_COLOR_ATTACHMENT6_NV: u32 = 36070;
+pub const GL_COLOR_ATTACHMENT7: u32 = 36071;
+pub const GL_COLOR_ATTACHMENT7_EXT: u32 = 36071;
+pub const GL_COLOR_ATTACHMENT7_NV: u32 = 36071;
+pub const GL_COLOR_ATTACHMENT8: u32 = 36072;
+pub const GL_COLOR_ATTACHMENT8_EXT: u32 = 36072;
+pub const GL_COLOR_ATTACHMENT8_NV: u32 = 36072;
+pub const GL_COLOR_ATTACHMENT9: u32 = 36073;
+pub const GL_COLOR_ATTACHMENT9_EXT: u32 = 36073;
+pub const GL_COLOR_ATTACHMENT9_NV: u32 = 36073;
+pub const GL_COLOR_ATTACHMENT10: u32 = 36074;
+pub const GL_COLOR_ATTACHMENT10_EXT: u32 = 36074;
+pub const GL_COLOR_ATTACHMENT10_NV: u32 = 36074;
+pub const GL_COLOR_ATTACHMENT11: u32 = 36075;
+pub const GL_COLOR_ATTACHMENT11_EXT: u32 = 36075;
+pub const GL_COLOR_ATTACHMENT11_NV: u32 = 36075;
+pub const GL_COLOR_ATTACHMENT12: u32 = 36076;
+pub const GL_COLOR_ATTACHMENT12_EXT: u32 = 36076;
+pub const GL_COLOR_ATTACHMENT12_NV: u32 = 36076;
+pub const GL_COLOR_ATTACHMENT13: u32 = 36077;
+pub const GL_COLOR_ATTACHMENT13_EXT: u32 = 36077;
+pub const GL_COLOR_ATTACHMENT13_NV: u32 = 36077;
+pub const GL_COLOR_ATTACHMENT14: u32 = 36078;
+pub const GL_COLOR_ATTACHMENT14_EXT: u32 = 36078;
+pub const GL_COLOR_ATTACHMENT14_NV: u32 = 36078;
+pub const GL_COLOR_ATTACHMENT15: u32 = 36079;
+pub const GL_COLOR_ATTACHMENT15_EXT: u32 = 36079;
+pub const GL_COLOR_ATTACHMENT15_NV: u32 = 36079;
+pub const GL_COLOR_ATTACHMENT16: u32 = 36080;
+pub const GL_COLOR_ATTACHMENT17: u32 = 36081;
+pub const GL_COLOR_ATTACHMENT18: u32 = 36082;
+pub const GL_COLOR_ATTACHMENT19: u32 = 36083;
+pub const GL_COLOR_ATTACHMENT20: u32 = 36084;
+pub const GL_COLOR_ATTACHMENT21: u32 = 36085;
+pub const GL_COLOR_ATTACHMENT22: u32 = 36086;
+pub const GL_COLOR_ATTACHMENT23: u32 = 36087;
+pub const GL_COLOR_ATTACHMENT24: u32 = 36088;
+pub const GL_COLOR_ATTACHMENT25: u32 = 36089;
+pub const GL_COLOR_ATTACHMENT26: u32 = 36090;
+pub const GL_COLOR_ATTACHMENT27: u32 = 36091;
+pub const GL_COLOR_ATTACHMENT28: u32 = 36092;
+pub const GL_COLOR_ATTACHMENT29: u32 = 36093;
+pub const GL_COLOR_ATTACHMENT30: u32 = 36094;
+pub const GL_COLOR_ATTACHMENT31: u32 = 36095;
+pub const GL_DEPTH_ATTACHMENT: u32 = 36096;
+pub const GL_DEPTH_ATTACHMENT_EXT: u32 = 36096;
+pub const GL_DEPTH_ATTACHMENT_OES: u32 = 36096;
+pub const GL_STENCIL_ATTACHMENT: u32 = 36128;
+pub const GL_STENCIL_ATTACHMENT_EXT: u32 = 36128;
+pub const GL_STENCIL_ATTACHMENT_OES: u32 = 36128;
+pub const GL_FRAMEBUFFER: u32 = 36160;
+pub const GL_FRAMEBUFFER_EXT: u32 = 36160;
+pub const GL_FRAMEBUFFER_OES: u32 = 36160;
+pub const GL_RENDERBUFFER: u32 = 36161;
+pub const GL_RENDERBUFFER_EXT: u32 = 36161;
+pub const GL_RENDERBUFFER_OES: u32 = 36161;
+pub const GL_RENDERBUFFER_WIDTH: u32 = 36162;
+pub const GL_RENDERBUFFER_WIDTH_EXT: u32 = 36162;
+pub const GL_RENDERBUFFER_WIDTH_OES: u32 = 36162;
+pub const GL_RENDERBUFFER_HEIGHT: u32 = 36163;
+pub const GL_RENDERBUFFER_HEIGHT_EXT: u32 = 36163;
+pub const GL_RENDERBUFFER_HEIGHT_OES: u32 = 36163;
+pub const GL_RENDERBUFFER_INTERNAL_FORMAT: u32 = 36164;
+pub const GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: u32 = 36164;
+pub const GL_RENDERBUFFER_INTERNAL_FORMAT_OES: u32 = 36164;
+pub const GL_STENCIL_INDEX1: u32 = 36166;
+pub const GL_STENCIL_INDEX1_EXT: u32 = 36166;
+pub const GL_STENCIL_INDEX1_OES: u32 = 36166;
+pub const GL_STENCIL_INDEX4: u32 = 36167;
+pub const GL_STENCIL_INDEX4_EXT: u32 = 36167;
+pub const GL_STENCIL_INDEX4_OES: u32 = 36167;
+pub const GL_STENCIL_INDEX8: u32 = 36168;
+pub const GL_STENCIL_INDEX8_EXT: u32 = 36168;
+pub const GL_STENCIL_INDEX8_OES: u32 = 36168;
+pub const GL_STENCIL_INDEX16: u32 = 36169;
+pub const GL_STENCIL_INDEX16_EXT: u32 = 36169;
+pub const GL_RENDERBUFFER_RED_SIZE: u32 = 36176;
+pub const GL_RENDERBUFFER_RED_SIZE_EXT: u32 = 36176;
+pub const GL_RENDERBUFFER_RED_SIZE_OES: u32 = 36176;
+pub const GL_RENDERBUFFER_GREEN_SIZE: u32 = 36177;
+pub const GL_RENDERBUFFER_GREEN_SIZE_EXT: u32 = 36177;
+pub const GL_RENDERBUFFER_GREEN_SIZE_OES: u32 = 36177;
+pub const GL_RENDERBUFFER_BLUE_SIZE: u32 = 36178;
+pub const GL_RENDERBUFFER_BLUE_SIZE_EXT: u32 = 36178;
+pub const GL_RENDERBUFFER_BLUE_SIZE_OES: u32 = 36178;
+pub const GL_RENDERBUFFER_ALPHA_SIZE: u32 = 36179;
+pub const GL_RENDERBUFFER_ALPHA_SIZE_EXT: u32 = 36179;
+pub const GL_RENDERBUFFER_ALPHA_SIZE_OES: u32 = 36179;
+pub const GL_RENDERBUFFER_DEPTH_SIZE: u32 = 36180;
+pub const GL_RENDERBUFFER_DEPTH_SIZE_EXT: u32 = 36180;
+pub const GL_RENDERBUFFER_DEPTH_SIZE_OES: u32 = 36180;
+pub const GL_RENDERBUFFER_STENCIL_SIZE: u32 = 36181;
+pub const GL_RENDERBUFFER_STENCIL_SIZE_EXT: u32 = 36181;
+pub const GL_RENDERBUFFER_STENCIL_SIZE_OES: u32 = 36181;
+pub const GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: u32 = 36182;
+pub const GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE: u32 = 36182;
+pub const GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE: u32 = 36182;
+pub const GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT: u32 = 36182;
+pub const GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_NV: u32 = 36182;
+pub const GL_MAX_SAMPLES: u32 = 36183;
+pub const GL_MAX_SAMPLES_ANGLE: u32 = 36183;
+pub const GL_MAX_SAMPLES_APPLE: u32 = 36183;
+pub const GL_MAX_SAMPLES_EXT: u32 = 36183;
+pub const GL_MAX_SAMPLES_NV: u32 = 36183;
+pub const GL_TEXTURE_GEN_STR_OES: u32 = 36192;
+pub const GL_HALF_FLOAT_OES: u32 = 36193;
+pub const GL_RGB565: u32 = 36194;
+pub const GL_RGB565_OES: u32 = 36194;
+pub const GL_ETC1_RGB8_OES: u32 = 36196;
+pub const GL_TEXTURE_EXTERNAL_OES: u32 = 36197;
+pub const GL_SAMPLER_EXTERNAL_OES: u32 = 36198;
+pub const GL_TEXTURE_BINDING_EXTERNAL_OES: u32 = 36199;
+pub const GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES: u32 = 36200;
+pub const GL_PRIMITIVE_RESTART_FIXED_INDEX: u32 = 36201;
+pub const GL_ANY_SAMPLES_PASSED_CONSERVATIVE: u32 = 36202;
+pub const GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: u32 = 36202;
+pub const GL_MAX_ELEMENT_INDEX: u32 = 36203;
+pub const GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT: u32 = 36204;
+pub const GL_RGBA32UI: u32 = 36208;
+pub const GL_RGBA32UI_EXT: u32 = 36208;
+pub const GL_RGB32UI: u32 = 36209;
+pub const GL_RGB32UI_EXT: u32 = 36209;
+pub const GL_ALPHA32UI_EXT: u32 = 36210;
+pub const GL_INTENSITY32UI_EXT: u32 = 36211;
+pub const GL_LUMINANCE32UI_EXT: u32 = 36212;
+pub const GL_LUMINANCE_ALPHA32UI_EXT: u32 = 36213;
+pub const GL_RGBA16UI: u32 = 36214;
+pub const GL_RGBA16UI_EXT: u32 = 36214;
+pub const GL_RGB16UI: u32 = 36215;
+pub const GL_RGB16UI_EXT: u32 = 36215;
+pub const GL_ALPHA16UI_EXT: u32 = 36216;
+pub const GL_INTENSITY16UI_EXT: u32 = 36217;
+pub const GL_LUMINANCE16UI_EXT: u32 = 36218;
+pub const GL_LUMINANCE_ALPHA16UI_EXT: u32 = 36219;
+pub const GL_RGBA8UI: u32 = 36220;
+pub const GL_RGBA8UI_EXT: u32 = 36220;
+pub const GL_RGB8UI: u32 = 36221;
+pub const GL_RGB8UI_EXT: u32 = 36221;
+pub const GL_ALPHA8UI_EXT: u32 = 36222;
+pub const GL_INTENSITY8UI_EXT: u32 = 36223;
+pub const GL_LUMINANCE8UI_EXT: u32 = 36224;
+pub const GL_LUMINANCE_ALPHA8UI_EXT: u32 = 36225;
+pub const GL_RGBA32I: u32 = 36226;
+pub const GL_RGBA32I_EXT: u32 = 36226;
+pub const GL_RGB32I: u32 = 36227;
+pub const GL_RGB32I_EXT: u32 = 36227;
+pub const GL_ALPHA32I_EXT: u32 = 36228;
+pub const GL_INTENSITY32I_EXT: u32 = 36229;
+pub const GL_LUMINANCE32I_EXT: u32 = 36230;
+pub const GL_LUMINANCE_ALPHA32I_EXT: u32 = 36231;
+pub const GL_RGBA16I: u32 = 36232;
+pub const GL_RGBA16I_EXT: u32 = 36232;
+pub const GL_RGB16I: u32 = 36233;
+pub const GL_RGB16I_EXT: u32 = 36233;
+pub const GL_ALPHA16I_EXT: u32 = 36234;
+pub const GL_INTENSITY16I_EXT: u32 = 36235;
+pub const GL_LUMINANCE16I_EXT: u32 = 36236;
+pub const GL_LUMINANCE_ALPHA16I_EXT: u32 = 36237;
+pub const GL_RGBA8I: u32 = 36238;
+pub const GL_RGBA8I_EXT: u32 = 36238;
+pub const GL_RGB8I: u32 = 36239;
+pub const GL_RGB8I_EXT: u32 = 36239;
+pub const GL_ALPHA8I_EXT: u32 = 36240;
+pub const GL_INTENSITY8I_EXT: u32 = 36241;
+pub const GL_LUMINANCE8I_EXT: u32 = 36242;
+pub const GL_LUMINANCE_ALPHA8I_EXT: u32 = 36243;
+pub const GL_RED_INTEGER: u32 = 36244;
+pub const GL_RED_INTEGER_EXT: u32 = 36244;
+pub const GL_GREEN_INTEGER: u32 = 36245;
+pub const GL_GREEN_INTEGER_EXT: u32 = 36245;
+pub const GL_BLUE_INTEGER: u32 = 36246;
+pub const GL_BLUE_INTEGER_EXT: u32 = 36246;
+pub const GL_ALPHA_INTEGER: u32 = 36247;
+pub const GL_ALPHA_INTEGER_EXT: u32 = 36247;
+pub const GL_RGB_INTEGER: u32 = 36248;
+pub const GL_RGB_INTEGER_EXT: u32 = 36248;
+pub const GL_RGBA_INTEGER: u32 = 36249;
+pub const GL_RGBA_INTEGER_EXT: u32 = 36249;
+pub const GL_BGR_INTEGER: u32 = 36250;
+pub const GL_BGR_INTEGER_EXT: u32 = 36250;
+pub const GL_BGRA_INTEGER: u32 = 36251;
+pub const GL_BGRA_INTEGER_EXT: u32 = 36251;
+pub const GL_LUMINANCE_INTEGER_EXT: u32 = 36252;
+pub const GL_LUMINANCE_ALPHA_INTEGER_EXT: u32 = 36253;
+pub const GL_RGBA_INTEGER_MODE_EXT: u32 = 36254;
+pub const GL_INT_2_10_10_10_REV: u32 = 36255;
+pub const GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV: u32 = 36256;
+pub const GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV: u32 = 36257;
+pub const GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV: u32 = 36258;
+pub const GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV: u32 = 36259;
+pub const GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV: u32 = 36260;
+pub const GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV: u32 = 36261;
+pub const GL_MAX_PROGRAM_GENERIC_RESULTS_NV: u32 = 36262;
+pub const GL_FRAMEBUFFER_ATTACHMENT_LAYERED: u32 = 36263;
+pub const GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB: u32 = 36263;
+pub const GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT: u32 = 36263;
+pub const GL_FRAMEBUFFER_ATTACHMENT_LAYERED_OES: u32 = 36263;
+pub const GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: u32 = 36264;
+pub const GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB: u32 = 36264;
+pub const GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT: u32 = 36264;
+pub const GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_OES: u32 = 36264;
+pub const GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB: u32 = 36265;
+pub const GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT: u32 = 36265;
+pub const GL_LAYER_NV: u32 = 36266;
+pub const GL_DEPTH_COMPONENT32F_NV: u32 = 36267;
+pub const GL_DEPTH32F_STENCIL8_NV: u32 = 36268;
+pub const GL_FLOAT_32_UNSIGNED_INT_24_8_REV: u32 = 36269;
+pub const GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV: u32 = 36269;
+pub const GL_SHADER_INCLUDE_ARB: u32 = 36270;
+pub const GL_DEPTH_BUFFER_FLOAT_MODE_NV: u32 = 36271;
+pub const GL_FRAMEBUFFER_SRGB: u32 = 36281;
+pub const GL_FRAMEBUFFER_SRGB_EXT: u32 = 36281;
+pub const GL_FRAMEBUFFER_SRGB_CAPABLE_EXT: u32 = 36282;
+pub const GL_COMPRESSED_RED_RGTC1: u32 = 36283;
+pub const GL_COMPRESSED_RED_RGTC1_EXT: u32 = 36283;
+pub const GL_COMPRESSED_SIGNED_RED_RGTC1: u32 = 36284;
+pub const GL_COMPRESSED_SIGNED_RED_RGTC1_EXT: u32 = 36284;
+pub const GL_COMPRESSED_RED_GREEN_RGTC2_EXT: u32 = 36285;
+pub const GL_COMPRESSED_RG_RGTC2: u32 = 36285;
+pub const GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: u32 = 36286;
+pub const GL_COMPRESSED_SIGNED_RG_RGTC2: u32 = 36286;
+pub const GL_SAMPLER_1D_ARRAY: u32 = 36288;
+pub const GL_SAMPLER_1D_ARRAY_EXT: u32 = 36288;
+pub const GL_SAMPLER_2D_ARRAY: u32 = 36289;
+pub const GL_SAMPLER_2D_ARRAY_EXT: u32 = 36289;
+pub const GL_SAMPLER_BUFFER: u32 = 36290;
+pub const GL_SAMPLER_BUFFER_EXT: u32 = 36290;
+pub const GL_SAMPLER_BUFFER_OES: u32 = 36290;
+pub const GL_SAMPLER_1D_ARRAY_SHADOW: u32 = 36291;
+pub const GL_SAMPLER_1D_ARRAY_SHADOW_EXT: u32 = 36291;
+pub const GL_SAMPLER_2D_ARRAY_SHADOW: u32 = 36292;
+pub const GL_SAMPLER_2D_ARRAY_SHADOW_EXT: u32 = 36292;
+pub const GL_SAMPLER_2D_ARRAY_SHADOW_NV: u32 = 36292;
+pub const GL_SAMPLER_CUBE_SHADOW: u32 = 36293;
+pub const GL_SAMPLER_CUBE_SHADOW_EXT: u32 = 36293;
+pub const GL_SAMPLER_CUBE_SHADOW_NV: u32 = 36293;
+pub const GL_UNSIGNED_INT_VEC2: u32 = 36294;
+pub const GL_UNSIGNED_INT_VEC2_EXT: u32 = 36294;
+pub const GL_UNSIGNED_INT_VEC3: u32 = 36295;
+pub const GL_UNSIGNED_INT_VEC3_EXT: u32 = 36295;
+pub const GL_UNSIGNED_INT_VEC4: u32 = 36296;
+pub const GL_UNSIGNED_INT_VEC4_EXT: u32 = 36296;
+pub const GL_INT_SAMPLER_1D: u32 = 36297;
+pub const GL_INT_SAMPLER_1D_EXT: u32 = 36297;
+pub const GL_INT_SAMPLER_2D: u32 = 36298;
+pub const GL_INT_SAMPLER_2D_EXT: u32 = 36298;
+pub const GL_INT_SAMPLER_3D: u32 = 36299;
+pub const GL_INT_SAMPLER_3D_EXT: u32 = 36299;
+pub const GL_INT_SAMPLER_CUBE: u32 = 36300;
+pub const GL_INT_SAMPLER_CUBE_EXT: u32 = 36300;
+pub const GL_INT_SAMPLER_2D_RECT: u32 = 36301;
+pub const GL_INT_SAMPLER_2D_RECT_EXT: u32 = 36301;
+pub const GL_INT_SAMPLER_1D_ARRAY: u32 = 36302;
+pub const GL_INT_SAMPLER_1D_ARRAY_EXT: u32 = 36302;
+pub const GL_INT_SAMPLER_2D_ARRAY: u32 = 36303;
+pub const GL_INT_SAMPLER_2D_ARRAY_EXT: u32 = 36303;
+pub const GL_INT_SAMPLER_BUFFER: u32 = 36304;
+pub const GL_INT_SAMPLER_BUFFER_EXT: u32 = 36304;
+pub const GL_INT_SAMPLER_BUFFER_OES: u32 = 36304;
+pub const GL_UNSIGNED_INT_SAMPLER_1D: u32 = 36305;
+pub const GL_UNSIGNED_INT_SAMPLER_1D_EXT: u32 = 36305;
+pub const GL_UNSIGNED_INT_SAMPLER_2D: u32 = 36306;
+pub const GL_UNSIGNED_INT_SAMPLER_2D_EXT: u32 = 36306;
+pub const GL_UNSIGNED_INT_SAMPLER_3D: u32 = 36307;
+pub const GL_UNSIGNED_INT_SAMPLER_3D_EXT: u32 = 36307;
+pub const GL_UNSIGNED_INT_SAMPLER_CUBE: u32 = 36308;
+pub const GL_UNSIGNED_INT_SAMPLER_CUBE_EXT: u32 = 36308;
+pub const GL_UNSIGNED_INT_SAMPLER_2D_RECT: u32 = 36309;
+pub const GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT: u32 = 36309;
+pub const GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: u32 = 36310;
+pub const GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT: u32 = 36310;
+pub const GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: u32 = 36311;
+pub const GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT: u32 = 36311;
+pub const GL_UNSIGNED_INT_SAMPLER_BUFFER: u32 = 36312;
+pub const GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT: u32 = 36312;
+pub const GL_UNSIGNED_INT_SAMPLER_BUFFER_OES: u32 = 36312;
+pub const GL_GEOMETRY_SHADER: u32 = 36313;
+pub const GL_GEOMETRY_SHADER_ARB: u32 = 36313;
+pub const GL_GEOMETRY_SHADER_EXT: u32 = 36313;
+pub const GL_GEOMETRY_SHADER_OES: u32 = 36313;
+pub const GL_GEOMETRY_VERTICES_OUT_ARB: u32 = 36314;
+pub const GL_GEOMETRY_VERTICES_OUT_EXT: u32 = 36314;
+pub const GL_GEOMETRY_INPUT_TYPE_ARB: u32 = 36315;
+pub const GL_GEOMETRY_INPUT_TYPE_EXT: u32 = 36315;
+pub const GL_GEOMETRY_OUTPUT_TYPE_ARB: u32 = 36316;
+pub const GL_GEOMETRY_OUTPUT_TYPE_EXT: u32 = 36316;
+pub const GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB: u32 = 36317;
+pub const GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT: u32 = 36317;
+pub const GL_MAX_VERTEX_VARYING_COMPONENTS_ARB: u32 = 36318;
+pub const GL_MAX_VERTEX_VARYING_COMPONENTS_EXT: u32 = 36318;
+pub const GL_MAX_GEOMETRY_UNIFORM_COMPONENTS: u32 = 36319;
+pub const GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB: u32 = 36319;
+pub const GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT: u32 = 36319;
+pub const GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_OES: u32 = 36319;
+pub const GL_MAX_GEOMETRY_OUTPUT_VERTICES: u32 = 36320;
+pub const GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB: u32 = 36320;
+pub const GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT: u32 = 36320;
+pub const GL_MAX_GEOMETRY_OUTPUT_VERTICES_OES: u32 = 36320;
+pub const GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS: u32 = 36321;
+pub const GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB: u32 = 36321;
+pub const GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT: u32 = 36321;
+pub const GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_OES: u32 = 36321;
+pub const GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT: u32 = 36322;
+pub const GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT: u32 = 36323;
+pub const GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT: u32 = 36324;
+pub const GL_ACTIVE_SUBROUTINES: u32 = 36325;
+pub const GL_ACTIVE_SUBROUTINE_UNIFORMS: u32 = 36326;
+pub const GL_MAX_SUBROUTINES: u32 = 36327;
+pub const GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS: u32 = 36328;
+pub const GL_NAMED_STRING_LENGTH_ARB: u32 = 36329;
+pub const GL_NAMED_STRING_TYPE_ARB: u32 = 36330;
+pub const GL_MAX_BINDABLE_UNIFORM_SIZE_EXT: u32 = 36333;
+pub const GL_UNIFORM_BUFFER_EXT: u32 = 36334;
+pub const GL_UNIFORM_BUFFER_BINDING_EXT: u32 = 36335;
+pub const GL_LOW_FLOAT: u32 = 36336;
+pub const GL_MEDIUM_FLOAT: u32 = 36337;
+pub const GL_HIGH_FLOAT: u32 = 36338;
+pub const GL_LOW_INT: u32 = 36339;
+pub const GL_MEDIUM_INT: u32 = 36340;
+pub const GL_HIGH_INT: u32 = 36341;
+pub const GL_UNSIGNED_INT_10_10_10_2_OES: u32 = 36342;
+pub const GL_INT_10_10_10_2_OES: u32 = 36343;
+pub const GL_SHADER_BINARY_FORMATS: u32 = 36344;
+pub const GL_NUM_SHADER_BINARY_FORMATS: u32 = 36345;
+pub const GL_SHADER_COMPILER: u32 = 36346;
+pub const GL_MAX_VERTEX_UNIFORM_VECTORS: u32 = 36347;
+pub const GL_MAX_VARYING_VECTORS: u32 = 36348;
+pub const GL_MAX_FRAGMENT_UNIFORM_VECTORS: u32 = 36349;
+pub const GL_RENDERBUFFER_COLOR_SAMPLES_NV: u32 = 36368;
+pub const GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV: u32 = 36369;
+pub const GL_MULTISAMPLE_COVERAGE_MODES_NV: u32 = 36370;
+pub const GL_QUERY_WAIT: u32 = 36371;
+pub const GL_QUERY_WAIT_NV: u32 = 36371;
+pub const GL_QUERY_NO_WAIT: u32 = 36372;
+pub const GL_QUERY_NO_WAIT_NV: u32 = 36372;
+pub const GL_QUERY_BY_REGION_WAIT: u32 = 36373;
+pub const GL_QUERY_BY_REGION_WAIT_NV: u32 = 36373;
+pub const GL_QUERY_BY_REGION_NO_WAIT: u32 = 36374;
+pub const GL_QUERY_BY_REGION_NO_WAIT_NV: u32 = 36374;
+pub const GL_QUERY_WAIT_INVERTED: u32 = 36375;
+pub const GL_QUERY_NO_WAIT_INVERTED: u32 = 36376;
+pub const GL_QUERY_BY_REGION_WAIT_INVERTED: u32 = 36377;
+pub const GL_QUERY_BY_REGION_NO_WAIT_INVERTED: u32 = 36378;
+pub const GL_POLYGON_OFFSET_CLAMP_EXT: u32 = 36379;
+pub const GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS: u32 = 36382;
+pub const GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_EXT: u32 = 36382;
+pub const GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_OES: u32 = 36382;
+pub const GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS: u32 = 36383;
+pub const GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT: u32 = 36383;
+pub const GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_OES: u32 = 36383;
+pub const GL_COLOR_SAMPLES_NV: u32 = 36384;
+pub const GL_TRANSFORM_FEEDBACK: u32 = 36386;
+pub const GL_TRANSFORM_FEEDBACK_NV: u32 = 36386;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED: u32 = 36387;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV: u32 = 36387;
+pub const GL_TRANSFORM_FEEDBACK_PAUSED: u32 = 36387;
+pub const GL_TRANSFORM_FEEDBACK_ACTIVE: u32 = 36388;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE: u32 = 36388;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV: u32 = 36388;
+pub const GL_TRANSFORM_FEEDBACK_BINDING: u32 = 36389;
+pub const GL_TRANSFORM_FEEDBACK_BINDING_NV: u32 = 36389;
+pub const GL_FRAME_NV: u32 = 36390;
+pub const GL_FIELDS_NV: u32 = 36391;
+pub const GL_CURRENT_TIME_NV: u32 = 36392;
+pub const GL_TIMESTAMP: u32 = 36392;
+pub const GL_TIMESTAMP_EXT: u32 = 36392;
+pub const GL_NUM_FILL_STREAMS_NV: u32 = 36393;
+pub const GL_PRESENT_TIME_NV: u32 = 36394;
+pub const GL_PRESENT_DURATION_NV: u32 = 36395;
+pub const GL_DEPTH_COMPONENT16_NONLINEAR_NV: u32 = 36396;
+pub const GL_PROGRAM_MATRIX_EXT: u32 = 36397;
+pub const GL_TRANSPOSE_PROGRAM_MATRIX_EXT: u32 = 36398;
+pub const GL_PROGRAM_MATRIX_STACK_DEPTH_EXT: u32 = 36399;
+pub const GL_TEXTURE_SWIZZLE_R: u32 = 36418;
+pub const GL_TEXTURE_SWIZZLE_R_EXT: u32 = 36418;
+pub const GL_TEXTURE_SWIZZLE_G: u32 = 36419;
+pub const GL_TEXTURE_SWIZZLE_G_EXT: u32 = 36419;
+pub const GL_TEXTURE_SWIZZLE_B: u32 = 36420;
+pub const GL_TEXTURE_SWIZZLE_B_EXT: u32 = 36420;
+pub const GL_TEXTURE_SWIZZLE_A: u32 = 36421;
+pub const GL_TEXTURE_SWIZZLE_A_EXT: u32 = 36421;
+pub const GL_TEXTURE_SWIZZLE_RGBA: u32 = 36422;
+pub const GL_TEXTURE_SWIZZLE_RGBA_EXT: u32 = 36422;
+pub const GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS: u32 = 36423;
+pub const GL_ACTIVE_SUBROUTINE_MAX_LENGTH: u32 = 36424;
+pub const GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH: u32 = 36425;
+pub const GL_NUM_COMPATIBLE_SUBROUTINES: u32 = 36426;
+pub const GL_COMPATIBLE_SUBROUTINES: u32 = 36427;
+pub const GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION: u32 = 36428;
+pub const GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT: u32 = 36428;
+pub const GL_FIRST_VERTEX_CONVENTION: u32 = 36429;
+pub const GL_FIRST_VERTEX_CONVENTION_EXT: u32 = 36429;
+pub const GL_FIRST_VERTEX_CONVENTION_OES: u32 = 36429;
+pub const GL_LAST_VERTEX_CONVENTION: u32 = 36430;
+pub const GL_LAST_VERTEX_CONVENTION_EXT: u32 = 36430;
+pub const GL_LAST_VERTEX_CONVENTION_OES: u32 = 36430;
+pub const GL_PROVOKING_VERTEX: u32 = 36431;
+pub const GL_PROVOKING_VERTEX_EXT: u32 = 36431;
+pub const GL_SAMPLE_LOCATION_ARB: u32 = 36432;
+pub const GL_SAMPLE_LOCATION_NV: u32 = 36432;
+pub const GL_SAMPLE_POSITION: u32 = 36432;
+pub const GL_SAMPLE_POSITION_NV: u32 = 36432;
+pub const GL_SAMPLE_MASK: u32 = 36433;
+pub const GL_SAMPLE_MASK_NV: u32 = 36433;
+pub const GL_SAMPLE_MASK_VALUE: u32 = 36434;
+pub const GL_SAMPLE_MASK_VALUE_NV: u32 = 36434;
+pub const GL_TEXTURE_BINDING_RENDERBUFFER_NV: u32 = 36435;
+pub const GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV: u32 = 36436;
+pub const GL_TEXTURE_RENDERBUFFER_NV: u32 = 36437;
+pub const GL_SAMPLER_RENDERBUFFER_NV: u32 = 36438;
+pub const GL_INT_SAMPLER_RENDERBUFFER_NV: u32 = 36439;
+pub const GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV: u32 = 36440;
+pub const GL_MAX_SAMPLE_MASK_WORDS: u32 = 36441;
+pub const GL_MAX_SAMPLE_MASK_WORDS_NV: u32 = 36441;
+pub const GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV: u32 = 36442;
+pub const GL_MAX_GEOMETRY_SHADER_INVOCATIONS: u32 = 36442;
+pub const GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT: u32 = 36442;
+pub const GL_MAX_GEOMETRY_SHADER_INVOCATIONS_OES: u32 = 36442;
+pub const GL_MIN_FRAGMENT_INTERPOLATION_OFFSET: u32 = 36443;
+pub const GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV: u32 = 36443;
+pub const GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_OES: u32 = 36443;
+pub const GL_MAX_FRAGMENT_INTERPOLATION_OFFSET: u32 = 36444;
+pub const GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV: u32 = 36444;
+pub const GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_OES: u32 = 36444;
+pub const GL_FRAGMENT_INTERPOLATION_OFFSET_BITS: u32 = 36445;
+pub const GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES: u32 = 36445;
+pub const GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV: u32 = 36445;
+pub const GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET: u32 = 36446;
+pub const GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB: u32 = 36446;
+pub const GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV: u32 = 36446;
+pub const GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET: u32 = 36447;
+pub const GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB: u32 = 36447;
+pub const GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV: u32 = 36447;
+pub const GL_MAX_TRANSFORM_FEEDBACK_BUFFERS: u32 = 36464;
+pub const GL_MAX_VERTEX_STREAMS: u32 = 36465;
+pub const GL_PATCH_VERTICES: u32 = 36466;
+pub const GL_PATCH_VERTICES_EXT: u32 = 36466;
+pub const GL_PATCH_VERTICES_OES: u32 = 36466;
+pub const GL_PATCH_DEFAULT_INNER_LEVEL: u32 = 36467;
+pub const GL_PATCH_DEFAULT_INNER_LEVEL_EXT: u32 = 36467;
+pub const GL_PATCH_DEFAULT_OUTER_LEVEL: u32 = 36468;
+pub const GL_PATCH_DEFAULT_OUTER_LEVEL_EXT: u32 = 36468;
+pub const GL_TESS_CONTROL_OUTPUT_VERTICES: u32 = 36469;
+pub const GL_TESS_CONTROL_OUTPUT_VERTICES_EXT: u32 = 36469;
+pub const GL_TESS_CONTROL_OUTPUT_VERTICES_OES: u32 = 36469;
+pub const GL_TESS_GEN_MODE: u32 = 36470;
+pub const GL_TESS_GEN_MODE_EXT: u32 = 36470;
+pub const GL_TESS_GEN_MODE_OES: u32 = 36470;
+pub const GL_TESS_GEN_SPACING: u32 = 36471;
+pub const GL_TESS_GEN_SPACING_EXT: u32 = 36471;
+pub const GL_TESS_GEN_SPACING_OES: u32 = 36471;
+pub const GL_TESS_GEN_VERTEX_ORDER: u32 = 36472;
+pub const GL_TESS_GEN_VERTEX_ORDER_EXT: u32 = 36472;
+pub const GL_TESS_GEN_VERTEX_ORDER_OES: u32 = 36472;
+pub const GL_TESS_GEN_POINT_MODE: u32 = 36473;
+pub const GL_TESS_GEN_POINT_MODE_EXT: u32 = 36473;
+pub const GL_TESS_GEN_POINT_MODE_OES: u32 = 36473;
+pub const GL_ISOLINES: u32 = 36474;
+pub const GL_ISOLINES_EXT: u32 = 36474;
+pub const GL_ISOLINES_OES: u32 = 36474;
+pub const GL_FRACTIONAL_ODD: u32 = 36475;
+pub const GL_FRACTIONAL_ODD_EXT: u32 = 36475;
+pub const GL_FRACTIONAL_ODD_OES: u32 = 36475;
+pub const GL_FRACTIONAL_EVEN: u32 = 36476;
+pub const GL_FRACTIONAL_EVEN_EXT: u32 = 36476;
+pub const GL_FRACTIONAL_EVEN_OES: u32 = 36476;
+pub const GL_MAX_PATCH_VERTICES: u32 = 36477;
+pub const GL_MAX_PATCH_VERTICES_EXT: u32 = 36477;
+pub const GL_MAX_PATCH_VERTICES_OES: u32 = 36477;
+pub const GL_MAX_TESS_GEN_LEVEL: u32 = 36478;
+pub const GL_MAX_TESS_GEN_LEVEL_EXT: u32 = 36478;
+pub const GL_MAX_TESS_GEN_LEVEL_OES: u32 = 36478;
+pub const GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS: u32 = 36479;
+pub const GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_EXT: u32 = 36479;
+pub const GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_OES: u32 = 36479;
+pub const GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS: u32 = 36480;
+pub const GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT: u32 = 36480;
+pub const GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_OES: u32 = 36480;
+pub const GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS: u32 = 36481;
+pub const GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_EXT: u32 = 36481;
+pub const GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_OES: u32 = 36481;
+pub const GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS: u32 = 36482;
+pub const GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_EXT: u32 = 36482;
+pub const GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_OES: u32 = 36482;
+pub const GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS: u32 = 36483;
+pub const GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT: u32 = 36483;
+pub const GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_OES: u32 = 36483;
+pub const GL_MAX_TESS_PATCH_COMPONENTS: u32 = 36484;
+pub const GL_MAX_TESS_PATCH_COMPONENTS_EXT: u32 = 36484;
+pub const GL_MAX_TESS_PATCH_COMPONENTS_OES: u32 = 36484;
+pub const GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS: u32 = 36485;
+pub const GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_EXT: u32 = 36485;
+pub const GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_OES: u32 = 36485;
+pub const GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS: u32 = 36486;
+pub const GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT: u32 = 36486;
+pub const GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_OES: u32 = 36486;
+pub const GL_TESS_EVALUATION_SHADER: u32 = 36487;
+pub const GL_TESS_EVALUATION_SHADER_EXT: u32 = 36487;
+pub const GL_TESS_EVALUATION_SHADER_OES: u32 = 36487;
+pub const GL_TESS_CONTROL_SHADER: u32 = 36488;
+pub const GL_TESS_CONTROL_SHADER_EXT: u32 = 36488;
+pub const GL_TESS_CONTROL_SHADER_OES: u32 = 36488;
+pub const GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS: u32 = 36489;
+pub const GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_EXT: u32 = 36489;
+pub const GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_OES: u32 = 36489;
+pub const GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS: u32 = 36490;
+pub const GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_EXT: u32 = 36490;
+pub const GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_OES: u32 = 36490;
+pub const GL_COMPRESSED_RGBA_BPTC_UNORM: u32 = 36492;
+pub const GL_COMPRESSED_RGBA_BPTC_UNORM_ARB: u32 = 36492;
+pub const GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: u32 = 36493;
+pub const GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB: u32 = 36493;
+pub const GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: u32 = 36494;
+pub const GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB: u32 = 36494;
+pub const GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: u32 = 36495;
+pub const GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB: u32 = 36495;
+pub const GL_COVERAGE_COMPONENT_NV: u32 = 36560;
+pub const GL_COVERAGE_COMPONENT4_NV: u32 = 36561;
+pub const GL_COVERAGE_ATTACHMENT_NV: u32 = 36562;
+pub const GL_COVERAGE_BUFFERS_NV: u32 = 36563;
+pub const GL_COVERAGE_SAMPLES_NV: u32 = 36564;
+pub const GL_COVERAGE_ALL_FRAGMENTS_NV: u32 = 36565;
+pub const GL_COVERAGE_EDGE_FRAGMENTS_NV: u32 = 36566;
+pub const GL_COVERAGE_AUTOMATIC_NV: u32 = 36567;
+pub const GL_INCLUSIVE_EXT: u32 = 36624;
+pub const GL_EXCLUSIVE_EXT: u32 = 36625;
+pub const GL_WINDOW_RECTANGLE_EXT: u32 = 36626;
+pub const GL_WINDOW_RECTANGLE_MODE_EXT: u32 = 36627;
+pub const GL_MAX_WINDOW_RECTANGLES_EXT: u32 = 36628;
+pub const GL_NUM_WINDOW_RECTANGLES_EXT: u32 = 36629;
+pub const GL_BUFFER_GPU_ADDRESS_NV: u32 = 36637;
+pub const GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV: u32 = 36638;
+pub const GL_ELEMENT_ARRAY_UNIFIED_NV: u32 = 36639;
+pub const GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV: u32 = 36640;
+pub const GL_VERTEX_ARRAY_ADDRESS_NV: u32 = 36641;
+pub const GL_NORMAL_ARRAY_ADDRESS_NV: u32 = 36642;
+pub const GL_COLOR_ARRAY_ADDRESS_NV: u32 = 36643;
+pub const GL_INDEX_ARRAY_ADDRESS_NV: u32 = 36644;
+pub const GL_TEXTURE_COORD_ARRAY_ADDRESS_NV: u32 = 36645;
+pub const GL_EDGE_FLAG_ARRAY_ADDRESS_NV: u32 = 36646;
+pub const GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV: u32 = 36647;
+pub const GL_FOG_COORD_ARRAY_ADDRESS_NV: u32 = 36648;
+pub const GL_ELEMENT_ARRAY_ADDRESS_NV: u32 = 36649;
+pub const GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV: u32 = 36650;
+pub const GL_VERTEX_ARRAY_LENGTH_NV: u32 = 36651;
+pub const GL_NORMAL_ARRAY_LENGTH_NV: u32 = 36652;
+pub const GL_COLOR_ARRAY_LENGTH_NV: u32 = 36653;
+pub const GL_INDEX_ARRAY_LENGTH_NV: u32 = 36654;
+pub const GL_TEXTURE_COORD_ARRAY_LENGTH_NV: u32 = 36655;
+pub const GL_EDGE_FLAG_ARRAY_LENGTH_NV: u32 = 36656;
+pub const GL_SECONDARY_COLOR_ARRAY_LENGTH_NV: u32 = 36657;
+pub const GL_FOG_COORD_ARRAY_LENGTH_NV: u32 = 36658;
+pub const GL_ELEMENT_ARRAY_LENGTH_NV: u32 = 36659;
+pub const GL_GPU_ADDRESS_NV: u32 = 36660;
+pub const GL_MAX_SHADER_BUFFER_ADDRESS_NV: u32 = 36661;
+pub const GL_COPY_READ_BUFFER: u32 = 36662;
+pub const GL_COPY_READ_BUFFER_BINDING: u32 = 36662;
+pub const GL_COPY_READ_BUFFER_NV: u32 = 36662;
+pub const GL_COPY_WRITE_BUFFER: u32 = 36663;
+pub const GL_COPY_WRITE_BUFFER_BINDING: u32 = 36663;
+pub const GL_COPY_WRITE_BUFFER_NV: u32 = 36663;
+pub const GL_MAX_IMAGE_UNITS: u32 = 36664;
+pub const GL_MAX_IMAGE_UNITS_EXT: u32 = 36664;
+pub const GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS: u32 = 36665;
+pub const GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT: u32 = 36665;
+pub const GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES: u32 = 36665;
+pub const GL_IMAGE_BINDING_NAME: u32 = 36666;
+pub const GL_IMAGE_BINDING_NAME_EXT: u32 = 36666;
+pub const GL_IMAGE_BINDING_LEVEL: u32 = 36667;
+pub const GL_IMAGE_BINDING_LEVEL_EXT: u32 = 36667;
+pub const GL_IMAGE_BINDING_LAYERED: u32 = 36668;
+pub const GL_IMAGE_BINDING_LAYERED_EXT: u32 = 36668;
+pub const GL_IMAGE_BINDING_LAYER: u32 = 36669;
+pub const GL_IMAGE_BINDING_LAYER_EXT: u32 = 36669;
+pub const GL_IMAGE_BINDING_ACCESS: u32 = 36670;
+pub const GL_IMAGE_BINDING_ACCESS_EXT: u32 = 36670;
+pub const GL_DRAW_INDIRECT_BUFFER: u32 = 36671;
+pub const GL_DRAW_INDIRECT_UNIFIED_NV: u32 = 36672;
+pub const GL_DRAW_INDIRECT_ADDRESS_NV: u32 = 36673;
+pub const GL_DRAW_INDIRECT_LENGTH_NV: u32 = 36674;
+pub const GL_DRAW_INDIRECT_BUFFER_BINDING: u32 = 36675;
+pub const GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV: u32 = 36676;
+pub const GL_MAX_PROGRAM_SUBROUTINE_NUM_NV: u32 = 36677;
+pub const GL_DOUBLE_MAT2: u32 = 36678;
+pub const GL_DOUBLE_MAT2_EXT: u32 = 36678;
+pub const GL_DOUBLE_MAT3: u32 = 36679;
+pub const GL_DOUBLE_MAT3_EXT: u32 = 36679;
+pub const GL_DOUBLE_MAT4: u32 = 36680;
+pub const GL_DOUBLE_MAT4_EXT: u32 = 36680;
+pub const GL_DOUBLE_MAT2x3: u32 = 36681;
+pub const GL_DOUBLE_MAT2x3_EXT: u32 = 36681;
+pub const GL_DOUBLE_MAT2x4: u32 = 36682;
+pub const GL_DOUBLE_MAT2x4_EXT: u32 = 36682;
+pub const GL_DOUBLE_MAT3x2: u32 = 36683;
+pub const GL_DOUBLE_MAT3x2_EXT: u32 = 36683;
+pub const GL_DOUBLE_MAT3x4: u32 = 36684;
+pub const GL_DOUBLE_MAT3x4_EXT: u32 = 36684;
+pub const GL_DOUBLE_MAT4x2: u32 = 36685;
+pub const GL_DOUBLE_MAT4x2_EXT: u32 = 36685;
+pub const GL_DOUBLE_MAT4x3: u32 = 36686;
+pub const GL_DOUBLE_MAT4x3_EXT: u32 = 36686;
+pub const GL_VERTEX_BINDING_BUFFER: u32 = 36687;
+pub const GL_MALI_SHADER_BINARY_ARM: u32 = 36704;
+pub const GL_MALI_PROGRAM_BINARY_ARM: u32 = 36705;
+pub const GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT: u32 = 36707;
+pub const GL_SHADER_PIXEL_LOCAL_STORAGE_EXT: u32 = 36708;
+pub const GL_FETCH_PER_SAMPLE_ARM: u32 = 36709;
+pub const GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM: u32 = 36710;
+pub const GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_SIZE_EXT: u32 = 36711;
+pub const GL_RED_SNORM: u32 = 36752;
+pub const GL_RG_SNORM: u32 = 36753;
+pub const GL_RGB_SNORM: u32 = 36754;
+pub const GL_RGBA_SNORM: u32 = 36755;
+pub const GL_R8_SNORM: u32 = 36756;
+pub const GL_RG8_SNORM: u32 = 36757;
+pub const GL_RGB8_SNORM: u32 = 36758;
+pub const GL_RGBA8_SNORM: u32 = 36759;
+pub const GL_R16_SNORM: u32 = 36760;
+pub const GL_R16_SNORM_EXT: u32 = 36760;
+pub const GL_RG16_SNORM: u32 = 36761;
+pub const GL_RG16_SNORM_EXT: u32 = 36761;
+pub const GL_RGB16_SNORM: u32 = 36762;
+pub const GL_RGB16_SNORM_EXT: u32 = 36762;
+pub const GL_RGBA16_SNORM: u32 = 36763;
+pub const GL_RGBA16_SNORM_EXT: u32 = 36763;
+pub const GL_SIGNED_NORMALIZED: u32 = 36764;
+pub const GL_PRIMITIVE_RESTART: u32 = 36765;
+pub const GL_PRIMITIVE_RESTART_INDEX: u32 = 36766;
+pub const GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB: u32 = 36767;
+pub const GL_PERFMON_GLOBAL_MODE_QCOM: u32 = 36768;
+pub const GL_BINNING_CONTROL_HINT_QCOM: u32 = 36784;
+pub const GL_CPU_OPTIMIZED_QCOM: u32 = 36785;
+pub const GL_GPU_OPTIMIZED_QCOM: u32 = 36786;
+pub const GL_RENDER_DIRECT_TO_FRAMEBUFFER_QCOM: u32 = 36787;
+pub const GL_GPU_DISJOINT_EXT: u32 = 36795;
+pub const GL_SR8_EXT: u32 = 36797;
+pub const GL_SRG8_EXT: u32 = 36798;
+pub const GL_SHADER_BINARY_VIV: u32 = 36804;
+pub const GL_INT8_NV: u32 = 36832;
+pub const GL_INT8_VEC2_NV: u32 = 36833;
+pub const GL_INT8_VEC3_NV: u32 = 36834;
+pub const GL_INT8_VEC4_NV: u32 = 36835;
+pub const GL_INT16_NV: u32 = 36836;
+pub const GL_INT16_VEC2_NV: u32 = 36837;
+pub const GL_INT16_VEC3_NV: u32 = 36838;
+pub const GL_INT16_VEC4_NV: u32 = 36839;
+pub const GL_INT64_VEC2_ARB: u32 = 36841;
+pub const GL_INT64_VEC2_NV: u32 = 36841;
+pub const GL_INT64_VEC3_ARB: u32 = 36842;
+pub const GL_INT64_VEC3_NV: u32 = 36842;
+pub const GL_INT64_VEC4_ARB: u32 = 36843;
+pub const GL_INT64_VEC4_NV: u32 = 36843;
+pub const GL_UNSIGNED_INT8_NV: u32 = 36844;
+pub const GL_UNSIGNED_INT8_VEC2_NV: u32 = 36845;
+pub const GL_UNSIGNED_INT8_VEC3_NV: u32 = 36846;
+pub const GL_UNSIGNED_INT8_VEC4_NV: u32 = 36847;
+pub const GL_UNSIGNED_INT16_NV: u32 = 36848;
+pub const GL_UNSIGNED_INT16_VEC2_NV: u32 = 36849;
+pub const GL_UNSIGNED_INT16_VEC3_NV: u32 = 36850;
+pub const GL_UNSIGNED_INT16_VEC4_NV: u32 = 36851;
+pub const GL_UNSIGNED_INT64_VEC2_ARB: u32 = 36853;
+pub const GL_UNSIGNED_INT64_VEC2_NV: u32 = 36853;
+pub const GL_UNSIGNED_INT64_VEC3_ARB: u32 = 36854;
+pub const GL_UNSIGNED_INT64_VEC3_NV: u32 = 36854;
+pub const GL_UNSIGNED_INT64_VEC4_ARB: u32 = 36855;
+pub const GL_UNSIGNED_INT64_VEC4_NV: u32 = 36855;
+pub const GL_FLOAT16_NV: u32 = 36856;
+pub const GL_FLOAT16_VEC2_NV: u32 = 36857;
+pub const GL_FLOAT16_VEC3_NV: u32 = 36858;
+pub const GL_FLOAT16_VEC4_NV: u32 = 36859;
+pub const GL_DOUBLE_VEC2: u32 = 36860;
+pub const GL_DOUBLE_VEC2_EXT: u32 = 36860;
+pub const GL_DOUBLE_VEC3: u32 = 36861;
+pub const GL_DOUBLE_VEC3_EXT: u32 = 36861;
+pub const GL_DOUBLE_VEC4: u32 = 36862;
+pub const GL_DOUBLE_VEC4_EXT: u32 = 36862;
+pub const GL_SAMPLER_BUFFER_AMD: u32 = 36865;
+pub const GL_INT_SAMPLER_BUFFER_AMD: u32 = 36866;
+pub const GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD: u32 = 36867;
+pub const GL_TESSELLATION_MODE_AMD: u32 = 36868;
+pub const GL_TESSELLATION_FACTOR_AMD: u32 = 36869;
+pub const GL_DISCRETE_AMD: u32 = 36870;
+pub const GL_CONTINUOUS_AMD: u32 = 36871;
+pub const GL_TEXTURE_CUBE_MAP_ARRAY: u32 = 36873;
+pub const GL_TEXTURE_CUBE_MAP_ARRAY_ARB: u32 = 36873;
+pub const GL_TEXTURE_CUBE_MAP_ARRAY_EXT: u32 = 36873;
+pub const GL_TEXTURE_CUBE_MAP_ARRAY_OES: u32 = 36873;
+pub const GL_TEXTURE_BINDING_CUBE_MAP_ARRAY: u32 = 36874;
+pub const GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB: u32 = 36874;
+pub const GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_EXT: u32 = 36874;
+pub const GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_OES: u32 = 36874;
+pub const GL_PROXY_TEXTURE_CUBE_MAP_ARRAY: u32 = 36875;
+pub const GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB: u32 = 36875;
+pub const GL_SAMPLER_CUBE_MAP_ARRAY: u32 = 36876;
+pub const GL_SAMPLER_CUBE_MAP_ARRAY_ARB: u32 = 36876;
+pub const GL_SAMPLER_CUBE_MAP_ARRAY_EXT: u32 = 36876;
+pub const GL_SAMPLER_CUBE_MAP_ARRAY_OES: u32 = 36876;
+pub const GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW: u32 = 36877;
+pub const GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB: u32 = 36877;
+pub const GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_EXT: u32 = 36877;
+pub const GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_OES: u32 = 36877;
+pub const GL_INT_SAMPLER_CUBE_MAP_ARRAY: u32 = 36878;
+pub const GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB: u32 = 36878;
+pub const GL_INT_SAMPLER_CUBE_MAP_ARRAY_EXT: u32 = 36878;
+pub const GL_INT_SAMPLER_CUBE_MAP_ARRAY_OES: u32 = 36878;
+pub const GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY: u32 = 36879;
+pub const GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB: u32 = 36879;
+pub const GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_EXT: u32 = 36879;
+pub const GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_OES: u32 = 36879;
+pub const GL_ALPHA_SNORM: u32 = 36880;
+pub const GL_LUMINANCE_SNORM: u32 = 36881;
+pub const GL_LUMINANCE_ALPHA_SNORM: u32 = 36882;
+pub const GL_INTENSITY_SNORM: u32 = 36883;
+pub const GL_ALPHA8_SNORM: u32 = 36884;
+pub const GL_LUMINANCE8_SNORM: u32 = 36885;
+pub const GL_LUMINANCE8_ALPHA8_SNORM: u32 = 36886;
+pub const GL_INTENSITY8_SNORM: u32 = 36887;
+pub const GL_ALPHA16_SNORM: u32 = 36888;
+pub const GL_LUMINANCE16_SNORM: u32 = 36889;
+pub const GL_LUMINANCE16_ALPHA16_SNORM: u32 = 36890;
+pub const GL_INTENSITY16_SNORM: u32 = 36891;
+pub const GL_FACTOR_MIN_AMD: u32 = 36892;
+pub const GL_FACTOR_MAX_AMD: u32 = 36893;
+pub const GL_DEPTH_CLAMP_NEAR_AMD: u32 = 36894;
+pub const GL_DEPTH_CLAMP_FAR_AMD: u32 = 36895;
+pub const GL_VIDEO_BUFFER_NV: u32 = 36896;
+pub const GL_VIDEO_BUFFER_BINDING_NV: u32 = 36897;
+pub const GL_FIELD_UPPER_NV: u32 = 36898;
+pub const GL_FIELD_LOWER_NV: u32 = 36899;
+pub const GL_NUM_VIDEO_CAPTURE_STREAMS_NV: u32 = 36900;
+pub const GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV: u32 = 36901;
+pub const GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV: u32 = 36902;
+pub const GL_LAST_VIDEO_CAPTURE_STATUS_NV: u32 = 36903;
+pub const GL_VIDEO_BUFFER_PITCH_NV: u32 = 36904;
+pub const GL_VIDEO_COLOR_CONVERSION_MATRIX_NV: u32 = 36905;
+pub const GL_VIDEO_COLOR_CONVERSION_MAX_NV: u32 = 36906;
+pub const GL_VIDEO_COLOR_CONVERSION_MIN_NV: u32 = 36907;
+pub const GL_VIDEO_COLOR_CONVERSION_OFFSET_NV: u32 = 36908;
+pub const GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV: u32 = 36909;
+pub const GL_PARTIAL_SUCCESS_NV: u32 = 36910;
+pub const GL_SUCCESS_NV: u32 = 36911;
+pub const GL_FAILURE_NV: u32 = 36912;
+pub const GL_YCBYCR8_422_NV: u32 = 36913;
+pub const GL_YCBAYCR8A_4224_NV: u32 = 36914;
+pub const GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV: u32 = 36915;
+pub const GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV: u32 = 36916;
+pub const GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV: u32 = 36917;
+pub const GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV: u32 = 36918;
+pub const GL_Z4Y12Z4CB12Z4CR12_444_NV: u32 = 36919;
+pub const GL_VIDEO_CAPTURE_FRAME_WIDTH_NV: u32 = 36920;
+pub const GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV: u32 = 36921;
+pub const GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV: u32 = 36922;
+pub const GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV: u32 = 36923;
+pub const GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV: u32 = 36924;
+pub const GL_TEXTURE_COVERAGE_SAMPLES_NV: u32 = 36933;
+pub const GL_TEXTURE_COLOR_SAMPLES_NV: u32 = 36934;
+pub const GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX: u32 = 36935;
+pub const GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX: u32 = 36936;
+pub const GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX: u32 = 36937;
+pub const GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX: u32 = 36938;
+pub const GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX: u32 = 36939;
+pub const GL_IMAGE_1D: u32 = 36940;
+pub const GL_IMAGE_1D_EXT: u32 = 36940;
+pub const GL_IMAGE_2D: u32 = 36941;
+pub const GL_IMAGE_2D_EXT: u32 = 36941;
+pub const GL_IMAGE_3D: u32 = 36942;
+pub const GL_IMAGE_3D_EXT: u32 = 36942;
+pub const GL_IMAGE_2D_RECT: u32 = 36943;
+pub const GL_IMAGE_2D_RECT_EXT: u32 = 36943;
+pub const GL_IMAGE_CUBE: u32 = 36944;
+pub const GL_IMAGE_CUBE_EXT: u32 = 36944;
+pub const GL_IMAGE_BUFFER: u32 = 36945;
+pub const GL_IMAGE_BUFFER_EXT: u32 = 36945;
+pub const GL_IMAGE_BUFFER_OES: u32 = 36945;
+pub const GL_IMAGE_1D_ARRAY: u32 = 36946;
+pub const GL_IMAGE_1D_ARRAY_EXT: u32 = 36946;
+pub const GL_IMAGE_2D_ARRAY: u32 = 36947;
+pub const GL_IMAGE_2D_ARRAY_EXT: u32 = 36947;
+pub const GL_IMAGE_CUBE_MAP_ARRAY: u32 = 36948;
+pub const GL_IMAGE_CUBE_MAP_ARRAY_EXT: u32 = 36948;
+pub const GL_IMAGE_CUBE_MAP_ARRAY_OES: u32 = 36948;
+pub const GL_IMAGE_2D_MULTISAMPLE: u32 = 36949;
+pub const GL_IMAGE_2D_MULTISAMPLE_EXT: u32 = 36949;
+pub const GL_IMAGE_2D_MULTISAMPLE_ARRAY: u32 = 36950;
+pub const GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT: u32 = 36950;
+pub const GL_INT_IMAGE_1D: u32 = 36951;
+pub const GL_INT_IMAGE_1D_EXT: u32 = 36951;
+pub const GL_INT_IMAGE_2D: u32 = 36952;
+pub const GL_INT_IMAGE_2D_EXT: u32 = 36952;
+pub const GL_INT_IMAGE_3D: u32 = 36953;
+pub const GL_INT_IMAGE_3D_EXT: u32 = 36953;
+pub const GL_INT_IMAGE_2D_RECT: u32 = 36954;
+pub const GL_INT_IMAGE_2D_RECT_EXT: u32 = 36954;
+pub const GL_INT_IMAGE_CUBE: u32 = 36955;
+pub const GL_INT_IMAGE_CUBE_EXT: u32 = 36955;
+pub const GL_INT_IMAGE_BUFFER: u32 = 36956;
+pub const GL_INT_IMAGE_BUFFER_EXT: u32 = 36956;
+pub const GL_INT_IMAGE_BUFFER_OES: u32 = 36956;
+pub const GL_INT_IMAGE_1D_ARRAY: u32 = 36957;
+pub const GL_INT_IMAGE_1D_ARRAY_EXT: u32 = 36957;
+pub const GL_INT_IMAGE_2D_ARRAY: u32 = 36958;
+pub const GL_INT_IMAGE_2D_ARRAY_EXT: u32 = 36958;
+pub const GL_INT_IMAGE_CUBE_MAP_ARRAY: u32 = 36959;
+pub const GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT: u32 = 36959;
+pub const GL_INT_IMAGE_CUBE_MAP_ARRAY_OES: u32 = 36959;
+pub const GL_INT_IMAGE_2D_MULTISAMPLE: u32 = 36960;
+pub const GL_INT_IMAGE_2D_MULTISAMPLE_EXT: u32 = 36960;
+pub const GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY: u32 = 36961;
+pub const GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT: u32 = 36961;
+pub const GL_UNSIGNED_INT_IMAGE_1D: u32 = 36962;
+pub const GL_UNSIGNED_INT_IMAGE_1D_EXT: u32 = 36962;
+pub const GL_UNSIGNED_INT_IMAGE_2D: u32 = 36963;
+pub const GL_UNSIGNED_INT_IMAGE_2D_EXT: u32 = 36963;
+pub const GL_UNSIGNED_INT_IMAGE_3D: u32 = 36964;
+pub const GL_UNSIGNED_INT_IMAGE_3D_EXT: u32 = 36964;
+pub const GL_UNSIGNED_INT_IMAGE_2D_RECT: u32 = 36965;
+pub const GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT: u32 = 36965;
+pub const GL_UNSIGNED_INT_IMAGE_CUBE: u32 = 36966;
+pub const GL_UNSIGNED_INT_IMAGE_CUBE_EXT: u32 = 36966;
+pub const GL_UNSIGNED_INT_IMAGE_BUFFER: u32 = 36967;
+pub const GL_UNSIGNED_INT_IMAGE_BUFFER_EXT: u32 = 36967;
+pub const GL_UNSIGNED_INT_IMAGE_BUFFER_OES: u32 = 36967;
+pub const GL_UNSIGNED_INT_IMAGE_1D_ARRAY: u32 = 36968;
+pub const GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT: u32 = 36968;
+pub const GL_UNSIGNED_INT_IMAGE_2D_ARRAY: u32 = 36969;
+pub const GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT: u32 = 36969;
+pub const GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY: u32 = 36970;
+pub const GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT: u32 = 36970;
+pub const GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_OES: u32 = 36970;
+pub const GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE: u32 = 36971;
+pub const GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT: u32 = 36971;
+pub const GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: u32 = 36972;
+pub const GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT: u32 = 36972;
+pub const GL_MAX_IMAGE_SAMPLES: u32 = 36973;
+pub const GL_MAX_IMAGE_SAMPLES_EXT: u32 = 36973;
+pub const GL_IMAGE_BINDING_FORMAT: u32 = 36974;
+pub const GL_IMAGE_BINDING_FORMAT_EXT: u32 = 36974;
+pub const GL_RGB10_A2UI: u32 = 36975;
+pub const GL_PATH_FORMAT_SVG_NV: u32 = 36976;
+pub const GL_PATH_FORMAT_PS_NV: u32 = 36977;
+pub const GL_STANDARD_FONT_NAME_NV: u32 = 36978;
+pub const GL_SYSTEM_FONT_NAME_NV: u32 = 36979;
+pub const GL_FILE_NAME_NV: u32 = 36980;
+pub const GL_PATH_STROKE_WIDTH_NV: u32 = 36981;
+pub const GL_PATH_END_CAPS_NV: u32 = 36982;
+pub const GL_PATH_INITIAL_END_CAP_NV: u32 = 36983;
+pub const GL_PATH_TERMINAL_END_CAP_NV: u32 = 36984;
+pub const GL_PATH_JOIN_STYLE_NV: u32 = 36985;
+pub const GL_PATH_MITER_LIMIT_NV: u32 = 36986;
+pub const GL_PATH_DASH_CAPS_NV: u32 = 36987;
+pub const GL_PATH_INITIAL_DASH_CAP_NV: u32 = 36988;
+pub const GL_PATH_TERMINAL_DASH_CAP_NV: u32 = 36989;
+pub const GL_PATH_DASH_OFFSET_NV: u32 = 36990;
+pub const GL_PATH_CLIENT_LENGTH_NV: u32 = 36991;
+pub const GL_PATH_FILL_MODE_NV: u32 = 36992;
+pub const GL_PATH_FILL_MASK_NV: u32 = 36993;
+pub const GL_PATH_FILL_COVER_MODE_NV: u32 = 36994;
+pub const GL_PATH_STROKE_COVER_MODE_NV: u32 = 36995;
+pub const GL_PATH_STROKE_MASK_NV: u32 = 36996;
+pub const GL_COUNT_UP_NV: u32 = 37000;
+pub const GL_COUNT_DOWN_NV: u32 = 37001;
+pub const GL_PATH_OBJECT_BOUNDING_BOX_NV: u32 = 37002;
+pub const GL_CONVEX_HULL_NV: u32 = 37003;
+pub const GL_BOUNDING_BOX_NV: u32 = 37005;
+pub const GL_TRANSLATE_X_NV: u32 = 37006;
+pub const GL_TRANSLATE_Y_NV: u32 = 37007;
+pub const GL_TRANSLATE_2D_NV: u32 = 37008;
+pub const GL_TRANSLATE_3D_NV: u32 = 37009;
+pub const GL_AFFINE_2D_NV: u32 = 37010;
+pub const GL_AFFINE_3D_NV: u32 = 37012;
+pub const GL_TRANSPOSE_AFFINE_2D_NV: u32 = 37014;
+pub const GL_TRANSPOSE_AFFINE_3D_NV: u32 = 37016;
+pub const GL_UTF8_NV: u32 = 37018;
+pub const GL_UTF16_NV: u32 = 37019;
+pub const GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV: u32 = 37020;
+pub const GL_PATH_COMMAND_COUNT_NV: u32 = 37021;
+pub const GL_PATH_COORD_COUNT_NV: u32 = 37022;
+pub const GL_PATH_DASH_ARRAY_COUNT_NV: u32 = 37023;
+pub const GL_PATH_COMPUTED_LENGTH_NV: u32 = 37024;
+pub const GL_PATH_FILL_BOUNDING_BOX_NV: u32 = 37025;
+pub const GL_PATH_STROKE_BOUNDING_BOX_NV: u32 = 37026;
+pub const GL_SQUARE_NV: u32 = 37027;
+pub const GL_ROUND_NV: u32 = 37028;
+pub const GL_TRIANGULAR_NV: u32 = 37029;
+pub const GL_BEVEL_NV: u32 = 37030;
+pub const GL_MITER_REVERT_NV: u32 = 37031;
+pub const GL_MITER_TRUNCATE_NV: u32 = 37032;
+pub const GL_SKIP_MISSING_GLYPH_NV: u32 = 37033;
+pub const GL_USE_MISSING_GLYPH_NV: u32 = 37034;
+pub const GL_PATH_ERROR_POSITION_NV: u32 = 37035;
+pub const GL_PATH_FOG_GEN_MODE_NV: u32 = 37036;
+pub const GL_ACCUM_ADJACENT_PAIRS_NV: u32 = 37037;
+pub const GL_ADJACENT_PAIRS_NV: u32 = 37038;
+pub const GL_FIRST_TO_REST_NV: u32 = 37039;
+pub const GL_PATH_GEN_MODE_NV: u32 = 37040;
+pub const GL_PATH_GEN_COEFF_NV: u32 = 37041;
+pub const GL_PATH_GEN_COLOR_FORMAT_NV: u32 = 37042;
+pub const GL_PATH_GEN_COMPONENTS_NV: u32 = 37043;
+pub const GL_PATH_DASH_OFFSET_RESET_NV: u32 = 37044;
+pub const GL_MOVE_TO_RESETS_NV: u32 = 37045;
+pub const GL_MOVE_TO_CONTINUES_NV: u32 = 37046;
+pub const GL_PATH_STENCIL_FUNC_NV: u32 = 37047;
+pub const GL_PATH_STENCIL_REF_NV: u32 = 37048;
+pub const GL_PATH_STENCIL_VALUE_MASK_NV: u32 = 37049;
+pub const GL_SCALED_RESOLVE_FASTEST_EXT: u32 = 37050;
+pub const GL_SCALED_RESOLVE_NICEST_EXT: u32 = 37051;
+pub const GL_MIN_MAP_BUFFER_ALIGNMENT: u32 = 37052;
+pub const GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV: u32 = 37053;
+pub const GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV: u32 = 37054;
+pub const GL_PATH_COVER_DEPTH_FUNC_NV: u32 = 37055;
+pub const GL_IMAGE_FORMAT_COMPATIBILITY_TYPE: u32 = 37063;
+pub const GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE: u32 = 37064;
+pub const GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS: u32 = 37065;
+pub const GL_MAX_VERTEX_IMAGE_UNIFORMS: u32 = 37066;
+pub const GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS: u32 = 37067;
+pub const GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_EXT: u32 = 37067;
+pub const GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_OES: u32 = 37067;
+pub const GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS: u32 = 37068;
+pub const GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_EXT: u32 = 37068;
+pub const GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_OES: u32 = 37068;
+pub const GL_MAX_GEOMETRY_IMAGE_UNIFORMS: u32 = 37069;
+pub const GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT: u32 = 37069;
+pub const GL_MAX_GEOMETRY_IMAGE_UNIFORMS_OES: u32 = 37069;
+pub const GL_MAX_FRAGMENT_IMAGE_UNIFORMS: u32 = 37070;
+pub const GL_MAX_COMBINED_IMAGE_UNIFORMS: u32 = 37071;
+pub const GL_MAX_DEEP_3D_TEXTURE_WIDTH_HEIGHT_NV: u32 = 37072;
+pub const GL_MAX_DEEP_3D_TEXTURE_DEPTH_NV: u32 = 37073;
+pub const GL_SHADER_STORAGE_BUFFER: u32 = 37074;
+pub const GL_SHADER_STORAGE_BUFFER_BINDING: u32 = 37075;
+pub const GL_SHADER_STORAGE_BUFFER_START: u32 = 37076;
+pub const GL_SHADER_STORAGE_BUFFER_SIZE: u32 = 37077;
+pub const GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS: u32 = 37078;
+pub const GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS: u32 = 37079;
+pub const GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT: u32 = 37079;
+pub const GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_OES: u32 = 37079;
+pub const GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS: u32 = 37080;
+pub const GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_EXT: u32 = 37080;
+pub const GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_OES: u32 = 37080;
+pub const GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS: u32 = 37081;
+pub const GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_EXT: u32 = 37081;
+pub const GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_OES: u32 = 37081;
+pub const GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS: u32 = 37082;
+pub const GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS: u32 = 37083;
+pub const GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS: u32 = 37084;
+pub const GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS: u32 = 37085;
+pub const GL_MAX_SHADER_STORAGE_BLOCK_SIZE: u32 = 37086;
+pub const GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT: u32 = 37087;
+pub const GL_SYNC_X11_FENCE_EXT: u32 = 37089;
+pub const GL_DEPTH_STENCIL_TEXTURE_MODE: u32 = 37098;
+pub const GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB: u32 = 37099;
+pub const GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS: u32 = 37099;
+pub const GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER: u32 = 37100;
+pub const GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER: u32 = 37101;
+pub const GL_DISPATCH_INDIRECT_BUFFER: u32 = 37102;
+pub const GL_DISPATCH_INDIRECT_BUFFER_BINDING: u32 = 37103;
+pub const GL_COLOR_ATTACHMENT_EXT: u32 = 37104;
+pub const GL_MULTIVIEW_EXT: u32 = 37105;
+pub const GL_MAX_MULTIVIEW_BUFFERS_EXT: u32 = 37106;
+pub const GL_CONTEXT_ROBUST_ACCESS: u32 = 37107;
+pub const GL_CONTEXT_ROBUST_ACCESS_EXT: u32 = 37107;
+pub const GL_CONTEXT_ROBUST_ACCESS_KHR: u32 = 37107;
+pub const GL_COMPUTE_PROGRAM_NV: u32 = 37115;
+pub const GL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV: u32 = 37116;
+pub const GL_TEXTURE_2D_MULTISAMPLE: u32 = 37120;
+pub const GL_PROXY_TEXTURE_2D_MULTISAMPLE: u32 = 37121;
+pub const GL_TEXTURE_2D_MULTISAMPLE_ARRAY: u32 = 37122;
+pub const GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES: u32 = 37122;
+pub const GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY: u32 = 37123;
+pub const GL_TEXTURE_BINDING_2D_MULTISAMPLE: u32 = 37124;
+pub const GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY: u32 = 37125;
+pub const GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY_OES: u32 = 37125;
+pub const GL_TEXTURE_SAMPLES: u32 = 37126;
+pub const GL_TEXTURE_FIXED_SAMPLE_LOCATIONS: u32 = 37127;
+pub const GL_SAMPLER_2D_MULTISAMPLE: u32 = 37128;
+pub const GL_INT_SAMPLER_2D_MULTISAMPLE: u32 = 37129;
+pub const GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: u32 = 37130;
+pub const GL_SAMPLER_2D_MULTISAMPLE_ARRAY: u32 = 37131;
+pub const GL_SAMPLER_2D_MULTISAMPLE_ARRAY_OES: u32 = 37131;
+pub const GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: u32 = 37132;
+pub const GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES: u32 = 37132;
+pub const GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: u32 = 37133;
+pub const GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES: u32 = 37133;
+pub const GL_MAX_COLOR_TEXTURE_SAMPLES: u32 = 37134;
+pub const GL_MAX_DEPTH_TEXTURE_SAMPLES: u32 = 37135;
+pub const GL_MAX_INTEGER_SAMPLES: u32 = 37136;
+pub const GL_MAX_SERVER_WAIT_TIMEOUT: u32 = 37137;
+pub const GL_MAX_SERVER_WAIT_TIMEOUT_APPLE: u32 = 37137;
+pub const GL_OBJECT_TYPE: u32 = 37138;
+pub const GL_OBJECT_TYPE_APPLE: u32 = 37138;
+pub const GL_SYNC_CONDITION: u32 = 37139;
+pub const GL_SYNC_CONDITION_APPLE: u32 = 37139;
+pub const GL_SYNC_STATUS: u32 = 37140;
+pub const GL_SYNC_STATUS_APPLE: u32 = 37140;
+pub const GL_SYNC_FLAGS: u32 = 37141;
+pub const GL_SYNC_FLAGS_APPLE: u32 = 37141;
+pub const GL_SYNC_FENCE: u32 = 37142;
+pub const GL_SYNC_FENCE_APPLE: u32 = 37142;
+pub const GL_SYNC_GPU_COMMANDS_COMPLETE: u32 = 37143;
+pub const GL_SYNC_GPU_COMMANDS_COMPLETE_APPLE: u32 = 37143;
+pub const GL_UNSIGNALED: u32 = 37144;
+pub const GL_UNSIGNALED_APPLE: u32 = 37144;
+pub const GL_SIGNALED: u32 = 37145;
+pub const GL_SIGNALED_APPLE: u32 = 37145;
+pub const GL_ALREADY_SIGNALED: u32 = 37146;
+pub const GL_ALREADY_SIGNALED_APPLE: u32 = 37146;
+pub const GL_TIMEOUT_EXPIRED: u32 = 37147;
+pub const GL_TIMEOUT_EXPIRED_APPLE: u32 = 37147;
+pub const GL_CONDITION_SATISFIED: u32 = 37148;
+pub const GL_CONDITION_SATISFIED_APPLE: u32 = 37148;
+pub const GL_WAIT_FAILED: u32 = 37149;
+pub const GL_WAIT_FAILED_APPLE: u32 = 37149;
+pub const GL_BUFFER_ACCESS_FLAGS: u32 = 37151;
+pub const GL_BUFFER_MAP_LENGTH: u32 = 37152;
+pub const GL_BUFFER_MAP_OFFSET: u32 = 37153;
+pub const GL_MAX_VERTEX_OUTPUT_COMPONENTS: u32 = 37154;
+pub const GL_MAX_GEOMETRY_INPUT_COMPONENTS: u32 = 37155;
+pub const GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT: u32 = 37155;
+pub const GL_MAX_GEOMETRY_INPUT_COMPONENTS_OES: u32 = 37155;
+pub const GL_MAX_GEOMETRY_OUTPUT_COMPONENTS: u32 = 37156;
+pub const GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT: u32 = 37156;
+pub const GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_OES: u32 = 37156;
+pub const GL_MAX_FRAGMENT_INPUT_COMPONENTS: u32 = 37157;
+pub const GL_CONTEXT_PROFILE_MASK: u32 = 37158;
+pub const GL_UNPACK_COMPRESSED_BLOCK_WIDTH: u32 = 37159;
+pub const GL_UNPACK_COMPRESSED_BLOCK_HEIGHT: u32 = 37160;
+pub const GL_UNPACK_COMPRESSED_BLOCK_DEPTH: u32 = 37161;
+pub const GL_UNPACK_COMPRESSED_BLOCK_SIZE: u32 = 37162;
+pub const GL_PACK_COMPRESSED_BLOCK_WIDTH: u32 = 37163;
+pub const GL_PACK_COMPRESSED_BLOCK_HEIGHT: u32 = 37164;
+pub const GL_PACK_COMPRESSED_BLOCK_DEPTH: u32 = 37165;
+pub const GL_PACK_COMPRESSED_BLOCK_SIZE: u32 = 37166;
+pub const GL_TEXTURE_IMMUTABLE_FORMAT: u32 = 37167;
+pub const GL_TEXTURE_IMMUTABLE_FORMAT_EXT: u32 = 37167;
+pub const GL_SGX_PROGRAM_BINARY_IMG: u32 = 37168;
+pub const GL_RENDERBUFFER_SAMPLES_IMG: u32 = 37171;
+pub const GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG: u32 = 37172;
+pub const GL_MAX_SAMPLES_IMG: u32 = 37173;
+pub const GL_TEXTURE_SAMPLES_IMG: u32 = 37174;
+pub const GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG: u32 = 37175;
+pub const GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG: u32 = 37176;
+pub const GL_CUBIC_IMG: u32 = 37177;
+pub const GL_CUBIC_MIPMAP_NEAREST_IMG: u32 = 37178;
+pub const GL_CUBIC_MIPMAP_LINEAR_IMG: u32 = 37179;
+pub const GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_AND_DOWNSAMPLE_IMG: u32 = 37180;
+pub const GL_NUM_DOWNSAMPLE_SCALES_IMG: u32 = 37181;
+pub const GL_DOWNSAMPLE_SCALES_IMG: u32 = 37182;
+pub const GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SCALE_IMG: u32 = 37183;
+pub const GL_MAX_DEBUG_MESSAGE_LENGTH: u32 = 37187;
+pub const GL_MAX_DEBUG_MESSAGE_LENGTH_AMD: u32 = 37187;
+pub const GL_MAX_DEBUG_MESSAGE_LENGTH_ARB: u32 = 37187;
+pub const GL_MAX_DEBUG_MESSAGE_LENGTH_KHR: u32 = 37187;
+pub const GL_MAX_DEBUG_LOGGED_MESSAGES: u32 = 37188;
+pub const GL_MAX_DEBUG_LOGGED_MESSAGES_AMD: u32 = 37188;
+pub const GL_MAX_DEBUG_LOGGED_MESSAGES_ARB: u32 = 37188;
+pub const GL_MAX_DEBUG_LOGGED_MESSAGES_KHR: u32 = 37188;
+pub const GL_DEBUG_LOGGED_MESSAGES: u32 = 37189;
+pub const GL_DEBUG_LOGGED_MESSAGES_AMD: u32 = 37189;
+pub const GL_DEBUG_LOGGED_MESSAGES_ARB: u32 = 37189;
+pub const GL_DEBUG_LOGGED_MESSAGES_KHR: u32 = 37189;
+pub const GL_DEBUG_SEVERITY_HIGH: u32 = 37190;
+pub const GL_DEBUG_SEVERITY_HIGH_AMD: u32 = 37190;
+pub const GL_DEBUG_SEVERITY_HIGH_ARB: u32 = 37190;
+pub const GL_DEBUG_SEVERITY_HIGH_KHR: u32 = 37190;
+pub const GL_DEBUG_SEVERITY_MEDIUM: u32 = 37191;
+pub const GL_DEBUG_SEVERITY_MEDIUM_AMD: u32 = 37191;
+pub const GL_DEBUG_SEVERITY_MEDIUM_ARB: u32 = 37191;
+pub const GL_DEBUG_SEVERITY_MEDIUM_KHR: u32 = 37191;
+pub const GL_DEBUG_SEVERITY_LOW: u32 = 37192;
+pub const GL_DEBUG_SEVERITY_LOW_AMD: u32 = 37192;
+pub const GL_DEBUG_SEVERITY_LOW_ARB: u32 = 37192;
+pub const GL_DEBUG_SEVERITY_LOW_KHR: u32 = 37192;
+pub const GL_DEBUG_CATEGORY_API_ERROR_AMD: u32 = 37193;
+pub const GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD: u32 = 37194;
+pub const GL_DEBUG_CATEGORY_DEPRECATION_AMD: u32 = 37195;
+pub const GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD: u32 = 37196;
+pub const GL_DEBUG_CATEGORY_PERFORMANCE_AMD: u32 = 37197;
+pub const GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD: u32 = 37198;
+pub const GL_DEBUG_CATEGORY_APPLICATION_AMD: u32 = 37199;
+pub const GL_DEBUG_CATEGORY_OTHER_AMD: u32 = 37200;
+pub const GL_BUFFER_OBJECT_EXT: u32 = 37201;
+pub const GL_DATA_BUFFER_AMD: u32 = 37201;
+pub const GL_PERFORMANCE_MONITOR_AMD: u32 = 37202;
+pub const GL_QUERY_OBJECT_AMD: u32 = 37203;
+pub const GL_QUERY_OBJECT_EXT: u32 = 37203;
+pub const GL_VERTEX_ARRAY_OBJECT_AMD: u32 = 37204;
+pub const GL_VERTEX_ARRAY_OBJECT_EXT: u32 = 37204;
+pub const GL_SAMPLER_OBJECT_AMD: u32 = 37205;
+pub const GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD: u32 = 37216;
+pub const GL_QUERY_BUFFER: u32 = 37266;
+pub const GL_QUERY_BUFFER_AMD: u32 = 37266;
+pub const GL_QUERY_BUFFER_BINDING: u32 = 37267;
+pub const GL_QUERY_BUFFER_BINDING_AMD: u32 = 37267;
+pub const GL_QUERY_RESULT_NO_WAIT: u32 = 37268;
+pub const GL_QUERY_RESULT_NO_WAIT_AMD: u32 = 37268;
+pub const GL_VIRTUAL_PAGE_SIZE_X_AMD: u32 = 37269;
+pub const GL_VIRTUAL_PAGE_SIZE_X_ARB: u32 = 37269;
+pub const GL_VIRTUAL_PAGE_SIZE_X_EXT: u32 = 37269;
+pub const GL_VIRTUAL_PAGE_SIZE_Y_AMD: u32 = 37270;
+pub const GL_VIRTUAL_PAGE_SIZE_Y_ARB: u32 = 37270;
+pub const GL_VIRTUAL_PAGE_SIZE_Y_EXT: u32 = 37270;
+pub const GL_VIRTUAL_PAGE_SIZE_Z_AMD: u32 = 37271;
+pub const GL_VIRTUAL_PAGE_SIZE_Z_ARB: u32 = 37271;
+pub const GL_VIRTUAL_PAGE_SIZE_Z_EXT: u32 = 37271;
+pub const GL_MAX_SPARSE_TEXTURE_SIZE_AMD: u32 = 37272;
+pub const GL_MAX_SPARSE_TEXTURE_SIZE_ARB: u32 = 37272;
+pub const GL_MAX_SPARSE_TEXTURE_SIZE_EXT: u32 = 37272;
+pub const GL_MAX_SPARSE_3D_TEXTURE_SIZE_AMD: u32 = 37273;
+pub const GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB: u32 = 37273;
+pub const GL_MAX_SPARSE_3D_TEXTURE_SIZE_EXT: u32 = 37273;
+pub const GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS: u32 = 37274;
+pub const GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB: u32 = 37274;
+pub const GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_EXT: u32 = 37274;
+pub const GL_MIN_SPARSE_LEVEL_AMD: u32 = 37275;
+pub const GL_MIN_LOD_WARNING_AMD: u32 = 37276;
+pub const GL_TEXTURE_BUFFER_OFFSET: u32 = 37277;
+pub const GL_TEXTURE_BUFFER_OFFSET_EXT: u32 = 37277;
+pub const GL_TEXTURE_BUFFER_OFFSET_OES: u32 = 37277;
+pub const GL_TEXTURE_BUFFER_SIZE: u32 = 37278;
+pub const GL_TEXTURE_BUFFER_SIZE_EXT: u32 = 37278;
+pub const GL_TEXTURE_BUFFER_SIZE_OES: u32 = 37278;
+pub const GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT: u32 = 37279;
+pub const GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_EXT: u32 = 37279;
+pub const GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_OES: u32 = 37279;
+pub const GL_STREAM_RASTERIZATION_AMD: u32 = 37280;
+pub const GL_VERTEX_ELEMENT_SWIZZLE_AMD: u32 = 37284;
+pub const GL_VERTEX_ID_SWIZZLE_AMD: u32 = 37285;
+pub const GL_TEXTURE_SPARSE_ARB: u32 = 37286;
+pub const GL_TEXTURE_SPARSE_EXT: u32 = 37286;
+pub const GL_VIRTUAL_PAGE_SIZE_INDEX_ARB: u32 = 37287;
+pub const GL_VIRTUAL_PAGE_SIZE_INDEX_EXT: u32 = 37287;
+pub const GL_NUM_VIRTUAL_PAGE_SIZES_ARB: u32 = 37288;
+pub const GL_NUM_VIRTUAL_PAGE_SIZES_EXT: u32 = 37288;
+pub const GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB: u32 = 37289;
+pub const GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_EXT: u32 = 37289;
+pub const GL_NUM_SPARSE_LEVELS_ARB: u32 = 37290;
+pub const GL_NUM_SPARSE_LEVELS_EXT: u32 = 37290;
+pub const GL_PIXELS_PER_SAMPLE_PATTERN_X_AMD: u32 = 37294;
+pub const GL_PIXELS_PER_SAMPLE_PATTERN_Y_AMD: u32 = 37295;
+pub const GL_MAX_SHADER_COMPILER_THREADS_ARB: u32 = 37296;
+pub const GL_COMPLETION_STATUS_ARB: u32 = 37297;
+pub const GL_COMPUTE_SHADER: u32 = 37305;
+pub const GL_MAX_COMPUTE_UNIFORM_BLOCKS: u32 = 37307;
+pub const GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS: u32 = 37308;
+pub const GL_MAX_COMPUTE_IMAGE_UNIFORMS: u32 = 37309;
+pub const GL_MAX_COMPUTE_WORK_GROUP_COUNT: u32 = 37310;
+pub const GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB: u32 = 37311;
+pub const GL_MAX_COMPUTE_WORK_GROUP_SIZE: u32 = 37311;
+pub const GL_FLOAT16_MAT2_AMD: u32 = 37317;
+pub const GL_FLOAT16_MAT3_AMD: u32 = 37318;
+pub const GL_FLOAT16_MAT4_AMD: u32 = 37319;
+pub const GL_FLOAT16_MAT2x3_AMD: u32 = 37320;
+pub const GL_FLOAT16_MAT2x4_AMD: u32 = 37321;
+pub const GL_FLOAT16_MAT3x2_AMD: u32 = 37322;
+pub const GL_FLOAT16_MAT3x4_AMD: u32 = 37323;
+pub const GL_FLOAT16_MAT4x2_AMD: u32 = 37324;
+pub const GL_FLOAT16_MAT4x3_AMD: u32 = 37325;
+pub const GL_UNPACK_FLIP_Y_WEBGL: u32 = 37440;
+pub const GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL: u32 = 37441;
+pub const GL_CONTEXT_LOST_WEBGL: u32 = 37442;
+pub const GL_UNPACK_COLORSPACE_CONVERSION_WEBGL: u32 = 37443;
+pub const GL_BROWSER_DEFAULT_WEBGL: u32 = 37444;
+pub const GL_SHADER_BINARY_DMP: u32 = 37456;
+pub const GL_SMAPHS30_PROGRAM_BINARY_DMP: u32 = 37457;
+pub const GL_SMAPHS_PROGRAM_BINARY_DMP: u32 = 37458;
+pub const GL_DMP_PROGRAM_BINARY_DMP: u32 = 37459;
+pub const GL_GCCSO_SHADER_BINARY_FJ: u32 = 37472;
+pub const GL_COMPRESSED_R11_EAC: u32 = 37488;
+pub const GL_COMPRESSED_R11_EAC_OES: u32 = 37488;
+pub const GL_COMPRESSED_SIGNED_R11_EAC: u32 = 37489;
+pub const GL_COMPRESSED_SIGNED_R11_EAC_OES: u32 = 37489;
+pub const GL_COMPRESSED_RG11_EAC: u32 = 37490;
+pub const GL_COMPRESSED_RG11_EAC_OES: u32 = 37490;
+pub const GL_COMPRESSED_SIGNED_RG11_EAC: u32 = 37491;
+pub const GL_COMPRESSED_SIGNED_RG11_EAC_OES: u32 = 37491;
+pub const GL_COMPRESSED_RGB8_ETC2: u32 = 37492;
+pub const GL_COMPRESSED_RGB8_ETC2_OES: u32 = 37492;
+pub const GL_COMPRESSED_SRGB8_ETC2: u32 = 37493;
+pub const GL_COMPRESSED_SRGB8_ETC2_OES: u32 = 37493;
+pub const GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: u32 = 37494;
+pub const GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2_OES: u32 = 37494;
+pub const GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: u32 = 37495;
+pub const GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2_OES: u32 = 37495;
+pub const GL_COMPRESSED_RGBA8_ETC2_EAC: u32 = 37496;
+pub const GL_COMPRESSED_RGBA8_ETC2_EAC_OES: u32 = 37496;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: u32 = 37497;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC_OES: u32 = 37497;
+pub const GL_BLEND_PREMULTIPLIED_SRC_NV: u32 = 37504;
+pub const GL_BLEND_OVERLAP_NV: u32 = 37505;
+pub const GL_UNCORRELATED_NV: u32 = 37506;
+pub const GL_DISJOINT_NV: u32 = 37507;
+pub const GL_CONJOINT_NV: u32 = 37508;
+pub const GL_BLEND_ADVANCED_COHERENT_KHR: u32 = 37509;
+pub const GL_BLEND_ADVANCED_COHERENT_NV: u32 = 37509;
+pub const GL_SRC_NV: u32 = 37510;
+pub const GL_DST_NV: u32 = 37511;
+pub const GL_SRC_OVER_NV: u32 = 37512;
+pub const GL_DST_OVER_NV: u32 = 37513;
+pub const GL_SRC_IN_NV: u32 = 37514;
+pub const GL_DST_IN_NV: u32 = 37515;
+pub const GL_SRC_OUT_NV: u32 = 37516;
+pub const GL_DST_OUT_NV: u32 = 37517;
+pub const GL_SRC_ATOP_NV: u32 = 37518;
+pub const GL_DST_ATOP_NV: u32 = 37519;
+pub const GL_PLUS_NV: u32 = 37521;
+pub const GL_PLUS_DARKER_NV: u32 = 37522;
+pub const GL_MULTIPLY: u32 = 37524;
+pub const GL_MULTIPLY_KHR: u32 = 37524;
+pub const GL_MULTIPLY_NV: u32 = 37524;
+pub const GL_SCREEN: u32 = 37525;
+pub const GL_SCREEN_KHR: u32 = 37525;
+pub const GL_SCREEN_NV: u32 = 37525;
+pub const GL_OVERLAY: u32 = 37526;
+pub const GL_OVERLAY_KHR: u32 = 37526;
+pub const GL_OVERLAY_NV: u32 = 37526;
+pub const GL_DARKEN: u32 = 37527;
+pub const GL_DARKEN_KHR: u32 = 37527;
+pub const GL_DARKEN_NV: u32 = 37527;
+pub const GL_LIGHTEN: u32 = 37528;
+pub const GL_LIGHTEN_KHR: u32 = 37528;
+pub const GL_LIGHTEN_NV: u32 = 37528;
+pub const GL_COLORDODGE: u32 = 37529;
+pub const GL_COLORDODGE_KHR: u32 = 37529;
+pub const GL_COLORDODGE_NV: u32 = 37529;
+pub const GL_COLORBURN: u32 = 37530;
+pub const GL_COLORBURN_KHR: u32 = 37530;
+pub const GL_COLORBURN_NV: u32 = 37530;
+pub const GL_HARDLIGHT: u32 = 37531;
+pub const GL_HARDLIGHT_KHR: u32 = 37531;
+pub const GL_HARDLIGHT_NV: u32 = 37531;
+pub const GL_SOFTLIGHT: u32 = 37532;
+pub const GL_SOFTLIGHT_KHR: u32 = 37532;
+pub const GL_SOFTLIGHT_NV: u32 = 37532;
+pub const GL_DIFFERENCE: u32 = 37534;
+pub const GL_DIFFERENCE_KHR: u32 = 37534;
+pub const GL_DIFFERENCE_NV: u32 = 37534;
+pub const GL_MINUS_NV: u32 = 37535;
+pub const GL_EXCLUSION: u32 = 37536;
+pub const GL_EXCLUSION_KHR: u32 = 37536;
+pub const GL_EXCLUSION_NV: u32 = 37536;
+pub const GL_CONTRAST_NV: u32 = 37537;
+pub const GL_INVERT_RGB_NV: u32 = 37539;
+pub const GL_LINEARDODGE_NV: u32 = 37540;
+pub const GL_LINEARBURN_NV: u32 = 37541;
+pub const GL_VIVIDLIGHT_NV: u32 = 37542;
+pub const GL_LINEARLIGHT_NV: u32 = 37543;
+pub const GL_PINLIGHT_NV: u32 = 37544;
+pub const GL_HARDMIX_NV: u32 = 37545;
+pub const GL_HSL_HUE: u32 = 37549;
+pub const GL_HSL_HUE_KHR: u32 = 37549;
+pub const GL_HSL_HUE_NV: u32 = 37549;
+pub const GL_HSL_SATURATION: u32 = 37550;
+pub const GL_HSL_SATURATION_KHR: u32 = 37550;
+pub const GL_HSL_SATURATION_NV: u32 = 37550;
+pub const GL_HSL_COLOR: u32 = 37551;
+pub const GL_HSL_COLOR_KHR: u32 = 37551;
+pub const GL_HSL_COLOR_NV: u32 = 37551;
+pub const GL_HSL_LUMINOSITY: u32 = 37552;
+pub const GL_HSL_LUMINOSITY_KHR: u32 = 37552;
+pub const GL_HSL_LUMINOSITY_NV: u32 = 37552;
+pub const GL_PLUS_CLAMPED_NV: u32 = 37553;
+pub const GL_PLUS_CLAMPED_ALPHA_NV: u32 = 37554;
+pub const GL_MINUS_CLAMPED_NV: u32 = 37555;
+pub const GL_INVERT_OVG_NV: u32 = 37556;
+pub const GL_PURGED_CONTEXT_RESET_NV: u32 = 37563;
+pub const GL_PRIMITIVE_BOUNDING_BOX: u32 = 37566;
+pub const GL_PRIMITIVE_BOUNDING_BOX_ARB: u32 = 37566;
+pub const GL_PRIMITIVE_BOUNDING_BOX_EXT: u32 = 37566;
+pub const GL_PRIMITIVE_BOUNDING_BOX_OES: u32 = 37566;
+pub const GL_ATOMIC_COUNTER_BUFFER: u32 = 37568;
+pub const GL_ATOMIC_COUNTER_BUFFER_BINDING: u32 = 37569;
+pub const GL_ATOMIC_COUNTER_BUFFER_START: u32 = 37570;
+pub const GL_ATOMIC_COUNTER_BUFFER_SIZE: u32 = 37571;
+pub const GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE: u32 = 37572;
+pub const GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS: u32 = 37573;
+pub const GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES: u32 = 37574;
+pub const GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER: u32 = 37575;
+pub const GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER: u32 = 37576;
+pub const GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER: u32 = 37577;
+pub const GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER: u32 = 37578;
+pub const GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER: u32 = 37579;
+pub const GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS: u32 = 37580;
+pub const GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS: u32 = 37581;
+pub const GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_EXT: u32 = 37581;
+pub const GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_OES: u32 = 37581;
+pub const GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS: u32 = 37582;
+pub const GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT: u32 = 37582;
+pub const GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_OES: u32 = 37582;
+pub const GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS: u32 = 37583;
+pub const GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT: u32 = 37583;
+pub const GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_OES: u32 = 37583;
+pub const GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS: u32 = 37584;
+pub const GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS: u32 = 37585;
+pub const GL_MAX_VERTEX_ATOMIC_COUNTERS: u32 = 37586;
+pub const GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS: u32 = 37587;
+pub const GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_EXT: u32 = 37587;
+pub const GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_OES: u32 = 37587;
+pub const GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS: u32 = 37588;
+pub const GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT: u32 = 37588;
+pub const GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_OES: u32 = 37588;
+pub const GL_MAX_GEOMETRY_ATOMIC_COUNTERS: u32 = 37589;
+pub const GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT: u32 = 37589;
+pub const GL_MAX_GEOMETRY_ATOMIC_COUNTERS_OES: u32 = 37589;
+pub const GL_MAX_FRAGMENT_ATOMIC_COUNTERS: u32 = 37590;
+pub const GL_MAX_COMBINED_ATOMIC_COUNTERS: u32 = 37591;
+pub const GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE: u32 = 37592;
+pub const GL_ACTIVE_ATOMIC_COUNTER_BUFFERS: u32 = 37593;
+pub const GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX: u32 = 37594;
+pub const GL_UNSIGNED_INT_ATOMIC_COUNTER: u32 = 37595;
+pub const GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS: u32 = 37596;
+pub const GL_FRAGMENT_COVERAGE_TO_COLOR_NV: u32 = 37597;
+pub const GL_FRAGMENT_COVERAGE_COLOR_NV: u32 = 37598;
+pub const GL_DEBUG_OUTPUT: u32 = 37600;
+pub const GL_DEBUG_OUTPUT_KHR: u32 = 37600;
+pub const GL_UNIFORM: u32 = 37601;
+pub const GL_UNIFORM_BLOCK: u32 = 37602;
+pub const GL_PROGRAM_INPUT: u32 = 37603;
+pub const GL_PROGRAM_OUTPUT: u32 = 37604;
+pub const GL_BUFFER_VARIABLE: u32 = 37605;
+pub const GL_SHADER_STORAGE_BLOCK: u32 = 37606;
+pub const GL_IS_PER_PATCH: u32 = 37607;
+pub const GL_IS_PER_PATCH_EXT: u32 = 37607;
+pub const GL_IS_PER_PATCH_OES: u32 = 37607;
+pub const GL_VERTEX_SUBROUTINE: u32 = 37608;
+pub const GL_TESS_CONTROL_SUBROUTINE: u32 = 37609;
+pub const GL_TESS_EVALUATION_SUBROUTINE: u32 = 37610;
+pub const GL_GEOMETRY_SUBROUTINE: u32 = 37611;
+pub const GL_FRAGMENT_SUBROUTINE: u32 = 37612;
+pub const GL_COMPUTE_SUBROUTINE: u32 = 37613;
+pub const GL_VERTEX_SUBROUTINE_UNIFORM: u32 = 37614;
+pub const GL_TESS_CONTROL_SUBROUTINE_UNIFORM: u32 = 37615;
+pub const GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: u32 = 37616;
+pub const GL_GEOMETRY_SUBROUTINE_UNIFORM: u32 = 37617;
+pub const GL_FRAGMENT_SUBROUTINE_UNIFORM: u32 = 37618;
+pub const GL_COMPUTE_SUBROUTINE_UNIFORM: u32 = 37619;
+pub const GL_TRANSFORM_FEEDBACK_VARYING: u32 = 37620;
+pub const GL_ACTIVE_RESOURCES: u32 = 37621;
+pub const GL_MAX_NAME_LENGTH: u32 = 37622;
+pub const GL_MAX_NUM_ACTIVE_VARIABLES: u32 = 37623;
+pub const GL_MAX_NUM_COMPATIBLE_SUBROUTINES: u32 = 37624;
+pub const GL_NAME_LENGTH: u32 = 37625;
+pub const GL_TYPE: u32 = 37626;
+pub const GL_ARRAY_SIZE: u32 = 37627;
+pub const GL_OFFSET: u32 = 37628;
+pub const GL_BLOCK_INDEX: u32 = 37629;
+pub const GL_ARRAY_STRIDE: u32 = 37630;
+pub const GL_MATRIX_STRIDE: u32 = 37631;
+pub const GL_IS_ROW_MAJOR: u32 = 37632;
+pub const GL_ATOMIC_COUNTER_BUFFER_INDEX: u32 = 37633;
+pub const GL_BUFFER_BINDING: u32 = 37634;
+pub const GL_BUFFER_DATA_SIZE: u32 = 37635;
+pub const GL_NUM_ACTIVE_VARIABLES: u32 = 37636;
+pub const GL_ACTIVE_VARIABLES: u32 = 37637;
+pub const GL_REFERENCED_BY_VERTEX_SHADER: u32 = 37638;
+pub const GL_REFERENCED_BY_TESS_CONTROL_SHADER: u32 = 37639;
+pub const GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT: u32 = 37639;
+pub const GL_REFERENCED_BY_TESS_CONTROL_SHADER_OES: u32 = 37639;
+pub const GL_REFERENCED_BY_TESS_EVALUATION_SHADER: u32 = 37640;
+pub const GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT: u32 = 37640;
+pub const GL_REFERENCED_BY_TESS_EVALUATION_SHADER_OES: u32 = 37640;
+pub const GL_REFERENCED_BY_GEOMETRY_SHADER: u32 = 37641;
+pub const GL_REFERENCED_BY_GEOMETRY_SHADER_EXT: u32 = 37641;
+pub const GL_REFERENCED_BY_GEOMETRY_SHADER_OES: u32 = 37641;
+pub const GL_REFERENCED_BY_FRAGMENT_SHADER: u32 = 37642;
+pub const GL_REFERENCED_BY_COMPUTE_SHADER: u32 = 37643;
+pub const GL_TOP_LEVEL_ARRAY_SIZE: u32 = 37644;
+pub const GL_TOP_LEVEL_ARRAY_STRIDE: u32 = 37645;
+pub const GL_LOCATION: u32 = 37646;
+pub const GL_LOCATION_INDEX: u32 = 37647;
+pub const GL_LOCATION_INDEX_EXT: u32 = 37647;
+pub const GL_FRAMEBUFFER_DEFAULT_WIDTH: u32 = 37648;
+pub const GL_FRAMEBUFFER_DEFAULT_HEIGHT: u32 = 37649;
+pub const GL_FRAMEBUFFER_DEFAULT_LAYERS: u32 = 37650;
+pub const GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT: u32 = 37650;
+pub const GL_FRAMEBUFFER_DEFAULT_LAYERS_OES: u32 = 37650;
+pub const GL_FRAMEBUFFER_DEFAULT_SAMPLES: u32 = 37651;
+pub const GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: u32 = 37652;
+pub const GL_MAX_FRAMEBUFFER_WIDTH: u32 = 37653;
+pub const GL_MAX_FRAMEBUFFER_HEIGHT: u32 = 37654;
+pub const GL_MAX_FRAMEBUFFER_LAYERS: u32 = 37655;
+pub const GL_MAX_FRAMEBUFFER_LAYERS_EXT: u32 = 37655;
+pub const GL_MAX_FRAMEBUFFER_LAYERS_OES: u32 = 37655;
+pub const GL_MAX_FRAMEBUFFER_SAMPLES: u32 = 37656;
+pub const GL_RASTER_MULTISAMPLE_EXT: u32 = 37671;
+pub const GL_RASTER_SAMPLES_EXT: u32 = 37672;
+pub const GL_MAX_RASTER_SAMPLES_EXT: u32 = 37673;
+pub const GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT: u32 = 37674;
+pub const GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT: u32 = 37675;
+pub const GL_EFFECTIVE_RASTER_SAMPLES_EXT: u32 = 37676;
+pub const GL_DEPTH_SAMPLES_NV: u32 = 37677;
+pub const GL_STENCIL_SAMPLES_NV: u32 = 37678;
+pub const GL_MIXED_DEPTH_SAMPLES_SUPPORTED_NV: u32 = 37679;
+pub const GL_MIXED_STENCIL_SAMPLES_SUPPORTED_NV: u32 = 37680;
+pub const GL_COVERAGE_MODULATION_TABLE_NV: u32 = 37681;
+pub const GL_COVERAGE_MODULATION_NV: u32 = 37682;
+pub const GL_COVERAGE_MODULATION_TABLE_SIZE_NV: u32 = 37683;
+pub const GL_WARP_SIZE_NV: u32 = 37689;
+pub const GL_WARPS_PER_SM_NV: u32 = 37690;
+pub const GL_SM_COUNT_NV: u32 = 37691;
+pub const GL_FILL_RECTANGLE_NV: u32 = 37692;
+pub const GL_SAMPLE_LOCATION_SUBPIXEL_BITS_ARB: u32 = 37693;
+pub const GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV: u32 = 37693;
+pub const GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB: u32 = 37694;
+pub const GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV: u32 = 37694;
+pub const GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB: u32 = 37695;
+pub const GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_NV: u32 = 37695;
+pub const GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB: u32 = 37696;
+pub const GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_NV: u32 = 37696;
+pub const GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB: u32 = 37697;
+pub const GL_PROGRAMMABLE_SAMPLE_LOCATION_NV: u32 = 37697;
+pub const GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: u32 = 37698;
+pub const GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_NV: u32 = 37698;
+pub const GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: u32 = 37699;
+pub const GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_NV: u32 = 37699;
+pub const GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB: u32 = 37700;
+pub const GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB: u32 = 37701;
+pub const GL_CONSERVATIVE_RASTERIZATION_NV: u32 = 37702;
+pub const GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV: u32 = 37703;
+pub const GL_SUBPIXEL_PRECISION_BIAS_Y_BITS_NV: u32 = 37704;
+pub const GL_MAX_SUBPIXEL_PRECISION_BIAS_BITS_NV: u32 = 37705;
+pub const GL_LOCATION_COMPONENT: u32 = 37706;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_INDEX: u32 = 37707;
+pub const GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE: u32 = 37708;
+pub const GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV: u32 = 37712;
+pub const GL_VIEWPORT_SWIZZLE_NEGATIVE_X_NV: u32 = 37713;
+pub const GL_VIEWPORT_SWIZZLE_POSITIVE_Y_NV: u32 = 37714;
+pub const GL_VIEWPORT_SWIZZLE_NEGATIVE_Y_NV: u32 = 37715;
+pub const GL_VIEWPORT_SWIZZLE_POSITIVE_Z_NV: u32 = 37716;
+pub const GL_VIEWPORT_SWIZZLE_NEGATIVE_Z_NV: u32 = 37717;
+pub const GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV: u32 = 37718;
+pub const GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV: u32 = 37719;
+pub const GL_VIEWPORT_SWIZZLE_X_NV: u32 = 37720;
+pub const GL_VIEWPORT_SWIZZLE_Y_NV: u32 = 37721;
+pub const GL_VIEWPORT_SWIZZLE_Z_NV: u32 = 37722;
+pub const GL_VIEWPORT_SWIZZLE_W_NV: u32 = 37723;
+pub const GL_CLIP_ORIGIN: u32 = 37724;
+pub const GL_CLIP_DEPTH_MODE: u32 = 37725;
+pub const GL_NEGATIVE_ONE_TO_ONE: u32 = 37726;
+pub const GL_ZERO_TO_ONE: u32 = 37727;
+pub const GL_CLEAR_TEXTURE: u32 = 37733;
+pub const GL_TEXTURE_REDUCTION_MODE_ARB: u32 = 37734;
+pub const GL_WEIGHTED_AVERAGE_ARB: u32 = 37735;
+pub const GL_FONT_GLYPHS_AVAILABLE_NV: u32 = 37736;
+pub const GL_FONT_TARGET_UNAVAILABLE_NV: u32 = 37737;
+pub const GL_FONT_UNAVAILABLE_NV: u32 = 37738;
+pub const GL_FONT_UNINTELLIGIBLE_NV: u32 = 37739;
+pub const GL_STANDARD_FONT_FORMAT_NV: u32 = 37740;
+pub const GL_FRAGMENT_INPUT_NV: u32 = 37741;
+pub const GL_UNIFORM_BUFFER_UNIFIED_NV: u32 = 37742;
+pub const GL_UNIFORM_BUFFER_ADDRESS_NV: u32 = 37743;
+pub const GL_UNIFORM_BUFFER_LENGTH_NV: u32 = 37744;
+pub const GL_MULTISAMPLES_NV: u32 = 37745;
+pub const GL_SUPERSAMPLE_SCALE_X_NV: u32 = 37746;
+pub const GL_SUPERSAMPLE_SCALE_Y_NV: u32 = 37747;
+pub const GL_CONFORMANT_NV: u32 = 37748;
+pub const GL_CONSERVATIVE_RASTER_DILATE_NV: u32 = 37753;
+pub const GL_CONSERVATIVE_RASTER_DILATE_RANGE_NV: u32 = 37754;
+pub const GL_CONSERVATIVE_RASTER_DILATE_GRANULARITY_NV: u32 = 37755;
+pub const GL_VIEWPORT_POSITION_W_SCALE_NV: u32 = 37756;
+pub const GL_VIEWPORT_POSITION_W_SCALE_X_COEFF_NV: u32 = 37757;
+pub const GL_VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV: u32 = 37758;
+pub const GL_NUM_SAMPLE_COUNTS: u32 = 37760;
+pub const GL_MULTISAMPLE_LINE_WIDTH_RANGE: u32 = 37761;
+pub const GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB: u32 = 37761;
+pub const GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY: u32 = 37762;
+pub const GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY_ARB: u32 = 37762;
+pub const GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE: u32 = 37792;
+pub const GL_BGRA8_EXT: u32 = 37793;
+pub const GL_TEXTURE_USAGE_ANGLE: u32 = 37794;
+pub const GL_FRAMEBUFFER_ATTACHMENT_ANGLE: u32 = 37795;
+pub const GL_PACK_REVERSE_ROW_ORDER_ANGLE: u32 = 37796;
+pub const GL_PROGRAM_BINARY_ANGLE: u32 = 37798;
+pub const GL_COMPRESSED_RGBA_ASTC_4x4: u32 = 37808;
+pub const GL_COMPRESSED_RGBA_ASTC_4x4_KHR: u32 = 37808;
+pub const GL_COMPRESSED_RGBA_ASTC_5x4: u32 = 37809;
+pub const GL_COMPRESSED_RGBA_ASTC_5x4_KHR: u32 = 37809;
+pub const GL_COMPRESSED_RGBA_ASTC_5x5: u32 = 37810;
+pub const GL_COMPRESSED_RGBA_ASTC_5x5_KHR: u32 = 37810;
+pub const GL_COMPRESSED_RGBA_ASTC_6x5: u32 = 37811;
+pub const GL_COMPRESSED_RGBA_ASTC_6x5_KHR: u32 = 37811;
+pub const GL_COMPRESSED_RGBA_ASTC_6x6: u32 = 37812;
+pub const GL_COMPRESSED_RGBA_ASTC_6x6_KHR: u32 = 37812;
+pub const GL_COMPRESSED_RGBA_ASTC_8x5: u32 = 37813;
+pub const GL_COMPRESSED_RGBA_ASTC_8x5_KHR: u32 = 37813;
+pub const GL_COMPRESSED_RGBA_ASTC_8x6: u32 = 37814;
+pub const GL_COMPRESSED_RGBA_ASTC_8x6_KHR: u32 = 37814;
+pub const GL_COMPRESSED_RGBA_ASTC_8x8: u32 = 37815;
+pub const GL_COMPRESSED_RGBA_ASTC_8x8_KHR: u32 = 37815;
+pub const GL_COMPRESSED_RGBA_ASTC_10x5: u32 = 37816;
+pub const GL_COMPRESSED_RGBA_ASTC_10x5_KHR: u32 = 37816;
+pub const GL_COMPRESSED_RGBA_ASTC_10x6: u32 = 37817;
+pub const GL_COMPRESSED_RGBA_ASTC_10x6_KHR: u32 = 37817;
+pub const GL_COMPRESSED_RGBA_ASTC_10x8: u32 = 37818;
+pub const GL_COMPRESSED_RGBA_ASTC_10x8_KHR: u32 = 37818;
+pub const GL_COMPRESSED_RGBA_ASTC_10x10: u32 = 37819;
+pub const GL_COMPRESSED_RGBA_ASTC_10x10_KHR: u32 = 37819;
+pub const GL_COMPRESSED_RGBA_ASTC_12x10: u32 = 37820;
+pub const GL_COMPRESSED_RGBA_ASTC_12x10_KHR: u32 = 37820;
+pub const GL_COMPRESSED_RGBA_ASTC_12x12: u32 = 37821;
+pub const GL_COMPRESSED_RGBA_ASTC_12x12_KHR: u32 = 37821;
+pub const GL_COMPRESSED_RGBA_ASTC_3x3x3_OES: u32 = 37824;
+pub const GL_COMPRESSED_RGBA_ASTC_4x3x3_OES: u32 = 37825;
+pub const GL_COMPRESSED_RGBA_ASTC_4x4x3_OES: u32 = 37826;
+pub const GL_COMPRESSED_RGBA_ASTC_4x4x4_OES: u32 = 37827;
+pub const GL_COMPRESSED_RGBA_ASTC_5x4x4_OES: u32 = 37828;
+pub const GL_COMPRESSED_RGBA_ASTC_5x5x4_OES: u32 = 37829;
+pub const GL_COMPRESSED_RGBA_ASTC_5x5x5_OES: u32 = 37830;
+pub const GL_COMPRESSED_RGBA_ASTC_6x5x5_OES: u32 = 37831;
+pub const GL_COMPRESSED_RGBA_ASTC_6x6x5_OES: u32 = 37832;
+pub const GL_COMPRESSED_RGBA_ASTC_6x6x6_OES: u32 = 37833;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4: u32 = 37840;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: u32 = 37840;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4: u32 = 37841;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: u32 = 37841;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5: u32 = 37842;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: u32 = 37842;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5: u32 = 37843;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: u32 = 37843;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6: u32 = 37844;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: u32 = 37844;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5: u32 = 37845;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: u32 = 37845;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6: u32 = 37846;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: u32 = 37846;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8: u32 = 37847;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: u32 = 37847;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5: u32 = 37848;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: u32 = 37848;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6: u32 = 37849;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: u32 = 37849;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8: u32 = 37850;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: u32 = 37850;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10: u32 = 37851;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: u32 = 37851;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10: u32 = 37852;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: u32 = 37852;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12: u32 = 37853;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: u32 = 37853;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES: u32 = 37856;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES: u32 = 37857;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES: u32 = 37858;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES: u32 = 37859;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES: u32 = 37860;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES: u32 = 37861;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES: u32 = 37862;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES: u32 = 37863;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES: u32 = 37864;
+pub const GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES: u32 = 37865;
+pub const GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG: u32 = 37872;
+pub const GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG: u32 = 37873;
+pub const GL_PERFQUERY_COUNTER_EVENT_INTEL: u32 = 38128;
+pub const GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL: u32 = 38129;
+pub const GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL: u32 = 38130;
+pub const GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL: u32 = 38131;
+pub const GL_PERFQUERY_COUNTER_RAW_INTEL: u32 = 38132;
+pub const GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL: u32 = 38133;
+pub const GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL: u32 = 38136;
+pub const GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL: u32 = 38137;
+pub const GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL: u32 = 38138;
+pub const GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL: u32 = 38139;
+pub const GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL: u32 = 38140;
+pub const GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL: u32 = 38141;
+pub const GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL: u32 = 38142;
+pub const GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL: u32 = 38143;
+pub const GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL: u32 = 38144;
+pub const GL_CONSERVATIVE_RASTER_MODE_NV: u32 = 38221;
+pub const GL_CONSERVATIVE_RASTER_MODE_POST_SNAP_NV: u32 = 38222;
+pub const GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_TRIANGLES_NV: u32 = 38223;
+pub const GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR: u32 = 38448;
+pub const GL_MAX_VIEWS_OVR: u32 = 38449;
+pub const GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR: u32 = 38450;
+pub const GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR: u32 = 38451;
+pub const GL_GS_SHADER_BINARY_MTK: u32 = 38464;
+pub const GL_GS_PROGRAM_BINARY_MTK: u32 = 38465;
+pub const GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_FAST_SIZE_EXT: u32 = 38480;
+pub const GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_SIZE_EXT: u32 = 38481;
+pub const GL_FRAMEBUFFER_INCOMPLETE_INSUFFICIENT_SHADER_COMBINED_LOCAL_STORAGE_EXT: u32 = 38482;
+pub const GL_SHARED_EDGE_NV: u32 = 192;
+pub const GL_ROUNDED_RECT_NV: u32 = 232;
+pub const GL_RELATIVE_ROUNDED_RECT_NV: u32 = 233;
+pub const GL_ROUNDED_RECT2_NV: u32 = 234;
+pub const GL_RELATIVE_ROUNDED_RECT2_NV: u32 = 235;
+pub const GL_ROUNDED_RECT4_NV: u32 = 236;
+pub const GL_RELATIVE_ROUNDED_RECT4_NV: u32 = 237;
+pub const GL_ROUNDED_RECT8_NV: u32 = 238;
+pub const GL_RELATIVE_ROUNDED_RECT8_NV: u32 = 239;
+pub const GL_RESTART_PATH_NV: u32 = 240;
+pub const GL_DUP_FIRST_CUBIC_CURVE_TO_NV: u32 = 242;
+pub const GL_DUP_LAST_CUBIC_CURVE_TO_NV: u32 = 244;
+pub const GL_RECT_NV: u32 = 246;
+pub const GL_RELATIVE_RECT_NV: u32 = 247;
+pub const GL_CIRCULAR_CCW_ARC_TO_NV: u32 = 248;
+pub const GL_CIRCULAR_CW_ARC_TO_NV: u32 = 250;
+pub const GL_CIRCULAR_TANGENT_ARC_TO_NV: u32 = 252;
+pub const GL_ARC_TO_NV: u32 = 254;
+pub const GL_RELATIVE_ARC_TO_NV: u32 = 255;
+pub const GL_TRACE_ALL_BITS_MESA: u32 = 65535;
+pub const GL_ALL_BARRIER_BITS: u32 = 4294967295;
+pub const GL_ALL_BARRIER_BITS_EXT: u32 = 4294967295;
+pub const GL_ALL_PIXELS_AMD: u32 = 4294967295;
+pub const GL_ALL_SHADER_BITS: u32 = 4294967295;
+pub const GL_ALL_SHADER_BITS_EXT: u32 = 4294967295;
+pub const GL_CLIENT_ALL_ATTRIB_BITS: u32 = 4294967295;
+pub const GL_INVALID_INDEX: u32 = 4294967295;
+pub const GL_QUERY_ALL_EVENT_BITS_AMD: u32 = 4294967295;
+pub const GL_TIMEOUT_IGNORED: i32 = -1;
+pub const GL_TIMEOUT_IGNORED_APPLE: i32 = -1;
+pub const GL_LAYOUT_LINEAR_INTEL: u32 = 1;
+pub const GL_ONE: u32 = 1;
+pub const GL_TRUE: u32 = 1;
+pub const GL_VERSION_ES_CL_1_0: u32 = 1;
+pub const GL_VERSION_ES_CL_1_1: u32 = 1;
+pub const GL_VERSION_ES_CM_1_1: u32 = 1;
+pub const GL_CULL_VERTEX_IBM: u32 = 103050;
+pub const GL_ALL_STATIC_DATA_IBM: u32 = 103060;
+pub const GL_STATIC_VERTEX_ARRAY_IBM: u32 = 103061;
+pub const GL_VERTEX_ARRAY_LIST_IBM: u32 = 103070;
+pub const GL_NORMAL_ARRAY_LIST_IBM: u32 = 103071;
+pub const GL_COLOR_ARRAY_LIST_IBM: u32 = 103072;
+pub const GL_INDEX_ARRAY_LIST_IBM: u32 = 103073;
+pub const GL_TEXTURE_COORD_ARRAY_LIST_IBM: u32 = 103074;
+pub const GL_EDGE_FLAG_ARRAY_LIST_IBM: u32 = 103075;
+pub const GL_FOG_COORDINATE_ARRAY_LIST_IBM: u32 = 103076;
+pub const GL_SECONDARY_COLOR_ARRAY_LIST_IBM: u32 = 103077;
+pub const GL_VERTEX_ARRAY_LIST_STRIDE_IBM: u32 = 103080;
+pub const GL_NORMAL_ARRAY_LIST_STRIDE_IBM: u32 = 103081;
+pub const GL_COLOR_ARRAY_LIST_STRIDE_IBM: u32 = 103082;
+pub const GL_INDEX_ARRAY_LIST_STRIDE_IBM: u32 = 103083;
+pub const GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM: u32 = 103084;
+pub const GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM: u32 = 103085;
+pub const GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM: u32 = 103086;
+pub const GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM: u32 = 103087;
+pub const GL_LAYOUT_LINEAR_CPU_CACHED_INTEL: u32 = 2;
+pub const EGL_VERSION_1_0: u32 = 1;
+pub const EGL_VERSION_1_1: u32 = 1;
+pub const EGL_VERSION_1_2: u32 = 1;
+pub const EGL_VERSION_1_3: u32 = 1;
+pub const EGL_VERSION_1_4: u32 = 1;
+pub const EGL_VERSION_1_5: u32 = 1;
+pub const EGL_ANDROID_blob_cache: u32 = 1;
+pub const EGL_ANDROID_create_native_client_buffer: u32 = 1;
+pub const EGL_ANDROID_framebuffer_target: u32 = 1;
+pub const EGL_ANDROID_front_buffer_auto_refresh: u32 = 1;
+pub const EGL_ANDROID_image_native_buffer: u32 = 1;
+pub const EGL_ANDROID_native_fence_sync: u32 = 1;
+pub const EGL_ANDROID_presentation_time: u32 = 1;
+pub const EGL_ANDROID_recordable: u32 = 1;
+pub const EGL_ANGLE_d3d_share_handle_client_buffer: u32 = 1;
+pub const EGL_ANGLE_device_d3d: u32 = 1;
+pub const EGL_ANGLE_query_surface_pointer: u32 = 1;
+pub const EGL_ANGLE_surface_d3d_texture_2d_share_handle: u32 = 1;
+pub const EGL_ANGLE_window_fixed_size: u32 = 1;
+pub const EGL_ARM_implicit_external_sync: u32 = 1;
+pub const EGL_ARM_pixmap_multisample_discard: u32 = 1;
+pub const EGL_EXT_buffer_age: u32 = 1;
+pub const EGL_EXT_client_extensions: u32 = 1;
+pub const EGL_EXT_create_context_robustness: u32 = 1;
+pub const EGL_EXT_device_base: u32 = 1;
+pub const EGL_EXT_device_drm: u32 = 1;
+pub const EGL_EXT_device_enumeration: u32 = 1;
+pub const EGL_EXT_device_openwf: u32 = 1;
+pub const EGL_EXT_device_query: u32 = 1;
+pub const EGL_EXT_gl_colorspace_bt2020_linear: u32 = 1;
+pub const EGL_EXT_gl_colorspace_bt2020_pq: u32 = 1;
+pub const EGL_EXT_gl_colorspace_scrgb_linear: u32 = 1;
+pub const EGL_EXT_image_dma_buf_import: u32 = 1;
+pub const EGL_EXT_image_dma_buf_import_modifiers: u32 = 1;
+pub const EGL_EXT_multiview_window: u32 = 1;
+pub const EGL_EXT_output_base: u32 = 1;
+pub const EGL_EXT_output_drm: u32 = 1;
+pub const EGL_EXT_output_openwf: u32 = 1;
+pub const EGL_EXT_pixel_format_float: u32 = 1;
+pub const EGL_EXT_platform_base: u32 = 1;
+pub const EGL_EXT_platform_device: u32 = 1;
+pub const EGL_EXT_platform_wayland: u32 = 1;
+pub const EGL_EXT_platform_x11: u32 = 1;
+pub const EGL_EXT_protected_content: u32 = 1;
+pub const EGL_EXT_protected_surface: u32 = 1;
+pub const EGL_EXT_stream_consumer_egloutput: u32 = 1;
+pub const EGL_EXT_surface_SMPTE2086_metadata: u32 = 1;
+pub const EGL_EXT_swap_buffers_with_damage: u32 = 1;
+pub const EGL_EXT_yuv_surface: u32 = 1;
+pub const EGL_HI_clientpixmap: u32 = 1;
+pub const EGL_HI_colorformats: u32 = 1;
+pub const EGL_IMG_context_priority: u32 = 1;
+pub const EGL_IMG_image_plane_attribs: u32 = 1;
+pub const EGL_KHR_cl_event: u32 = 1;
+pub const EGL_KHR_cl_event2: u32 = 1;
+pub const EGL_KHR_client_get_all_proc_addresses: u32 = 1;
+pub const EGL_KHR_config_attribs: u32 = 1;
+pub const EGL_KHR_context_flush_control: u32 = 1;
+pub const EGL_KHR_create_context: u32 = 1;
+pub const EGL_KHR_create_context_no_error: u32 = 1;
+pub const EGL_KHR_debug: u32 = 1;
+pub const EGL_KHR_fence_sync: u32 = 1;
+pub const EGL_KHR_get_all_proc_addresses: u32 = 1;
+pub const EGL_KHR_gl_colorspace: u32 = 1;
+pub const EGL_KHR_gl_renderbuffer_image: u32 = 1;
+pub const EGL_KHR_gl_texture_2D_image: u32 = 1;
+pub const EGL_KHR_gl_texture_3D_image: u32 = 1;
+pub const EGL_KHR_gl_texture_cubemap_image: u32 = 1;
+pub const EGL_KHR_image: u32 = 1;
+pub const EGL_KHR_image_base: u32 = 1;
+pub const EGL_KHR_image_pixmap: u32 = 1;
+pub const EGL_KHR_lock_surface: u32 = 1;
+pub const EGL_KHR_lock_surface2: u32 = 1;
+pub const EGL_KHR_lock_surface3: u32 = 1;
+pub const EGL_KHR_mutable_render_buffer: u32 = 1;
+pub const EGL_KHR_no_config_context: u32 = 1;
+pub const EGL_KHR_partial_update: u32 = 1;
+pub const EGL_KHR_platform_android: u32 = 1;
+pub const EGL_KHR_platform_gbm: u32 = 1;
+pub const EGL_KHR_platform_wayland: u32 = 1;
+pub const EGL_KHR_platform_x11: u32 = 1;
+pub const EGL_KHR_reusable_sync: u32 = 1;
+pub const EGL_KHR_stream: u32 = 1;
+pub const EGL_KHR_stream_attrib: u32 = 1;
+pub const EGL_KHR_stream_consumer_gltexture: u32 = 1;
+pub const EGL_KHR_stream_cross_process_fd: u32 = 1;
+pub const EGL_KHR_stream_fifo: u32 = 1;
+pub const EGL_KHR_stream_producer_aldatalocator: u32 = 1;
+pub const EGL_KHR_stream_producer_eglsurface: u32 = 1;
+pub const EGL_KHR_surfaceless_context: u32 = 1;
+pub const EGL_KHR_swap_buffers_with_damage: u32 = 1;
+pub const EGL_KHR_vg_parent_image: u32 = 1;
+pub const EGL_KHR_wait_sync: u32 = 1;
+pub const EGL_MESA_drm_image: u32 = 1;
+pub const EGL_MESA_image_dma_buf_export: u32 = 1;
+pub const EGL_MESA_platform_gbm: u32 = 1;
+pub const EGL_MESA_platform_surfaceless: u32 = 1;
+pub const EGL_NOK_swap_region: u32 = 1;
+pub const EGL_NOK_swap_region2: u32 = 1;
+pub const EGL_NOK_texture_from_pixmap: u32 = 1;
+pub const EGL_NV_3dvision_surface: u32 = 1;
+pub const EGL_NV_coverage_sample: u32 = 1;
+pub const EGL_NV_coverage_sample_resolve: u32 = 1;
+pub const EGL_NV_cuda_event: u32 = 1;
+pub const EGL_NV_depth_nonlinear: u32 = 1;
+pub const EGL_NV_device_cuda: u32 = 1;
+pub const EGL_NV_native_query: u32 = 1;
+pub const EGL_NV_post_convert_rounding: u32 = 1;
+pub const EGL_NV_post_sub_buffer: u32 = 1;
+pub const EGL_NV_robustness_video_memory_purge: u32 = 1;
+pub const EGL_NV_stream_consumer_gltexture_yuv: u32 = 1;
+pub const EGL_NV_stream_cross_display: u32 = 1;
+pub const EGL_NV_stream_cross_object: u32 = 1;
+pub const EGL_NV_stream_cross_partition: u32 = 1;
+pub const EGL_NV_stream_cross_process: u32 = 1;
+pub const EGL_NV_stream_cross_system: u32 = 1;
+pub const EGL_NV_stream_fifo_next: u32 = 1;
+pub const EGL_NV_stream_fifo_synchronous: u32 = 1;
+pub const EGL_NV_stream_frame_limits: u32 = 1;
+pub const EGL_NV_stream_metadata: u32 = 1;
+pub const EGL_NV_stream_remote: u32 = 1;
+pub const EGL_NV_stream_reset: u32 = 1;
+pub const EGL_NV_stream_socket: u32 = 1;
+pub const EGL_NV_stream_socket_inet: u32 = 1;
+pub const EGL_NV_stream_socket_unix: u32 = 1;
+pub const EGL_NV_stream_sync: u32 = 1;
+pub const EGL_NV_sync: u32 = 1;
+pub const EGL_NV_system_time: u32 = 1;
+pub const EGL_TIZEN_image_native_buffer: u32 = 1;
+pub const EGL_TIZEN_image_native_surface: u32 = 1;
+pub const EGL_NO_NATIVE_FENCE_FD_ANDROID: i32 = -1;
+pub const EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR: u32 = 0;
+pub const EGL_DEPTH_ENCODING_NONE_NV: u32 = 0;
+pub const EGL_FALSE: u32 = 0;
+pub const EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT: u32 = 1;
+pub const EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR: u32 = 1;
+pub const EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR: u32 = 1;
+pub const EGL_DRM_BUFFER_USE_SCANOUT_MESA: u32 = 1;
+pub const EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID: u32 = 1;
+pub const EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT: u32 = 2;
+pub const EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR: u32 = 2;
+pub const EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR: u32 = 2;
+pub const EGL_DRM_BUFFER_USE_SHARE_MESA: u32 = 2;
+pub const EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID: u32 = 2;
+pub const EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR: u32 = 4;
+pub const EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID: u32 = 4;
+pub const EGL_OPENGL_ES3_BIT: u32 = 64;
+pub const EGL_OPENGL_ES3_BIT_KHR: u32 = 64;
+pub const EGL_OPENGL_ES_BIT: u32 = 1;
+pub const EGL_PBUFFER_BIT: u32 = 1;
+pub const EGL_READ_SURFACE_BIT_KHR: u32 = 1;
+pub const EGL_SYNC_FLUSH_COMMANDS_BIT: u32 = 1;
+pub const EGL_SYNC_FLUSH_COMMANDS_BIT_KHR: u32 = 1;
+pub const EGL_SYNC_FLUSH_COMMANDS_BIT_NV: u32 = 1;
+pub const EGL_OPENVG_BIT: u32 = 2;
+pub const EGL_PIXMAP_BIT: u32 = 2;
+pub const EGL_WRITE_SURFACE_BIT_KHR: u32 = 2;
+pub const EGL_OPENGL_ES2_BIT: u32 = 4;
+pub const EGL_WINDOW_BIT: u32 = 4;
+pub const EGL_OPENGL_BIT: u32 = 8;
+pub const EGL_PBUFFER_IMAGE_BIT_TAO: u32 = 8;
+pub const EGL_INTEROP_BIT_KHR: u32 = 16;
+pub const EGL_PBUFFER_PALETTE_IMAGE_BIT_TAO: u32 = 16;
+pub const EGL_OPENMAX_IL_BIT_KHR: u32 = 32;
+pub const EGL_VG_COLORSPACE_LINEAR_BIT: u32 = 32;
+pub const EGL_VG_COLORSPACE_LINEAR_BIT_KHR: u32 = 32;
+pub const EGL_VG_ALPHA_FORMAT_PRE_BIT: u32 = 64;
+pub const EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR: u32 = 64;
+pub const EGL_LOCK_SURFACE_BIT_KHR: u32 = 128;
+pub const EGL_OPTIMAL_FORMAT_BIT_KHR: u32 = 256;
+pub const EGL_MULTISAMPLE_RESOLVE_BOX_BIT: u32 = 512;
+pub const EGL_SWAP_BEHAVIOR_PRESERVED_BIT: u32 = 1024;
+pub const EGL_STREAM_BIT_KHR: u32 = 2048;
+pub const EGL_MUTABLE_RENDER_BUFFER_BIT_KHR: u32 = 4096;
+pub const EGL_CONTEXT_RELEASE_BEHAVIOR_KHR: u32 = 8343;
+pub const EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR: u32 = 8344;
+pub const EGL_SUCCESS: u32 = 12288;
+pub const EGL_NOT_INITIALIZED: u32 = 12289;
+pub const EGL_BAD_ACCESS: u32 = 12290;
+pub const EGL_BAD_ALLOC: u32 = 12291;
+pub const EGL_BAD_ATTRIBUTE: u32 = 12292;
+pub const EGL_BAD_CONFIG: u32 = 12293;
+pub const EGL_BAD_CONTEXT: u32 = 12294;
+pub const EGL_BAD_CURRENT_SURFACE: u32 = 12295;
+pub const EGL_BAD_DISPLAY: u32 = 12296;
+pub const EGL_BAD_MATCH: u32 = 12297;
+pub const EGL_BAD_NATIVE_PIXMAP: u32 = 12298;
+pub const EGL_BAD_NATIVE_WINDOW: u32 = 12299;
+pub const EGL_BAD_PARAMETER: u32 = 12300;
+pub const EGL_BAD_SURFACE: u32 = 12301;
+pub const EGL_CONTEXT_LOST: u32 = 12302;
+pub const EGL_BUFFER_SIZE: u32 = 12320;
+pub const EGL_ALPHA_SIZE: u32 = 12321;
+pub const EGL_BLUE_SIZE: u32 = 12322;
+pub const EGL_GREEN_SIZE: u32 = 12323;
+pub const EGL_RED_SIZE: u32 = 12324;
+pub const EGL_DEPTH_SIZE: u32 = 12325;
+pub const EGL_STENCIL_SIZE: u32 = 12326;
+pub const EGL_CONFIG_CAVEAT: u32 = 12327;
+pub const EGL_CONFIG_ID: u32 = 12328;
+pub const EGL_LEVEL: u32 = 12329;
+pub const EGL_MAX_PBUFFER_HEIGHT: u32 = 12330;
+pub const EGL_MAX_PBUFFER_PIXELS: u32 = 12331;
+pub const EGL_MAX_PBUFFER_WIDTH: u32 = 12332;
+pub const EGL_NATIVE_RENDERABLE: u32 = 12333;
+pub const EGL_NATIVE_VISUAL_ID: u32 = 12334;
+pub const EGL_NATIVE_VISUAL_TYPE: u32 = 12335;
+pub const EGL_SAMPLES: u32 = 12337;
+pub const EGL_SAMPLE_BUFFERS: u32 = 12338;
+pub const EGL_SURFACE_TYPE: u32 = 12339;
+pub const EGL_TRANSPARENT_TYPE: u32 = 12340;
+pub const EGL_TRANSPARENT_BLUE_VALUE: u32 = 12341;
+pub const EGL_TRANSPARENT_GREEN_VALUE: u32 = 12342;
+pub const EGL_TRANSPARENT_RED_VALUE: u32 = 12343;
+pub const EGL_NONE: u32 = 12344;
+pub const EGL_BIND_TO_TEXTURE_RGB: u32 = 12345;
+pub const EGL_BIND_TO_TEXTURE_RGBA: u32 = 12346;
+pub const EGL_MIN_SWAP_INTERVAL: u32 = 12347;
+pub const EGL_MAX_SWAP_INTERVAL: u32 = 12348;
+pub const EGL_LUMINANCE_SIZE: u32 = 12349;
+pub const EGL_ALPHA_MASK_SIZE: u32 = 12350;
+pub const EGL_COLOR_BUFFER_TYPE: u32 = 12351;
+pub const EGL_RENDERABLE_TYPE: u32 = 12352;
+pub const EGL_MATCH_NATIVE_PIXMAP: u32 = 12353;
+pub const EGL_CONFORMANT: u32 = 12354;
+pub const EGL_CONFORMANT_KHR: u32 = 12354;
+pub const EGL_MATCH_FORMAT_KHR: u32 = 12355;
+pub const EGL_SLOW_CONFIG: u32 = 12368;
+pub const EGL_NON_CONFORMANT_CONFIG: u32 = 12369;
+pub const EGL_TRANSPARENT_RGB: u32 = 12370;
+pub const EGL_VENDOR: u32 = 12371;
+pub const EGL_VERSION: u32 = 12372;
+pub const EGL_EXTENSIONS: u32 = 12373;
+pub const EGL_HEIGHT: u32 = 12374;
+pub const EGL_WIDTH: u32 = 12375;
+pub const EGL_LARGEST_PBUFFER: u32 = 12376;
+pub const EGL_DRAW: u32 = 12377;
+pub const EGL_READ: u32 = 12378;
+pub const EGL_CORE_NATIVE_ENGINE: u32 = 12379;
+pub const EGL_NO_TEXTURE: u32 = 12380;
+pub const EGL_TEXTURE_RGB: u32 = 12381;
+pub const EGL_TEXTURE_RGBA: u32 = 12382;
+pub const EGL_TEXTURE_2D: u32 = 12383;
+pub const EGL_Y_INVERTED_NOK: u32 = 12415;
+pub const EGL_TEXTURE_FORMAT: u32 = 12416;
+pub const EGL_TEXTURE_TARGET: u32 = 12417;
+pub const EGL_MIPMAP_TEXTURE: u32 = 12418;
+pub const EGL_MIPMAP_LEVEL: u32 = 12419;
+pub const EGL_BACK_BUFFER: u32 = 12420;
+pub const EGL_SINGLE_BUFFER: u32 = 12421;
+pub const EGL_RENDER_BUFFER: u32 = 12422;
+pub const EGL_COLORSPACE: u32 = 12423;
+pub const EGL_VG_COLORSPACE: u32 = 12423;
+pub const EGL_ALPHA_FORMAT: u32 = 12424;
+pub const EGL_VG_ALPHA_FORMAT: u32 = 12424;
+pub const EGL_COLORSPACE_sRGB: u32 = 12425;
+pub const EGL_GL_COLORSPACE_SRGB: u32 = 12425;
+pub const EGL_GL_COLORSPACE_SRGB_KHR: u32 = 12425;
+pub const EGL_VG_COLORSPACE_sRGB: u32 = 12425;
+pub const EGL_COLORSPACE_LINEAR: u32 = 12426;
+pub const EGL_GL_COLORSPACE_LINEAR: u32 = 12426;
+pub const EGL_GL_COLORSPACE_LINEAR_KHR: u32 = 12426;
+pub const EGL_VG_COLORSPACE_LINEAR: u32 = 12426;
+pub const EGL_ALPHA_FORMAT_NONPRE: u32 = 12427;
+pub const EGL_VG_ALPHA_FORMAT_NONPRE: u32 = 12427;
+pub const EGL_ALPHA_FORMAT_PRE: u32 = 12428;
+pub const EGL_VG_ALPHA_FORMAT_PRE: u32 = 12428;
+pub const EGL_CLIENT_APIS: u32 = 12429;
+pub const EGL_RGB_BUFFER: u32 = 12430;
+pub const EGL_LUMINANCE_BUFFER: u32 = 12431;
+pub const EGL_HORIZONTAL_RESOLUTION: u32 = 12432;
+pub const EGL_VERTICAL_RESOLUTION: u32 = 12433;
+pub const EGL_PIXEL_ASPECT_RATIO: u32 = 12434;
+pub const EGL_SWAP_BEHAVIOR: u32 = 12435;
+pub const EGL_BUFFER_PRESERVED: u32 = 12436;
+pub const EGL_BUFFER_DESTROYED: u32 = 12437;
+pub const EGL_OPENVG_IMAGE: u32 = 12438;
+pub const EGL_CONTEXT_CLIENT_TYPE: u32 = 12439;
+pub const EGL_CONTEXT_CLIENT_VERSION: u32 = 12440;
+pub const EGL_CONTEXT_MAJOR_VERSION: u32 = 12440;
+pub const EGL_CONTEXT_MAJOR_VERSION_KHR: u32 = 12440;
+pub const EGL_MULTISAMPLE_RESOLVE: u32 = 12441;
+pub const EGL_MULTISAMPLE_RESOLVE_DEFAULT: u32 = 12442;
+pub const EGL_MULTISAMPLE_RESOLVE_BOX: u32 = 12443;
+pub const EGL_CL_EVENT_HANDLE: u32 = 12444;
+pub const EGL_CL_EVENT_HANDLE_KHR: u32 = 12444;
+pub const EGL_GL_COLORSPACE: u32 = 12445;
+pub const EGL_GL_COLORSPACE_KHR: u32 = 12445;
+pub const EGL_OPENGL_ES_API: u32 = 12448;
+pub const EGL_OPENVG_API: u32 = 12449;
+pub const EGL_OPENGL_API: u32 = 12450;
+pub const EGL_NATIVE_PIXMAP_KHR: u32 = 12464;
+pub const EGL_GL_TEXTURE_2D: u32 = 12465;
+pub const EGL_GL_TEXTURE_2D_KHR: u32 = 12465;
+pub const EGL_GL_TEXTURE_3D: u32 = 12466;
+pub const EGL_GL_TEXTURE_3D_KHR: u32 = 12466;
+pub const EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: u32 = 12467;
+pub const EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR: u32 = 12467;
+pub const EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X: u32 = 12468;
+pub const EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR: u32 = 12468;
+pub const EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y: u32 = 12469;
+pub const EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR: u32 = 12469;
+pub const EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: u32 = 12470;
+pub const EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR: u32 = 12470;
+pub const EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z: u32 = 12471;
+pub const EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR: u32 = 12471;
+pub const EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: u32 = 12472;
+pub const EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR: u32 = 12472;
+pub const EGL_GL_RENDERBUFFER: u32 = 12473;
+pub const EGL_GL_RENDERBUFFER_KHR: u32 = 12473;
+pub const EGL_VG_PARENT_IMAGE_KHR: u32 = 12474;
+pub const EGL_GL_TEXTURE_LEVEL: u32 = 12476;
+pub const EGL_GL_TEXTURE_LEVEL_KHR: u32 = 12476;
+pub const EGL_GL_TEXTURE_ZOFFSET: u32 = 12477;
+pub const EGL_GL_TEXTURE_ZOFFSET_KHR: u32 = 12477;
+pub const EGL_POST_SUB_BUFFER_SUPPORTED_NV: u32 = 12478;
+pub const EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: u32 = 12479;
+pub const EGL_FORMAT_RGB_565_EXACT_KHR: u32 = 12480;
+pub const EGL_FORMAT_RGB_565_KHR: u32 = 12481;
+pub const EGL_FORMAT_RGBA_8888_EXACT_KHR: u32 = 12482;
+pub const EGL_FORMAT_RGBA_8888_KHR: u32 = 12483;
+pub const EGL_MAP_PRESERVE_PIXELS_KHR: u32 = 12484;
+pub const EGL_LOCK_USAGE_HINT_KHR: u32 = 12485;
+pub const EGL_BITMAP_POINTER_KHR: u32 = 12486;
+pub const EGL_BITMAP_PITCH_KHR: u32 = 12487;
+pub const EGL_BITMAP_ORIGIN_KHR: u32 = 12488;
+pub const EGL_BITMAP_PIXEL_RED_OFFSET_KHR: u32 = 12489;
+pub const EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR: u32 = 12490;
+pub const EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR: u32 = 12491;
+pub const EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR: u32 = 12492;
+pub const EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR: u32 = 12493;
+pub const EGL_LOWER_LEFT_KHR: u32 = 12494;
+pub const EGL_UPPER_LEFT_KHR: u32 = 12495;
+pub const EGL_IMAGE_PRESERVED: u32 = 12498;
+pub const EGL_IMAGE_PRESERVED_KHR: u32 = 12498;
+pub const EGL_SHARED_IMAGE_NOK: u32 = 12506;
+pub const EGL_COVERAGE_BUFFERS_NV: u32 = 12512;
+pub const EGL_COVERAGE_SAMPLES_NV: u32 = 12513;
+pub const EGL_DEPTH_ENCODING_NV: u32 = 12514;
+pub const EGL_DEPTH_ENCODING_NONLINEAR_NV: u32 = 12515;
+pub const EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV: u32 = 12518;
+pub const EGL_SYNC_STATUS_NV: u32 = 12519;
+pub const EGL_SIGNALED_NV: u32 = 12520;
+pub const EGL_UNSIGNALED_NV: u32 = 12521;
+pub const EGL_ALREADY_SIGNALED_NV: u32 = 12522;
+pub const EGL_TIMEOUT_EXPIRED_NV: u32 = 12523;
+pub const EGL_CONDITION_SATISFIED_NV: u32 = 12524;
+pub const EGL_SYNC_TYPE_NV: u32 = 12525;
+pub const EGL_SYNC_CONDITION_NV: u32 = 12526;
+pub const EGL_SYNC_FENCE_NV: u32 = 12527;
+pub const EGL_SYNC_PRIOR_COMMANDS_COMPLETE: u32 = 12528;
+pub const EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR: u32 = 12528;
+pub const EGL_SYNC_STATUS: u32 = 12529;
+pub const EGL_SYNC_STATUS_KHR: u32 = 12529;
+pub const EGL_SIGNALED: u32 = 12530;
+pub const EGL_SIGNALED_KHR: u32 = 12530;
+pub const EGL_UNSIGNALED: u32 = 12531;
+pub const EGL_UNSIGNALED_KHR: u32 = 12531;
+pub const EGL_TIMEOUT_EXPIRED: u32 = 12533;
+pub const EGL_TIMEOUT_EXPIRED_KHR: u32 = 12533;
+pub const EGL_CONDITION_SATISFIED: u32 = 12534;
+pub const EGL_CONDITION_SATISFIED_KHR: u32 = 12534;
+pub const EGL_SYNC_TYPE: u32 = 12535;
+pub const EGL_SYNC_TYPE_KHR: u32 = 12535;
+pub const EGL_SYNC_CONDITION: u32 = 12536;
+pub const EGL_SYNC_CONDITION_KHR: u32 = 12536;
+pub const EGL_SYNC_FENCE: u32 = 12537;
+pub const EGL_SYNC_FENCE_KHR: u32 = 12537;
+pub const EGL_SYNC_REUSABLE_KHR: u32 = 12538;
+pub const EGL_CONTEXT_MINOR_VERSION: u32 = 12539;
+pub const EGL_CONTEXT_MINOR_VERSION_KHR: u32 = 12539;
+pub const EGL_CONTEXT_FLAGS_KHR: u32 = 12540;
+pub const EGL_CONTEXT_OPENGL_PROFILE_MASK: u32 = 12541;
+pub const EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR: u32 = 12541;
+pub const EGL_SYNC_CL_EVENT: u32 = 12542;
+pub const EGL_SYNC_CL_EVENT_KHR: u32 = 12542;
+pub const EGL_SYNC_CL_EVENT_COMPLETE: u32 = 12543;
+pub const EGL_SYNC_CL_EVENT_COMPLETE_KHR: u32 = 12543;
+pub const EGL_CONTEXT_PRIORITY_LEVEL_IMG: u32 = 12544;
+pub const EGL_CONTEXT_PRIORITY_HIGH_IMG: u32 = 12545;
+pub const EGL_CONTEXT_PRIORITY_MEDIUM_IMG: u32 = 12546;
+pub const EGL_CONTEXT_PRIORITY_LOW_IMG: u32 = 12547;
+pub const EGL_NATIVE_BUFFER_MULTIPLANE_SEPARATE_IMG: u32 = 12549;
+pub const EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG: u32 = 12550;
+pub const EGL_BITMAP_PIXEL_SIZE_KHR: u32 = 12560;
+pub const EGL_COVERAGE_SAMPLE_RESOLVE_NV: u32 = 12593;
+pub const EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV: u32 = 12594;
+pub const EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV: u32 = 12595;
+pub const EGL_MULTIVIEW_VIEW_COUNT_EXT: u32 = 12596;
+pub const EGL_AUTO_STEREO_NV: u32 = 12598;
+pub const EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: u32 = 12600;
+pub const EGL_BUFFER_AGE_EXT: u32 = 12605;
+pub const EGL_BUFFER_AGE_KHR: u32 = 12605;
+pub const EGL_PLATFORM_DEVICE_EXT: u32 = 12607;
+pub const EGL_NATIVE_BUFFER_ANDROID: u32 = 12608;
+pub const EGL_PLATFORM_ANDROID_KHR: u32 = 12609;
+pub const EGL_RECORDABLE_ANDROID: u32 = 12610;
+pub const EGL_NATIVE_BUFFER_USAGE_ANDROID: u32 = 12611;
+pub const EGL_SYNC_NATIVE_FENCE_ANDROID: u32 = 12612;
+pub const EGL_SYNC_NATIVE_FENCE_FD_ANDROID: u32 = 12613;
+pub const EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID: u32 = 12614;
+pub const EGL_FRAMEBUFFER_TARGET_ANDROID: u32 = 12615;
+pub const EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID: u32 = 12620;
+pub const EGL_CONTEXT_OPENGL_DEBUG: u32 = 12720;
+pub const EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE: u32 = 12721;
+pub const EGL_CONTEXT_OPENGL_ROBUST_ACCESS: u32 = 12722;
+pub const EGL_CONTEXT_OPENGL_NO_ERROR_KHR: u32 = 12723;
+pub const EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY: u32 = 12733;
+pub const EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR: u32 = 12733;
+pub const EGL_NO_RESET_NOTIFICATION: u32 = 12734;
+pub const EGL_NO_RESET_NOTIFICATION_EXT: u32 = 12734;
+pub const EGL_NO_RESET_NOTIFICATION_KHR: u32 = 12734;
+pub const EGL_LOSE_CONTEXT_ON_RESET: u32 = 12735;
+pub const EGL_LOSE_CONTEXT_ON_RESET_EXT: u32 = 12735;
+pub const EGL_LOSE_CONTEXT_ON_RESET_KHR: u32 = 12735;
+pub const EGL_DRM_BUFFER_FORMAT_MESA: u32 = 12752;
+pub const EGL_DRM_BUFFER_USE_MESA: u32 = 12753;
+pub const EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: u32 = 12754;
+pub const EGL_DRM_BUFFER_MESA: u32 = 12755;
+pub const EGL_DRM_BUFFER_STRIDE_MESA: u32 = 12756;
+pub const EGL_PLATFORM_X11_EXT: u32 = 12757;
+pub const EGL_PLATFORM_X11_KHR: u32 = 12757;
+pub const EGL_PLATFORM_X11_SCREEN_EXT: u32 = 12758;
+pub const EGL_PLATFORM_X11_SCREEN_KHR: u32 = 12758;
+pub const EGL_PLATFORM_GBM_KHR: u32 = 12759;
+pub const EGL_PLATFORM_GBM_MESA: u32 = 12759;
+pub const EGL_PLATFORM_WAYLAND_EXT: u32 = 12760;
+pub const EGL_PLATFORM_WAYLAND_KHR: u32 = 12760;
+pub const EGL_PLATFORM_SURFACELESS_MESA: u32 = 12765;
+pub const EGL_STREAM_FIFO_LENGTH_KHR: u32 = 12796;
+pub const EGL_STREAM_TIME_NOW_KHR: u32 = 12797;
+pub const EGL_STREAM_TIME_CONSUMER_KHR: u32 = 12798;
+pub const EGL_STREAM_TIME_PRODUCER_KHR: u32 = 12799;
+pub const EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: u32 = 12800;
+pub const EGL_FIXED_SIZE_ANGLE: u32 = 12801;
+pub const EGL_CONSUMER_LATENCY_USEC_KHR: u32 = 12816;
+pub const EGL_PRODUCER_FRAME_KHR: u32 = 12818;
+pub const EGL_CONSUMER_FRAME_KHR: u32 = 12819;
+pub const EGL_STREAM_STATE_KHR: u32 = 12820;
+pub const EGL_STREAM_STATE_CREATED_KHR: u32 = 12821;
+pub const EGL_STREAM_STATE_CONNECTING_KHR: u32 = 12822;
+pub const EGL_STREAM_STATE_EMPTY_KHR: u32 = 12823;
+pub const EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR: u32 = 12824;
+pub const EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR: u32 = 12825;
+pub const EGL_STREAM_STATE_DISCONNECTED_KHR: u32 = 12826;
+pub const EGL_BAD_STREAM_KHR: u32 = 12827;
+pub const EGL_BAD_STATE_KHR: u32 = 12828;
+pub const EGL_BUFFER_COUNT_NV: u32 = 12829;
+pub const EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR: u32 = 12830;
+pub const EGL_SYNC_NEW_FRAME_NV: u32 = 12831;
+pub const EGL_BAD_DEVICE_EXT: u32 = 12843;
+pub const EGL_DEVICE_EXT: u32 = 12844;
+pub const EGL_BAD_OUTPUT_LAYER_EXT: u32 = 12845;
+pub const EGL_BAD_OUTPUT_PORT_EXT: u32 = 12846;
+pub const EGL_SWAP_INTERVAL_EXT: u32 = 12847;
+pub const EGL_DRM_DEVICE_FILE_EXT: u32 = 12851;
+pub const EGL_DRM_CRTC_EXT: u32 = 12852;
+pub const EGL_DRM_PLANE_EXT: u32 = 12853;
+pub const EGL_DRM_CONNECTOR_EXT: u32 = 12854;
+pub const EGL_OPENWF_DEVICE_ID_EXT: u32 = 12855;
+pub const EGL_OPENWF_PIPELINE_ID_EXT: u32 = 12856;
+pub const EGL_OPENWF_PORT_ID_EXT: u32 = 12857;
+pub const EGL_CUDA_DEVICE_NV: u32 = 12858;
+pub const EGL_CUDA_EVENT_HANDLE_NV: u32 = 12859;
+pub const EGL_SYNC_CUDA_EVENT_NV: u32 = 12860;
+pub const EGL_SYNC_CUDA_EVENT_COMPLETE_NV: u32 = 12861;
+pub const EGL_STREAM_CROSS_PARTITION_NV: u32 = 12863;
+pub const EGL_STREAM_STATE_INITIALIZING_NV: u32 = 12864;
+pub const EGL_STREAM_TYPE_NV: u32 = 12865;
+pub const EGL_STREAM_PROTOCOL_NV: u32 = 12866;
+pub const EGL_STREAM_ENDPOINT_NV: u32 = 12867;
+pub const EGL_STREAM_LOCAL_NV: u32 = 12868;
+pub const EGL_STREAM_CROSS_PROCESS_NV: u32 = 12869;
+pub const EGL_STREAM_PROTOCOL_FD_NV: u32 = 12870;
+pub const EGL_STREAM_PRODUCER_NV: u32 = 12871;
+pub const EGL_STREAM_CONSUMER_NV: u32 = 12872;
+pub const EGL_STREAM_PROTOCOL_SOCKET_NV: u32 = 12875;
+pub const EGL_SOCKET_HANDLE_NV: u32 = 12876;
+pub const EGL_SOCKET_TYPE_NV: u32 = 12877;
+pub const EGL_SOCKET_TYPE_UNIX_NV: u32 = 12878;
+pub const EGL_SOCKET_TYPE_INET_NV: u32 = 12879;
+pub const EGL_MAX_STREAM_METADATA_BLOCKS_NV: u32 = 12880;
+pub const EGL_MAX_STREAM_METADATA_BLOCK_SIZE_NV: u32 = 12881;
+pub const EGL_MAX_STREAM_METADATA_TOTAL_SIZE_NV: u32 = 12882;
+pub const EGL_PRODUCER_METADATA_NV: u32 = 12883;
+pub const EGL_CONSUMER_METADATA_NV: u32 = 12884;
+pub const EGL_METADATA0_SIZE_NV: u32 = 12885;
+pub const EGL_METADATA1_SIZE_NV: u32 = 12886;
+pub const EGL_METADATA2_SIZE_NV: u32 = 12887;
+pub const EGL_METADATA3_SIZE_NV: u32 = 12888;
+pub const EGL_METADATA0_TYPE_NV: u32 = 12889;
+pub const EGL_METADATA1_TYPE_NV: u32 = 12890;
+pub const EGL_METADATA2_TYPE_NV: u32 = 12891;
+pub const EGL_METADATA3_TYPE_NV: u32 = 12892;
+pub const EGL_LINUX_DMA_BUF_EXT: u32 = 12912;
+pub const EGL_LINUX_DRM_FOURCC_EXT: u32 = 12913;
+pub const EGL_DMA_BUF_PLANE0_FD_EXT: u32 = 12914;
+pub const EGL_DMA_BUF_PLANE0_OFFSET_EXT: u32 = 12915;
+pub const EGL_DMA_BUF_PLANE0_PITCH_EXT: u32 = 12916;
+pub const EGL_DMA_BUF_PLANE1_FD_EXT: u32 = 12917;
+pub const EGL_DMA_BUF_PLANE1_OFFSET_EXT: u32 = 12918;
+pub const EGL_DMA_BUF_PLANE1_PITCH_EXT: u32 = 12919;
+pub const EGL_DMA_BUF_PLANE2_FD_EXT: u32 = 12920;
+pub const EGL_DMA_BUF_PLANE2_OFFSET_EXT: u32 = 12921;
+pub const EGL_DMA_BUF_PLANE2_PITCH_EXT: u32 = 12922;
+pub const EGL_YUV_COLOR_SPACE_HINT_EXT: u32 = 12923;
+pub const EGL_SAMPLE_RANGE_HINT_EXT: u32 = 12924;
+pub const EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT: u32 = 12925;
+pub const EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT: u32 = 12926;
+pub const EGL_ITU_REC601_EXT: u32 = 12927;
+pub const EGL_ITU_REC709_EXT: u32 = 12928;
+pub const EGL_ITU_REC2020_EXT: u32 = 12929;
+pub const EGL_YUV_FULL_RANGE_EXT: u32 = 12930;
+pub const EGL_YUV_NARROW_RANGE_EXT: u32 = 12931;
+pub const EGL_YUV_CHROMA_SITING_0_EXT: u32 = 12932;
+pub const EGL_YUV_CHROMA_SITING_0_5_EXT: u32 = 12933;
+pub const EGL_DISCARD_SAMPLES_ARM: u32 = 12934;
+pub const EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM: u32 = 12938;
+pub const EGL_NATIVE_BUFFER_TIZEN: u32 = 12960;
+pub const EGL_NATIVE_SURFACE_TIZEN: u32 = 12961;
+pub const EGL_PROTECTED_CONTENT_EXT: u32 = 12992;
+pub const EGL_YUV_BUFFER_EXT: u32 = 13056;
+pub const EGL_YUV_ORDER_EXT: u32 = 13057;
+pub const EGL_YUV_ORDER_YUV_EXT: u32 = 13058;
+pub const EGL_YUV_ORDER_YVU_EXT: u32 = 13059;
+pub const EGL_YUV_ORDER_YUYV_EXT: u32 = 13060;
+pub const EGL_YUV_ORDER_UYVY_EXT: u32 = 13061;
+pub const EGL_YUV_ORDER_YVYU_EXT: u32 = 13062;
+pub const EGL_YUV_ORDER_VYUY_EXT: u32 = 13063;
+pub const EGL_YUV_ORDER_AYUV_EXT: u32 = 13064;
+pub const EGL_YUV_CSC_STANDARD_EXT: u32 = 13066;
+pub const EGL_YUV_CSC_STANDARD_601_EXT: u32 = 13067;
+pub const EGL_YUV_CSC_STANDARD_709_EXT: u32 = 13068;
+pub const EGL_YUV_CSC_STANDARD_2020_EXT: u32 = 13069;
+pub const EGL_YUV_NUMBER_OF_PLANES_EXT: u32 = 13073;
+pub const EGL_YUV_SUBSAMPLE_EXT: u32 = 13074;
+pub const EGL_YUV_SUBSAMPLE_4_2_0_EXT: u32 = 13075;
+pub const EGL_YUV_SUBSAMPLE_4_2_2_EXT: u32 = 13076;
+pub const EGL_YUV_SUBSAMPLE_4_4_4_EXT: u32 = 13077;
+pub const EGL_YUV_DEPTH_RANGE_EXT: u32 = 13079;
+pub const EGL_YUV_DEPTH_RANGE_LIMITED_EXT: u32 = 13080;
+pub const EGL_YUV_DEPTH_RANGE_FULL_EXT: u32 = 13081;
+pub const EGL_YUV_PLANE_BPP_EXT: u32 = 13082;
+pub const EGL_YUV_PLANE_BPP_0_EXT: u32 = 13083;
+pub const EGL_YUV_PLANE_BPP_8_EXT: u32 = 13084;
+pub const EGL_YUV_PLANE_BPP_10_EXT: u32 = 13085;
+pub const EGL_PENDING_METADATA_NV: u32 = 13096;
+pub const EGL_PENDING_FRAME_NV: u32 = 13097;
+pub const EGL_STREAM_TIME_PENDING_NV: u32 = 13098;
+pub const EGL_YUV_PLANE0_TEXTURE_UNIT_NV: u32 = 13100;
+pub const EGL_YUV_PLANE1_TEXTURE_UNIT_NV: u32 = 13101;
+pub const EGL_YUV_PLANE2_TEXTURE_UNIT_NV: u32 = 13102;
+pub const EGL_SUPPORT_RESET_NV: u32 = 13108;
+pub const EGL_SUPPORT_REUSE_NV: u32 = 13109;
+pub const EGL_STREAM_FIFO_SYNCHRONOUS_NV: u32 = 13110;
+pub const EGL_PRODUCER_MAX_FRAME_HINT_NV: u32 = 13111;
+pub const EGL_CONSUMER_MAX_FRAME_HINT_NV: u32 = 13112;
+pub const EGL_COLOR_COMPONENT_TYPE_EXT: u32 = 13113;
+pub const EGL_COLOR_COMPONENT_TYPE_FIXED_EXT: u32 = 13114;
+pub const EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT: u32 = 13115;
+pub const EGL_GL_COLORSPACE_BT2020_LINEAR_EXT: u32 = 13119;
+pub const EGL_GL_COLORSPACE_BT2020_PQ_EXT: u32 = 13120;
+pub const EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT: u32 = 13121;
+pub const EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT: u32 = 13122;
+pub const EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT: u32 = 13123;
+pub const EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT: u32 = 13124;
+pub const EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT: u32 = 13125;
+pub const EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT: u32 = 13126;
+pub const EGL_SMPTE2086_WHITE_POINT_X_EXT: u32 = 13127;
+pub const EGL_SMPTE2086_WHITE_POINT_Y_EXT: u32 = 13128;
+pub const EGL_SMPTE2086_MAX_LUMINANCE_EXT: u32 = 13129;
+pub const EGL_SMPTE2086_MIN_LUMINANCE_EXT: u32 = 13130;
+pub const EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV: u32 = 13132;
+pub const EGL_STREAM_CROSS_OBJECT_NV: u32 = 13133;
+pub const EGL_STREAM_CROSS_DISPLAY_NV: u32 = 13134;
+pub const EGL_STREAM_CROSS_SYSTEM_NV: u32 = 13135;
+pub const EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT: u32 = 13136;
+pub const EGL_D3D9_DEVICE_ANGLE: u32 = 13216;
+pub const EGL_D3D11_DEVICE_ANGLE: u32 = 13217;
+pub const EGL_OBJECT_THREAD_KHR: u32 = 13232;
+pub const EGL_OBJECT_DISPLAY_KHR: u32 = 13233;
+pub const EGL_OBJECT_CONTEXT_KHR: u32 = 13234;
+pub const EGL_OBJECT_SURFACE_KHR: u32 = 13235;
+pub const EGL_OBJECT_IMAGE_KHR: u32 = 13236;
+pub const EGL_OBJECT_SYNC_KHR: u32 = 13237;
+pub const EGL_OBJECT_STREAM_KHR: u32 = 13238;
+pub const EGL_DEBUG_CALLBACK_KHR: u32 = 13240;
+pub const EGL_DEBUG_MSG_CRITICAL_KHR: u32 = 13241;
+pub const EGL_DEBUG_MSG_ERROR_KHR: u32 = 13242;
+pub const EGL_DEBUG_MSG_WARN_KHR: u32 = 13243;
+pub const EGL_DEBUG_MSG_INFO_KHR: u32 = 13244;
+pub const EGL_DMA_BUF_PLANE3_FD_EXT: u32 = 13376;
+pub const EGL_DMA_BUF_PLANE3_OFFSET_EXT: u32 = 13377;
+pub const EGL_DMA_BUF_PLANE3_PITCH_EXT: u32 = 13378;
+pub const EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT: u32 = 13379;
+pub const EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT: u32 = 13380;
+pub const EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT: u32 = 13381;
+pub const EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT: u32 = 13382;
+pub const EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT: u32 = 13383;
+pub const EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT: u32 = 13384;
+pub const EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT: u32 = 13385;
+pub const EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT: u32 = 13386;
+pub const EGL_COLOR_FORMAT_HI: u32 = 36720;
+pub const EGL_COLOR_RGB_HI: u32 = 36721;
+pub const EGL_COLOR_RGBA_HI: u32 = 36722;
+pub const EGL_COLOR_ARGB_HI: u32 = 36723;
+pub const EGL_CLIENT_PIXMAP_POINTER_HI: u32 = 36724;
+pub const EGL_FOREVER: i32 = -1;
+pub const EGL_FOREVER_KHR: i32 = -1;
+pub const EGL_FOREVER_NV: i32 = -1;
+pub const EGL_TRUE: u32 = 1;
+pub const EGL_DISPLAY_SCALING: u32 = 10000;
+pub type __int32_t = ::std::os::raw::c_int;
+pub type __int64_t = ::std::os::raw::c_long;
+pub type __uint64_t = ::std::os::raw::c_ulong;
+pub type khronos_int32_t = i32;
+pub type khronos_uint64_t = u64;
+pub type khronos_ssize_t = ::std::os::raw::c_long;
+pub type khronos_utime_nanoseconds_t = u64;
+pub type khronos_stime_nanoseconds_t = i64;
+pub type GLenum = ::std::os::raw::c_uint;
+pub type GLboolean = ::std::os::raw::c_uchar;
+pub type GLbitfield = ::std::os::raw::c_uint;
+pub type GLvoid = ::std::os::raw::c_void;
+pub type GLbyte = ::std::os::raw::c_schar;
+pub type GLshort = ::std::os::raw::c_short;
+pub type GLint = ::std::os::raw::c_int;
+pub type GLclampx = ::std::os::raw::c_int;
+pub type GLubyte = ::std::os::raw::c_uchar;
+pub type GLushort = ::std::os::raw::c_ushort;
+pub type GLuint = ::std::os::raw::c_uint;
+pub type GLsizei = ::std::os::raw::c_int;
+pub type GLfloat = f32;
+pub type GLclampf = f32;
+pub type GLdouble = f64;
+pub type GLclampd = f64;
+pub type GLeglImageOES = *mut ::std::os::raw::c_void;
+pub type GLchar = ::std::os::raw::c_char;
+pub type GLcharARB = ::std::os::raw::c_char;
+pub type GLhandleARB = ::std::os::raw::c_uint;
+pub type GLhalfARB = ::std::os::raw::c_ushort;
+pub type GLhalf = ::std::os::raw::c_ushort;
+pub type GLfixed = GLint;
+pub type GLintptr = isize;
+pub type GLsizeiptr = isize;
+pub type GLint64 = i64;
+pub type GLuint64 = u64;
+pub type GLintptrARB = isize;
+pub type GLsizeiptrARB = isize;
+pub type GLint64EXT = i64;
+pub type GLuint64EXT = u64;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __GLsync {
+    _unused: [u8; 0],
+}
+pub type GLsync = *mut __GLsync;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct _cl_context {
+    _unused: [u8; 0],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct _cl_event {
+    _unused: [u8; 0],
+}
+pub type GLDEBUGPROC = ::std::option::Option<
+    unsafe extern "C" fn(
+        source: GLenum,
+        type_: GLenum,
+        id: GLuint,
+        severity: GLenum,
+        length: GLsizei,
+        message: *const GLchar,
+        userParam: *const ::std::os::raw::c_void,
+    ),
+>;
+pub type GLDEBUGPROCARB = ::std::option::Option<
+    unsafe extern "C" fn(
+        source: GLenum,
+        type_: GLenum,
+        id: GLuint,
+        severity: GLenum,
+        length: GLsizei,
+        message: *const GLchar,
+        userParam: *const ::std::os::raw::c_void,
+    ),
+>;
+pub type GLDEBUGPROCKHR = ::std::option::Option<
+    unsafe extern "C" fn(
+        source: GLenum,
+        type_: GLenum,
+        id: GLuint,
+        severity: GLenum,
+        length: GLsizei,
+        message: *const GLchar,
+        userParam: *const ::std::os::raw::c_void,
+    ),
+>;
+pub type GLDEBUGPROCAMD = ::std::option::Option<
+    unsafe extern "C" fn(
+        id: GLuint,
+        category: GLenum,
+        severity: GLenum,
+        length: GLsizei,
+        message: *const GLchar,
+        userParam: *mut ::std::os::raw::c_void,
+    ),
+>;
+pub type GLhalfNV = ::std::os::raw::c_ushort;
+pub type GLvdpauSurfaceNV = GLintptr;
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAccum"]
+    pub static mut epoxy_glAccum:
+        ::std::option::Option<unsafe extern "C" fn(op: GLenum, value: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAccumxOES"]
+    pub static mut epoxy_glAccumxOES:
+        ::std::option::Option<unsafe extern "C" fn(op: GLenum, value: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glActiveProgramEXT"]
+    pub static mut epoxy_glActiveProgramEXT:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glActiveShaderProgram"]
+    pub static mut epoxy_glActiveShaderProgram:
+        ::std::option::Option<unsafe extern "C" fn(pipeline: GLuint, program: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glActiveShaderProgramEXT"]
+    pub static mut epoxy_glActiveShaderProgramEXT:
+        ::std::option::Option<unsafe extern "C" fn(pipeline: GLuint, program: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glActiveStencilFaceEXT"]
+    pub static mut epoxy_glActiveStencilFaceEXT:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glActiveTexture"]
+    pub static mut epoxy_glActiveTexture:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glActiveTextureARB"]
+    pub static mut epoxy_glActiveTextureARB:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glActiveVaryingNV"]
+    pub static mut epoxy_glActiveVaryingNV:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, name: *const GLchar)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAlphaFragmentOp1ATI"]
+    pub static mut epoxy_glAlphaFragmentOp1ATI: ::std::option::Option<
+        unsafe extern "C" fn(
+            op: GLenum,
+            dst: GLuint,
+            dstMod: GLuint,
+            arg1: GLuint,
+            arg1Rep: GLuint,
+            arg1Mod: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAlphaFragmentOp2ATI"]
+    pub static mut epoxy_glAlphaFragmentOp2ATI: ::std::option::Option<
+        unsafe extern "C" fn(
+            op: GLenum,
+            dst: GLuint,
+            dstMod: GLuint,
+            arg1: GLuint,
+            arg1Rep: GLuint,
+            arg1Mod: GLuint,
+            arg2: GLuint,
+            arg2Rep: GLuint,
+            arg2Mod: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAlphaFragmentOp3ATI"]
+    pub static mut epoxy_glAlphaFragmentOp3ATI: ::std::option::Option<
+        unsafe extern "C" fn(
+            op: GLenum,
+            dst: GLuint,
+            dstMod: GLuint,
+            arg1: GLuint,
+            arg1Rep: GLuint,
+            arg1Mod: GLuint,
+            arg2: GLuint,
+            arg2Rep: GLuint,
+            arg2Mod: GLuint,
+            arg3: GLuint,
+            arg3Rep: GLuint,
+            arg3Mod: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAlphaFunc"]
+    pub static mut epoxy_glAlphaFunc:
+        ::std::option::Option<unsafe extern "C" fn(func: GLenum, ref_: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAlphaFuncQCOM"]
+    pub static mut epoxy_glAlphaFuncQCOM:
+        ::std::option::Option<unsafe extern "C" fn(func: GLenum, ref_: GLclampf)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAlphaFuncx"]
+    pub static mut epoxy_glAlphaFuncx:
+        ::std::option::Option<unsafe extern "C" fn(func: GLenum, ref_: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAlphaFuncxOES"]
+    pub static mut epoxy_glAlphaFuncxOES:
+        ::std::option::Option<unsafe extern "C" fn(func: GLenum, ref_: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glApplyFramebufferAttachmentCMAAINTEL"]
+    pub static mut epoxy_glApplyFramebufferAttachmentCMAAINTEL:
+        ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glApplyTextureEXT"]
+    pub static mut epoxy_glApplyTextureEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAreProgramsResidentNV"]
+    pub static mut epoxy_glAreProgramsResidentNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            n: GLsizei,
+            programs: *const GLuint,
+            residences: *mut GLboolean,
+        ) -> GLboolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAreTexturesResident"]
+    pub static mut epoxy_glAreTexturesResident: ::std::option::Option<
+        unsafe extern "C" fn(
+            n: GLsizei,
+            textures: *const GLuint,
+            residences: *mut GLboolean,
+        ) -> GLboolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAreTexturesResidentEXT"]
+    pub static mut epoxy_glAreTexturesResidentEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            n: GLsizei,
+            textures: *const GLuint,
+            residences: *mut GLboolean,
+        ) -> GLboolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glArrayElement"]
+    pub static mut epoxy_glArrayElement: ::std::option::Option<unsafe extern "C" fn(i: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glArrayElementEXT"]
+    pub static mut epoxy_glArrayElementEXT: ::std::option::Option<unsafe extern "C" fn(i: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glArrayObjectATI"]
+    pub static mut epoxy_glArrayObjectATI: ::std::option::Option<
+        unsafe extern "C" fn(
+            array: GLenum,
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            buffer: GLuint,
+            offset: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAsyncMarkerSGIX"]
+    pub static mut epoxy_glAsyncMarkerSGIX:
+        ::std::option::Option<unsafe extern "C" fn(marker: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAttachObjectARB"]
+    pub static mut epoxy_glAttachObjectARB:
+        ::std::option::Option<unsafe extern "C" fn(containerObj: GLhandleARB, obj: GLhandleARB)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glAttachShader"]
+    pub static mut epoxy_glAttachShader:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, shader: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBegin"]
+    pub static mut epoxy_glBegin: ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginConditionalRender"]
+    pub static mut epoxy_glBeginConditionalRender:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginConditionalRenderNV"]
+    pub static mut epoxy_glBeginConditionalRenderNV:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginConditionalRenderNVX"]
+    pub static mut epoxy_glBeginConditionalRenderNVX:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginFragmentShaderATI"]
+    pub static mut epoxy_glBeginFragmentShaderATI: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginOcclusionQueryNV"]
+    pub static mut epoxy_glBeginOcclusionQueryNV:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginPerfMonitorAMD"]
+    pub static mut epoxy_glBeginPerfMonitorAMD:
+        ::std::option::Option<unsafe extern "C" fn(monitor: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginPerfQueryINTEL"]
+    pub static mut epoxy_glBeginPerfQueryINTEL:
+        ::std::option::Option<unsafe extern "C" fn(queryHandle: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginQuery"]
+    pub static mut epoxy_glBeginQuery:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginQueryARB"]
+    pub static mut epoxy_glBeginQueryARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginQueryEXT"]
+    pub static mut epoxy_glBeginQueryEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginQueryIndexed"]
+    pub static mut epoxy_glBeginQueryIndexed:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint, id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginTransformFeedback"]
+    pub static mut epoxy_glBeginTransformFeedback:
+        ::std::option::Option<unsafe extern "C" fn(primitiveMode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginTransformFeedbackEXT"]
+    pub static mut epoxy_glBeginTransformFeedbackEXT:
+        ::std::option::Option<unsafe extern "C" fn(primitiveMode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginTransformFeedbackNV"]
+    pub static mut epoxy_glBeginTransformFeedbackNV:
+        ::std::option::Option<unsafe extern "C" fn(primitiveMode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginVertexShaderEXT"]
+    pub static mut epoxy_glBeginVertexShaderEXT: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBeginVideoCaptureNV"]
+    pub static mut epoxy_glBeginVideoCaptureNV:
+        ::std::option::Option<unsafe extern "C" fn(video_capture_slot: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindAttribLocation"]
+    pub static mut epoxy_glBindAttribLocation: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, index: GLuint, name: *const GLchar),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindAttribLocationARB"]
+    pub static mut epoxy_glBindAttribLocationARB: ::std::option::Option<
+        unsafe extern "C" fn(programObj: GLhandleARB, index: GLuint, name: *const GLcharARB),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindBuffer"]
+    pub static mut epoxy_glBindBuffer:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, buffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindBufferARB"]
+    pub static mut epoxy_glBindBufferARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, buffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindBufferBase"]
+    pub static mut epoxy_glBindBufferBase:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint, buffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindBufferBaseEXT"]
+    pub static mut epoxy_glBindBufferBaseEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint, buffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindBufferBaseNV"]
+    pub static mut epoxy_glBindBufferBaseNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint, buffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindBufferOffsetEXT"]
+    pub static mut epoxy_glBindBufferOffsetEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, buffer: GLuint, offset: GLintptr),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindBufferOffsetNV"]
+    pub static mut epoxy_glBindBufferOffsetNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, buffer: GLuint, offset: GLintptr),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindBufferRange"]
+    pub static mut epoxy_glBindBufferRange: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            index: GLuint,
+            buffer: GLuint,
+            offset: GLintptr,
+            size: GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindBufferRangeEXT"]
+    pub static mut epoxy_glBindBufferRangeEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            index: GLuint,
+            buffer: GLuint,
+            offset: GLintptr,
+            size: GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindBufferRangeNV"]
+    pub static mut epoxy_glBindBufferRangeNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            index: GLuint,
+            buffer: GLuint,
+            offset: GLintptr,
+            size: GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindBuffersBase"]
+    pub static mut epoxy_glBindBuffersBase: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, first: GLuint, count: GLsizei, buffers: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindBuffersRange"]
+    pub static mut epoxy_glBindBuffersRange: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            first: GLuint,
+            count: GLsizei,
+            buffers: *const GLuint,
+            offsets: *const GLintptr,
+            sizes: *const GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindFragDataLocation"]
+    pub static mut epoxy_glBindFragDataLocation: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, color: GLuint, name: *const GLchar),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindFragDataLocationEXT"]
+    pub static mut epoxy_glBindFragDataLocationEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, color: GLuint, name: *const GLchar),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindFragDataLocationIndexed"]
+    pub static mut epoxy_glBindFragDataLocationIndexed: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            colorNumber: GLuint,
+            index: GLuint,
+            name: *const GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindFragDataLocationIndexedEXT"]
+    pub static mut epoxy_glBindFragDataLocationIndexedEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            colorNumber: GLuint,
+            index: GLuint,
+            name: *const GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindFragmentShaderATI"]
+    pub static mut epoxy_glBindFragmentShaderATI:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindFramebuffer"]
+    pub static mut epoxy_glBindFramebuffer:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, framebuffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindFramebufferEXT"]
+    pub static mut epoxy_glBindFramebufferEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, framebuffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindFramebufferOES"]
+    pub static mut epoxy_glBindFramebufferOES:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, framebuffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindImageTexture"]
+    pub static mut epoxy_glBindImageTexture: ::std::option::Option<
+        unsafe extern "C" fn(
+            unit: GLuint,
+            texture: GLuint,
+            level: GLint,
+            layered: GLboolean,
+            layer: GLint,
+            access: GLenum,
+            format: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindImageTextureEXT"]
+    pub static mut epoxy_glBindImageTextureEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            texture: GLuint,
+            level: GLint,
+            layered: GLboolean,
+            layer: GLint,
+            access: GLenum,
+            format: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindImageTextures"]
+    pub static mut epoxy_glBindImageTextures: ::std::option::Option<
+        unsafe extern "C" fn(first: GLuint, count: GLsizei, textures: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindLightParameterEXT"]
+    pub static mut epoxy_glBindLightParameterEXT:
+        ::std::option::Option<unsafe extern "C" fn(light: GLenum, value: GLenum) -> GLuint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindMaterialParameterEXT"]
+    pub static mut epoxy_glBindMaterialParameterEXT:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, value: GLenum) -> GLuint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindMultiTextureEXT"]
+    pub static mut epoxy_glBindMultiTextureEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, texture: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindParameterEXT"]
+    pub static mut epoxy_glBindParameterEXT:
+        ::std::option::Option<unsafe extern "C" fn(value: GLenum) -> GLuint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindProgramARB"]
+    pub static mut epoxy_glBindProgramARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, program: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindProgramNV"]
+    pub static mut epoxy_glBindProgramNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindProgramPipeline"]
+    pub static mut epoxy_glBindProgramPipeline:
+        ::std::option::Option<unsafe extern "C" fn(pipeline: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindProgramPipelineEXT"]
+    pub static mut epoxy_glBindProgramPipelineEXT:
+        ::std::option::Option<unsafe extern "C" fn(pipeline: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindRenderbuffer"]
+    pub static mut epoxy_glBindRenderbuffer:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, renderbuffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindRenderbufferEXT"]
+    pub static mut epoxy_glBindRenderbufferEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, renderbuffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindRenderbufferOES"]
+    pub static mut epoxy_glBindRenderbufferOES:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, renderbuffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindSampler"]
+    pub static mut epoxy_glBindSampler:
+        ::std::option::Option<unsafe extern "C" fn(unit: GLuint, sampler: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindSamplers"]
+    pub static mut epoxy_glBindSamplers: ::std::option::Option<
+        unsafe extern "C" fn(first: GLuint, count: GLsizei, samplers: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindTexGenParameterEXT"]
+    pub static mut epoxy_glBindTexGenParameterEXT: ::std::option::Option<
+        unsafe extern "C" fn(unit: GLenum, coord: GLenum, value: GLenum) -> GLuint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindTexture"]
+    pub static mut epoxy_glBindTexture:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, texture: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindTextureEXT"]
+    pub static mut epoxy_glBindTextureEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, texture: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindTextureUnit"]
+    pub static mut epoxy_glBindTextureUnit:
+        ::std::option::Option<unsafe extern "C" fn(unit: GLuint, texture: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindTextureUnitParameterEXT"]
+    pub static mut epoxy_glBindTextureUnitParameterEXT:
+        ::std::option::Option<unsafe extern "C" fn(unit: GLenum, value: GLenum) -> GLuint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindTextures"]
+    pub static mut epoxy_glBindTextures: ::std::option::Option<
+        unsafe extern "C" fn(first: GLuint, count: GLsizei, textures: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindTransformFeedback"]
+    pub static mut epoxy_glBindTransformFeedback:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindTransformFeedbackNV"]
+    pub static mut epoxy_glBindTransformFeedbackNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindVertexArray"]
+    pub static mut epoxy_glBindVertexArray:
+        ::std::option::Option<unsafe extern "C" fn(array: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindVertexArrayAPPLE"]
+    pub static mut epoxy_glBindVertexArrayAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(array: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindVertexArrayOES"]
+    pub static mut epoxy_glBindVertexArrayOES:
+        ::std::option::Option<unsafe extern "C" fn(array: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindVertexBuffer"]
+    pub static mut epoxy_glBindVertexBuffer: ::std::option::Option<
+        unsafe extern "C" fn(
+            bindingindex: GLuint,
+            buffer: GLuint,
+            offset: GLintptr,
+            stride: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindVertexBuffers"]
+    pub static mut epoxy_glBindVertexBuffers: ::std::option::Option<
+        unsafe extern "C" fn(
+            first: GLuint,
+            count: GLsizei,
+            buffers: *const GLuint,
+            offsets: *const GLintptr,
+            strides: *const GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindVertexShaderEXT"]
+    pub static mut epoxy_glBindVertexShaderEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindVideoCaptureStreamBufferNV"]
+    pub static mut epoxy_glBindVideoCaptureStreamBufferNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            video_capture_slot: GLuint,
+            stream: GLuint,
+            frame_region: GLenum,
+            offset: GLintptrARB,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBindVideoCaptureStreamTextureNV"]
+    pub static mut epoxy_glBindVideoCaptureStreamTextureNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            video_capture_slot: GLuint,
+            stream: GLuint,
+            frame_region: GLenum,
+            target: GLenum,
+            texture: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBinormal3bEXT"]
+    pub static mut epoxy_glBinormal3bEXT:
+        ::std::option::Option<unsafe extern "C" fn(bx: GLbyte, by: GLbyte, bz: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBinormal3bvEXT"]
+    pub static mut epoxy_glBinormal3bvEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBinormal3dEXT"]
+    pub static mut epoxy_glBinormal3dEXT:
+        ::std::option::Option<unsafe extern "C" fn(bx: GLdouble, by: GLdouble, bz: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBinormal3dvEXT"]
+    pub static mut epoxy_glBinormal3dvEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBinormal3fEXT"]
+    pub static mut epoxy_glBinormal3fEXT:
+        ::std::option::Option<unsafe extern "C" fn(bx: GLfloat, by: GLfloat, bz: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBinormal3fvEXT"]
+    pub static mut epoxy_glBinormal3fvEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBinormal3iEXT"]
+    pub static mut epoxy_glBinormal3iEXT:
+        ::std::option::Option<unsafe extern "C" fn(bx: GLint, by: GLint, bz: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBinormal3ivEXT"]
+    pub static mut epoxy_glBinormal3ivEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBinormal3sEXT"]
+    pub static mut epoxy_glBinormal3sEXT:
+        ::std::option::Option<unsafe extern "C" fn(bx: GLshort, by: GLshort, bz: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBinormal3svEXT"]
+    pub static mut epoxy_glBinormal3svEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBinormalPointerEXT"]
+    pub static mut epoxy_glBinormalPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBitmap"]
+    pub static mut epoxy_glBitmap: ::std::option::Option<
+        unsafe extern "C" fn(
+            width: GLsizei,
+            height: GLsizei,
+            xorig: GLfloat,
+            yorig: GLfloat,
+            xmove: GLfloat,
+            ymove: GLfloat,
+            bitmap: *const GLubyte,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBitmapxOES"]
+    pub static mut epoxy_glBitmapxOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            width: GLsizei,
+            height: GLsizei,
+            xorig: GLfixed,
+            yorig: GLfixed,
+            xmove: GLfixed,
+            ymove: GLfixed,
+            bitmap: *const GLubyte,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendBarrier"]
+    pub static mut epoxy_glBlendBarrier: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendBarrierKHR"]
+    pub static mut epoxy_glBlendBarrierKHR: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendBarrierNV"]
+    pub static mut epoxy_glBlendBarrierNV: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendColor"]
+    pub static mut epoxy_glBlendColor: ::std::option::Option<
+        unsafe extern "C" fn(red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendColorEXT"]
+    pub static mut epoxy_glBlendColorEXT: ::std::option::Option<
+        unsafe extern "C" fn(red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendColorxOES"]
+    pub static mut epoxy_glBlendColorxOES: ::std::option::Option<
+        unsafe extern "C" fn(red: GLfixed, green: GLfixed, blue: GLfixed, alpha: GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquation"]
+    pub static mut epoxy_glBlendEquation: ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationEXT"]
+    pub static mut epoxy_glBlendEquationEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationIndexedAMD"]
+    pub static mut epoxy_glBlendEquationIndexedAMD:
+        ::std::option::Option<unsafe extern "C" fn(buf: GLuint, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationOES"]
+    pub static mut epoxy_glBlendEquationOES:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationSeparate"]
+    pub static mut epoxy_glBlendEquationSeparate:
+        ::std::option::Option<unsafe extern "C" fn(modeRGB: GLenum, modeAlpha: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationSeparateEXT"]
+    pub static mut epoxy_glBlendEquationSeparateEXT:
+        ::std::option::Option<unsafe extern "C" fn(modeRGB: GLenum, modeAlpha: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationSeparateIndexedAMD"]
+    pub static mut epoxy_glBlendEquationSeparateIndexedAMD: ::std::option::Option<
+        unsafe extern "C" fn(buf: GLuint, modeRGB: GLenum, modeAlpha: GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationSeparateOES"]
+    pub static mut epoxy_glBlendEquationSeparateOES:
+        ::std::option::Option<unsafe extern "C" fn(modeRGB: GLenum, modeAlpha: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationSeparatei"]
+    pub static mut epoxy_glBlendEquationSeparatei: ::std::option::Option<
+        unsafe extern "C" fn(buf: GLuint, modeRGB: GLenum, modeAlpha: GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationSeparateiARB"]
+    pub static mut epoxy_glBlendEquationSeparateiARB: ::std::option::Option<
+        unsafe extern "C" fn(buf: GLuint, modeRGB: GLenum, modeAlpha: GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationSeparateiEXT"]
+    pub static mut epoxy_glBlendEquationSeparateiEXT: ::std::option::Option<
+        unsafe extern "C" fn(buf: GLuint, modeRGB: GLenum, modeAlpha: GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationSeparateiOES"]
+    pub static mut epoxy_glBlendEquationSeparateiOES: ::std::option::Option<
+        unsafe extern "C" fn(buf: GLuint, modeRGB: GLenum, modeAlpha: GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationi"]
+    pub static mut epoxy_glBlendEquationi:
+        ::std::option::Option<unsafe extern "C" fn(buf: GLuint, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationiARB"]
+    pub static mut epoxy_glBlendEquationiARB:
+        ::std::option::Option<unsafe extern "C" fn(buf: GLuint, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationiEXT"]
+    pub static mut epoxy_glBlendEquationiEXT:
+        ::std::option::Option<unsafe extern "C" fn(buf: GLuint, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendEquationiOES"]
+    pub static mut epoxy_glBlendEquationiOES:
+        ::std::option::Option<unsafe extern "C" fn(buf: GLuint, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFunc"]
+    pub static mut epoxy_glBlendFunc:
+        ::std::option::Option<unsafe extern "C" fn(sfactor: GLenum, dfactor: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFuncIndexedAMD"]
+    pub static mut epoxy_glBlendFuncIndexedAMD:
+        ::std::option::Option<unsafe extern "C" fn(buf: GLuint, src: GLenum, dst: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFuncSeparate"]
+    pub static mut epoxy_glBlendFuncSeparate: ::std::option::Option<
+        unsafe extern "C" fn(
+            sfactorRGB: GLenum,
+            dfactorRGB: GLenum,
+            sfactorAlpha: GLenum,
+            dfactorAlpha: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFuncSeparateEXT"]
+    pub static mut epoxy_glBlendFuncSeparateEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            sfactorRGB: GLenum,
+            dfactorRGB: GLenum,
+            sfactorAlpha: GLenum,
+            dfactorAlpha: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFuncSeparateINGR"]
+    pub static mut epoxy_glBlendFuncSeparateINGR: ::std::option::Option<
+        unsafe extern "C" fn(
+            sfactorRGB: GLenum,
+            dfactorRGB: GLenum,
+            sfactorAlpha: GLenum,
+            dfactorAlpha: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFuncSeparateIndexedAMD"]
+    pub static mut epoxy_glBlendFuncSeparateIndexedAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            buf: GLuint,
+            srcRGB: GLenum,
+            dstRGB: GLenum,
+            srcAlpha: GLenum,
+            dstAlpha: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFuncSeparateOES"]
+    pub static mut epoxy_glBlendFuncSeparateOES: ::std::option::Option<
+        unsafe extern "C" fn(srcRGB: GLenum, dstRGB: GLenum, srcAlpha: GLenum, dstAlpha: GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFuncSeparatei"]
+    pub static mut epoxy_glBlendFuncSeparatei: ::std::option::Option<
+        unsafe extern "C" fn(
+            buf: GLuint,
+            srcRGB: GLenum,
+            dstRGB: GLenum,
+            srcAlpha: GLenum,
+            dstAlpha: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFuncSeparateiARB"]
+    pub static mut epoxy_glBlendFuncSeparateiARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            buf: GLuint,
+            srcRGB: GLenum,
+            dstRGB: GLenum,
+            srcAlpha: GLenum,
+            dstAlpha: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFuncSeparateiEXT"]
+    pub static mut epoxy_glBlendFuncSeparateiEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            buf: GLuint,
+            srcRGB: GLenum,
+            dstRGB: GLenum,
+            srcAlpha: GLenum,
+            dstAlpha: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFuncSeparateiOES"]
+    pub static mut epoxy_glBlendFuncSeparateiOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            buf: GLuint,
+            srcRGB: GLenum,
+            dstRGB: GLenum,
+            srcAlpha: GLenum,
+            dstAlpha: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFunci"]
+    pub static mut epoxy_glBlendFunci:
+        ::std::option::Option<unsafe extern "C" fn(buf: GLuint, src: GLenum, dst: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFunciARB"]
+    pub static mut epoxy_glBlendFunciARB:
+        ::std::option::Option<unsafe extern "C" fn(buf: GLuint, src: GLenum, dst: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFunciEXT"]
+    pub static mut epoxy_glBlendFunciEXT:
+        ::std::option::Option<unsafe extern "C" fn(buf: GLuint, src: GLenum, dst: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendFunciOES"]
+    pub static mut epoxy_glBlendFunciOES:
+        ::std::option::Option<unsafe extern "C" fn(buf: GLuint, src: GLenum, dst: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlendParameteriNV"]
+    pub static mut epoxy_glBlendParameteriNV:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, value: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlitFramebuffer"]
+    pub static mut epoxy_glBlitFramebuffer: ::std::option::Option<
+        unsafe extern "C" fn(
+            srcX0: GLint,
+            srcY0: GLint,
+            srcX1: GLint,
+            srcY1: GLint,
+            dstX0: GLint,
+            dstY0: GLint,
+            dstX1: GLint,
+            dstY1: GLint,
+            mask: GLbitfield,
+            filter: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlitFramebufferANGLE"]
+    pub static mut epoxy_glBlitFramebufferANGLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            srcX0: GLint,
+            srcY0: GLint,
+            srcX1: GLint,
+            srcY1: GLint,
+            dstX0: GLint,
+            dstY0: GLint,
+            dstX1: GLint,
+            dstY1: GLint,
+            mask: GLbitfield,
+            filter: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlitFramebufferEXT"]
+    pub static mut epoxy_glBlitFramebufferEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            srcX0: GLint,
+            srcY0: GLint,
+            srcX1: GLint,
+            srcY1: GLint,
+            dstX0: GLint,
+            dstY0: GLint,
+            dstX1: GLint,
+            dstY1: GLint,
+            mask: GLbitfield,
+            filter: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlitFramebufferNV"]
+    pub static mut epoxy_glBlitFramebufferNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            srcX0: GLint,
+            srcY0: GLint,
+            srcX1: GLint,
+            srcY1: GLint,
+            dstX0: GLint,
+            dstY0: GLint,
+            dstX1: GLint,
+            dstY1: GLint,
+            mask: GLbitfield,
+            filter: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBlitNamedFramebuffer"]
+    pub static mut epoxy_glBlitNamedFramebuffer: ::std::option::Option<
+        unsafe extern "C" fn(
+            readFramebuffer: GLuint,
+            drawFramebuffer: GLuint,
+            srcX0: GLint,
+            srcY0: GLint,
+            srcX1: GLint,
+            srcY1: GLint,
+            dstX0: GLint,
+            dstY0: GLint,
+            dstX1: GLint,
+            dstY1: GLint,
+            mask: GLbitfield,
+            filter: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBufferAddressRangeNV"]
+    pub static mut epoxy_glBufferAddressRangeNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            pname: GLenum,
+            index: GLuint,
+            address: GLuint64EXT,
+            length: GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBufferData"]
+    pub static mut epoxy_glBufferData: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            size: GLsizeiptr,
+            data: *const ::std::os::raw::c_void,
+            usage: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBufferDataARB"]
+    pub static mut epoxy_glBufferDataARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            size: GLsizeiptrARB,
+            data: *const ::std::os::raw::c_void,
+            usage: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBufferPageCommitmentARB"]
+    pub static mut epoxy_glBufferPageCommitmentARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, offset: GLintptr, size: GLsizeiptr, commit: GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBufferParameteriAPPLE"]
+    pub static mut epoxy_glBufferParameteriAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBufferStorage"]
+    pub static mut epoxy_glBufferStorage: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            size: GLsizeiptr,
+            data: *const ::std::os::raw::c_void,
+            flags: GLbitfield,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBufferStorageEXT"]
+    pub static mut epoxy_glBufferStorageEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            size: GLsizeiptr,
+            data: *const ::std::os::raw::c_void,
+            flags: GLbitfield,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBufferSubData"]
+    pub static mut epoxy_glBufferSubData: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            offset: GLintptr,
+            size: GLsizeiptr,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glBufferSubDataARB"]
+    pub static mut epoxy_glBufferSubDataARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            offset: GLintptrARB,
+            size: GLsizeiptrARB,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCallCommandListNV"]
+    pub static mut epoxy_glCallCommandListNV:
+        ::std::option::Option<unsafe extern "C" fn(list: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCallList"]
+    pub static mut epoxy_glCallList: ::std::option::Option<unsafe extern "C" fn(list: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCallLists"]
+    pub static mut epoxy_glCallLists: ::std::option::Option<
+        unsafe extern "C" fn(n: GLsizei, type_: GLenum, lists: *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCheckFramebufferStatus"]
+    pub static mut epoxy_glCheckFramebufferStatus:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum) -> GLenum>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCheckFramebufferStatusEXT"]
+    pub static mut epoxy_glCheckFramebufferStatusEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum) -> GLenum>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCheckFramebufferStatusOES"]
+    pub static mut epoxy_glCheckFramebufferStatusOES:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum) -> GLenum>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCheckNamedFramebufferStatus"]
+    pub static mut epoxy_glCheckNamedFramebufferStatus:
+        ::std::option::Option<unsafe extern "C" fn(framebuffer: GLuint, target: GLenum) -> GLenum>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCheckNamedFramebufferStatusEXT"]
+    pub static mut epoxy_glCheckNamedFramebufferStatusEXT:
+        ::std::option::Option<unsafe extern "C" fn(framebuffer: GLuint, target: GLenum) -> GLenum>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClampColor"]
+    pub static mut epoxy_glClampColor:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, clamp: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClampColorARB"]
+    pub static mut epoxy_glClampColorARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, clamp: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClear"]
+    pub static mut epoxy_glClear: ::std::option::Option<unsafe extern "C" fn(mask: GLbitfield)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearAccum"]
+    pub static mut epoxy_glClearAccum: ::std::option::Option<
+        unsafe extern "C" fn(red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearAccumxOES"]
+    pub static mut epoxy_glClearAccumxOES: ::std::option::Option<
+        unsafe extern "C" fn(red: GLfixed, green: GLfixed, blue: GLfixed, alpha: GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearBufferData"]
+    pub static mut epoxy_glClearBufferData: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearBufferSubData"]
+    pub static mut epoxy_glClearBufferSubData: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            offset: GLintptr,
+            size: GLsizeiptr,
+            format: GLenum,
+            type_: GLenum,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearBufferfi"]
+    pub static mut epoxy_glClearBufferfi: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLenum, drawbuffer: GLint, depth: GLfloat, stencil: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearBufferfv"]
+    pub static mut epoxy_glClearBufferfv: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLenum, drawbuffer: GLint, value: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearBufferiv"]
+    pub static mut epoxy_glClearBufferiv: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLenum, drawbuffer: GLint, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearBufferuiv"]
+    pub static mut epoxy_glClearBufferuiv: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLenum, drawbuffer: GLint, value: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearColor"]
+    pub static mut epoxy_glClearColor: ::std::option::Option<
+        unsafe extern "C" fn(red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearColorIiEXT"]
+    pub static mut epoxy_glClearColorIiEXT: ::std::option::Option<
+        unsafe extern "C" fn(red: GLint, green: GLint, blue: GLint, alpha: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearColorIuiEXT"]
+    pub static mut epoxy_glClearColorIuiEXT: ::std::option::Option<
+        unsafe extern "C" fn(red: GLuint, green: GLuint, blue: GLuint, alpha: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearColorx"]
+    pub static mut epoxy_glClearColorx: ::std::option::Option<
+        unsafe extern "C" fn(red: GLfixed, green: GLfixed, blue: GLfixed, alpha: GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearColorxOES"]
+    pub static mut epoxy_glClearColorxOES: ::std::option::Option<
+        unsafe extern "C" fn(red: GLfixed, green: GLfixed, blue: GLfixed, alpha: GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearDepth"]
+    pub static mut epoxy_glClearDepth: ::std::option::Option<unsafe extern "C" fn(depth: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearDepthdNV"]
+    pub static mut epoxy_glClearDepthdNV:
+        ::std::option::Option<unsafe extern "C" fn(depth: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearDepthf"]
+    pub static mut epoxy_glClearDepthf: ::std::option::Option<unsafe extern "C" fn(d: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearDepthfOES"]
+    pub static mut epoxy_glClearDepthfOES:
+        ::std::option::Option<unsafe extern "C" fn(depth: GLclampf)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearDepthx"]
+    pub static mut epoxy_glClearDepthx: ::std::option::Option<unsafe extern "C" fn(depth: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearDepthxOES"]
+    pub static mut epoxy_glClearDepthxOES:
+        ::std::option::Option<unsafe extern "C" fn(depth: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearIndex"]
+    pub static mut epoxy_glClearIndex: ::std::option::Option<unsafe extern "C" fn(c: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearNamedBufferData"]
+    pub static mut epoxy_glClearNamedBufferData: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            internalformat: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearNamedBufferDataEXT"]
+    pub static mut epoxy_glClearNamedBufferDataEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            internalformat: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearNamedBufferSubData"]
+    pub static mut epoxy_glClearNamedBufferSubData: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            internalformat: GLenum,
+            offset: GLintptr,
+            size: GLsizeiptr,
+            format: GLenum,
+            type_: GLenum,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearNamedBufferSubDataEXT"]
+    pub static mut epoxy_glClearNamedBufferSubDataEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            internalformat: GLenum,
+            offset: GLsizeiptr,
+            size: GLsizeiptr,
+            format: GLenum,
+            type_: GLenum,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearNamedFramebufferfi"]
+    pub static mut epoxy_glClearNamedFramebufferfi: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            buffer: GLenum,
+            drawbuffer: GLint,
+            depth: GLfloat,
+            stencil: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearNamedFramebufferfv"]
+    pub static mut epoxy_glClearNamedFramebufferfv: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            buffer: GLenum,
+            drawbuffer: GLint,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearNamedFramebufferiv"]
+    pub static mut epoxy_glClearNamedFramebufferiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            buffer: GLenum,
+            drawbuffer: GLint,
+            value: *const GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearNamedFramebufferuiv"]
+    pub static mut epoxy_glClearNamedFramebufferuiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            buffer: GLenum,
+            drawbuffer: GLint,
+            value: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearPixelLocalStorageuiEXT"]
+    pub static mut epoxy_glClearPixelLocalStorageuiEXT: ::std::option::Option<
+        unsafe extern "C" fn(offset: GLsizei, n: GLsizei, values: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearStencil"]
+    pub static mut epoxy_glClearStencil: ::std::option::Option<unsafe extern "C" fn(s: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearTexImage"]
+    pub static mut epoxy_glClearTexImage: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            format: GLenum,
+            type_: GLenum,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearTexImageEXT"]
+    pub static mut epoxy_glClearTexImageEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            format: GLenum,
+            type_: GLenum,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearTexSubImage"]
+    pub static mut epoxy_glClearTexSubImage: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClearTexSubImageEXT"]
+    pub static mut epoxy_glClearTexSubImageEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClientActiveTexture"]
+    pub static mut epoxy_glClientActiveTexture:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClientActiveTextureARB"]
+    pub static mut epoxy_glClientActiveTextureARB:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClientActiveVertexStreamATI"]
+    pub static mut epoxy_glClientActiveVertexStreamATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClientAttribDefaultEXT"]
+    pub static mut epoxy_glClientAttribDefaultEXT:
+        ::std::option::Option<unsafe extern "C" fn(mask: GLbitfield)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClientWaitSync"]
+    pub static mut epoxy_glClientWaitSync: ::std::option::Option<
+        unsafe extern "C" fn(sync: GLsync, flags: GLbitfield, timeout: GLuint64) -> GLenum,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClientWaitSyncAPPLE"]
+    pub static mut epoxy_glClientWaitSyncAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(sync: GLsync, flags: GLbitfield, timeout: GLuint64) -> GLenum,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClipControl"]
+    pub static mut epoxy_glClipControl:
+        ::std::option::Option<unsafe extern "C" fn(origin: GLenum, depth: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClipPlane"]
+    pub static mut epoxy_glClipPlane:
+        ::std::option::Option<unsafe extern "C" fn(plane: GLenum, equation: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClipPlanef"]
+    pub static mut epoxy_glClipPlanef:
+        ::std::option::Option<unsafe extern "C" fn(p: GLenum, eqn: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClipPlanefIMG"]
+    pub static mut epoxy_glClipPlanefIMG:
+        ::std::option::Option<unsafe extern "C" fn(p: GLenum, eqn: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClipPlanefOES"]
+    pub static mut epoxy_glClipPlanefOES:
+        ::std::option::Option<unsafe extern "C" fn(plane: GLenum, equation: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClipPlanex"]
+    pub static mut epoxy_glClipPlanex:
+        ::std::option::Option<unsafe extern "C" fn(plane: GLenum, equation: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClipPlanexIMG"]
+    pub static mut epoxy_glClipPlanexIMG:
+        ::std::option::Option<unsafe extern "C" fn(p: GLenum, eqn: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glClipPlanexOES"]
+    pub static mut epoxy_glClipPlanexOES:
+        ::std::option::Option<unsafe extern "C" fn(plane: GLenum, equation: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3b"]
+    pub static mut epoxy_glColor3b:
+        ::std::option::Option<unsafe extern "C" fn(red: GLbyte, green: GLbyte, blue: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3bv"]
+    pub static mut epoxy_glColor3bv: ::std::option::Option<unsafe extern "C" fn(v: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3d"]
+    pub static mut epoxy_glColor3d:
+        ::std::option::Option<unsafe extern "C" fn(red: GLdouble, green: GLdouble, blue: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3dv"]
+    pub static mut epoxy_glColor3dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3f"]
+    pub static mut epoxy_glColor3f:
+        ::std::option::Option<unsafe extern "C" fn(red: GLfloat, green: GLfloat, blue: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3fVertex3fSUN"]
+    pub static mut epoxy_glColor3fVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            r: GLfloat,
+            g: GLfloat,
+            b: GLfloat,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3fVertex3fvSUN"]
+    pub static mut epoxy_glColor3fVertex3fvSUN:
+        ::std::option::Option<unsafe extern "C" fn(c: *const GLfloat, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3fv"]
+    pub static mut epoxy_glColor3fv: ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3hNV"]
+    pub static mut epoxy_glColor3hNV:
+        ::std::option::Option<unsafe extern "C" fn(red: GLhalfNV, green: GLhalfNV, blue: GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3hvNV"]
+    pub static mut epoxy_glColor3hvNV:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3i"]
+    pub static mut epoxy_glColor3i:
+        ::std::option::Option<unsafe extern "C" fn(red: GLint, green: GLint, blue: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3iv"]
+    pub static mut epoxy_glColor3iv: ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3s"]
+    pub static mut epoxy_glColor3s:
+        ::std::option::Option<unsafe extern "C" fn(red: GLshort, green: GLshort, blue: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3sv"]
+    pub static mut epoxy_glColor3sv: ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3ub"]
+    pub static mut epoxy_glColor3ub:
+        ::std::option::Option<unsafe extern "C" fn(red: GLubyte, green: GLubyte, blue: GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3ubv"]
+    pub static mut epoxy_glColor3ubv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3ui"]
+    pub static mut epoxy_glColor3ui:
+        ::std::option::Option<unsafe extern "C" fn(red: GLuint, green: GLuint, blue: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3uiv"]
+    pub static mut epoxy_glColor3uiv: ::std::option::Option<unsafe extern "C" fn(v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3us"]
+    pub static mut epoxy_glColor3us:
+        ::std::option::Option<unsafe extern "C" fn(red: GLushort, green: GLushort, blue: GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3usv"]
+    pub static mut epoxy_glColor3usv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3xOES"]
+    pub static mut epoxy_glColor3xOES:
+        ::std::option::Option<unsafe extern "C" fn(red: GLfixed, green: GLfixed, blue: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor3xvOES"]
+    pub static mut epoxy_glColor3xvOES:
+        ::std::option::Option<unsafe extern "C" fn(components: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4b"]
+    pub static mut epoxy_glColor4b: ::std::option::Option<
+        unsafe extern "C" fn(red: GLbyte, green: GLbyte, blue: GLbyte, alpha: GLbyte),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4bv"]
+    pub static mut epoxy_glColor4bv: ::std::option::Option<unsafe extern "C" fn(v: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4d"]
+    pub static mut epoxy_glColor4d: ::std::option::Option<
+        unsafe extern "C" fn(red: GLdouble, green: GLdouble, blue: GLdouble, alpha: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4dv"]
+    pub static mut epoxy_glColor4dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4f"]
+    pub static mut epoxy_glColor4f: ::std::option::Option<
+        unsafe extern "C" fn(red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4fNormal3fVertex3fSUN"]
+    pub static mut epoxy_glColor4fNormal3fVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            r: GLfloat,
+            g: GLfloat,
+            b: GLfloat,
+            a: GLfloat,
+            nx: GLfloat,
+            ny: GLfloat,
+            nz: GLfloat,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4fNormal3fVertex3fvSUN"]
+    pub static mut epoxy_glColor4fNormal3fVertex3fvSUN: ::std::option::Option<
+        unsafe extern "C" fn(c: *const GLfloat, n: *const GLfloat, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4fv"]
+    pub static mut epoxy_glColor4fv: ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4hNV"]
+    pub static mut epoxy_glColor4hNV: ::std::option::Option<
+        unsafe extern "C" fn(red: GLhalfNV, green: GLhalfNV, blue: GLhalfNV, alpha: GLhalfNV),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4hvNV"]
+    pub static mut epoxy_glColor4hvNV:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4i"]
+    pub static mut epoxy_glColor4i: ::std::option::Option<
+        unsafe extern "C" fn(red: GLint, green: GLint, blue: GLint, alpha: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4iv"]
+    pub static mut epoxy_glColor4iv: ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4s"]
+    pub static mut epoxy_glColor4s: ::std::option::Option<
+        unsafe extern "C" fn(red: GLshort, green: GLshort, blue: GLshort, alpha: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4sv"]
+    pub static mut epoxy_glColor4sv: ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4ub"]
+    pub static mut epoxy_glColor4ub: ::std::option::Option<
+        unsafe extern "C" fn(red: GLubyte, green: GLubyte, blue: GLubyte, alpha: GLubyte),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4ubVertex2fSUN"]
+    pub static mut epoxy_glColor4ubVertex2fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            r: GLubyte,
+            g: GLubyte,
+            b: GLubyte,
+            a: GLubyte,
+            x: GLfloat,
+            y: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4ubVertex2fvSUN"]
+    pub static mut epoxy_glColor4ubVertex2fvSUN:
+        ::std::option::Option<unsafe extern "C" fn(c: *const GLubyte, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4ubVertex3fSUN"]
+    pub static mut epoxy_glColor4ubVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            r: GLubyte,
+            g: GLubyte,
+            b: GLubyte,
+            a: GLubyte,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4ubVertex3fvSUN"]
+    pub static mut epoxy_glColor4ubVertex3fvSUN:
+        ::std::option::Option<unsafe extern "C" fn(c: *const GLubyte, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4ubv"]
+    pub static mut epoxy_glColor4ubv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4ui"]
+    pub static mut epoxy_glColor4ui: ::std::option::Option<
+        unsafe extern "C" fn(red: GLuint, green: GLuint, blue: GLuint, alpha: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4uiv"]
+    pub static mut epoxy_glColor4uiv: ::std::option::Option<unsafe extern "C" fn(v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4us"]
+    pub static mut epoxy_glColor4us: ::std::option::Option<
+        unsafe extern "C" fn(red: GLushort, green: GLushort, blue: GLushort, alpha: GLushort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4usv"]
+    pub static mut epoxy_glColor4usv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4x"]
+    pub static mut epoxy_glColor4x: ::std::option::Option<
+        unsafe extern "C" fn(red: GLfixed, green: GLfixed, blue: GLfixed, alpha: GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4xOES"]
+    pub static mut epoxy_glColor4xOES: ::std::option::Option<
+        unsafe extern "C" fn(red: GLfixed, green: GLfixed, blue: GLfixed, alpha: GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColor4xvOES"]
+    pub static mut epoxy_glColor4xvOES:
+        ::std::option::Option<unsafe extern "C" fn(components: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorFormatNV"]
+    pub static mut epoxy_glColorFormatNV:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, type_: GLenum, stride: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorFragmentOp1ATI"]
+    pub static mut epoxy_glColorFragmentOp1ATI: ::std::option::Option<
+        unsafe extern "C" fn(
+            op: GLenum,
+            dst: GLuint,
+            dstMask: GLuint,
+            dstMod: GLuint,
+            arg1: GLuint,
+            arg1Rep: GLuint,
+            arg1Mod: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorFragmentOp2ATI"]
+    pub static mut epoxy_glColorFragmentOp2ATI: ::std::option::Option<
+        unsafe extern "C" fn(
+            op: GLenum,
+            dst: GLuint,
+            dstMask: GLuint,
+            dstMod: GLuint,
+            arg1: GLuint,
+            arg1Rep: GLuint,
+            arg1Mod: GLuint,
+            arg2: GLuint,
+            arg2Rep: GLuint,
+            arg2Mod: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorFragmentOp3ATI"]
+    pub static mut epoxy_glColorFragmentOp3ATI: ::std::option::Option<
+        unsafe extern "C" fn(
+            op: GLenum,
+            dst: GLuint,
+            dstMask: GLuint,
+            dstMod: GLuint,
+            arg1: GLuint,
+            arg1Rep: GLuint,
+            arg1Mod: GLuint,
+            arg2: GLuint,
+            arg2Rep: GLuint,
+            arg2Mod: GLuint,
+            arg3: GLuint,
+            arg3Rep: GLuint,
+            arg3Mod: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorMask"]
+    pub static mut epoxy_glColorMask: ::std::option::Option<
+        unsafe extern "C" fn(red: GLboolean, green: GLboolean, blue: GLboolean, alpha: GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorMaskIndexedEXT"]
+    pub static mut epoxy_glColorMaskIndexedEXT: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, r: GLboolean, g: GLboolean, b: GLboolean, a: GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorMaski"]
+    pub static mut epoxy_glColorMaski: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, r: GLboolean, g: GLboolean, b: GLboolean, a: GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorMaskiEXT"]
+    pub static mut epoxy_glColorMaskiEXT: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, r: GLboolean, g: GLboolean, b: GLboolean, a: GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorMaskiOES"]
+    pub static mut epoxy_glColorMaskiOES: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, r: GLboolean, g: GLboolean, b: GLboolean, a: GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorMaterial"]
+    pub static mut epoxy_glColorMaterial:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorP3ui"]
+    pub static mut epoxy_glColorP3ui:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, color: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorP3uiv"]
+    pub static mut epoxy_glColorP3uiv:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, color: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorP4ui"]
+    pub static mut epoxy_glColorP4ui:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, color: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorP4uiv"]
+    pub static mut epoxy_glColorP4uiv:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, color: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorPointer"]
+    pub static mut epoxy_glColorPointer: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorPointerEXT"]
+    pub static mut epoxy_glColorPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            count: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorPointerListIBM"]
+    pub static mut epoxy_glColorPointerListIBM: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLint,
+            pointer: *mut *const ::std::os::raw::c_void,
+            ptrstride: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorPointervINTEL"]
+    pub static mut epoxy_glColorPointervINTEL: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            pointer: *mut *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorSubTable"]
+    pub static mut epoxy_glColorSubTable: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            start: GLsizei,
+            count: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorSubTableEXT"]
+    pub static mut epoxy_glColorSubTableEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            start: GLsizei,
+            count: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorTable"]
+    pub static mut epoxy_glColorTable: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            width: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            table: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorTableEXT"]
+    pub static mut epoxy_glColorTableEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalFormat: GLenum,
+            width: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            table: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorTableParameterfv"]
+    pub static mut epoxy_glColorTableParameterfv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorTableParameterfvSGI"]
+    pub static mut epoxy_glColorTableParameterfvSGI: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorTableParameteriv"]
+    pub static mut epoxy_glColorTableParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorTableParameterivSGI"]
+    pub static mut epoxy_glColorTableParameterivSGI: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glColorTableSGI"]
+    pub static mut epoxy_glColorTableSGI: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            width: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            table: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCombinerInputNV"]
+    pub static mut epoxy_glCombinerInputNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            stage: GLenum,
+            portion: GLenum,
+            variable: GLenum,
+            input: GLenum,
+            mapping: GLenum,
+            componentUsage: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCombinerOutputNV"]
+    pub static mut epoxy_glCombinerOutputNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            stage: GLenum,
+            portion: GLenum,
+            abOutput: GLenum,
+            cdOutput: GLenum,
+            sumOutput: GLenum,
+            scale: GLenum,
+            bias: GLenum,
+            abDotProduct: GLboolean,
+            cdDotProduct: GLboolean,
+            muxSum: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCombinerParameterfNV"]
+    pub static mut epoxy_glCombinerParameterfNV:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCombinerParameterfvNV"]
+    pub static mut epoxy_glCombinerParameterfvNV:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCombinerParameteriNV"]
+    pub static mut epoxy_glCombinerParameteriNV:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCombinerParameterivNV"]
+    pub static mut epoxy_glCombinerParameterivNV:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCombinerStageParameterfvNV"]
+    pub static mut epoxy_glCombinerStageParameterfvNV: ::std::option::Option<
+        unsafe extern "C" fn(stage: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCommandListSegmentsNV"]
+    pub static mut epoxy_glCommandListSegmentsNV:
+        ::std::option::Option<unsafe extern "C" fn(list: GLuint, segments: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompileCommandListNV"]
+    pub static mut epoxy_glCompileCommandListNV:
+        ::std::option::Option<unsafe extern "C" fn(list: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompileShader"]
+    pub static mut epoxy_glCompileShader:
+        ::std::option::Option<unsafe extern "C" fn(shader: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompileShaderARB"]
+    pub static mut epoxy_glCompileShaderARB:
+        ::std::option::Option<unsafe extern "C" fn(shaderObj: GLhandleARB)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompileShaderIncludeARB"]
+    pub static mut epoxy_glCompileShaderIncludeARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            shader: GLuint,
+            count: GLsizei,
+            path: *const *const GLchar,
+            length: *const GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedMultiTexImage1DEXT"]
+    pub static mut epoxy_glCompressedMultiTexImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            border: GLint,
+            imageSize: GLsizei,
+            bits: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedMultiTexImage2DEXT"]
+    pub static mut epoxy_glCompressedMultiTexImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            border: GLint,
+            imageSize: GLsizei,
+            bits: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedMultiTexImage3DEXT"]
+    pub static mut epoxy_glCompressedMultiTexImage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            border: GLint,
+            imageSize: GLsizei,
+            bits: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedMultiTexSubImage1DEXT"]
+    pub static mut epoxy_glCompressedMultiTexSubImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            width: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            bits: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedMultiTexSubImage2DEXT"]
+    pub static mut epoxy_glCompressedMultiTexSubImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            bits: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedMultiTexSubImage3DEXT"]
+    pub static mut epoxy_glCompressedMultiTexSubImage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            bits: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTexImage1D"]
+    pub static mut epoxy_glCompressedTexImage1D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            border: GLint,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTexImage1DARB"]
+    pub static mut epoxy_glCompressedTexImage1DARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            border: GLint,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTexImage2D"]
+    pub static mut epoxy_glCompressedTexImage2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            border: GLint,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTexImage2DARB"]
+    pub static mut epoxy_glCompressedTexImage2DARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            border: GLint,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTexImage3D"]
+    pub static mut epoxy_glCompressedTexImage3D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            border: GLint,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTexImage3DARB"]
+    pub static mut epoxy_glCompressedTexImage3DARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            border: GLint,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTexImage3DOES"]
+    pub static mut epoxy_glCompressedTexImage3DOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            border: GLint,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTexSubImage1D"]
+    pub static mut epoxy_glCompressedTexSubImage1D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            width: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTexSubImage1DARB"]
+    pub static mut epoxy_glCompressedTexSubImage1DARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            width: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTexSubImage2D"]
+    pub static mut epoxy_glCompressedTexSubImage2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTexSubImage2DARB"]
+    pub static mut epoxy_glCompressedTexSubImage2DARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTexSubImage3D"]
+    pub static mut epoxy_glCompressedTexSubImage3D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTexSubImage3DARB"]
+    pub static mut epoxy_glCompressedTexSubImage3DARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTexSubImage3DOES"]
+    pub static mut epoxy_glCompressedTexSubImage3DOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTextureImage1DEXT"]
+    pub static mut epoxy_glCompressedTextureImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            border: GLint,
+            imageSize: GLsizei,
+            bits: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTextureImage2DEXT"]
+    pub static mut epoxy_glCompressedTextureImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            border: GLint,
+            imageSize: GLsizei,
+            bits: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTextureImage3DEXT"]
+    pub static mut epoxy_glCompressedTextureImage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            border: GLint,
+            imageSize: GLsizei,
+            bits: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTextureSubImage1D"]
+    pub static mut epoxy_glCompressedTextureSubImage1D: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            width: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTextureSubImage1DEXT"]
+    pub static mut epoxy_glCompressedTextureSubImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            width: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            bits: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTextureSubImage2D"]
+    pub static mut epoxy_glCompressedTextureSubImage2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTextureSubImage2DEXT"]
+    pub static mut epoxy_glCompressedTextureSubImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            bits: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTextureSubImage3D"]
+    pub static mut epoxy_glCompressedTextureSubImage3D: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCompressedTextureSubImage3DEXT"]
+    pub static mut epoxy_glCompressedTextureSubImage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            imageSize: GLsizei,
+            bits: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConservativeRasterParameterfNV"]
+    pub static mut epoxy_glConservativeRasterParameterfNV:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, value: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConservativeRasterParameteriNV"]
+    pub static mut epoxy_glConservativeRasterParameteriNV:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConvolutionFilter1D"]
+    pub static mut epoxy_glConvolutionFilter1D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            width: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            image: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConvolutionFilter1DEXT"]
+    pub static mut epoxy_glConvolutionFilter1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            width: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            image: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConvolutionFilter2D"]
+    pub static mut epoxy_glConvolutionFilter2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            image: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConvolutionFilter2DEXT"]
+    pub static mut epoxy_glConvolutionFilter2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            image: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConvolutionParameterf"]
+    pub static mut epoxy_glConvolutionParameterf:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, params: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConvolutionParameterfEXT"]
+    pub static mut epoxy_glConvolutionParameterfEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, params: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConvolutionParameterfv"]
+    pub static mut epoxy_glConvolutionParameterfv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConvolutionParameterfvEXT"]
+    pub static mut epoxy_glConvolutionParameterfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConvolutionParameteri"]
+    pub static mut epoxy_glConvolutionParameteri:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, params: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConvolutionParameteriEXT"]
+    pub static mut epoxy_glConvolutionParameteriEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, params: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConvolutionParameteriv"]
+    pub static mut epoxy_glConvolutionParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConvolutionParameterivEXT"]
+    pub static mut epoxy_glConvolutionParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConvolutionParameterxOES"]
+    pub static mut epoxy_glConvolutionParameterxOES:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glConvolutionParameterxvOES"]
+    pub static mut epoxy_glConvolutionParameterxvOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyBufferSubData"]
+    pub static mut epoxy_glCopyBufferSubData: ::std::option::Option<
+        unsafe extern "C" fn(
+            readTarget: GLenum,
+            writeTarget: GLenum,
+            readOffset: GLintptr,
+            writeOffset: GLintptr,
+            size: GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyBufferSubDataNV"]
+    pub static mut epoxy_glCopyBufferSubDataNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            readTarget: GLenum,
+            writeTarget: GLenum,
+            readOffset: GLintptr,
+            writeOffset: GLintptr,
+            size: GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyColorSubTable"]
+    pub static mut epoxy_glCopyColorSubTable: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, start: GLsizei, x: GLint, y: GLint, width: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyColorSubTableEXT"]
+    pub static mut epoxy_glCopyColorSubTableEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, start: GLsizei, x: GLint, y: GLint, width: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyColorTable"]
+    pub static mut epoxy_glCopyColorTable: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyColorTableSGI"]
+    pub static mut epoxy_glCopyColorTableSGI: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyConvolutionFilter1D"]
+    pub static mut epoxy_glCopyConvolutionFilter1D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyConvolutionFilter1DEXT"]
+    pub static mut epoxy_glCopyConvolutionFilter1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyConvolutionFilter2D"]
+    pub static mut epoxy_glCopyConvolutionFilter2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyConvolutionFilter2DEXT"]
+    pub static mut epoxy_glCopyConvolutionFilter2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyImageSubData"]
+    pub static mut epoxy_glCopyImageSubData: ::std::option::Option<
+        unsafe extern "C" fn(
+            srcName: GLuint,
+            srcTarget: GLenum,
+            srcLevel: GLint,
+            srcX: GLint,
+            srcY: GLint,
+            srcZ: GLint,
+            dstName: GLuint,
+            dstTarget: GLenum,
+            dstLevel: GLint,
+            dstX: GLint,
+            dstY: GLint,
+            dstZ: GLint,
+            srcWidth: GLsizei,
+            srcHeight: GLsizei,
+            srcDepth: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyImageSubDataEXT"]
+    pub static mut epoxy_glCopyImageSubDataEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            srcName: GLuint,
+            srcTarget: GLenum,
+            srcLevel: GLint,
+            srcX: GLint,
+            srcY: GLint,
+            srcZ: GLint,
+            dstName: GLuint,
+            dstTarget: GLenum,
+            dstLevel: GLint,
+            dstX: GLint,
+            dstY: GLint,
+            dstZ: GLint,
+            srcWidth: GLsizei,
+            srcHeight: GLsizei,
+            srcDepth: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyImageSubDataNV"]
+    pub static mut epoxy_glCopyImageSubDataNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            srcName: GLuint,
+            srcTarget: GLenum,
+            srcLevel: GLint,
+            srcX: GLint,
+            srcY: GLint,
+            srcZ: GLint,
+            dstName: GLuint,
+            dstTarget: GLenum,
+            dstLevel: GLint,
+            dstX: GLint,
+            dstY: GLint,
+            dstZ: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyImageSubDataOES"]
+    pub static mut epoxy_glCopyImageSubDataOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            srcName: GLuint,
+            srcTarget: GLenum,
+            srcLevel: GLint,
+            srcX: GLint,
+            srcY: GLint,
+            srcZ: GLint,
+            dstName: GLuint,
+            dstTarget: GLenum,
+            dstLevel: GLint,
+            dstX: GLint,
+            dstY: GLint,
+            dstZ: GLint,
+            srcWidth: GLsizei,
+            srcHeight: GLsizei,
+            srcDepth: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyMultiTexImage1DEXT"]
+    pub static mut epoxy_glCopyMultiTexImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            border: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyMultiTexImage2DEXT"]
+    pub static mut epoxy_glCopyMultiTexImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            border: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyMultiTexSubImage1DEXT"]
+    pub static mut epoxy_glCopyMultiTexSubImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyMultiTexSubImage2DEXT"]
+    pub static mut epoxy_glCopyMultiTexSubImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyMultiTexSubImage3DEXT"]
+    pub static mut epoxy_glCopyMultiTexSubImage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyNamedBufferSubData"]
+    pub static mut epoxy_glCopyNamedBufferSubData: ::std::option::Option<
+        unsafe extern "C" fn(
+            readBuffer: GLuint,
+            writeBuffer: GLuint,
+            readOffset: GLintptr,
+            writeOffset: GLintptr,
+            size: GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyPathNV"]
+    pub static mut epoxy_glCopyPathNV:
+        ::std::option::Option<unsafe extern "C" fn(resultPath: GLuint, srcPath: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyPixels"]
+    pub static mut epoxy_glCopyPixels: ::std::option::Option<
+        unsafe extern "C" fn(x: GLint, y: GLint, width: GLsizei, height: GLsizei, type_: GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTexImage1D"]
+    pub static mut epoxy_glCopyTexImage1D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            border: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTexImage1DEXT"]
+    pub static mut epoxy_glCopyTexImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            border: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTexImage2D"]
+    pub static mut epoxy_glCopyTexImage2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            border: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTexImage2DEXT"]
+    pub static mut epoxy_glCopyTexImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            border: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTexSubImage1D"]
+    pub static mut epoxy_glCopyTexSubImage1D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTexSubImage1DEXT"]
+    pub static mut epoxy_glCopyTexSubImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTexSubImage2D"]
+    pub static mut epoxy_glCopyTexSubImage2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTexSubImage2DEXT"]
+    pub static mut epoxy_glCopyTexSubImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTexSubImage3D"]
+    pub static mut epoxy_glCopyTexSubImage3D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTexSubImage3DEXT"]
+    pub static mut epoxy_glCopyTexSubImage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTexSubImage3DOES"]
+    pub static mut epoxy_glCopyTexSubImage3DOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTextureImage1DEXT"]
+    pub static mut epoxy_glCopyTextureImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            border: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTextureImage2DEXT"]
+    pub static mut epoxy_glCopyTextureImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            border: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTextureLevelsAPPLE"]
+    pub static mut epoxy_glCopyTextureLevelsAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            destinationTexture: GLuint,
+            sourceTexture: GLuint,
+            sourceBaseLevel: GLint,
+            sourceLevelCount: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTextureSubImage1D"]
+    pub static mut epoxy_glCopyTextureSubImage1D: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTextureSubImage1DEXT"]
+    pub static mut epoxy_glCopyTextureSubImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTextureSubImage2D"]
+    pub static mut epoxy_glCopyTextureSubImage2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTextureSubImage2DEXT"]
+    pub static mut epoxy_glCopyTextureSubImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTextureSubImage3D"]
+    pub static mut epoxy_glCopyTextureSubImage3D: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCopyTextureSubImage3DEXT"]
+    pub static mut epoxy_glCopyTextureSubImage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCoverFillPathInstancedNV"]
+    pub static mut epoxy_glCoverFillPathInstancedNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            numPaths: GLsizei,
+            pathNameType: GLenum,
+            paths: *const ::std::os::raw::c_void,
+            pathBase: GLuint,
+            coverMode: GLenum,
+            transformType: GLenum,
+            transformValues: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCoverFillPathNV"]
+    pub static mut epoxy_glCoverFillPathNV:
+        ::std::option::Option<unsafe extern "C" fn(path: GLuint, coverMode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCoverStrokePathInstancedNV"]
+    pub static mut epoxy_glCoverStrokePathInstancedNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            numPaths: GLsizei,
+            pathNameType: GLenum,
+            paths: *const ::std::os::raw::c_void,
+            pathBase: GLuint,
+            coverMode: GLenum,
+            transformType: GLenum,
+            transformValues: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCoverStrokePathNV"]
+    pub static mut epoxy_glCoverStrokePathNV:
+        ::std::option::Option<unsafe extern "C" fn(path: GLuint, coverMode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCoverageMaskNV"]
+    pub static mut epoxy_glCoverageMaskNV:
+        ::std::option::Option<unsafe extern "C" fn(mask: GLboolean)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCoverageModulationNV"]
+    pub static mut epoxy_glCoverageModulationNV:
+        ::std::option::Option<unsafe extern "C" fn(components: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCoverageModulationTableNV"]
+    pub static mut epoxy_glCoverageModulationTableNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCoverageOperationNV"]
+    pub static mut epoxy_glCoverageOperationNV:
+        ::std::option::Option<unsafe extern "C" fn(operation: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateBuffers"]
+    pub static mut epoxy_glCreateBuffers:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, buffers: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateCommandListsNV"]
+    pub static mut epoxy_glCreateCommandListsNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, lists: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateFramebuffers"]
+    pub static mut epoxy_glCreateFramebuffers:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, framebuffers: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreatePerfQueryINTEL"]
+    pub static mut epoxy_glCreatePerfQueryINTEL:
+        ::std::option::Option<unsafe extern "C" fn(queryId: GLuint, queryHandle: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateProgram"]
+    pub static mut epoxy_glCreateProgram: ::std::option::Option<unsafe extern "C" fn() -> GLuint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateProgramObjectARB"]
+    pub static mut epoxy_glCreateProgramObjectARB:
+        ::std::option::Option<unsafe extern "C" fn() -> GLhandleARB>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateProgramPipelines"]
+    pub static mut epoxy_glCreateProgramPipelines:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, pipelines: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateQueries"]
+    pub static mut epoxy_glCreateQueries:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, n: GLsizei, ids: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateRenderbuffers"]
+    pub static mut epoxy_glCreateRenderbuffers:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, renderbuffers: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateSamplers"]
+    pub static mut epoxy_glCreateSamplers:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, samplers: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateShader"]
+    pub static mut epoxy_glCreateShader:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum) -> GLuint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateShaderObjectARB"]
+    pub static mut epoxy_glCreateShaderObjectARB:
+        ::std::option::Option<unsafe extern "C" fn(shaderType: GLenum) -> GLhandleARB>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateShaderProgramEXT"]
+    pub static mut epoxy_glCreateShaderProgramEXT:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, string: *const GLchar) -> GLuint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateShaderProgramv"]
+    pub static mut epoxy_glCreateShaderProgramv: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            count: GLsizei,
+            strings: *const *const GLchar,
+        ) -> GLuint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateShaderProgramvEXT"]
+    pub static mut epoxy_glCreateShaderProgramvEXT: ::std::option::Option<
+        unsafe extern "C" fn(type_: GLenum, count: GLsizei, strings: *mut *const GLchar) -> GLuint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateStatesNV"]
+    pub static mut epoxy_glCreateStatesNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, states: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateSyncFromCLeventARB"]
+    pub static mut epoxy_glCreateSyncFromCLeventARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            context: *mut _cl_context,
+            event: *mut _cl_event,
+            flags: GLbitfield,
+        ) -> GLsync,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateTextures"]
+    pub static mut epoxy_glCreateTextures: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, n: GLsizei, textures: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateTransformFeedbacks"]
+    pub static mut epoxy_glCreateTransformFeedbacks:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, ids: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCreateVertexArrays"]
+    pub static mut epoxy_glCreateVertexArrays:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, arrays: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCullFace"]
+    pub static mut epoxy_glCullFace: ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCullParameterdvEXT"]
+    pub static mut epoxy_glCullParameterdvEXT:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *mut GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCullParameterfvEXT"]
+    pub static mut epoxy_glCullParameterfvEXT:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCurrentPaletteMatrixARB"]
+    pub static mut epoxy_glCurrentPaletteMatrixARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glCurrentPaletteMatrixOES"]
+    pub static mut epoxy_glCurrentPaletteMatrixOES:
+        ::std::option::Option<unsafe extern "C" fn(matrixpaletteindex: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDebugMessageCallback"]
+    pub static mut epoxy_glDebugMessageCallback: ::std::option::Option<
+        unsafe extern "C" fn(callback: GLDEBUGPROC, userParam: *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDebugMessageCallbackAMD"]
+    pub static mut epoxy_glDebugMessageCallbackAMD: ::std::option::Option<
+        unsafe extern "C" fn(callback: GLDEBUGPROCAMD, userParam: *mut ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDebugMessageCallbackARB"]
+    pub static mut epoxy_glDebugMessageCallbackARB: ::std::option::Option<
+        unsafe extern "C" fn(callback: GLDEBUGPROCARB, userParam: *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDebugMessageCallbackKHR"]
+    pub static mut epoxy_glDebugMessageCallbackKHR: ::std::option::Option<
+        unsafe extern "C" fn(callback: GLDEBUGPROCKHR, userParam: *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDebugMessageControl"]
+    pub static mut epoxy_glDebugMessageControl: ::std::option::Option<
+        unsafe extern "C" fn(
+            source: GLenum,
+            type_: GLenum,
+            severity: GLenum,
+            count: GLsizei,
+            ids: *const GLuint,
+            enabled: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDebugMessageControlARB"]
+    pub static mut epoxy_glDebugMessageControlARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            source: GLenum,
+            type_: GLenum,
+            severity: GLenum,
+            count: GLsizei,
+            ids: *const GLuint,
+            enabled: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDebugMessageControlKHR"]
+    pub static mut epoxy_glDebugMessageControlKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            source: GLenum,
+            type_: GLenum,
+            severity: GLenum,
+            count: GLsizei,
+            ids: *const GLuint,
+            enabled: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDebugMessageEnableAMD"]
+    pub static mut epoxy_glDebugMessageEnableAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            category: GLenum,
+            severity: GLenum,
+            count: GLsizei,
+            ids: *const GLuint,
+            enabled: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDebugMessageInsert"]
+    pub static mut epoxy_glDebugMessageInsert: ::std::option::Option<
+        unsafe extern "C" fn(
+            source: GLenum,
+            type_: GLenum,
+            id: GLuint,
+            severity: GLenum,
+            length: GLsizei,
+            buf: *const GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDebugMessageInsertAMD"]
+    pub static mut epoxy_glDebugMessageInsertAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            category: GLenum,
+            severity: GLenum,
+            id: GLuint,
+            length: GLsizei,
+            buf: *const GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDebugMessageInsertARB"]
+    pub static mut epoxy_glDebugMessageInsertARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            source: GLenum,
+            type_: GLenum,
+            id: GLuint,
+            severity: GLenum,
+            length: GLsizei,
+            buf: *const GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDebugMessageInsertKHR"]
+    pub static mut epoxy_glDebugMessageInsertKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            source: GLenum,
+            type_: GLenum,
+            id: GLuint,
+            severity: GLenum,
+            length: GLsizei,
+            buf: *const GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeformSGIX"]
+    pub static mut epoxy_glDeformSGIX:
+        ::std::option::Option<unsafe extern "C" fn(mask: GLbitfield)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeformationMap3dSGIX"]
+    pub static mut epoxy_glDeformationMap3dSGIX: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            u1: GLdouble,
+            u2: GLdouble,
+            ustride: GLint,
+            uorder: GLint,
+            v1: GLdouble,
+            v2: GLdouble,
+            vstride: GLint,
+            vorder: GLint,
+            w1: GLdouble,
+            w2: GLdouble,
+            wstride: GLint,
+            worder: GLint,
+            points: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeformationMap3fSGIX"]
+    pub static mut epoxy_glDeformationMap3fSGIX: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            u1: GLfloat,
+            u2: GLfloat,
+            ustride: GLint,
+            uorder: GLint,
+            v1: GLfloat,
+            v2: GLfloat,
+            vstride: GLint,
+            vorder: GLint,
+            w1: GLfloat,
+            w2: GLfloat,
+            wstride: GLint,
+            worder: GLint,
+            points: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteAsyncMarkersSGIX"]
+    pub static mut epoxy_glDeleteAsyncMarkersSGIX:
+        ::std::option::Option<unsafe extern "C" fn(marker: GLuint, range: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteBuffers"]
+    pub static mut epoxy_glDeleteBuffers:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, buffers: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteBuffersARB"]
+    pub static mut epoxy_glDeleteBuffersARB:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, buffers: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteCommandListsNV"]
+    pub static mut epoxy_glDeleteCommandListsNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, lists: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteFencesAPPLE"]
+    pub static mut epoxy_glDeleteFencesAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, fences: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteFencesNV"]
+    pub static mut epoxy_glDeleteFencesNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, fences: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteFragmentShaderATI"]
+    pub static mut epoxy_glDeleteFragmentShaderATI:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteFramebuffers"]
+    pub static mut epoxy_glDeleteFramebuffers:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, framebuffers: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteFramebuffersEXT"]
+    pub static mut epoxy_glDeleteFramebuffersEXT:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, framebuffers: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteFramebuffersOES"]
+    pub static mut epoxy_glDeleteFramebuffersOES:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, framebuffers: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteLists"]
+    pub static mut epoxy_glDeleteLists:
+        ::std::option::Option<unsafe extern "C" fn(list: GLuint, range: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteNamedStringARB"]
+    pub static mut epoxy_glDeleteNamedStringARB:
+        ::std::option::Option<unsafe extern "C" fn(namelen: GLint, name: *const GLchar)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteNamesAMD"]
+    pub static mut epoxy_glDeleteNamesAMD: ::std::option::Option<
+        unsafe extern "C" fn(identifier: GLenum, num: GLuint, names: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteObjectARB"]
+    pub static mut epoxy_glDeleteObjectARB:
+        ::std::option::Option<unsafe extern "C" fn(obj: GLhandleARB)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteOcclusionQueriesNV"]
+    pub static mut epoxy_glDeleteOcclusionQueriesNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, ids: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeletePathsNV"]
+    pub static mut epoxy_glDeletePathsNV:
+        ::std::option::Option<unsafe extern "C" fn(path: GLuint, range: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeletePerfMonitorsAMD"]
+    pub static mut epoxy_glDeletePerfMonitorsAMD:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, monitors: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeletePerfQueryINTEL"]
+    pub static mut epoxy_glDeletePerfQueryINTEL:
+        ::std::option::Option<unsafe extern "C" fn(queryHandle: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteProgram"]
+    pub static mut epoxy_glDeleteProgram:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteProgramPipelines"]
+    pub static mut epoxy_glDeleteProgramPipelines:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, pipelines: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteProgramPipelinesEXT"]
+    pub static mut epoxy_glDeleteProgramPipelinesEXT:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, pipelines: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteProgramsARB"]
+    pub static mut epoxy_glDeleteProgramsARB:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, programs: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteProgramsNV"]
+    pub static mut epoxy_glDeleteProgramsNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, programs: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteQueries"]
+    pub static mut epoxy_glDeleteQueries:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, ids: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteQueriesARB"]
+    pub static mut epoxy_glDeleteQueriesARB:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, ids: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteQueriesEXT"]
+    pub static mut epoxy_glDeleteQueriesEXT:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, ids: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteRenderbuffers"]
+    pub static mut epoxy_glDeleteRenderbuffers:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, renderbuffers: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteRenderbuffersEXT"]
+    pub static mut epoxy_glDeleteRenderbuffersEXT:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, renderbuffers: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteRenderbuffersOES"]
+    pub static mut epoxy_glDeleteRenderbuffersOES:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, renderbuffers: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteSamplers"]
+    pub static mut epoxy_glDeleteSamplers:
+        ::std::option::Option<unsafe extern "C" fn(count: GLsizei, samplers: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteShader"]
+    pub static mut epoxy_glDeleteShader:
+        ::std::option::Option<unsafe extern "C" fn(shader: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteStatesNV"]
+    pub static mut epoxy_glDeleteStatesNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, states: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteSync"]
+    pub static mut epoxy_glDeleteSync: ::std::option::Option<unsafe extern "C" fn(sync: GLsync)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteSyncAPPLE"]
+    pub static mut epoxy_glDeleteSyncAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(sync: GLsync)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteTextures"]
+    pub static mut epoxy_glDeleteTextures:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, textures: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteTexturesEXT"]
+    pub static mut epoxy_glDeleteTexturesEXT:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, textures: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteTransformFeedbacks"]
+    pub static mut epoxy_glDeleteTransformFeedbacks:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, ids: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteTransformFeedbacksNV"]
+    pub static mut epoxy_glDeleteTransformFeedbacksNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, ids: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteVertexArrays"]
+    pub static mut epoxy_glDeleteVertexArrays:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, arrays: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteVertexArraysAPPLE"]
+    pub static mut epoxy_glDeleteVertexArraysAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, arrays: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteVertexArraysOES"]
+    pub static mut epoxy_glDeleteVertexArraysOES:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, arrays: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDeleteVertexShaderEXT"]
+    pub static mut epoxy_glDeleteVertexShaderEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthBoundsEXT"]
+    pub static mut epoxy_glDepthBoundsEXT:
+        ::std::option::Option<unsafe extern "C" fn(zmin: GLclampd, zmax: GLclampd)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthBoundsdNV"]
+    pub static mut epoxy_glDepthBoundsdNV:
+        ::std::option::Option<unsafe extern "C" fn(zmin: GLdouble, zmax: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthFunc"]
+    pub static mut epoxy_glDepthFunc: ::std::option::Option<unsafe extern "C" fn(func: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthMask"]
+    pub static mut epoxy_glDepthMask: ::std::option::Option<unsafe extern "C" fn(flag: GLboolean)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthRange"]
+    pub static mut epoxy_glDepthRange:
+        ::std::option::Option<unsafe extern "C" fn(hither: GLdouble, yon: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthRangeArrayfvNV"]
+    pub static mut epoxy_glDepthRangeArrayfvNV: ::std::option::Option<
+        unsafe extern "C" fn(first: GLuint, count: GLsizei, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthRangeArrayfvOES"]
+    pub static mut epoxy_glDepthRangeArrayfvOES: ::std::option::Option<
+        unsafe extern "C" fn(first: GLuint, count: GLsizei, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthRangeArrayv"]
+    pub static mut epoxy_glDepthRangeArrayv: ::std::option::Option<
+        unsafe extern "C" fn(first: GLuint, count: GLsizei, v: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthRangeIndexed"]
+    pub static mut epoxy_glDepthRangeIndexed:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, n: GLdouble, f: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthRangeIndexedfNV"]
+    pub static mut epoxy_glDepthRangeIndexedfNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, n: GLfloat, f: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthRangeIndexedfOES"]
+    pub static mut epoxy_glDepthRangeIndexedfOES:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, n: GLfloat, f: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthRangedNV"]
+    pub static mut epoxy_glDepthRangedNV:
+        ::std::option::Option<unsafe extern "C" fn(zNear: GLdouble, zFar: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthRangef"]
+    pub static mut epoxy_glDepthRangef:
+        ::std::option::Option<unsafe extern "C" fn(n: GLfloat, f: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthRangefOES"]
+    pub static mut epoxy_glDepthRangefOES:
+        ::std::option::Option<unsafe extern "C" fn(n: GLclampf, f: GLclampf)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthRangex"]
+    pub static mut epoxy_glDepthRangex:
+        ::std::option::Option<unsafe extern "C" fn(n: GLfixed, f: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDepthRangexOES"]
+    pub static mut epoxy_glDepthRangexOES:
+        ::std::option::Option<unsafe extern "C" fn(n: GLfixed, f: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDetachObjectARB"]
+    pub static mut epoxy_glDetachObjectARB: ::std::option::Option<
+        unsafe extern "C" fn(containerObj: GLhandleARB, attachedObj: GLhandleARB),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDetachShader"]
+    pub static mut epoxy_glDetachShader:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, shader: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDetailTexFuncSGIS"]
+    pub static mut epoxy_glDetailTexFuncSGIS: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, n: GLsizei, points: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisable"]
+    pub static mut epoxy_glDisable: ::std::option::Option<unsafe extern "C" fn(cap: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableClientState"]
+    pub static mut epoxy_glDisableClientState:
+        ::std::option::Option<unsafe extern "C" fn(array: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableClientStateIndexedEXT"]
+    pub static mut epoxy_glDisableClientStateIndexedEXT:
+        ::std::option::Option<unsafe extern "C" fn(array: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableClientStateiEXT"]
+    pub static mut epoxy_glDisableClientStateiEXT:
+        ::std::option::Option<unsafe extern "C" fn(array: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableDriverControlQCOM"]
+    pub static mut epoxy_glDisableDriverControlQCOM:
+        ::std::option::Option<unsafe extern "C" fn(driverControl: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableIndexedEXT"]
+    pub static mut epoxy_glDisableIndexedEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableVariantClientStateEXT"]
+    pub static mut epoxy_glDisableVariantClientStateEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableVertexArrayAttrib"]
+    pub static mut epoxy_glDisableVertexArrayAttrib:
+        ::std::option::Option<unsafe extern "C" fn(vaobj: GLuint, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableVertexArrayAttribEXT"]
+    pub static mut epoxy_glDisableVertexArrayAttribEXT:
+        ::std::option::Option<unsafe extern "C" fn(vaobj: GLuint, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableVertexArrayEXT"]
+    pub static mut epoxy_glDisableVertexArrayEXT:
+        ::std::option::Option<unsafe extern "C" fn(vaobj: GLuint, array: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableVertexAttribAPPLE"]
+    pub static mut epoxy_glDisableVertexAttribAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, pname: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableVertexAttribArray"]
+    pub static mut epoxy_glDisableVertexAttribArray:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableVertexAttribArrayARB"]
+    pub static mut epoxy_glDisableVertexAttribArrayARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisablei"]
+    pub static mut epoxy_glDisablei:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableiEXT"]
+    pub static mut epoxy_glDisableiEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableiNV"]
+    pub static mut epoxy_glDisableiNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDisableiOES"]
+    pub static mut epoxy_glDisableiOES:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDiscardFramebufferEXT"]
+    pub static mut epoxy_glDiscardFramebufferEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, numAttachments: GLsizei, attachments: *const GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDispatchCompute"]
+    pub static mut epoxy_glDispatchCompute: ::std::option::Option<
+        unsafe extern "C" fn(num_groups_x: GLuint, num_groups_y: GLuint, num_groups_z: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDispatchComputeGroupSizeARB"]
+    pub static mut epoxy_glDispatchComputeGroupSizeARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            num_groups_x: GLuint,
+            num_groups_y: GLuint,
+            num_groups_z: GLuint,
+            group_size_x: GLuint,
+            group_size_y: GLuint,
+            group_size_z: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDispatchComputeIndirect"]
+    pub static mut epoxy_glDispatchComputeIndirect:
+        ::std::option::Option<unsafe extern "C" fn(indirect: GLintptr)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawArrays"]
+    pub static mut epoxy_glDrawArrays:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, first: GLint, count: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawArraysEXT"]
+    pub static mut epoxy_glDrawArraysEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, first: GLint, count: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawArraysIndirect"]
+    pub static mut epoxy_glDrawArraysIndirect: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, indirect: *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawArraysInstanced"]
+    pub static mut epoxy_glDrawArraysInstanced: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, first: GLint, count: GLsizei, instancecount: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawArraysInstancedANGLE"]
+    pub static mut epoxy_glDrawArraysInstancedANGLE: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, first: GLint, count: GLsizei, primcount: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawArraysInstancedARB"]
+    pub static mut epoxy_glDrawArraysInstancedARB: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, first: GLint, count: GLsizei, primcount: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawArraysInstancedBaseInstance"]
+    pub static mut epoxy_glDrawArraysInstancedBaseInstance: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            first: GLint,
+            count: GLsizei,
+            instancecount: GLsizei,
+            baseinstance: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawArraysInstancedBaseInstanceEXT"]
+    pub static mut epoxy_glDrawArraysInstancedBaseInstanceEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            first: GLint,
+            count: GLsizei,
+            instancecount: GLsizei,
+            baseinstance: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawArraysInstancedEXT"]
+    pub static mut epoxy_glDrawArraysInstancedEXT: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, start: GLint, count: GLsizei, primcount: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawArraysInstancedNV"]
+    pub static mut epoxy_glDrawArraysInstancedNV: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, first: GLint, count: GLsizei, primcount: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawBuffer"]
+    pub static mut epoxy_glDrawBuffer: ::std::option::Option<unsafe extern "C" fn(buf: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawBuffers"]
+    pub static mut epoxy_glDrawBuffers:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, bufs: *const GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawBuffersARB"]
+    pub static mut epoxy_glDrawBuffersARB:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, bufs: *const GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawBuffersATI"]
+    pub static mut epoxy_glDrawBuffersATI:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, bufs: *const GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawBuffersEXT"]
+    pub static mut epoxy_glDrawBuffersEXT:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, bufs: *const GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawBuffersIndexedEXT"]
+    pub static mut epoxy_glDrawBuffersIndexedEXT: ::std::option::Option<
+        unsafe extern "C" fn(n: GLint, location: *const GLenum, indices: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawBuffersNV"]
+    pub static mut epoxy_glDrawBuffersNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, bufs: *const GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawCommandsAddressNV"]
+    pub static mut epoxy_glDrawCommandsAddressNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            primitiveMode: GLenum,
+            indirects: *const GLuint64,
+            sizes: *const GLsizei,
+            count: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawCommandsNV"]
+    pub static mut epoxy_glDrawCommandsNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            primitiveMode: GLenum,
+            buffer: GLuint,
+            indirects: *const GLintptr,
+            sizes: *const GLsizei,
+            count: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawCommandsStatesAddressNV"]
+    pub static mut epoxy_glDrawCommandsStatesAddressNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            indirects: *const GLuint64,
+            sizes: *const GLsizei,
+            states: *const GLuint,
+            fbos: *const GLuint,
+            count: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawCommandsStatesNV"]
+    pub static mut epoxy_glDrawCommandsStatesNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            indirects: *const GLintptr,
+            sizes: *const GLsizei,
+            states: *const GLuint,
+            fbos: *const GLuint,
+            count: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementArrayAPPLE"]
+    pub static mut epoxy_glDrawElementArrayAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, first: GLint, count: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementArrayATI"]
+    pub static mut epoxy_glDrawElementArrayATI:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, count: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElements"]
+    pub static mut epoxy_glDrawElements: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsBaseVertex"]
+    pub static mut epoxy_glDrawElementsBaseVertex: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            basevertex: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsBaseVertexEXT"]
+    pub static mut epoxy_glDrawElementsBaseVertexEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            basevertex: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsBaseVertexOES"]
+    pub static mut epoxy_glDrawElementsBaseVertexOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            basevertex: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsIndirect"]
+    pub static mut epoxy_glDrawElementsIndirect: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, type_: GLenum, indirect: *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsInstanced"]
+    pub static mut epoxy_glDrawElementsInstanced: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            instancecount: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsInstancedANGLE"]
+    pub static mut epoxy_glDrawElementsInstancedANGLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            primcount: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsInstancedARB"]
+    pub static mut epoxy_glDrawElementsInstancedARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            primcount: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsInstancedBaseInstance"]
+    pub static mut epoxy_glDrawElementsInstancedBaseInstance: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            instancecount: GLsizei,
+            baseinstance: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsInstancedBaseInstanceEXT"]
+    pub static mut epoxy_glDrawElementsInstancedBaseInstanceEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            instancecount: GLsizei,
+            baseinstance: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsInstancedBaseVertex"]
+    pub static mut epoxy_glDrawElementsInstancedBaseVertex: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            instancecount: GLsizei,
+            basevertex: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsInstancedBaseVertexBaseInstance"]
+    pub static mut epoxy_glDrawElementsInstancedBaseVertexBaseInstance: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            instancecount: GLsizei,
+            basevertex: GLint,
+            baseinstance: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsInstancedBaseVertexBaseInstanceEXT"]
+    pub static mut epoxy_glDrawElementsInstancedBaseVertexBaseInstanceEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            instancecount: GLsizei,
+            basevertex: GLint,
+            baseinstance: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsInstancedBaseVertexEXT"]
+    pub static mut epoxy_glDrawElementsInstancedBaseVertexEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            instancecount: GLsizei,
+            basevertex: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsInstancedBaseVertexOES"]
+    pub static mut epoxy_glDrawElementsInstancedBaseVertexOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            instancecount: GLsizei,
+            basevertex: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsInstancedEXT"]
+    pub static mut epoxy_glDrawElementsInstancedEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            primcount: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawElementsInstancedNV"]
+    pub static mut epoxy_glDrawElementsInstancedNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            primcount: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawMeshArraysSUN"]
+    pub static mut epoxy_glDrawMeshArraysSUN: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, first: GLint, count: GLsizei, width: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawPixels"]
+    pub static mut epoxy_glDrawPixels: ::std::option::Option<
+        unsafe extern "C" fn(
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawRangeElementArrayAPPLE"]
+    pub static mut epoxy_glDrawRangeElementArrayAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            start: GLuint,
+            end: GLuint,
+            first: GLint,
+            count: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawRangeElementArrayATI"]
+    pub static mut epoxy_glDrawRangeElementArrayATI: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, start: GLuint, end: GLuint, count: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawRangeElements"]
+    pub static mut epoxy_glDrawRangeElements: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            start: GLuint,
+            end: GLuint,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawRangeElementsBaseVertex"]
+    pub static mut epoxy_glDrawRangeElementsBaseVertex: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            start: GLuint,
+            end: GLuint,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            basevertex: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawRangeElementsBaseVertexEXT"]
+    pub static mut epoxy_glDrawRangeElementsBaseVertexEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            start: GLuint,
+            end: GLuint,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            basevertex: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawRangeElementsBaseVertexOES"]
+    pub static mut epoxy_glDrawRangeElementsBaseVertexOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            start: GLuint,
+            end: GLuint,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+            basevertex: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawRangeElementsEXT"]
+    pub static mut epoxy_glDrawRangeElementsEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            start: GLuint,
+            end: GLuint,
+            count: GLsizei,
+            type_: GLenum,
+            indices: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTexfOES"]
+    pub static mut epoxy_glDrawTexfOES: ::std::option::Option<
+        unsafe extern "C" fn(x: GLfloat, y: GLfloat, z: GLfloat, width: GLfloat, height: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTexfvOES"]
+    pub static mut epoxy_glDrawTexfvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTexiOES"]
+    pub static mut epoxy_glDrawTexiOES: ::std::option::Option<
+        unsafe extern "C" fn(x: GLint, y: GLint, z: GLint, width: GLint, height: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTexivOES"]
+    pub static mut epoxy_glDrawTexivOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTexsOES"]
+    pub static mut epoxy_glDrawTexsOES: ::std::option::Option<
+        unsafe extern "C" fn(x: GLshort, y: GLshort, z: GLshort, width: GLshort, height: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTexsvOES"]
+    pub static mut epoxy_glDrawTexsvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTextureNV"]
+    pub static mut epoxy_glDrawTextureNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            sampler: GLuint,
+            x0: GLfloat,
+            y0: GLfloat,
+            x1: GLfloat,
+            y1: GLfloat,
+            z: GLfloat,
+            s0: GLfloat,
+            t0: GLfloat,
+            s1: GLfloat,
+            t1: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTexxOES"]
+    pub static mut epoxy_glDrawTexxOES: ::std::option::Option<
+        unsafe extern "C" fn(x: GLfixed, y: GLfixed, z: GLfixed, width: GLfixed, height: GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTexxvOES"]
+    pub static mut epoxy_glDrawTexxvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTransformFeedback"]
+    pub static mut epoxy_glDrawTransformFeedback:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTransformFeedbackEXT"]
+    pub static mut epoxy_glDrawTransformFeedbackEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTransformFeedbackInstanced"]
+    pub static mut epoxy_glDrawTransformFeedbackInstanced: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, id: GLuint, instancecount: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTransformFeedbackInstancedEXT"]
+    pub static mut epoxy_glDrawTransformFeedbackInstancedEXT: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, id: GLuint, instancecount: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTransformFeedbackNV"]
+    pub static mut epoxy_glDrawTransformFeedbackNV:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTransformFeedbackStream"]
+    pub static mut epoxy_glDrawTransformFeedbackStream:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, id: GLuint, stream: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glDrawTransformFeedbackStreamInstanced"]
+    pub static mut epoxy_glDrawTransformFeedbackStreamInstanced: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, id: GLuint, stream: GLuint, instancecount: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEGLImageTargetRenderbufferStorageOES"]
+    pub static mut epoxy_glEGLImageTargetRenderbufferStorageOES:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, image: GLeglImageOES)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEGLImageTargetTexture2DOES"]
+    pub static mut epoxy_glEGLImageTargetTexture2DOES:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, image: GLeglImageOES)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEdgeFlag"]
+    pub static mut epoxy_glEdgeFlag: ::std::option::Option<unsafe extern "C" fn(flag: GLboolean)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEdgeFlagFormatNV"]
+    pub static mut epoxy_glEdgeFlagFormatNV:
+        ::std::option::Option<unsafe extern "C" fn(stride: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEdgeFlagPointer"]
+    pub static mut epoxy_glEdgeFlagPointer: ::std::option::Option<
+        unsafe extern "C" fn(stride: GLsizei, pointer: *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEdgeFlagPointerEXT"]
+    pub static mut epoxy_glEdgeFlagPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(stride: GLsizei, count: GLsizei, pointer: *const GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEdgeFlagPointerListIBM"]
+    pub static mut epoxy_glEdgeFlagPointerListIBM: ::std::option::Option<
+        unsafe extern "C" fn(stride: GLint, pointer: *mut *const GLboolean, ptrstride: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEdgeFlagv"]
+    pub static mut epoxy_glEdgeFlagv:
+        ::std::option::Option<unsafe extern "C" fn(flag: *const GLboolean)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glElementPointerAPPLE"]
+    pub static mut epoxy_glElementPointerAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(type_: GLenum, pointer: *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glElementPointerATI"]
+    pub static mut epoxy_glElementPointerATI: ::std::option::Option<
+        unsafe extern "C" fn(type_: GLenum, pointer: *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnable"]
+    pub static mut epoxy_glEnable: ::std::option::Option<unsafe extern "C" fn(cap: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableClientState"]
+    pub static mut epoxy_glEnableClientState:
+        ::std::option::Option<unsafe extern "C" fn(array: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableClientStateIndexedEXT"]
+    pub static mut epoxy_glEnableClientStateIndexedEXT:
+        ::std::option::Option<unsafe extern "C" fn(array: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableClientStateiEXT"]
+    pub static mut epoxy_glEnableClientStateiEXT:
+        ::std::option::Option<unsafe extern "C" fn(array: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableDriverControlQCOM"]
+    pub static mut epoxy_glEnableDriverControlQCOM:
+        ::std::option::Option<unsafe extern "C" fn(driverControl: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableIndexedEXT"]
+    pub static mut epoxy_glEnableIndexedEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableVariantClientStateEXT"]
+    pub static mut epoxy_glEnableVariantClientStateEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableVertexArrayAttrib"]
+    pub static mut epoxy_glEnableVertexArrayAttrib:
+        ::std::option::Option<unsafe extern "C" fn(vaobj: GLuint, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableVertexArrayAttribEXT"]
+    pub static mut epoxy_glEnableVertexArrayAttribEXT:
+        ::std::option::Option<unsafe extern "C" fn(vaobj: GLuint, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableVertexArrayEXT"]
+    pub static mut epoxy_glEnableVertexArrayEXT:
+        ::std::option::Option<unsafe extern "C" fn(vaobj: GLuint, array: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableVertexAttribAPPLE"]
+    pub static mut epoxy_glEnableVertexAttribAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, pname: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableVertexAttribArray"]
+    pub static mut epoxy_glEnableVertexAttribArray:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableVertexAttribArrayARB"]
+    pub static mut epoxy_glEnableVertexAttribArrayARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnablei"]
+    pub static mut epoxy_glEnablei:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableiEXT"]
+    pub static mut epoxy_glEnableiEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableiNV"]
+    pub static mut epoxy_glEnableiNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnableiOES"]
+    pub static mut epoxy_glEnableiOES:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEnd"]
+    pub static mut epoxy_glEnd: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndConditionalRender"]
+    pub static mut epoxy_glEndConditionalRender: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndConditionalRenderNV"]
+    pub static mut epoxy_glEndConditionalRenderNV: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndConditionalRenderNVX"]
+    pub static mut epoxy_glEndConditionalRenderNVX: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndFragmentShaderATI"]
+    pub static mut epoxy_glEndFragmentShaderATI: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndList"]
+    pub static mut epoxy_glEndList: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndOcclusionQueryNV"]
+    pub static mut epoxy_glEndOcclusionQueryNV: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndPerfMonitorAMD"]
+    pub static mut epoxy_glEndPerfMonitorAMD:
+        ::std::option::Option<unsafe extern "C" fn(monitor: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndPerfQueryINTEL"]
+    pub static mut epoxy_glEndPerfQueryINTEL:
+        ::std::option::Option<unsafe extern "C" fn(queryHandle: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndQuery"]
+    pub static mut epoxy_glEndQuery: ::std::option::Option<unsafe extern "C" fn(target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndQueryARB"]
+    pub static mut epoxy_glEndQueryARB: ::std::option::Option<unsafe extern "C" fn(target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndQueryEXT"]
+    pub static mut epoxy_glEndQueryEXT: ::std::option::Option<unsafe extern "C" fn(target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndQueryIndexed"]
+    pub static mut epoxy_glEndQueryIndexed:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndTilingQCOM"]
+    pub static mut epoxy_glEndTilingQCOM:
+        ::std::option::Option<unsafe extern "C" fn(preserveMask: GLbitfield)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndTransformFeedback"]
+    pub static mut epoxy_glEndTransformFeedback: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndTransformFeedbackEXT"]
+    pub static mut epoxy_glEndTransformFeedbackEXT: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndTransformFeedbackNV"]
+    pub static mut epoxy_glEndTransformFeedbackNV: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndVertexShaderEXT"]
+    pub static mut epoxy_glEndVertexShaderEXT: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEndVideoCaptureNV"]
+    pub static mut epoxy_glEndVideoCaptureNV:
+        ::std::option::Option<unsafe extern "C" fn(video_capture_slot: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalCoord1d"]
+    pub static mut epoxy_glEvalCoord1d: ::std::option::Option<unsafe extern "C" fn(u: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalCoord1dv"]
+    pub static mut epoxy_glEvalCoord1dv:
+        ::std::option::Option<unsafe extern "C" fn(u: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalCoord1f"]
+    pub static mut epoxy_glEvalCoord1f: ::std::option::Option<unsafe extern "C" fn(u: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalCoord1fv"]
+    pub static mut epoxy_glEvalCoord1fv:
+        ::std::option::Option<unsafe extern "C" fn(u: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalCoord1xOES"]
+    pub static mut epoxy_glEvalCoord1xOES: ::std::option::Option<unsafe extern "C" fn(u: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalCoord1xvOES"]
+    pub static mut epoxy_glEvalCoord1xvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalCoord2d"]
+    pub static mut epoxy_glEvalCoord2d:
+        ::std::option::Option<unsafe extern "C" fn(u: GLdouble, v: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalCoord2dv"]
+    pub static mut epoxy_glEvalCoord2dv:
+        ::std::option::Option<unsafe extern "C" fn(u: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalCoord2f"]
+    pub static mut epoxy_glEvalCoord2f:
+        ::std::option::Option<unsafe extern "C" fn(u: GLfloat, v: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalCoord2fv"]
+    pub static mut epoxy_glEvalCoord2fv:
+        ::std::option::Option<unsafe extern "C" fn(u: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalCoord2xOES"]
+    pub static mut epoxy_glEvalCoord2xOES:
+        ::std::option::Option<unsafe extern "C" fn(u: GLfixed, v: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalCoord2xvOES"]
+    pub static mut epoxy_glEvalCoord2xvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalMapsNV"]
+    pub static mut epoxy_glEvalMapsNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalMesh1"]
+    pub static mut epoxy_glEvalMesh1:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, i1: GLint, i2: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalMesh2"]
+    pub static mut epoxy_glEvalMesh2: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, i1: GLint, i2: GLint, j1: GLint, j2: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalPoint1"]
+    pub static mut epoxy_glEvalPoint1: ::std::option::Option<unsafe extern "C" fn(i: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvalPoint2"]
+    pub static mut epoxy_glEvalPoint2:
+        ::std::option::Option<unsafe extern "C" fn(i: GLint, j: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glEvaluateDepthValuesARB"]
+    pub static mut epoxy_glEvaluateDepthValuesARB: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glExecuteProgramNV"]
+    pub static mut epoxy_glExecuteProgramNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, id: GLuint, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glExtGetBufferPointervQCOM"]
+    pub static mut epoxy_glExtGetBufferPointervQCOM: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, params: *mut *mut ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glExtGetBuffersQCOM"]
+    pub static mut epoxy_glExtGetBuffersQCOM: ::std::option::Option<
+        unsafe extern "C" fn(buffers: *mut GLuint, maxBuffers: GLint, numBuffers: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glExtGetFramebuffersQCOM"]
+    pub static mut epoxy_glExtGetFramebuffersQCOM: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffers: *mut GLuint,
+            maxFramebuffers: GLint,
+            numFramebuffers: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glExtGetProgramBinarySourceQCOM"]
+    pub static mut epoxy_glExtGetProgramBinarySourceQCOM: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            shadertype: GLenum,
+            source: *mut GLchar,
+            length: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glExtGetProgramsQCOM"]
+    pub static mut epoxy_glExtGetProgramsQCOM: ::std::option::Option<
+        unsafe extern "C" fn(programs: *mut GLuint, maxPrograms: GLint, numPrograms: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glExtGetRenderbuffersQCOM"]
+    pub static mut epoxy_glExtGetRenderbuffersQCOM: ::std::option::Option<
+        unsafe extern "C" fn(
+            renderbuffers: *mut GLuint,
+            maxRenderbuffers: GLint,
+            numRenderbuffers: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glExtGetShadersQCOM"]
+    pub static mut epoxy_glExtGetShadersQCOM: ::std::option::Option<
+        unsafe extern "C" fn(shaders: *mut GLuint, maxShaders: GLint, numShaders: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glExtGetTexLevelParameterivQCOM"]
+    pub static mut epoxy_glExtGetTexLevelParameterivQCOM: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            face: GLenum,
+            level: GLint,
+            pname: GLenum,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glExtGetTexSubImageQCOM"]
+    pub static mut epoxy_glExtGetTexSubImageQCOM: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            texels: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glExtGetTexturesQCOM"]
+    pub static mut epoxy_glExtGetTexturesQCOM: ::std::option::Option<
+        unsafe extern "C" fn(textures: *mut GLuint, maxTextures: GLint, numTextures: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glExtIsProgramBinaryQCOM"]
+    pub static mut epoxy_glExtIsProgramBinaryQCOM:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glExtTexObjectStateOverrideiQCOM"]
+    pub static mut epoxy_glExtTexObjectStateOverrideiQCOM:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glExtractComponentEXT"]
+    pub static mut epoxy_glExtractComponentEXT:
+        ::std::option::Option<unsafe extern "C" fn(res: GLuint, src: GLuint, num: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFeedbackBuffer"]
+    pub static mut epoxy_glFeedbackBuffer: ::std::option::Option<
+        unsafe extern "C" fn(size: GLsizei, type_: GLenum, buffer: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFeedbackBufferxOES"]
+    pub static mut epoxy_glFeedbackBufferxOES: ::std::option::Option<
+        unsafe extern "C" fn(n: GLsizei, type_: GLenum, buffer: *const GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFenceSync"]
+    pub static mut epoxy_glFenceSync:
+        ::std::option::Option<unsafe extern "C" fn(condition: GLenum, flags: GLbitfield) -> GLsync>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFenceSyncAPPLE"]
+    pub static mut epoxy_glFenceSyncAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(condition: GLenum, flags: GLbitfield) -> GLsync>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFinalCombinerInputNV"]
+    pub static mut epoxy_glFinalCombinerInputNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            variable: GLenum,
+            input: GLenum,
+            mapping: GLenum,
+            componentUsage: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFinish"]
+    pub static mut epoxy_glFinish: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFinishAsyncSGIX"]
+    pub static mut epoxy_glFinishAsyncSGIX:
+        ::std::option::Option<unsafe extern "C" fn(markerp: *mut GLuint) -> GLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFinishFenceAPPLE"]
+    pub static mut epoxy_glFinishFenceAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(fence: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFinishFenceNV"]
+    pub static mut epoxy_glFinishFenceNV:
+        ::std::option::Option<unsafe extern "C" fn(fence: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFinishObjectAPPLE"]
+    pub static mut epoxy_glFinishObjectAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(object: GLenum, name: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFinishTextureSUNX"]
+    pub static mut epoxy_glFinishTextureSUNX: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFlush"]
+    pub static mut epoxy_glFlush: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFlushMappedBufferRange"]
+    pub static mut epoxy_glFlushMappedBufferRange: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, offset: GLintptr, length: GLsizeiptr),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFlushMappedBufferRangeAPPLE"]
+    pub static mut epoxy_glFlushMappedBufferRangeAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, offset: GLintptr, size: GLsizeiptr),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFlushMappedBufferRangeEXT"]
+    pub static mut epoxy_glFlushMappedBufferRangeEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, offset: GLintptr, length: GLsizeiptr),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFlushMappedNamedBufferRange"]
+    pub static mut epoxy_glFlushMappedNamedBufferRange: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLuint, offset: GLintptr, length: GLsizeiptr),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFlushMappedNamedBufferRangeEXT"]
+    pub static mut epoxy_glFlushMappedNamedBufferRangeEXT: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLuint, offset: GLintptr, length: GLsizeiptr),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFlushPixelDataRangeNV"]
+    pub static mut epoxy_glFlushPixelDataRangeNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFlushRasterSGIX"]
+    pub static mut epoxy_glFlushRasterSGIX: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFlushStaticDataIBM"]
+    pub static mut epoxy_glFlushStaticDataIBM:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFlushVertexArrayRangeAPPLE"]
+    pub static mut epoxy_glFlushVertexArrayRangeAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(length: GLsizei, pointer: *mut ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFlushVertexArrayRangeNV"]
+    pub static mut epoxy_glFlushVertexArrayRangeNV: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogCoordFormatNV"]
+    pub static mut epoxy_glFogCoordFormatNV:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, stride: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogCoordPointer"]
+    pub static mut epoxy_glFogCoordPointer: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogCoordPointerEXT"]
+    pub static mut epoxy_glFogCoordPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogCoordPointerListIBM"]
+    pub static mut epoxy_glFogCoordPointerListIBM: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            stride: GLint,
+            pointer: *mut *const ::std::os::raw::c_void,
+            ptrstride: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogCoordd"]
+    pub static mut epoxy_glFogCoordd: ::std::option::Option<unsafe extern "C" fn(coord: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogCoorddEXT"]
+    pub static mut epoxy_glFogCoorddEXT:
+        ::std::option::Option<unsafe extern "C" fn(coord: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogCoorddv"]
+    pub static mut epoxy_glFogCoorddv:
+        ::std::option::Option<unsafe extern "C" fn(coord: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogCoorddvEXT"]
+    pub static mut epoxy_glFogCoorddvEXT:
+        ::std::option::Option<unsafe extern "C" fn(coord: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogCoordf"]
+    pub static mut epoxy_glFogCoordf: ::std::option::Option<unsafe extern "C" fn(coord: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogCoordfEXT"]
+    pub static mut epoxy_glFogCoordfEXT:
+        ::std::option::Option<unsafe extern "C" fn(coord: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogCoordfv"]
+    pub static mut epoxy_glFogCoordfv:
+        ::std::option::Option<unsafe extern "C" fn(coord: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogCoordfvEXT"]
+    pub static mut epoxy_glFogCoordfvEXT:
+        ::std::option::Option<unsafe extern "C" fn(coord: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogCoordhNV"]
+    pub static mut epoxy_glFogCoordhNV: ::std::option::Option<unsafe extern "C" fn(fog: GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogCoordhvNV"]
+    pub static mut epoxy_glFogCoordhvNV:
+        ::std::option::Option<unsafe extern "C" fn(fog: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogFuncSGIS"]
+    pub static mut epoxy_glFogFuncSGIS:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, points: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogf"]
+    pub static mut epoxy_glFogf:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogfv"]
+    pub static mut epoxy_glFogfv:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogi"]
+    pub static mut epoxy_glFogi:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogiv"]
+    pub static mut epoxy_glFogiv:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogx"]
+    pub static mut epoxy_glFogx:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogxOES"]
+    pub static mut epoxy_glFogxOES:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogxv"]
+    pub static mut epoxy_glFogxv:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFogxvOES"]
+    pub static mut epoxy_glFogxvOES:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFragmentColorMaterialSGIX"]
+    pub static mut epoxy_glFragmentColorMaterialSGIX:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFragmentCoverageColorNV"]
+    pub static mut epoxy_glFragmentCoverageColorNV:
+        ::std::option::Option<unsafe extern "C" fn(color: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFragmentLightModelfSGIX"]
+    pub static mut epoxy_glFragmentLightModelfSGIX:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFragmentLightModelfvSGIX"]
+    pub static mut epoxy_glFragmentLightModelfvSGIX:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFragmentLightModeliSGIX"]
+    pub static mut epoxy_glFragmentLightModeliSGIX:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFragmentLightModelivSGIX"]
+    pub static mut epoxy_glFragmentLightModelivSGIX:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFragmentLightfSGIX"]
+    pub static mut epoxy_glFragmentLightfSGIX:
+        ::std::option::Option<unsafe extern "C" fn(light: GLenum, pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFragmentLightfvSGIX"]
+    pub static mut epoxy_glFragmentLightfvSGIX: ::std::option::Option<
+        unsafe extern "C" fn(light: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFragmentLightiSGIX"]
+    pub static mut epoxy_glFragmentLightiSGIX:
+        ::std::option::Option<unsafe extern "C" fn(light: GLenum, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFragmentLightivSGIX"]
+    pub static mut epoxy_glFragmentLightivSGIX: ::std::option::Option<
+        unsafe extern "C" fn(light: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFragmentMaterialfSGIX"]
+    pub static mut epoxy_glFragmentMaterialfSGIX:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFragmentMaterialfvSGIX"]
+    pub static mut epoxy_glFragmentMaterialfvSGIX: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFragmentMaterialiSGIX"]
+    pub static mut epoxy_glFragmentMaterialiSGIX:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFragmentMaterialivSGIX"]
+    pub static mut epoxy_glFragmentMaterialivSGIX: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFrameTerminatorGREMEDY"]
+    pub static mut epoxy_glFrameTerminatorGREMEDY: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFrameZoomSGIX"]
+    pub static mut epoxy_glFrameZoomSGIX:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferDrawBufferEXT"]
+    pub static mut epoxy_glFramebufferDrawBufferEXT:
+        ::std::option::Option<unsafe extern "C" fn(framebuffer: GLuint, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferDrawBuffersEXT"]
+    pub static mut epoxy_glFramebufferDrawBuffersEXT: ::std::option::Option<
+        unsafe extern "C" fn(framebuffer: GLuint, n: GLsizei, bufs: *const GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferParameteri"]
+    pub static mut epoxy_glFramebufferParameteri:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferPixelLocalStorageSizeEXT"]
+    pub static mut epoxy_glFramebufferPixelLocalStorageSizeEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLuint, size: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferReadBufferEXT"]
+    pub static mut epoxy_glFramebufferReadBufferEXT:
+        ::std::option::Option<unsafe extern "C" fn(framebuffer: GLuint, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferRenderbuffer"]
+    pub static mut epoxy_glFramebufferRenderbuffer: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            renderbuffertarget: GLenum,
+            renderbuffer: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferRenderbufferEXT"]
+    pub static mut epoxy_glFramebufferRenderbufferEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            renderbuffertarget: GLenum,
+            renderbuffer: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferRenderbufferOES"]
+    pub static mut epoxy_glFramebufferRenderbufferOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            renderbuffertarget: GLenum,
+            renderbuffer: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferSampleLocationsfvARB"]
+    pub static mut epoxy_glFramebufferSampleLocationsfvARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, start: GLuint, count: GLsizei, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferSampleLocationsfvNV"]
+    pub static mut epoxy_glFramebufferSampleLocationsfvNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, start: GLuint, count: GLsizei, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferSamplePositionsfvAMD"]
+    pub static mut epoxy_glFramebufferSamplePositionsfvAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            numsamples: GLuint,
+            pixelindex: GLuint,
+            values: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTexture"]
+    pub static mut epoxy_glFramebufferTexture: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, attachment: GLenum, texture: GLuint, level: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTexture1D"]
+    pub static mut epoxy_glFramebufferTexture1D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            textarget: GLenum,
+            texture: GLuint,
+            level: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTexture1DEXT"]
+    pub static mut epoxy_glFramebufferTexture1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            textarget: GLenum,
+            texture: GLuint,
+            level: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTexture2D"]
+    pub static mut epoxy_glFramebufferTexture2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            textarget: GLenum,
+            texture: GLuint,
+            level: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTexture2DDownsampleIMG"]
+    pub static mut epoxy_glFramebufferTexture2DDownsampleIMG: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            textarget: GLenum,
+            texture: GLuint,
+            level: GLint,
+            xscale: GLint,
+            yscale: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTexture2DEXT"]
+    pub static mut epoxy_glFramebufferTexture2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            textarget: GLenum,
+            texture: GLuint,
+            level: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTexture2DMultisampleEXT"]
+    pub static mut epoxy_glFramebufferTexture2DMultisampleEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            textarget: GLenum,
+            texture: GLuint,
+            level: GLint,
+            samples: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTexture2DMultisampleIMG"]
+    pub static mut epoxy_glFramebufferTexture2DMultisampleIMG: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            textarget: GLenum,
+            texture: GLuint,
+            level: GLint,
+            samples: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTexture2DOES"]
+    pub static mut epoxy_glFramebufferTexture2DOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            textarget: GLenum,
+            texture: GLuint,
+            level: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTexture3D"]
+    pub static mut epoxy_glFramebufferTexture3D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            textarget: GLenum,
+            texture: GLuint,
+            level: GLint,
+            zoffset: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTexture3DEXT"]
+    pub static mut epoxy_glFramebufferTexture3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            textarget: GLenum,
+            texture: GLuint,
+            level: GLint,
+            zoffset: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTexture3DOES"]
+    pub static mut epoxy_glFramebufferTexture3DOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            textarget: GLenum,
+            texture: GLuint,
+            level: GLint,
+            zoffset: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTextureARB"]
+    pub static mut epoxy_glFramebufferTextureARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, attachment: GLenum, texture: GLuint, level: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTextureEXT"]
+    pub static mut epoxy_glFramebufferTextureEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, attachment: GLenum, texture: GLuint, level: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTextureFaceARB"]
+    pub static mut epoxy_glFramebufferTextureFaceARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            texture: GLuint,
+            level: GLint,
+            face: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTextureFaceEXT"]
+    pub static mut epoxy_glFramebufferTextureFaceEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            texture: GLuint,
+            level: GLint,
+            face: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTextureLayer"]
+    pub static mut epoxy_glFramebufferTextureLayer: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            texture: GLuint,
+            level: GLint,
+            layer: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTextureLayerARB"]
+    pub static mut epoxy_glFramebufferTextureLayerARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            texture: GLuint,
+            level: GLint,
+            layer: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTextureLayerDownsampleIMG"]
+    pub static mut epoxy_glFramebufferTextureLayerDownsampleIMG: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            texture: GLuint,
+            level: GLint,
+            layer: GLint,
+            xscale: GLint,
+            yscale: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTextureLayerEXT"]
+    pub static mut epoxy_glFramebufferTextureLayerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            texture: GLuint,
+            level: GLint,
+            layer: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTextureMultisampleMultiviewOVR"]
+    pub static mut epoxy_glFramebufferTextureMultisampleMultiviewOVR: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            texture: GLuint,
+            level: GLint,
+            samples: GLsizei,
+            baseViewIndex: GLint,
+            numViews: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTextureMultiviewOVR"]
+    pub static mut epoxy_glFramebufferTextureMultiviewOVR: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            attachment: GLenum,
+            texture: GLuint,
+            level: GLint,
+            baseViewIndex: GLint,
+            numViews: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFramebufferTextureOES"]
+    pub static mut epoxy_glFramebufferTextureOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, attachment: GLenum, texture: GLuint, level: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFreeObjectBufferATI"]
+    pub static mut epoxy_glFreeObjectBufferATI:
+        ::std::option::Option<unsafe extern "C" fn(buffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFrontFace"]
+    pub static mut epoxy_glFrontFace: ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFrustum"]
+    pub static mut epoxy_glFrustum: ::std::option::Option<
+        unsafe extern "C" fn(
+            left: GLdouble,
+            right: GLdouble,
+            bottom: GLdouble,
+            top: GLdouble,
+            zNear: GLdouble,
+            zFar: GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFrustumf"]
+    pub static mut epoxy_glFrustumf: ::std::option::Option<
+        unsafe extern "C" fn(
+            l: GLfloat,
+            r: GLfloat,
+            b: GLfloat,
+            t: GLfloat,
+            n: GLfloat,
+            f: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFrustumfOES"]
+    pub static mut epoxy_glFrustumfOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            l: GLfloat,
+            r: GLfloat,
+            b: GLfloat,
+            t: GLfloat,
+            n: GLfloat,
+            f: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFrustumx"]
+    pub static mut epoxy_glFrustumx: ::std::option::Option<
+        unsafe extern "C" fn(
+            l: GLfixed,
+            r: GLfixed,
+            b: GLfixed,
+            t: GLfixed,
+            n: GLfixed,
+            f: GLfixed,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glFrustumxOES"]
+    pub static mut epoxy_glFrustumxOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            l: GLfixed,
+            r: GLfixed,
+            b: GLfixed,
+            t: GLfixed,
+            n: GLfixed,
+            f: GLfixed,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenAsyncMarkersSGIX"]
+    pub static mut epoxy_glGenAsyncMarkersSGIX:
+        ::std::option::Option<unsafe extern "C" fn(range: GLsizei) -> GLuint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenBuffers"]
+    pub static mut epoxy_glGenBuffers:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, buffers: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenBuffersARB"]
+    pub static mut epoxy_glGenBuffersARB:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, buffers: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenFencesAPPLE"]
+    pub static mut epoxy_glGenFencesAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, fences: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenFencesNV"]
+    pub static mut epoxy_glGenFencesNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, fences: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenFragmentShadersATI"]
+    pub static mut epoxy_glGenFragmentShadersATI:
+        ::std::option::Option<unsafe extern "C" fn(range: GLuint) -> GLuint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenFramebuffers"]
+    pub static mut epoxy_glGenFramebuffers:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, framebuffers: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenFramebuffersEXT"]
+    pub static mut epoxy_glGenFramebuffersEXT:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, framebuffers: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenFramebuffersOES"]
+    pub static mut epoxy_glGenFramebuffersOES:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, framebuffers: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenLists"]
+    pub static mut epoxy_glGenLists:
+        ::std::option::Option<unsafe extern "C" fn(range: GLsizei) -> GLuint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenNamesAMD"]
+    pub static mut epoxy_glGenNamesAMD: ::std::option::Option<
+        unsafe extern "C" fn(identifier: GLenum, num: GLuint, names: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenOcclusionQueriesNV"]
+    pub static mut epoxy_glGenOcclusionQueriesNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, ids: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenPathsNV"]
+    pub static mut epoxy_glGenPathsNV:
+        ::std::option::Option<unsafe extern "C" fn(range: GLsizei) -> GLuint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenPerfMonitorsAMD"]
+    pub static mut epoxy_glGenPerfMonitorsAMD:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, monitors: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenProgramPipelines"]
+    pub static mut epoxy_glGenProgramPipelines:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, pipelines: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenProgramPipelinesEXT"]
+    pub static mut epoxy_glGenProgramPipelinesEXT:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, pipelines: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenProgramsARB"]
+    pub static mut epoxy_glGenProgramsARB:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, programs: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenProgramsNV"]
+    pub static mut epoxy_glGenProgramsNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, programs: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenQueries"]
+    pub static mut epoxy_glGenQueries:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, ids: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenQueriesARB"]
+    pub static mut epoxy_glGenQueriesARB:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, ids: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenQueriesEXT"]
+    pub static mut epoxy_glGenQueriesEXT:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, ids: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenRenderbuffers"]
+    pub static mut epoxy_glGenRenderbuffers:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, renderbuffers: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenRenderbuffersEXT"]
+    pub static mut epoxy_glGenRenderbuffersEXT:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, renderbuffers: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenRenderbuffersOES"]
+    pub static mut epoxy_glGenRenderbuffersOES:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, renderbuffers: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenSamplers"]
+    pub static mut epoxy_glGenSamplers:
+        ::std::option::Option<unsafe extern "C" fn(count: GLsizei, samplers: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenSymbolsEXT"]
+    pub static mut epoxy_glGenSymbolsEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            datatype: GLenum,
+            storagetype: GLenum,
+            range: GLenum,
+            components: GLuint,
+        ) -> GLuint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenTextures"]
+    pub static mut epoxy_glGenTextures:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, textures: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenTexturesEXT"]
+    pub static mut epoxy_glGenTexturesEXT:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, textures: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenTransformFeedbacks"]
+    pub static mut epoxy_glGenTransformFeedbacks:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, ids: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenTransformFeedbacksNV"]
+    pub static mut epoxy_glGenTransformFeedbacksNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, ids: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenVertexArrays"]
+    pub static mut epoxy_glGenVertexArrays:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, arrays: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenVertexArraysAPPLE"]
+    pub static mut epoxy_glGenVertexArraysAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, arrays: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenVertexArraysOES"]
+    pub static mut epoxy_glGenVertexArraysOES:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, arrays: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenVertexShadersEXT"]
+    pub static mut epoxy_glGenVertexShadersEXT:
+        ::std::option::Option<unsafe extern "C" fn(range: GLuint) -> GLuint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenerateMipmap"]
+    pub static mut epoxy_glGenerateMipmap:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenerateMipmapEXT"]
+    pub static mut epoxy_glGenerateMipmapEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenerateMipmapOES"]
+    pub static mut epoxy_glGenerateMipmapOES:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenerateMultiTexMipmapEXT"]
+    pub static mut epoxy_glGenerateMultiTexMipmapEXT:
+        ::std::option::Option<unsafe extern "C" fn(texunit: GLenum, target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenerateTextureMipmap"]
+    pub static mut epoxy_glGenerateTextureMipmap:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGenerateTextureMipmapEXT"]
+    pub static mut epoxy_glGenerateTextureMipmapEXT:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint, target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetActiveAtomicCounterBufferiv"]
+    pub static mut epoxy_glGetActiveAtomicCounterBufferiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            bufferIndex: GLuint,
+            pname: GLenum,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetActiveAttrib"]
+    pub static mut epoxy_glGetActiveAttrib: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            index: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            size: *mut GLint,
+            type_: *mut GLenum,
+            name: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetActiveAttribARB"]
+    pub static mut epoxy_glGetActiveAttribARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            programObj: GLhandleARB,
+            index: GLuint,
+            maxLength: GLsizei,
+            length: *mut GLsizei,
+            size: *mut GLint,
+            type_: *mut GLenum,
+            name: *mut GLcharARB,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetActiveSubroutineName"]
+    pub static mut epoxy_glGetActiveSubroutineName: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            shadertype: GLenum,
+            index: GLuint,
+            bufsize: GLsizei,
+            length: *mut GLsizei,
+            name: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetActiveSubroutineUniformName"]
+    pub static mut epoxy_glGetActiveSubroutineUniformName: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            shadertype: GLenum,
+            index: GLuint,
+            bufsize: GLsizei,
+            length: *mut GLsizei,
+            name: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetActiveSubroutineUniformiv"]
+    pub static mut epoxy_glGetActiveSubroutineUniformiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            shadertype: GLenum,
+            index: GLuint,
+            pname: GLenum,
+            values: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetActiveUniform"]
+    pub static mut epoxy_glGetActiveUniform: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            index: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            size: *mut GLint,
+            type_: *mut GLenum,
+            name: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetActiveUniformARB"]
+    pub static mut epoxy_glGetActiveUniformARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            programObj: GLhandleARB,
+            index: GLuint,
+            maxLength: GLsizei,
+            length: *mut GLsizei,
+            size: *mut GLint,
+            type_: *mut GLenum,
+            name: *mut GLcharARB,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetActiveUniformBlockName"]
+    pub static mut epoxy_glGetActiveUniformBlockName: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            uniformBlockIndex: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            uniformBlockName: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetActiveUniformBlockiv"]
+    pub static mut epoxy_glGetActiveUniformBlockiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            uniformBlockIndex: GLuint,
+            pname: GLenum,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetActiveUniformName"]
+    pub static mut epoxy_glGetActiveUniformName: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            uniformIndex: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            uniformName: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetActiveUniformsiv"]
+    pub static mut epoxy_glGetActiveUniformsiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            uniformCount: GLsizei,
+            uniformIndices: *const GLuint,
+            pname: GLenum,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetActiveVaryingNV"]
+    pub static mut epoxy_glGetActiveVaryingNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            index: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            size: *mut GLsizei,
+            type_: *mut GLenum,
+            name: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetArrayObjectfvATI"]
+    pub static mut epoxy_glGetArrayObjectfvATI: ::std::option::Option<
+        unsafe extern "C" fn(array: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetArrayObjectivATI"]
+    pub static mut epoxy_glGetArrayObjectivATI: ::std::option::Option<
+        unsafe extern "C" fn(array: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetAttachedObjectsARB"]
+    pub static mut epoxy_glGetAttachedObjectsARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            containerObj: GLhandleARB,
+            maxCount: GLsizei,
+            count: *mut GLsizei,
+            obj: *mut GLhandleARB,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetAttachedShaders"]
+    pub static mut epoxy_glGetAttachedShaders: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            maxCount: GLsizei,
+            count: *mut GLsizei,
+            shaders: *mut GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetAttribLocation"]
+    pub static mut epoxy_glGetAttribLocation:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, name: *const GLchar) -> GLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetAttribLocationARB"]
+    pub static mut epoxy_glGetAttribLocationARB: ::std::option::Option<
+        unsafe extern "C" fn(programObj: GLhandleARB, name: *const GLcharARB) -> GLint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetBooleanIndexedvEXT"]
+    pub static mut epoxy_glGetBooleanIndexedvEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, data: *mut GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetBooleani_v"]
+    pub static mut epoxy_glGetBooleani_v: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, data: *mut GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetBooleanv"]
+    pub static mut epoxy_glGetBooleanv:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, data: *mut GLboolean)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetBufferParameteri64v"]
+    pub static mut epoxy_glGetBufferParameteri64v: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetBufferParameteriv"]
+    pub static mut epoxy_glGetBufferParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetBufferParameterivARB"]
+    pub static mut epoxy_glGetBufferParameterivARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetBufferParameterui64vNV"]
+    pub static mut epoxy_glGetBufferParameterui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetBufferPointerv"]
+    pub static mut epoxy_glGetBufferPointerv: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            pname: GLenum,
+            params: *mut *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetBufferPointervARB"]
+    pub static mut epoxy_glGetBufferPointervARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            pname: GLenum,
+            params: *mut *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetBufferPointervOES"]
+    pub static mut epoxy_glGetBufferPointervOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            pname: GLenum,
+            params: *mut *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetBufferSubData"]
+    pub static mut epoxy_glGetBufferSubData: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            offset: GLintptr,
+            size: GLsizeiptr,
+            data: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetBufferSubDataARB"]
+    pub static mut epoxy_glGetBufferSubDataARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            offset: GLintptrARB,
+            size: GLsizeiptrARB,
+            data: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetClipPlane"]
+    pub static mut epoxy_glGetClipPlane:
+        ::std::option::Option<unsafe extern "C" fn(plane: GLenum, equation: *mut GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetClipPlanef"]
+    pub static mut epoxy_glGetClipPlanef:
+        ::std::option::Option<unsafe extern "C" fn(plane: GLenum, equation: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetClipPlanefOES"]
+    pub static mut epoxy_glGetClipPlanefOES:
+        ::std::option::Option<unsafe extern "C" fn(plane: GLenum, equation: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetClipPlanex"]
+    pub static mut epoxy_glGetClipPlanex:
+        ::std::option::Option<unsafe extern "C" fn(plane: GLenum, equation: *mut GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetClipPlanexOES"]
+    pub static mut epoxy_glGetClipPlanexOES:
+        ::std::option::Option<unsafe extern "C" fn(plane: GLenum, equation: *mut GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetColorTable"]
+    pub static mut epoxy_glGetColorTable: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            table: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetColorTableEXT"]
+    pub static mut epoxy_glGetColorTableEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            data: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetColorTableParameterfv"]
+    pub static mut epoxy_glGetColorTableParameterfv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetColorTableParameterfvEXT"]
+    pub static mut epoxy_glGetColorTableParameterfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetColorTableParameterfvSGI"]
+    pub static mut epoxy_glGetColorTableParameterfvSGI: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetColorTableParameteriv"]
+    pub static mut epoxy_glGetColorTableParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetColorTableParameterivEXT"]
+    pub static mut epoxy_glGetColorTableParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetColorTableParameterivSGI"]
+    pub static mut epoxy_glGetColorTableParameterivSGI: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetColorTableSGI"]
+    pub static mut epoxy_glGetColorTableSGI: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            table: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetCombinerInputParameterfvNV"]
+    pub static mut epoxy_glGetCombinerInputParameterfvNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            stage: GLenum,
+            portion: GLenum,
+            variable: GLenum,
+            pname: GLenum,
+            params: *mut GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetCombinerInputParameterivNV"]
+    pub static mut epoxy_glGetCombinerInputParameterivNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            stage: GLenum,
+            portion: GLenum,
+            variable: GLenum,
+            pname: GLenum,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetCombinerOutputParameterfvNV"]
+    pub static mut epoxy_glGetCombinerOutputParameterfvNV: ::std::option::Option<
+        unsafe extern "C" fn(stage: GLenum, portion: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetCombinerOutputParameterivNV"]
+    pub static mut epoxy_glGetCombinerOutputParameterivNV: ::std::option::Option<
+        unsafe extern "C" fn(stage: GLenum, portion: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetCombinerStageParameterfvNV"]
+    pub static mut epoxy_glGetCombinerStageParameterfvNV: ::std::option::Option<
+        unsafe extern "C" fn(stage: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetCommandHeaderNV"]
+    pub static mut epoxy_glGetCommandHeaderNV:
+        ::std::option::Option<unsafe extern "C" fn(tokenID: GLenum, size: GLuint) -> GLuint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetCompressedMultiTexImageEXT"]
+    pub static mut epoxy_glGetCompressedMultiTexImageEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            lod: GLint,
+            img: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetCompressedTexImage"]
+    pub static mut epoxy_glGetCompressedTexImage: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, level: GLint, img: *mut ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetCompressedTexImageARB"]
+    pub static mut epoxy_glGetCompressedTexImageARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, level: GLint, img: *mut ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetCompressedTextureImage"]
+    pub static mut epoxy_glGetCompressedTextureImage: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            bufSize: GLsizei,
+            pixels: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetCompressedTextureImageEXT"]
+    pub static mut epoxy_glGetCompressedTextureImageEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            lod: GLint,
+            img: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetCompressedTextureSubImage"]
+    pub static mut epoxy_glGetCompressedTextureSubImage: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            bufSize: GLsizei,
+            pixels: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetConvolutionFilter"]
+    pub static mut epoxy_glGetConvolutionFilter: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            image: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetConvolutionFilterEXT"]
+    pub static mut epoxy_glGetConvolutionFilterEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            image: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetConvolutionParameterfv"]
+    pub static mut epoxy_glGetConvolutionParameterfv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetConvolutionParameterfvEXT"]
+    pub static mut epoxy_glGetConvolutionParameterfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetConvolutionParameteriv"]
+    pub static mut epoxy_glGetConvolutionParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetConvolutionParameterivEXT"]
+    pub static mut epoxy_glGetConvolutionParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetConvolutionParameterxvOES"]
+    pub static mut epoxy_glGetConvolutionParameterxvOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetCoverageModulationTableNV"]
+    pub static mut epoxy_glGetCoverageModulationTableNV:
+        ::std::option::Option<unsafe extern "C" fn(bufsize: GLsizei, v: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetDebugMessageLog"]
+    pub static mut epoxy_glGetDebugMessageLog: ::std::option::Option<
+        unsafe extern "C" fn(
+            count: GLuint,
+            bufSize: GLsizei,
+            sources: *mut GLenum,
+            types: *mut GLenum,
+            ids: *mut GLuint,
+            severities: *mut GLenum,
+            lengths: *mut GLsizei,
+            messageLog: *mut GLchar,
+        ) -> GLuint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetDebugMessageLogAMD"]
+    pub static mut epoxy_glGetDebugMessageLogAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            count: GLuint,
+            bufsize: GLsizei,
+            categories: *mut GLenum,
+            severities: *mut GLuint,
+            ids: *mut GLuint,
+            lengths: *mut GLsizei,
+            message: *mut GLchar,
+        ) -> GLuint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetDebugMessageLogARB"]
+    pub static mut epoxy_glGetDebugMessageLogARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            count: GLuint,
+            bufSize: GLsizei,
+            sources: *mut GLenum,
+            types: *mut GLenum,
+            ids: *mut GLuint,
+            severities: *mut GLenum,
+            lengths: *mut GLsizei,
+            messageLog: *mut GLchar,
+        ) -> GLuint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetDebugMessageLogKHR"]
+    pub static mut epoxy_glGetDebugMessageLogKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            count: GLuint,
+            bufSize: GLsizei,
+            sources: *mut GLenum,
+            types: *mut GLenum,
+            ids: *mut GLuint,
+            severities: *mut GLenum,
+            lengths: *mut GLsizei,
+            messageLog: *mut GLchar,
+        ) -> GLuint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetDetailTexFuncSGIS"]
+    pub static mut epoxy_glGetDetailTexFuncSGIS:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, points: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetDoubleIndexedvEXT"]
+    pub static mut epoxy_glGetDoubleIndexedvEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, data: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetDoublei_v"]
+    pub static mut epoxy_glGetDoublei_v: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, data: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetDoublei_vEXT"]
+    pub static mut epoxy_glGetDoublei_vEXT: ::std::option::Option<
+        unsafe extern "C" fn(pname: GLenum, index: GLuint, params: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetDoublev"]
+    pub static mut epoxy_glGetDoublev:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, data: *mut GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetDriverControlStringQCOM"]
+    pub static mut epoxy_glGetDriverControlStringQCOM: ::std::option::Option<
+        unsafe extern "C" fn(
+            driverControl: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            driverControlString: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetDriverControlsQCOM"]
+    pub static mut epoxy_glGetDriverControlsQCOM: ::std::option::Option<
+        unsafe extern "C" fn(num: *mut GLint, size: GLsizei, driverControls: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetError"]
+    pub static mut epoxy_glGetError: ::std::option::Option<unsafe extern "C" fn() -> GLenum>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFenceivNV"]
+    pub static mut epoxy_glGetFenceivNV: ::std::option::Option<
+        unsafe extern "C" fn(fence: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFinalCombinerInputParameterfvNV"]
+    pub static mut epoxy_glGetFinalCombinerInputParameterfvNV: ::std::option::Option<
+        unsafe extern "C" fn(variable: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFinalCombinerInputParameterivNV"]
+    pub static mut epoxy_glGetFinalCombinerInputParameterivNV: ::std::option::Option<
+        unsafe extern "C" fn(variable: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFirstPerfQueryIdINTEL"]
+    pub static mut epoxy_glGetFirstPerfQueryIdINTEL:
+        ::std::option::Option<unsafe extern "C" fn(queryId: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFixedv"]
+    pub static mut epoxy_glGetFixedv:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *mut GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFixedvOES"]
+    pub static mut epoxy_glGetFixedvOES:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *mut GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFloatIndexedvEXT"]
+    pub static mut epoxy_glGetFloatIndexedvEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, data: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFloati_v"]
+    pub static mut epoxy_glGetFloati_v: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, data: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFloati_vEXT"]
+    pub static mut epoxy_glGetFloati_vEXT: ::std::option::Option<
+        unsafe extern "C" fn(pname: GLenum, index: GLuint, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFloati_vNV"]
+    pub static mut epoxy_glGetFloati_vNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, data: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFloati_vOES"]
+    pub static mut epoxy_glGetFloati_vOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, data: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFloatv"]
+    pub static mut epoxy_glGetFloatv:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, data: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFogFuncSGIS"]
+    pub static mut epoxy_glGetFogFuncSGIS:
+        ::std::option::Option<unsafe extern "C" fn(points: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFragDataIndex"]
+    pub static mut epoxy_glGetFragDataIndex:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, name: *const GLchar) -> GLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFragDataIndexEXT"]
+    pub static mut epoxy_glGetFragDataIndexEXT:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, name: *const GLchar) -> GLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFragDataLocation"]
+    pub static mut epoxy_glGetFragDataLocation:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, name: *const GLchar) -> GLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFragDataLocationEXT"]
+    pub static mut epoxy_glGetFragDataLocationEXT:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, name: *const GLchar) -> GLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFragmentLightfvSGIX"]
+    pub static mut epoxy_glGetFragmentLightfvSGIX: ::std::option::Option<
+        unsafe extern "C" fn(light: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFragmentLightivSGIX"]
+    pub static mut epoxy_glGetFragmentLightivSGIX: ::std::option::Option<
+        unsafe extern "C" fn(light: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFragmentMaterialfvSGIX"]
+    pub static mut epoxy_glGetFragmentMaterialfvSGIX: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFragmentMaterialivSGIX"]
+    pub static mut epoxy_glGetFragmentMaterialivSGIX: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFramebufferAttachmentParameteriv"]
+    pub static mut epoxy_glGetFramebufferAttachmentParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, attachment: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFramebufferAttachmentParameterivEXT"]
+    pub static mut epoxy_glGetFramebufferAttachmentParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, attachment: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFramebufferAttachmentParameterivOES"]
+    pub static mut epoxy_glGetFramebufferAttachmentParameterivOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, attachment: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFramebufferParameterfvAMD"]
+    pub static mut epoxy_glGetFramebufferParameterfvAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            pname: GLenum,
+            numsamples: GLuint,
+            pixelindex: GLuint,
+            size: GLsizei,
+            values: *mut GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFramebufferParameteriv"]
+    pub static mut epoxy_glGetFramebufferParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFramebufferParameterivEXT"]
+    pub static mut epoxy_glGetFramebufferParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(framebuffer: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetFramebufferPixelLocalStorageSizeEXT"]
+    pub static mut epoxy_glGetFramebufferPixelLocalStorageSizeEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLuint) -> GLsizei>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetGraphicsResetStatus"]
+    pub static mut epoxy_glGetGraphicsResetStatus:
+        ::std::option::Option<unsafe extern "C" fn() -> GLenum>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetGraphicsResetStatusARB"]
+    pub static mut epoxy_glGetGraphicsResetStatusARB:
+        ::std::option::Option<unsafe extern "C" fn() -> GLenum>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetGraphicsResetStatusEXT"]
+    pub static mut epoxy_glGetGraphicsResetStatusEXT:
+        ::std::option::Option<unsafe extern "C" fn() -> GLenum>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetGraphicsResetStatusKHR"]
+    pub static mut epoxy_glGetGraphicsResetStatusKHR:
+        ::std::option::Option<unsafe extern "C" fn() -> GLenum>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetHandleARB"]
+    pub static mut epoxy_glGetHandleARB:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum) -> GLhandleARB>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetHistogram"]
+    pub static mut epoxy_glGetHistogram: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            reset: GLboolean,
+            format: GLenum,
+            type_: GLenum,
+            values: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetHistogramEXT"]
+    pub static mut epoxy_glGetHistogramEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            reset: GLboolean,
+            format: GLenum,
+            type_: GLenum,
+            values: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetHistogramParameterfv"]
+    pub static mut epoxy_glGetHistogramParameterfv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetHistogramParameterfvEXT"]
+    pub static mut epoxy_glGetHistogramParameterfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetHistogramParameteriv"]
+    pub static mut epoxy_glGetHistogramParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetHistogramParameterivEXT"]
+    pub static mut epoxy_glGetHistogramParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetHistogramParameterxvOES"]
+    pub static mut epoxy_glGetHistogramParameterxvOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetImageHandleARB"]
+    pub static mut epoxy_glGetImageHandleARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            layered: GLboolean,
+            layer: GLint,
+            format: GLenum,
+        ) -> GLuint64,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetImageHandleNV"]
+    pub static mut epoxy_glGetImageHandleNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            layered: GLboolean,
+            layer: GLint,
+            format: GLenum,
+        ) -> GLuint64,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetImageTransformParameterfvHP"]
+    pub static mut epoxy_glGetImageTransformParameterfvHP: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetImageTransformParameterivHP"]
+    pub static mut epoxy_glGetImageTransformParameterivHP: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetInfoLogARB"]
+    pub static mut epoxy_glGetInfoLogARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            obj: GLhandleARB,
+            maxLength: GLsizei,
+            length: *mut GLsizei,
+            infoLog: *mut GLcharARB,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetInstrumentsSGIX"]
+    pub static mut epoxy_glGetInstrumentsSGIX:
+        ::std::option::Option<unsafe extern "C" fn() -> GLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetInteger64i_v"]
+    pub static mut epoxy_glGetInteger64i_v: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, data: *mut GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetInteger64v"]
+    pub static mut epoxy_glGetInteger64v:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, data: *mut GLint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetInteger64vAPPLE"]
+    pub static mut epoxy_glGetInteger64vAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *mut GLint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetIntegerIndexedvEXT"]
+    pub static mut epoxy_glGetIntegerIndexedvEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, data: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetIntegeri_v"]
+    pub static mut epoxy_glGetIntegeri_v: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, data: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetIntegeri_vEXT"]
+    pub static mut epoxy_glGetIntegeri_vEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, data: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetIntegerui64i_vNV"]
+    pub static mut epoxy_glGetIntegerui64i_vNV: ::std::option::Option<
+        unsafe extern "C" fn(value: GLenum, index: GLuint, result: *mut GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetIntegerui64vNV"]
+    pub static mut epoxy_glGetIntegerui64vNV:
+        ::std::option::Option<unsafe extern "C" fn(value: GLenum, result: *mut GLuint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetIntegerv"]
+    pub static mut epoxy_glGetIntegerv:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, data: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetInternalformatSampleivNV"]
+    pub static mut epoxy_glGetInternalformatSampleivNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            samples: GLsizei,
+            pname: GLenum,
+            bufSize: GLsizei,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetInternalformati64v"]
+    pub static mut epoxy_glGetInternalformati64v: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            pname: GLenum,
+            bufSize: GLsizei,
+            params: *mut GLint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetInternalformativ"]
+    pub static mut epoxy_glGetInternalformativ: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            pname: GLenum,
+            bufSize: GLsizei,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetInvariantBooleanvEXT"]
+    pub static mut epoxy_glGetInvariantBooleanvEXT: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, value: GLenum, data: *mut GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetInvariantFloatvEXT"]
+    pub static mut epoxy_glGetInvariantFloatvEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, value: GLenum, data: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetInvariantIntegervEXT"]
+    pub static mut epoxy_glGetInvariantIntegervEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, value: GLenum, data: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetLightfv"]
+    pub static mut epoxy_glGetLightfv: ::std::option::Option<
+        unsafe extern "C" fn(light: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetLightiv"]
+    pub static mut epoxy_glGetLightiv: ::std::option::Option<
+        unsafe extern "C" fn(light: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetLightxOES"]
+    pub static mut epoxy_glGetLightxOES: ::std::option::Option<
+        unsafe extern "C" fn(light: GLenum, pname: GLenum, params: *mut GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetLightxv"]
+    pub static mut epoxy_glGetLightxv: ::std::option::Option<
+        unsafe extern "C" fn(light: GLenum, pname: GLenum, params: *mut GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetLightxvOES"]
+    pub static mut epoxy_glGetLightxvOES: ::std::option::Option<
+        unsafe extern "C" fn(light: GLenum, pname: GLenum, params: *mut GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetListParameterfvSGIX"]
+    pub static mut epoxy_glGetListParameterfvSGIX: ::std::option::Option<
+        unsafe extern "C" fn(list: GLuint, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetListParameterivSGIX"]
+    pub static mut epoxy_glGetListParameterivSGIX: ::std::option::Option<
+        unsafe extern "C" fn(list: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetLocalConstantBooleanvEXT"]
+    pub static mut epoxy_glGetLocalConstantBooleanvEXT: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, value: GLenum, data: *mut GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetLocalConstantFloatvEXT"]
+    pub static mut epoxy_glGetLocalConstantFloatvEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, value: GLenum, data: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetLocalConstantIntegervEXT"]
+    pub static mut epoxy_glGetLocalConstantIntegervEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, value: GLenum, data: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMapAttribParameterfvNV"]
+    pub static mut epoxy_glGetMapAttribParameterfvNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMapAttribParameterivNV"]
+    pub static mut epoxy_glGetMapAttribParameterivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMapControlPointsNV"]
+    pub static mut epoxy_glGetMapControlPointsNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            index: GLuint,
+            type_: GLenum,
+            ustride: GLsizei,
+            vstride: GLsizei,
+            packed: GLboolean,
+            points: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMapParameterfvNV"]
+    pub static mut epoxy_glGetMapParameterfvNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMapParameterivNV"]
+    pub static mut epoxy_glGetMapParameterivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMapdv"]
+    pub static mut epoxy_glGetMapdv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, query: GLenum, v: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMapfv"]
+    pub static mut epoxy_glGetMapfv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, query: GLenum, v: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMapiv"]
+    pub static mut epoxy_glGetMapiv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, query: GLenum, v: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMapxvOES"]
+    pub static mut epoxy_glGetMapxvOES:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, query: GLenum, v: *mut GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMaterialfv"]
+    pub static mut epoxy_glGetMaterialfv: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMaterialiv"]
+    pub static mut epoxy_glGetMaterialiv: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMaterialxOES"]
+    pub static mut epoxy_glGetMaterialxOES:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMaterialxv"]
+    pub static mut epoxy_glGetMaterialxv: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, pname: GLenum, params: *mut GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMaterialxvOES"]
+    pub static mut epoxy_glGetMaterialxvOES: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, pname: GLenum, params: *mut GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMinmax"]
+    pub static mut epoxy_glGetMinmax: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            reset: GLboolean,
+            format: GLenum,
+            type_: GLenum,
+            values: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMinmaxEXT"]
+    pub static mut epoxy_glGetMinmaxEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            reset: GLboolean,
+            format: GLenum,
+            type_: GLenum,
+            values: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMinmaxParameterfv"]
+    pub static mut epoxy_glGetMinmaxParameterfv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMinmaxParameterfvEXT"]
+    pub static mut epoxy_glGetMinmaxParameterfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMinmaxParameteriv"]
+    pub static mut epoxy_glGetMinmaxParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMinmaxParameterivEXT"]
+    pub static mut epoxy_glGetMinmaxParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMultiTexEnvfvEXT"]
+    pub static mut epoxy_glGetMultiTexEnvfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMultiTexEnvivEXT"]
+    pub static mut epoxy_glGetMultiTexEnvivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMultiTexGendvEXT"]
+    pub static mut epoxy_glGetMultiTexGendvEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, coord: GLenum, pname: GLenum, params: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMultiTexGenfvEXT"]
+    pub static mut epoxy_glGetMultiTexGenfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, coord: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMultiTexGenivEXT"]
+    pub static mut epoxy_glGetMultiTexGenivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, coord: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMultiTexImageEXT"]
+    pub static mut epoxy_glGetMultiTexImageEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMultiTexLevelParameterfvEXT"]
+    pub static mut epoxy_glGetMultiTexLevelParameterfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            pname: GLenum,
+            params: *mut GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMultiTexLevelParameterivEXT"]
+    pub static mut epoxy_glGetMultiTexLevelParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            pname: GLenum,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMultiTexParameterIivEXT"]
+    pub static mut epoxy_glGetMultiTexParameterIivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMultiTexParameterIuivEXT"]
+    pub static mut epoxy_glGetMultiTexParameterIuivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, pname: GLenum, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMultiTexParameterfvEXT"]
+    pub static mut epoxy_glGetMultiTexParameterfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMultiTexParameterivEXT"]
+    pub static mut epoxy_glGetMultiTexParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMultisamplefv"]
+    pub static mut epoxy_glGetMultisamplefv: ::std::option::Option<
+        unsafe extern "C" fn(pname: GLenum, index: GLuint, val: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetMultisamplefvNV"]
+    pub static mut epoxy_glGetMultisamplefvNV: ::std::option::Option<
+        unsafe extern "C" fn(pname: GLenum, index: GLuint, val: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedBufferParameteri64v"]
+    pub static mut epoxy_glGetNamedBufferParameteri64v: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLuint, pname: GLenum, params: *mut GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedBufferParameteriv"]
+    pub static mut epoxy_glGetNamedBufferParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedBufferParameterivEXT"]
+    pub static mut epoxy_glGetNamedBufferParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedBufferParameterui64vNV"]
+    pub static mut epoxy_glGetNamedBufferParameterui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLuint, pname: GLenum, params: *mut GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedBufferPointerv"]
+    pub static mut epoxy_glGetNamedBufferPointerv: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            pname: GLenum,
+            params: *mut *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedBufferPointervEXT"]
+    pub static mut epoxy_glGetNamedBufferPointervEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            pname: GLenum,
+            params: *mut *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedBufferSubData"]
+    pub static mut epoxy_glGetNamedBufferSubData: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            offset: GLintptr,
+            size: GLsizeiptr,
+            data: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedBufferSubDataEXT"]
+    pub static mut epoxy_glGetNamedBufferSubDataEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            offset: GLintptr,
+            size: GLsizeiptr,
+            data: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedFramebufferAttachmentParameteriv"]
+    pub static mut epoxy_glGetNamedFramebufferAttachmentParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            attachment: GLenum,
+            pname: GLenum,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedFramebufferAttachmentParameterivEXT"]
+    pub static mut epoxy_glGetNamedFramebufferAttachmentParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            attachment: GLenum,
+            pname: GLenum,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedFramebufferParameterfvAMD"]
+    pub static mut epoxy_glGetNamedFramebufferParameterfvAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLenum,
+            pname: GLenum,
+            numsamples: GLuint,
+            pixelindex: GLuint,
+            size: GLsizei,
+            values: *mut GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedFramebufferParameteriv"]
+    pub static mut epoxy_glGetNamedFramebufferParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(framebuffer: GLuint, pname: GLenum, param: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedFramebufferParameterivEXT"]
+    pub static mut epoxy_glGetNamedFramebufferParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(framebuffer: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedProgramLocalParameterIivEXT"]
+    pub static mut epoxy_glGetNamedProgramLocalParameterIivEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, target: GLenum, index: GLuint, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedProgramLocalParameterIuivEXT"]
+    pub static mut epoxy_glGetNamedProgramLocalParameterIuivEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, target: GLenum, index: GLuint, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedProgramLocalParameterdvEXT"]
+    pub static mut epoxy_glGetNamedProgramLocalParameterdvEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, target: GLenum, index: GLuint, params: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedProgramLocalParameterfvEXT"]
+    pub static mut epoxy_glGetNamedProgramLocalParameterfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, target: GLenum, index: GLuint, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedProgramStringEXT"]
+    pub static mut epoxy_glGetNamedProgramStringEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            target: GLenum,
+            pname: GLenum,
+            string: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedProgramivEXT"]
+    pub static mut epoxy_glGetNamedProgramivEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedRenderbufferParameteriv"]
+    pub static mut epoxy_glGetNamedRenderbufferParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(renderbuffer: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedRenderbufferParameterivEXT"]
+    pub static mut epoxy_glGetNamedRenderbufferParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(renderbuffer: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedStringARB"]
+    pub static mut epoxy_glGetNamedStringARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            namelen: GLint,
+            name: *const GLchar,
+            bufSize: GLsizei,
+            stringlen: *mut GLint,
+            string: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNamedStringivARB"]
+    pub static mut epoxy_glGetNamedStringivARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            namelen: GLint,
+            name: *const GLchar,
+            pname: GLenum,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetNextPerfQueryIdINTEL"]
+    pub static mut epoxy_glGetNextPerfQueryIdINTEL:
+        ::std::option::Option<unsafe extern "C" fn(queryId: GLuint, nextQueryId: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetObjectBufferfvATI"]
+    pub static mut epoxy_glGetObjectBufferfvATI: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLuint, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetObjectBufferivATI"]
+    pub static mut epoxy_glGetObjectBufferivATI: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetObjectLabel"]
+    pub static mut epoxy_glGetObjectLabel: ::std::option::Option<
+        unsafe extern "C" fn(
+            identifier: GLenum,
+            name: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            label: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetObjectLabelEXT"]
+    pub static mut epoxy_glGetObjectLabelEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            object: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            label: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetObjectLabelKHR"]
+    pub static mut epoxy_glGetObjectLabelKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            identifier: GLenum,
+            name: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            label: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetObjectParameterfvARB"]
+    pub static mut epoxy_glGetObjectParameterfvARB: ::std::option::Option<
+        unsafe extern "C" fn(obj: GLhandleARB, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetObjectParameterivAPPLE"]
+    pub static mut epoxy_glGetObjectParameterivAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(objectType: GLenum, name: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetObjectParameterivARB"]
+    pub static mut epoxy_glGetObjectParameterivARB: ::std::option::Option<
+        unsafe extern "C" fn(obj: GLhandleARB, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetObjectPtrLabel"]
+    pub static mut epoxy_glGetObjectPtrLabel: ::std::option::Option<
+        unsafe extern "C" fn(
+            ptr: *const ::std::os::raw::c_void,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            label: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetObjectPtrLabelKHR"]
+    pub static mut epoxy_glGetObjectPtrLabelKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            ptr: *const ::std::os::raw::c_void,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            label: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetOcclusionQueryivNV"]
+    pub static mut epoxy_glGetOcclusionQueryivNV:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetOcclusionQueryuivNV"]
+    pub static mut epoxy_glGetOcclusionQueryuivNV:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPathColorGenfvNV"]
+    pub static mut epoxy_glGetPathColorGenfvNV: ::std::option::Option<
+        unsafe extern "C" fn(color: GLenum, pname: GLenum, value: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPathColorGenivNV"]
+    pub static mut epoxy_glGetPathColorGenivNV: ::std::option::Option<
+        unsafe extern "C" fn(color: GLenum, pname: GLenum, value: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPathCommandsNV"]
+    pub static mut epoxy_glGetPathCommandsNV:
+        ::std::option::Option<unsafe extern "C" fn(path: GLuint, commands: *mut GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPathCoordsNV"]
+    pub static mut epoxy_glGetPathCoordsNV:
+        ::std::option::Option<unsafe extern "C" fn(path: GLuint, coords: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPathDashArrayNV"]
+    pub static mut epoxy_glGetPathDashArrayNV:
+        ::std::option::Option<unsafe extern "C" fn(path: GLuint, dashArray: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPathLengthNV"]
+    pub static mut epoxy_glGetPathLengthNV: ::std::option::Option<
+        unsafe extern "C" fn(path: GLuint, startSegment: GLsizei, numSegments: GLsizei) -> GLfloat,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPathMetricRangeNV"]
+    pub static mut epoxy_glGetPathMetricRangeNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            metricQueryMask: GLbitfield,
+            firstPathName: GLuint,
+            numPaths: GLsizei,
+            stride: GLsizei,
+            metrics: *mut GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPathMetricsNV"]
+    pub static mut epoxy_glGetPathMetricsNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            metricQueryMask: GLbitfield,
+            numPaths: GLsizei,
+            pathNameType: GLenum,
+            paths: *const ::std::os::raw::c_void,
+            pathBase: GLuint,
+            stride: GLsizei,
+            metrics: *mut GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPathParameterfvNV"]
+    pub static mut epoxy_glGetPathParameterfvNV: ::std::option::Option<
+        unsafe extern "C" fn(path: GLuint, pname: GLenum, value: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPathParameterivNV"]
+    pub static mut epoxy_glGetPathParameterivNV:
+        ::std::option::Option<unsafe extern "C" fn(path: GLuint, pname: GLenum, value: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPathSpacingNV"]
+    pub static mut epoxy_glGetPathSpacingNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            pathListMode: GLenum,
+            numPaths: GLsizei,
+            pathNameType: GLenum,
+            paths: *const ::std::os::raw::c_void,
+            pathBase: GLuint,
+            advanceScale: GLfloat,
+            kerningScale: GLfloat,
+            transformType: GLenum,
+            returnedSpacing: *mut GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPathTexGenfvNV"]
+    pub static mut epoxy_glGetPathTexGenfvNV: ::std::option::Option<
+        unsafe extern "C" fn(texCoordSet: GLenum, pname: GLenum, value: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPathTexGenivNV"]
+    pub static mut epoxy_glGetPathTexGenivNV: ::std::option::Option<
+        unsafe extern "C" fn(texCoordSet: GLenum, pname: GLenum, value: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPerfCounterInfoINTEL"]
+    pub static mut epoxy_glGetPerfCounterInfoINTEL: ::std::option::Option<
+        unsafe extern "C" fn(
+            queryId: GLuint,
+            counterId: GLuint,
+            counterNameLength: GLuint,
+            counterName: *mut GLchar,
+            counterDescLength: GLuint,
+            counterDesc: *mut GLchar,
+            counterOffset: *mut GLuint,
+            counterDataSize: *mut GLuint,
+            counterTypeEnum: *mut GLuint,
+            counterDataTypeEnum: *mut GLuint,
+            rawCounterMaxValue: *mut GLuint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPerfMonitorCounterDataAMD"]
+    pub static mut epoxy_glGetPerfMonitorCounterDataAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            monitor: GLuint,
+            pname: GLenum,
+            dataSize: GLsizei,
+            data: *mut GLuint,
+            bytesWritten: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPerfMonitorCounterInfoAMD"]
+    pub static mut epoxy_glGetPerfMonitorCounterInfoAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            group: GLuint,
+            counter: GLuint,
+            pname: GLenum,
+            data: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPerfMonitorCounterStringAMD"]
+    pub static mut epoxy_glGetPerfMonitorCounterStringAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            group: GLuint,
+            counter: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            counterString: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPerfMonitorCountersAMD"]
+    pub static mut epoxy_glGetPerfMonitorCountersAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            group: GLuint,
+            numCounters: *mut GLint,
+            maxActiveCounters: *mut GLint,
+            counterSize: GLsizei,
+            counters: *mut GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPerfMonitorGroupStringAMD"]
+    pub static mut epoxy_glGetPerfMonitorGroupStringAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            group: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            groupString: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPerfMonitorGroupsAMD"]
+    pub static mut epoxy_glGetPerfMonitorGroupsAMD: ::std::option::Option<
+        unsafe extern "C" fn(numGroups: *mut GLint, groupsSize: GLsizei, groups: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPerfQueryDataINTEL"]
+    pub static mut epoxy_glGetPerfQueryDataINTEL: ::std::option::Option<
+        unsafe extern "C" fn(
+            queryHandle: GLuint,
+            flags: GLuint,
+            dataSize: GLsizei,
+            data: *mut GLvoid,
+            bytesWritten: *mut GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPerfQueryIdByNameINTEL"]
+    pub static mut epoxy_glGetPerfQueryIdByNameINTEL:
+        ::std::option::Option<unsafe extern "C" fn(queryName: *mut GLchar, queryId: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPerfQueryInfoINTEL"]
+    pub static mut epoxy_glGetPerfQueryInfoINTEL: ::std::option::Option<
+        unsafe extern "C" fn(
+            queryId: GLuint,
+            queryNameLength: GLuint,
+            queryName: *mut GLchar,
+            dataSize: *mut GLuint,
+            noCounters: *mut GLuint,
+            noInstances: *mut GLuint,
+            capsMask: *mut GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPixelMapfv"]
+    pub static mut epoxy_glGetPixelMapfv:
+        ::std::option::Option<unsafe extern "C" fn(map: GLenum, values: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPixelMapuiv"]
+    pub static mut epoxy_glGetPixelMapuiv:
+        ::std::option::Option<unsafe extern "C" fn(map: GLenum, values: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPixelMapusv"]
+    pub static mut epoxy_glGetPixelMapusv:
+        ::std::option::Option<unsafe extern "C" fn(map: GLenum, values: *mut GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPixelMapxv"]
+    pub static mut epoxy_glGetPixelMapxv:
+        ::std::option::Option<unsafe extern "C" fn(map: GLenum, size: GLint, values: *mut GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPixelTexGenParameterfvSGIS"]
+    pub static mut epoxy_glGetPixelTexGenParameterfvSGIS:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPixelTexGenParameterivSGIS"]
+    pub static mut epoxy_glGetPixelTexGenParameterivSGIS:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPixelTransformParameterfvEXT"]
+    pub static mut epoxy_glGetPixelTransformParameterfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPixelTransformParameterivEXT"]
+    pub static mut epoxy_glGetPixelTransformParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPointerIndexedvEXT"]
+    pub static mut epoxy_glGetPointerIndexedvEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, data: *mut *mut ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPointeri_vEXT"]
+    pub static mut epoxy_glGetPointeri_vEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            pname: GLenum,
+            index: GLuint,
+            params: *mut *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPointerv"]
+    pub static mut epoxy_glGetPointerv: ::std::option::Option<
+        unsafe extern "C" fn(pname: GLenum, params: *mut *mut ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPointervEXT"]
+    pub static mut epoxy_glGetPointervEXT: ::std::option::Option<
+        unsafe extern "C" fn(pname: GLenum, params: *mut *mut ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPointervKHR"]
+    pub static mut epoxy_glGetPointervKHR: ::std::option::Option<
+        unsafe extern "C" fn(pname: GLenum, params: *mut *mut ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetPolygonStipple"]
+    pub static mut epoxy_glGetPolygonStipple:
+        ::std::option::Option<unsafe extern "C" fn(mask: *mut GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramBinary"]
+    pub static mut epoxy_glGetProgramBinary: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            binaryFormat: *mut GLenum,
+            binary: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramBinaryOES"]
+    pub static mut epoxy_glGetProgramBinaryOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            binaryFormat: *mut GLenum,
+            binary: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramEnvParameterIivNV"]
+    pub static mut epoxy_glGetProgramEnvParameterIivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramEnvParameterIuivNV"]
+    pub static mut epoxy_glGetProgramEnvParameterIuivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramEnvParameterdvARB"]
+    pub static mut epoxy_glGetProgramEnvParameterdvARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramEnvParameterfvARB"]
+    pub static mut epoxy_glGetProgramEnvParameterfvARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramInfoLog"]
+    pub static mut epoxy_glGetProgramInfoLog: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            infoLog: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramInterfaceiv"]
+    pub static mut epoxy_glGetProgramInterfaceiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            programInterface: GLenum,
+            pname: GLenum,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramLocalParameterIivNV"]
+    pub static mut epoxy_glGetProgramLocalParameterIivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramLocalParameterIuivNV"]
+    pub static mut epoxy_glGetProgramLocalParameterIuivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramLocalParameterdvARB"]
+    pub static mut epoxy_glGetProgramLocalParameterdvARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramLocalParameterfvARB"]
+    pub static mut epoxy_glGetProgramLocalParameterfvARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramNamedParameterdvNV"]
+    pub static mut epoxy_glGetProgramNamedParameterdvNV: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, len: GLsizei, name: *const GLubyte, params: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramNamedParameterfvNV"]
+    pub static mut epoxy_glGetProgramNamedParameterfvNV: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, len: GLsizei, name: *const GLubyte, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramParameterdvNV"]
+    pub static mut epoxy_glGetProgramParameterdvNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, pname: GLenum, params: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramParameterfvNV"]
+    pub static mut epoxy_glGetProgramParameterfvNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramPipelineInfoLog"]
+    pub static mut epoxy_glGetProgramPipelineInfoLog: ::std::option::Option<
+        unsafe extern "C" fn(
+            pipeline: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            infoLog: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramPipelineInfoLogEXT"]
+    pub static mut epoxy_glGetProgramPipelineInfoLogEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            pipeline: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            infoLog: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramPipelineiv"]
+    pub static mut epoxy_glGetProgramPipelineiv: ::std::option::Option<
+        unsafe extern "C" fn(pipeline: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramPipelineivEXT"]
+    pub static mut epoxy_glGetProgramPipelineivEXT: ::std::option::Option<
+        unsafe extern "C" fn(pipeline: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramResourceIndex"]
+    pub static mut epoxy_glGetProgramResourceIndex: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            programInterface: GLenum,
+            name: *const GLchar,
+        ) -> GLuint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramResourceLocation"]
+    pub static mut epoxy_glGetProgramResourceLocation: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            programInterface: GLenum,
+            name: *const GLchar,
+        ) -> GLint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramResourceLocationIndex"]
+    pub static mut epoxy_glGetProgramResourceLocationIndex: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            programInterface: GLenum,
+            name: *const GLchar,
+        ) -> GLint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramResourceLocationIndexEXT"]
+    pub static mut epoxy_glGetProgramResourceLocationIndexEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            programInterface: GLenum,
+            name: *const GLchar,
+        ) -> GLint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramResourceName"]
+    pub static mut epoxy_glGetProgramResourceName: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            programInterface: GLenum,
+            index: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            name: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramResourcefvNV"]
+    pub static mut epoxy_glGetProgramResourcefvNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            programInterface: GLenum,
+            index: GLuint,
+            propCount: GLsizei,
+            props: *const GLenum,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            params: *mut GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramResourceiv"]
+    pub static mut epoxy_glGetProgramResourceiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            programInterface: GLenum,
+            index: GLuint,
+            propCount: GLsizei,
+            props: *const GLenum,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramStageiv"]
+    pub static mut epoxy_glGetProgramStageiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            shadertype: GLenum,
+            pname: GLenum,
+            values: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramStringARB"]
+    pub static mut epoxy_glGetProgramStringARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, string: *mut ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramStringNV"]
+    pub static mut epoxy_glGetProgramStringNV: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, pname: GLenum, program: *mut GLubyte),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramSubroutineParameteruivNV"]
+    pub static mut epoxy_glGetProgramSubroutineParameteruivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, param: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramiv"]
+    pub static mut epoxy_glGetProgramiv: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramivARB"]
+    pub static mut epoxy_glGetProgramivARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetProgramivNV"]
+    pub static mut epoxy_glGetProgramivNV:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryBufferObjecti64v"]
+    pub static mut epoxy_glGetQueryBufferObjecti64v: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, buffer: GLuint, pname: GLenum, offset: GLintptr),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryBufferObjectiv"]
+    pub static mut epoxy_glGetQueryBufferObjectiv: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, buffer: GLuint, pname: GLenum, offset: GLintptr),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryBufferObjectui64v"]
+    pub static mut epoxy_glGetQueryBufferObjectui64v: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, buffer: GLuint, pname: GLenum, offset: GLintptr),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryBufferObjectuiv"]
+    pub static mut epoxy_glGetQueryBufferObjectuiv: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, buffer: GLuint, pname: GLenum, offset: GLintptr),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryIndexediv"]
+    pub static mut epoxy_glGetQueryIndexediv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryObjecti64v"]
+    pub static mut epoxy_glGetQueryObjecti64v: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryObjecti64vEXT"]
+    pub static mut epoxy_glGetQueryObjecti64vEXT: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryObjectiv"]
+    pub static mut epoxy_glGetQueryObjectiv:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryObjectivARB"]
+    pub static mut epoxy_glGetQueryObjectivARB:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryObjectivEXT"]
+    pub static mut epoxy_glGetQueryObjectivEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryObjectui64v"]
+    pub static mut epoxy_glGetQueryObjectui64v: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryObjectui64vEXT"]
+    pub static mut epoxy_glGetQueryObjectui64vEXT: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryObjectuiv"]
+    pub static mut epoxy_glGetQueryObjectuiv:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryObjectuivARB"]
+    pub static mut epoxy_glGetQueryObjectuivARB:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryObjectuivEXT"]
+    pub static mut epoxy_glGetQueryObjectuivEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryiv"]
+    pub static mut epoxy_glGetQueryiv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryivARB"]
+    pub static mut epoxy_glGetQueryivARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetQueryivEXT"]
+    pub static mut epoxy_glGetQueryivEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetRenderbufferParameteriv"]
+    pub static mut epoxy_glGetRenderbufferParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetRenderbufferParameterivEXT"]
+    pub static mut epoxy_glGetRenderbufferParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetRenderbufferParameterivOES"]
+    pub static mut epoxy_glGetRenderbufferParameterivOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSamplerParameterIiv"]
+    pub static mut epoxy_glGetSamplerParameterIiv: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSamplerParameterIivEXT"]
+    pub static mut epoxy_glGetSamplerParameterIivEXT: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSamplerParameterIivOES"]
+    pub static mut epoxy_glGetSamplerParameterIivOES: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSamplerParameterIuiv"]
+    pub static mut epoxy_glGetSamplerParameterIuiv: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSamplerParameterIuivEXT"]
+    pub static mut epoxy_glGetSamplerParameterIuivEXT: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSamplerParameterIuivOES"]
+    pub static mut epoxy_glGetSamplerParameterIuivOES: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSamplerParameterfv"]
+    pub static mut epoxy_glGetSamplerParameterfv: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSamplerParameteriv"]
+    pub static mut epoxy_glGetSamplerParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSeparableFilter"]
+    pub static mut epoxy_glGetSeparableFilter: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            row: *mut ::std::os::raw::c_void,
+            column: *mut ::std::os::raw::c_void,
+            span: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSeparableFilterEXT"]
+    pub static mut epoxy_glGetSeparableFilterEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            row: *mut ::std::os::raw::c_void,
+            column: *mut ::std::os::raw::c_void,
+            span: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetShaderInfoLog"]
+    pub static mut epoxy_glGetShaderInfoLog: ::std::option::Option<
+        unsafe extern "C" fn(
+            shader: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            infoLog: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetShaderPrecisionFormat"]
+    pub static mut epoxy_glGetShaderPrecisionFormat: ::std::option::Option<
+        unsafe extern "C" fn(
+            shadertype: GLenum,
+            precisiontype: GLenum,
+            range: *mut GLint,
+            precision: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetShaderSource"]
+    pub static mut epoxy_glGetShaderSource: ::std::option::Option<
+        unsafe extern "C" fn(
+            shader: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            source: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetShaderSourceARB"]
+    pub static mut epoxy_glGetShaderSourceARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            obj: GLhandleARB,
+            maxLength: GLsizei,
+            length: *mut GLsizei,
+            source: *mut GLcharARB,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetShaderiv"]
+    pub static mut epoxy_glGetShaderiv: ::std::option::Option<
+        unsafe extern "C" fn(shader: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSharpenTexFuncSGIS"]
+    pub static mut epoxy_glGetSharpenTexFuncSGIS:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, points: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetStageIndexNV"]
+    pub static mut epoxy_glGetStageIndexNV:
+        ::std::option::Option<unsafe extern "C" fn(shadertype: GLenum) -> GLushort>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetString"]
+    pub static mut epoxy_glGetString:
+        ::std::option::Option<unsafe extern "C" fn(name: GLenum) -> *const GLubyte>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetStringi"]
+    pub static mut epoxy_glGetStringi:
+        ::std::option::Option<unsafe extern "C" fn(name: GLenum, index: GLuint) -> *const GLubyte>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSubroutineIndex"]
+    pub static mut epoxy_glGetSubroutineIndex: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, shadertype: GLenum, name: *const GLchar) -> GLuint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSubroutineUniformLocation"]
+    pub static mut epoxy_glGetSubroutineUniformLocation: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, shadertype: GLenum, name: *const GLchar) -> GLint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSynciv"]
+    pub static mut epoxy_glGetSynciv: ::std::option::Option<
+        unsafe extern "C" fn(
+            sync: GLsync,
+            pname: GLenum,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            values: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetSyncivAPPLE"]
+    pub static mut epoxy_glGetSyncivAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            sync: GLsync,
+            pname: GLenum,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            values: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexBumpParameterfvATI"]
+    pub static mut epoxy_glGetTexBumpParameterfvATI:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexBumpParameterivATI"]
+    pub static mut epoxy_glGetTexBumpParameterivATI:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexEnvfv"]
+    pub static mut epoxy_glGetTexEnvfv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexEnviv"]
+    pub static mut epoxy_glGetTexEnviv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexEnvxv"]
+    pub static mut epoxy_glGetTexEnvxv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexEnvxvOES"]
+    pub static mut epoxy_glGetTexEnvxvOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexFilterFuncSGIS"]
+    pub static mut epoxy_glGetTexFilterFuncSGIS: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, filter: GLenum, weights: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexGendv"]
+    pub static mut epoxy_glGetTexGendv: ::std::option::Option<
+        unsafe extern "C" fn(coord: GLenum, pname: GLenum, params: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexGenfv"]
+    pub static mut epoxy_glGetTexGenfv: ::std::option::Option<
+        unsafe extern "C" fn(coord: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexGenfvOES"]
+    pub static mut epoxy_glGetTexGenfvOES: ::std::option::Option<
+        unsafe extern "C" fn(coord: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexGeniv"]
+    pub static mut epoxy_glGetTexGeniv: ::std::option::Option<
+        unsafe extern "C" fn(coord: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexGenivOES"]
+    pub static mut epoxy_glGetTexGenivOES: ::std::option::Option<
+        unsafe extern "C" fn(coord: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexGenxvOES"]
+    pub static mut epoxy_glGetTexGenxvOES: ::std::option::Option<
+        unsafe extern "C" fn(coord: GLenum, pname: GLenum, params: *mut GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexImage"]
+    pub static mut epoxy_glGetTexImage: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexLevelParameterfv"]
+    pub static mut epoxy_glGetTexLevelParameterfv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, level: GLint, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexLevelParameteriv"]
+    pub static mut epoxy_glGetTexLevelParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, level: GLint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexLevelParameterxvOES"]
+    pub static mut epoxy_glGetTexLevelParameterxvOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, level: GLint, pname: GLenum, params: *mut GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexParameterIiv"]
+    pub static mut epoxy_glGetTexParameterIiv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexParameterIivEXT"]
+    pub static mut epoxy_glGetTexParameterIivEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexParameterIivOES"]
+    pub static mut epoxy_glGetTexParameterIivOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexParameterIuiv"]
+    pub static mut epoxy_glGetTexParameterIuiv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexParameterIuivEXT"]
+    pub static mut epoxy_glGetTexParameterIuivEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexParameterIuivOES"]
+    pub static mut epoxy_glGetTexParameterIuivOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexParameterPointervAPPLE"]
+    pub static mut epoxy_glGetTexParameterPointervAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            pname: GLenum,
+            params: *mut *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexParameterfv"]
+    pub static mut epoxy_glGetTexParameterfv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexParameteriv"]
+    pub static mut epoxy_glGetTexParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexParameterxv"]
+    pub static mut epoxy_glGetTexParameterxv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTexParameterxvOES"]
+    pub static mut epoxy_glGetTexParameterxvOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *mut GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureHandleARB"]
+    pub static mut epoxy_glGetTextureHandleARB:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint) -> GLuint64>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureHandleIMG"]
+    pub static mut epoxy_glGetTextureHandleIMG:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint) -> GLuint64>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureHandleNV"]
+    pub static mut epoxy_glGetTextureHandleNV:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint) -> GLuint64>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureImage"]
+    pub static mut epoxy_glGetTextureImage: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            pixels: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureImageEXT"]
+    pub static mut epoxy_glGetTextureImageEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureLevelParameterfv"]
+    pub static mut epoxy_glGetTextureLevelParameterfv: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, level: GLint, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureLevelParameterfvEXT"]
+    pub static mut epoxy_glGetTextureLevelParameterfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            pname: GLenum,
+            params: *mut GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureLevelParameteriv"]
+    pub static mut epoxy_glGetTextureLevelParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, level: GLint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureLevelParameterivEXT"]
+    pub static mut epoxy_glGetTextureLevelParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            pname: GLenum,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureParameterIiv"]
+    pub static mut epoxy_glGetTextureParameterIiv: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureParameterIivEXT"]
+    pub static mut epoxy_glGetTextureParameterIivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureParameterIuiv"]
+    pub static mut epoxy_glGetTextureParameterIuiv: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, pname: GLenum, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureParameterIuivEXT"]
+    pub static mut epoxy_glGetTextureParameterIuivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, target: GLenum, pname: GLenum, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureParameterfv"]
+    pub static mut epoxy_glGetTextureParameterfv: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureParameterfvEXT"]
+    pub static mut epoxy_glGetTextureParameterfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, target: GLenum, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureParameteriv"]
+    pub static mut epoxy_glGetTextureParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureParameterivEXT"]
+    pub static mut epoxy_glGetTextureParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, target: GLenum, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureSamplerHandleARB"]
+    pub static mut epoxy_glGetTextureSamplerHandleARB:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint, sampler: GLuint) -> GLuint64>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureSamplerHandleIMG"]
+    pub static mut epoxy_glGetTextureSamplerHandleIMG:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint, sampler: GLuint) -> GLuint64>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureSamplerHandleNV"]
+    pub static mut epoxy_glGetTextureSamplerHandleNV:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint, sampler: GLuint) -> GLuint64>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTextureSubImage"]
+    pub static mut epoxy_glGetTextureSubImage: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            pixels: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTrackMatrixivNV"]
+    pub static mut epoxy_glGetTrackMatrixivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, address: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTransformFeedbackVarying"]
+    pub static mut epoxy_glGetTransformFeedbackVarying: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            index: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            size: *mut GLsizei,
+            type_: *mut GLenum,
+            name: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTransformFeedbackVaryingEXT"]
+    pub static mut epoxy_glGetTransformFeedbackVaryingEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            index: GLuint,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            size: *mut GLsizei,
+            type_: *mut GLenum,
+            name: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTransformFeedbackVaryingNV"]
+    pub static mut epoxy_glGetTransformFeedbackVaryingNV: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, index: GLuint, location: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTransformFeedbacki64_v"]
+    pub static mut epoxy_glGetTransformFeedbacki64_v: ::std::option::Option<
+        unsafe extern "C" fn(xfb: GLuint, pname: GLenum, index: GLuint, param: *mut GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTransformFeedbacki_v"]
+    pub static mut epoxy_glGetTransformFeedbacki_v: ::std::option::Option<
+        unsafe extern "C" fn(xfb: GLuint, pname: GLenum, index: GLuint, param: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTransformFeedbackiv"]
+    pub static mut epoxy_glGetTransformFeedbackiv:
+        ::std::option::Option<unsafe extern "C" fn(xfb: GLuint, pname: GLenum, param: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetTranslatedShaderSourceANGLE"]
+    pub static mut epoxy_glGetTranslatedShaderSourceANGLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            shader: GLuint,
+            bufsize: GLsizei,
+            length: *mut GLsizei,
+            source: *mut GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformBlockIndex"]
+    pub static mut epoxy_glGetUniformBlockIndex: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, uniformBlockName: *const GLchar) -> GLuint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformBufferSizeEXT"]
+    pub static mut epoxy_glGetUniformBufferSizeEXT:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, location: GLint) -> GLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformIndices"]
+    pub static mut epoxy_glGetUniformIndices: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            uniformCount: GLsizei,
+            uniformNames: *const *const GLchar,
+            uniformIndices: *mut GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformLocation"]
+    pub static mut epoxy_glGetUniformLocation:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, name: *const GLchar) -> GLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformLocationARB"]
+    pub static mut epoxy_glGetUniformLocationARB: ::std::option::Option<
+        unsafe extern "C" fn(programObj: GLhandleARB, name: *const GLcharARB) -> GLint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformOffsetEXT"]
+    pub static mut epoxy_glGetUniformOffsetEXT:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, location: GLint) -> GLintptr>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformSubroutineuiv"]
+    pub static mut epoxy_glGetUniformSubroutineuiv: ::std::option::Option<
+        unsafe extern "C" fn(shadertype: GLenum, location: GLint, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformdv"]
+    pub static mut epoxy_glGetUniformdv: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, params: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformfv"]
+    pub static mut epoxy_glGetUniformfv: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformfvARB"]
+    pub static mut epoxy_glGetUniformfvARB: ::std::option::Option<
+        unsafe extern "C" fn(programObj: GLhandleARB, location: GLint, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformi64vARB"]
+    pub static mut epoxy_glGetUniformi64vARB: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, params: *mut GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformi64vNV"]
+    pub static mut epoxy_glGetUniformi64vNV: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, params: *mut GLint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformiv"]
+    pub static mut epoxy_glGetUniformiv: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformivARB"]
+    pub static mut epoxy_glGetUniformivARB: ::std::option::Option<
+        unsafe extern "C" fn(programObj: GLhandleARB, location: GLint, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformui64vARB"]
+    pub static mut epoxy_glGetUniformui64vARB: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, params: *mut GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformui64vNV"]
+    pub static mut epoxy_glGetUniformui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, params: *mut GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformuiv"]
+    pub static mut epoxy_glGetUniformuiv: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetUniformuivEXT"]
+    pub static mut epoxy_glGetUniformuivEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVariantArrayObjectfvATI"]
+    pub static mut epoxy_glGetVariantArrayObjectfvATI: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVariantArrayObjectivATI"]
+    pub static mut epoxy_glGetVariantArrayObjectivATI:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, pname: GLenum, params: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVariantBooleanvEXT"]
+    pub static mut epoxy_glGetVariantBooleanvEXT: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, value: GLenum, data: *mut GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVariantFloatvEXT"]
+    pub static mut epoxy_glGetVariantFloatvEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, value: GLenum, data: *mut GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVariantIntegervEXT"]
+    pub static mut epoxy_glGetVariantIntegervEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, value: GLenum, data: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVariantPointervEXT"]
+    pub static mut epoxy_glGetVariantPointervEXT: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, value: GLenum, data: *mut *mut ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVaryingLocationNV"]
+    pub static mut epoxy_glGetVaryingLocationNV:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, name: *const GLchar) -> GLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexArrayIndexed64iv"]
+    pub static mut epoxy_glGetVertexArrayIndexed64iv: ::std::option::Option<
+        unsafe extern "C" fn(vaobj: GLuint, index: GLuint, pname: GLenum, param: *mut GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexArrayIndexediv"]
+    pub static mut epoxy_glGetVertexArrayIndexediv: ::std::option::Option<
+        unsafe extern "C" fn(vaobj: GLuint, index: GLuint, pname: GLenum, param: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexArrayIntegeri_vEXT"]
+    pub static mut epoxy_glGetVertexArrayIntegeri_vEXT: ::std::option::Option<
+        unsafe extern "C" fn(vaobj: GLuint, index: GLuint, pname: GLenum, param: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexArrayIntegervEXT"]
+    pub static mut epoxy_glGetVertexArrayIntegervEXT: ::std::option::Option<
+        unsafe extern "C" fn(vaobj: GLuint, pname: GLenum, param: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexArrayPointeri_vEXT"]
+    pub static mut epoxy_glGetVertexArrayPointeri_vEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            index: GLuint,
+            pname: GLenum,
+            param: *mut *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexArrayPointervEXT"]
+    pub static mut epoxy_glGetVertexArrayPointervEXT: ::std::option::Option<
+        unsafe extern "C" fn(vaobj: GLuint, pname: GLenum, param: *mut *mut ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexArrayiv"]
+    pub static mut epoxy_glGetVertexArrayiv: ::std::option::Option<
+        unsafe extern "C" fn(vaobj: GLuint, pname: GLenum, param: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribArrayObjectfvATI"]
+    pub static mut epoxy_glGetVertexAttribArrayObjectfvATI: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribArrayObjectivATI"]
+    pub static mut epoxy_glGetVertexAttribArrayObjectivATI: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribIiv"]
+    pub static mut epoxy_glGetVertexAttribIiv: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribIivEXT"]
+    pub static mut epoxy_glGetVertexAttribIivEXT: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribIuiv"]
+    pub static mut epoxy_glGetVertexAttribIuiv: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribIuivEXT"]
+    pub static mut epoxy_glGetVertexAttribIuivEXT: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribLdv"]
+    pub static mut epoxy_glGetVertexAttribLdv: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribLdvEXT"]
+    pub static mut epoxy_glGetVertexAttribLdvEXT: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribLi64vNV"]
+    pub static mut epoxy_glGetVertexAttribLi64vNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribLui64vARB"]
+    pub static mut epoxy_glGetVertexAttribLui64vARB: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribLui64vNV"]
+    pub static mut epoxy_glGetVertexAttribLui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribPointerv"]
+    pub static mut epoxy_glGetVertexAttribPointerv: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            pname: GLenum,
+            pointer: *mut *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribPointervARB"]
+    pub static mut epoxy_glGetVertexAttribPointervARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            pname: GLenum,
+            pointer: *mut *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribPointervNV"]
+    pub static mut epoxy_glGetVertexAttribPointervNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            pname: GLenum,
+            pointer: *mut *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribdv"]
+    pub static mut epoxy_glGetVertexAttribdv: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribdvARB"]
+    pub static mut epoxy_glGetVertexAttribdvARB: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribdvNV"]
+    pub static mut epoxy_glGetVertexAttribdvNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribfv"]
+    pub static mut epoxy_glGetVertexAttribfv: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribfvARB"]
+    pub static mut epoxy_glGetVertexAttribfvARB: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribfvNV"]
+    pub static mut epoxy_glGetVertexAttribfvNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribiv"]
+    pub static mut epoxy_glGetVertexAttribiv: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribivARB"]
+    pub static mut epoxy_glGetVertexAttribivARB: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVertexAttribivNV"]
+    pub static mut epoxy_glGetVertexAttribivNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVideoCaptureStreamdvNV"]
+    pub static mut epoxy_glGetVideoCaptureStreamdvNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            video_capture_slot: GLuint,
+            stream: GLuint,
+            pname: GLenum,
+            params: *mut GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVideoCaptureStreamfvNV"]
+    pub static mut epoxy_glGetVideoCaptureStreamfvNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            video_capture_slot: GLuint,
+            stream: GLuint,
+            pname: GLenum,
+            params: *mut GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVideoCaptureStreamivNV"]
+    pub static mut epoxy_glGetVideoCaptureStreamivNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            video_capture_slot: GLuint,
+            stream: GLuint,
+            pname: GLenum,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVideoCaptureivNV"]
+    pub static mut epoxy_glGetVideoCaptureivNV: ::std::option::Option<
+        unsafe extern "C" fn(video_capture_slot: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVideoi64vNV"]
+    pub static mut epoxy_glGetVideoi64vNV: ::std::option::Option<
+        unsafe extern "C" fn(video_slot: GLuint, pname: GLenum, params: *mut GLint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVideoivNV"]
+    pub static mut epoxy_glGetVideoivNV: ::std::option::Option<
+        unsafe extern "C" fn(video_slot: GLuint, pname: GLenum, params: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVideoui64vNV"]
+    pub static mut epoxy_glGetVideoui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(video_slot: GLuint, pname: GLenum, params: *mut GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetVideouivNV"]
+    pub static mut epoxy_glGetVideouivNV: ::std::option::Option<
+        unsafe extern "C" fn(video_slot: GLuint, pname: GLenum, params: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnColorTable"]
+    pub static mut epoxy_glGetnColorTable: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            table: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnColorTableARB"]
+    pub static mut epoxy_glGetnColorTableARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            table: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnCompressedTexImage"]
+    pub static mut epoxy_glGetnCompressedTexImage: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            lod: GLint,
+            bufSize: GLsizei,
+            pixels: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnCompressedTexImageARB"]
+    pub static mut epoxy_glGetnCompressedTexImageARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            lod: GLint,
+            bufSize: GLsizei,
+            img: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnConvolutionFilter"]
+    pub static mut epoxy_glGetnConvolutionFilter: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            image: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnConvolutionFilterARB"]
+    pub static mut epoxy_glGetnConvolutionFilterARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            image: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnHistogram"]
+    pub static mut epoxy_glGetnHistogram: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            reset: GLboolean,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            values: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnHistogramARB"]
+    pub static mut epoxy_glGetnHistogramARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            reset: GLboolean,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            values: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnMapdv"]
+    pub static mut epoxy_glGetnMapdv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, query: GLenum, bufSize: GLsizei, v: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnMapdvARB"]
+    pub static mut epoxy_glGetnMapdvARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, query: GLenum, bufSize: GLsizei, v: *mut GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnMapfv"]
+    pub static mut epoxy_glGetnMapfv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, query: GLenum, bufSize: GLsizei, v: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnMapfvARB"]
+    pub static mut epoxy_glGetnMapfvARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, query: GLenum, bufSize: GLsizei, v: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnMapiv"]
+    pub static mut epoxy_glGetnMapiv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, query: GLenum, bufSize: GLsizei, v: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnMapivARB"]
+    pub static mut epoxy_glGetnMapivARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, query: GLenum, bufSize: GLsizei, v: *mut GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnMinmax"]
+    pub static mut epoxy_glGetnMinmax: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            reset: GLboolean,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            values: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnMinmaxARB"]
+    pub static mut epoxy_glGetnMinmaxARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            reset: GLboolean,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            values: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnPixelMapfv"]
+    pub static mut epoxy_glGetnPixelMapfv: ::std::option::Option<
+        unsafe extern "C" fn(map: GLenum, bufSize: GLsizei, values: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnPixelMapfvARB"]
+    pub static mut epoxy_glGetnPixelMapfvARB: ::std::option::Option<
+        unsafe extern "C" fn(map: GLenum, bufSize: GLsizei, values: *mut GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnPixelMapuiv"]
+    pub static mut epoxy_glGetnPixelMapuiv: ::std::option::Option<
+        unsafe extern "C" fn(map: GLenum, bufSize: GLsizei, values: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnPixelMapuivARB"]
+    pub static mut epoxy_glGetnPixelMapuivARB: ::std::option::Option<
+        unsafe extern "C" fn(map: GLenum, bufSize: GLsizei, values: *mut GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnPixelMapusv"]
+    pub static mut epoxy_glGetnPixelMapusv: ::std::option::Option<
+        unsafe extern "C" fn(map: GLenum, bufSize: GLsizei, values: *mut GLushort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnPixelMapusvARB"]
+    pub static mut epoxy_glGetnPixelMapusvARB: ::std::option::Option<
+        unsafe extern "C" fn(map: GLenum, bufSize: GLsizei, values: *mut GLushort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnPolygonStipple"]
+    pub static mut epoxy_glGetnPolygonStipple:
+        ::std::option::Option<unsafe extern "C" fn(bufSize: GLsizei, pattern: *mut GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnPolygonStippleARB"]
+    pub static mut epoxy_glGetnPolygonStippleARB:
+        ::std::option::Option<unsafe extern "C" fn(bufSize: GLsizei, pattern: *mut GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnSeparableFilter"]
+    pub static mut epoxy_glGetnSeparableFilter: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            rowBufSize: GLsizei,
+            row: *mut ::std::os::raw::c_void,
+            columnBufSize: GLsizei,
+            column: *mut ::std::os::raw::c_void,
+            span: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnSeparableFilterARB"]
+    pub static mut epoxy_glGetnSeparableFilterARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            format: GLenum,
+            type_: GLenum,
+            rowBufSize: GLsizei,
+            row: *mut ::std::os::raw::c_void,
+            columnBufSize: GLsizei,
+            column: *mut ::std::os::raw::c_void,
+            span: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnTexImage"]
+    pub static mut epoxy_glGetnTexImage: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            pixels: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnTexImageARB"]
+    pub static mut epoxy_glGetnTexImageARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            img: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformdv"]
+    pub static mut epoxy_glGetnUniformdv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformdvARB"]
+    pub static mut epoxy_glGetnUniformdvARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformfv"]
+    pub static mut epoxy_glGetnUniformfv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformfvARB"]
+    pub static mut epoxy_glGetnUniformfvARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformfvEXT"]
+    pub static mut epoxy_glGetnUniformfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformfvKHR"]
+    pub static mut epoxy_glGetnUniformfvKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformi64vARB"]
+    pub static mut epoxy_glGetnUniformi64vARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformiv"]
+    pub static mut epoxy_glGetnUniformiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformivARB"]
+    pub static mut epoxy_glGetnUniformivARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformivEXT"]
+    pub static mut epoxy_glGetnUniformivEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformivKHR"]
+    pub static mut epoxy_glGetnUniformivKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformui64vARB"]
+    pub static mut epoxy_glGetnUniformui64vARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLuint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformuiv"]
+    pub static mut epoxy_glGetnUniformuiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformuivARB"]
+    pub static mut epoxy_glGetnUniformuivARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGetnUniformuivKHR"]
+    pub static mut epoxy_glGetnUniformuivKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            bufSize: GLsizei,
+            params: *mut GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGlobalAlphaFactorbSUN"]
+    pub static mut epoxy_glGlobalAlphaFactorbSUN:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGlobalAlphaFactordSUN"]
+    pub static mut epoxy_glGlobalAlphaFactordSUN:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGlobalAlphaFactorfSUN"]
+    pub static mut epoxy_glGlobalAlphaFactorfSUN:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGlobalAlphaFactoriSUN"]
+    pub static mut epoxy_glGlobalAlphaFactoriSUN:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGlobalAlphaFactorsSUN"]
+    pub static mut epoxy_glGlobalAlphaFactorsSUN:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGlobalAlphaFactorubSUN"]
+    pub static mut epoxy_glGlobalAlphaFactorubSUN:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGlobalAlphaFactoruiSUN"]
+    pub static mut epoxy_glGlobalAlphaFactoruiSUN:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glGlobalAlphaFactorusSUN"]
+    pub static mut epoxy_glGlobalAlphaFactorusSUN:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glHint"]
+    pub static mut epoxy_glHint:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glHintPGI"]
+    pub static mut epoxy_glHintPGI:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, mode: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glHistogram"]
+    pub static mut epoxy_glHistogram: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            width: GLsizei,
+            internalformat: GLenum,
+            sink: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glHistogramEXT"]
+    pub static mut epoxy_glHistogramEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            width: GLsizei,
+            internalformat: GLenum,
+            sink: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIglooInterfaceSGIX"]
+    pub static mut epoxy_glIglooInterfaceSGIX: ::std::option::Option<
+        unsafe extern "C" fn(pname: GLenum, params: *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glImageTransformParameterfHP"]
+    pub static mut epoxy_glImageTransformParameterfHP:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glImageTransformParameterfvHP"]
+    pub static mut epoxy_glImageTransformParameterfvHP: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glImageTransformParameteriHP"]
+    pub static mut epoxy_glImageTransformParameteriHP:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glImageTransformParameterivHP"]
+    pub static mut epoxy_glImageTransformParameterivHP: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glImportSyncEXT"]
+    pub static mut epoxy_glImportSyncEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            external_sync_type: GLenum,
+            external_sync: GLintptr,
+            flags: GLbitfield,
+        ) -> GLsync,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexFormatNV"]
+    pub static mut epoxy_glIndexFormatNV:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, stride: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexFuncEXT"]
+    pub static mut epoxy_glIndexFuncEXT:
+        ::std::option::Option<unsafe extern "C" fn(func: GLenum, ref_: GLclampf)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexMask"]
+    pub static mut epoxy_glIndexMask: ::std::option::Option<unsafe extern "C" fn(mask: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexMaterialEXT"]
+    pub static mut epoxy_glIndexMaterialEXT:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexPointer"]
+    pub static mut epoxy_glIndexPointer: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexPointerEXT"]
+    pub static mut epoxy_glIndexPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            stride: GLsizei,
+            count: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexPointerListIBM"]
+    pub static mut epoxy_glIndexPointerListIBM: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            stride: GLint,
+            pointer: *mut *const ::std::os::raw::c_void,
+            ptrstride: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexd"]
+    pub static mut epoxy_glIndexd: ::std::option::Option<unsafe extern "C" fn(c: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexdv"]
+    pub static mut epoxy_glIndexdv: ::std::option::Option<unsafe extern "C" fn(c: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexf"]
+    pub static mut epoxy_glIndexf: ::std::option::Option<unsafe extern "C" fn(c: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexfv"]
+    pub static mut epoxy_glIndexfv: ::std::option::Option<unsafe extern "C" fn(c: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexi"]
+    pub static mut epoxy_glIndexi: ::std::option::Option<unsafe extern "C" fn(c: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexiv"]
+    pub static mut epoxy_glIndexiv: ::std::option::Option<unsafe extern "C" fn(c: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexs"]
+    pub static mut epoxy_glIndexs: ::std::option::Option<unsafe extern "C" fn(c: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexsv"]
+    pub static mut epoxy_glIndexsv: ::std::option::Option<unsafe extern "C" fn(c: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexub"]
+    pub static mut epoxy_glIndexub: ::std::option::Option<unsafe extern "C" fn(c: GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexubv"]
+    pub static mut epoxy_glIndexubv: ::std::option::Option<unsafe extern "C" fn(c: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexxOES"]
+    pub static mut epoxy_glIndexxOES:
+        ::std::option::Option<unsafe extern "C" fn(component: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIndexxvOES"]
+    pub static mut epoxy_glIndexxvOES:
+        ::std::option::Option<unsafe extern "C" fn(component: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glInitNames"]
+    pub static mut epoxy_glInitNames: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glInsertComponentEXT"]
+    pub static mut epoxy_glInsertComponentEXT:
+        ::std::option::Option<unsafe extern "C" fn(res: GLuint, src: GLuint, num: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glInsertEventMarkerEXT"]
+    pub static mut epoxy_glInsertEventMarkerEXT:
+        ::std::option::Option<unsafe extern "C" fn(length: GLsizei, marker: *const GLchar)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glInstrumentsBufferSGIX"]
+    pub static mut epoxy_glInstrumentsBufferSGIX:
+        ::std::option::Option<unsafe extern "C" fn(size: GLsizei, buffer: *mut GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glInterleavedArrays"]
+    pub static mut epoxy_glInterleavedArrays: ::std::option::Option<
+        unsafe extern "C" fn(
+            format: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glInterpolatePathsNV"]
+    pub static mut epoxy_glInterpolatePathsNV: ::std::option::Option<
+        unsafe extern "C" fn(resultPath: GLuint, pathA: GLuint, pathB: GLuint, weight: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glInvalidateBufferData"]
+    pub static mut epoxy_glInvalidateBufferData:
+        ::std::option::Option<unsafe extern "C" fn(buffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glInvalidateBufferSubData"]
+    pub static mut epoxy_glInvalidateBufferSubData: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLuint, offset: GLintptr, length: GLsizeiptr),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glInvalidateFramebuffer"]
+    pub static mut epoxy_glInvalidateFramebuffer: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, numAttachments: GLsizei, attachments: *const GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glInvalidateNamedFramebufferData"]
+    pub static mut epoxy_glInvalidateNamedFramebufferData: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            numAttachments: GLsizei,
+            attachments: *const GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glInvalidateNamedFramebufferSubData"]
+    pub static mut epoxy_glInvalidateNamedFramebufferSubData: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            numAttachments: GLsizei,
+            attachments: *const GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glInvalidateSubFramebuffer"]
+    pub static mut epoxy_glInvalidateSubFramebuffer: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            numAttachments: GLsizei,
+            attachments: *const GLenum,
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glInvalidateTexImage"]
+    pub static mut epoxy_glInvalidateTexImage:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint, level: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glInvalidateTexSubImage"]
+    pub static mut epoxy_glInvalidateTexSubImage: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsAsyncMarkerSGIX"]
+    pub static mut epoxy_glIsAsyncMarkerSGIX:
+        ::std::option::Option<unsafe extern "C" fn(marker: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsBuffer"]
+    pub static mut epoxy_glIsBuffer:
+        ::std::option::Option<unsafe extern "C" fn(buffer: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsBufferARB"]
+    pub static mut epoxy_glIsBufferARB:
+        ::std::option::Option<unsafe extern "C" fn(buffer: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsBufferResidentNV"]
+    pub static mut epoxy_glIsBufferResidentNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsCommandListNV"]
+    pub static mut epoxy_glIsCommandListNV:
+        ::std::option::Option<unsafe extern "C" fn(list: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsEnabled"]
+    pub static mut epoxy_glIsEnabled:
+        ::std::option::Option<unsafe extern "C" fn(cap: GLenum) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsEnabledIndexedEXT"]
+    pub static mut epoxy_glIsEnabledIndexedEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsEnabledi"]
+    pub static mut epoxy_glIsEnabledi:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsEnablediEXT"]
+    pub static mut epoxy_glIsEnablediEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsEnablediNV"]
+    pub static mut epoxy_glIsEnablediNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsEnablediOES"]
+    pub static mut epoxy_glIsEnablediOES:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, index: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsFenceAPPLE"]
+    pub static mut epoxy_glIsFenceAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(fence: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsFenceNV"]
+    pub static mut epoxy_glIsFenceNV:
+        ::std::option::Option<unsafe extern "C" fn(fence: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsFramebuffer"]
+    pub static mut epoxy_glIsFramebuffer:
+        ::std::option::Option<unsafe extern "C" fn(framebuffer: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsFramebufferEXT"]
+    pub static mut epoxy_glIsFramebufferEXT:
+        ::std::option::Option<unsafe extern "C" fn(framebuffer: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsFramebufferOES"]
+    pub static mut epoxy_glIsFramebufferOES:
+        ::std::option::Option<unsafe extern "C" fn(framebuffer: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsImageHandleResidentARB"]
+    pub static mut epoxy_glIsImageHandleResidentARB:
+        ::std::option::Option<unsafe extern "C" fn(handle: GLuint64) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsImageHandleResidentNV"]
+    pub static mut epoxy_glIsImageHandleResidentNV:
+        ::std::option::Option<unsafe extern "C" fn(handle: GLuint64) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsList"]
+    pub static mut epoxy_glIsList:
+        ::std::option::Option<unsafe extern "C" fn(list: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsNameAMD"]
+    pub static mut epoxy_glIsNameAMD:
+        ::std::option::Option<unsafe extern "C" fn(identifier: GLenum, name: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsNamedBufferResidentNV"]
+    pub static mut epoxy_glIsNamedBufferResidentNV:
+        ::std::option::Option<unsafe extern "C" fn(buffer: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsNamedStringARB"]
+    pub static mut epoxy_glIsNamedStringARB: ::std::option::Option<
+        unsafe extern "C" fn(namelen: GLint, name: *const GLchar) -> GLboolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsObjectBufferATI"]
+    pub static mut epoxy_glIsObjectBufferATI:
+        ::std::option::Option<unsafe extern "C" fn(buffer: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsOcclusionQueryNV"]
+    pub static mut epoxy_glIsOcclusionQueryNV:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsPathNV"]
+    pub static mut epoxy_glIsPathNV:
+        ::std::option::Option<unsafe extern "C" fn(path: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsPointInFillPathNV"]
+    pub static mut epoxy_glIsPointInFillPathNV: ::std::option::Option<
+        unsafe extern "C" fn(path: GLuint, mask: GLuint, x: GLfloat, y: GLfloat) -> GLboolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsPointInStrokePathNV"]
+    pub static mut epoxy_glIsPointInStrokePathNV: ::std::option::Option<
+        unsafe extern "C" fn(path: GLuint, x: GLfloat, y: GLfloat) -> GLboolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsProgram"]
+    pub static mut epoxy_glIsProgram:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsProgramARB"]
+    pub static mut epoxy_glIsProgramARB:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsProgramNV"]
+    pub static mut epoxy_glIsProgramNV:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsProgramPipeline"]
+    pub static mut epoxy_glIsProgramPipeline:
+        ::std::option::Option<unsafe extern "C" fn(pipeline: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsProgramPipelineEXT"]
+    pub static mut epoxy_glIsProgramPipelineEXT:
+        ::std::option::Option<unsafe extern "C" fn(pipeline: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsQuery"]
+    pub static mut epoxy_glIsQuery:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsQueryARB"]
+    pub static mut epoxy_glIsQueryARB:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsQueryEXT"]
+    pub static mut epoxy_glIsQueryEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsRenderbuffer"]
+    pub static mut epoxy_glIsRenderbuffer:
+        ::std::option::Option<unsafe extern "C" fn(renderbuffer: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsRenderbufferEXT"]
+    pub static mut epoxy_glIsRenderbufferEXT:
+        ::std::option::Option<unsafe extern "C" fn(renderbuffer: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsRenderbufferOES"]
+    pub static mut epoxy_glIsRenderbufferOES:
+        ::std::option::Option<unsafe extern "C" fn(renderbuffer: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsSampler"]
+    pub static mut epoxy_glIsSampler:
+        ::std::option::Option<unsafe extern "C" fn(sampler: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsShader"]
+    pub static mut epoxy_glIsShader:
+        ::std::option::Option<unsafe extern "C" fn(shader: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsStateNV"]
+    pub static mut epoxy_glIsStateNV:
+        ::std::option::Option<unsafe extern "C" fn(state: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsSync"]
+    pub static mut epoxy_glIsSync:
+        ::std::option::Option<unsafe extern "C" fn(sync: GLsync) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsSyncAPPLE"]
+    pub static mut epoxy_glIsSyncAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(sync: GLsync) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsTexture"]
+    pub static mut epoxy_glIsTexture:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsTextureEXT"]
+    pub static mut epoxy_glIsTextureEXT:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsTextureHandleResidentARB"]
+    pub static mut epoxy_glIsTextureHandleResidentARB:
+        ::std::option::Option<unsafe extern "C" fn(handle: GLuint64) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsTextureHandleResidentNV"]
+    pub static mut epoxy_glIsTextureHandleResidentNV:
+        ::std::option::Option<unsafe extern "C" fn(handle: GLuint64) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsTransformFeedback"]
+    pub static mut epoxy_glIsTransformFeedback:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsTransformFeedbackNV"]
+    pub static mut epoxy_glIsTransformFeedbackNV:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsVariantEnabledEXT"]
+    pub static mut epoxy_glIsVariantEnabledEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, cap: GLenum) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsVertexArray"]
+    pub static mut epoxy_glIsVertexArray:
+        ::std::option::Option<unsafe extern "C" fn(array: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsVertexArrayAPPLE"]
+    pub static mut epoxy_glIsVertexArrayAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(array: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsVertexArrayOES"]
+    pub static mut epoxy_glIsVertexArrayOES:
+        ::std::option::Option<unsafe extern "C" fn(array: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glIsVertexAttribEnabledAPPLE"]
+    pub static mut epoxy_glIsVertexAttribEnabledAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, pname: GLenum) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLabelObjectEXT"]
+    pub static mut epoxy_glLabelObjectEXT: ::std::option::Option<
+        unsafe extern "C" fn(type_: GLenum, object: GLuint, length: GLsizei, label: *const GLchar),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightEnviSGIX"]
+    pub static mut epoxy_glLightEnviSGIX:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightModelf"]
+    pub static mut epoxy_glLightModelf:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightModelfv"]
+    pub static mut epoxy_glLightModelfv:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightModeli"]
+    pub static mut epoxy_glLightModeli:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightModeliv"]
+    pub static mut epoxy_glLightModeliv:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightModelx"]
+    pub static mut epoxy_glLightModelx:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightModelxOES"]
+    pub static mut epoxy_glLightModelxOES:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightModelxv"]
+    pub static mut epoxy_glLightModelxv:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightModelxvOES"]
+    pub static mut epoxy_glLightModelxvOES:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightf"]
+    pub static mut epoxy_glLightf:
+        ::std::option::Option<unsafe extern "C" fn(light: GLenum, pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightfv"]
+    pub static mut epoxy_glLightfv: ::std::option::Option<
+        unsafe extern "C" fn(light: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLighti"]
+    pub static mut epoxy_glLighti:
+        ::std::option::Option<unsafe extern "C" fn(light: GLenum, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightiv"]
+    pub static mut epoxy_glLightiv: ::std::option::Option<
+        unsafe extern "C" fn(light: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightx"]
+    pub static mut epoxy_glLightx:
+        ::std::option::Option<unsafe extern "C" fn(light: GLenum, pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightxOES"]
+    pub static mut epoxy_glLightxOES:
+        ::std::option::Option<unsafe extern "C" fn(light: GLenum, pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightxv"]
+    pub static mut epoxy_glLightxv: ::std::option::Option<
+        unsafe extern "C" fn(light: GLenum, pname: GLenum, params: *const GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLightxvOES"]
+    pub static mut epoxy_glLightxvOES: ::std::option::Option<
+        unsafe extern "C" fn(light: GLenum, pname: GLenum, params: *const GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLineStipple"]
+    pub static mut epoxy_glLineStipple:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLint, pattern: GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLineWidth"]
+    pub static mut epoxy_glLineWidth: ::std::option::Option<unsafe extern "C" fn(width: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLineWidthx"]
+    pub static mut epoxy_glLineWidthx: ::std::option::Option<unsafe extern "C" fn(width: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLineWidthxOES"]
+    pub static mut epoxy_glLineWidthxOES:
+        ::std::option::Option<unsafe extern "C" fn(width: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLinkProgram"]
+    pub static mut epoxy_glLinkProgram:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLinkProgramARB"]
+    pub static mut epoxy_glLinkProgramARB:
+        ::std::option::Option<unsafe extern "C" fn(programObj: GLhandleARB)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glListBase"]
+    pub static mut epoxy_glListBase: ::std::option::Option<unsafe extern "C" fn(base: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glListDrawCommandsStatesClientNV"]
+    pub static mut epoxy_glListDrawCommandsStatesClientNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            list: GLuint,
+            segment: GLuint,
+            indirects: *mut *const ::std::os::raw::c_void,
+            sizes: *const GLsizei,
+            states: *const GLuint,
+            fbos: *const GLuint,
+            count: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glListParameterfSGIX"]
+    pub static mut epoxy_glListParameterfSGIX:
+        ::std::option::Option<unsafe extern "C" fn(list: GLuint, pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glListParameterfvSGIX"]
+    pub static mut epoxy_glListParameterfvSGIX: ::std::option::Option<
+        unsafe extern "C" fn(list: GLuint, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glListParameteriSGIX"]
+    pub static mut epoxy_glListParameteriSGIX:
+        ::std::option::Option<unsafe extern "C" fn(list: GLuint, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glListParameterivSGIX"]
+    pub static mut epoxy_glListParameterivSGIX: ::std::option::Option<
+        unsafe extern "C" fn(list: GLuint, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLoadIdentity"]
+    pub static mut epoxy_glLoadIdentity: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLoadIdentityDeformationMapSGIX"]
+    pub static mut epoxy_glLoadIdentityDeformationMapSGIX:
+        ::std::option::Option<unsafe extern "C" fn(mask: GLbitfield)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLoadMatrixd"]
+    pub static mut epoxy_glLoadMatrixd:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLoadMatrixf"]
+    pub static mut epoxy_glLoadMatrixf:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLoadMatrixx"]
+    pub static mut epoxy_glLoadMatrixx:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLoadMatrixxOES"]
+    pub static mut epoxy_glLoadMatrixxOES:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLoadName"]
+    pub static mut epoxy_glLoadName: ::std::option::Option<unsafe extern "C" fn(name: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLoadPaletteFromModelViewMatrixOES"]
+    pub static mut epoxy_glLoadPaletteFromModelViewMatrixOES:
+        ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLoadProgramNV"]
+    pub static mut epoxy_glLoadProgramNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, id: GLuint, len: GLsizei, program: *const GLubyte),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLoadTransposeMatrixd"]
+    pub static mut epoxy_glLoadTransposeMatrixd:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLoadTransposeMatrixdARB"]
+    pub static mut epoxy_glLoadTransposeMatrixdARB:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLoadTransposeMatrixf"]
+    pub static mut epoxy_glLoadTransposeMatrixf:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLoadTransposeMatrixfARB"]
+    pub static mut epoxy_glLoadTransposeMatrixfARB:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLoadTransposeMatrixxOES"]
+    pub static mut epoxy_glLoadTransposeMatrixxOES:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLockArraysEXT"]
+    pub static mut epoxy_glLockArraysEXT:
+        ::std::option::Option<unsafe extern "C" fn(first: GLint, count: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glLogicOp"]
+    pub static mut epoxy_glLogicOp: ::std::option::Option<unsafe extern "C" fn(opcode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMakeBufferNonResidentNV"]
+    pub static mut epoxy_glMakeBufferNonResidentNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMakeBufferResidentNV"]
+    pub static mut epoxy_glMakeBufferResidentNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, access: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMakeImageHandleNonResidentARB"]
+    pub static mut epoxy_glMakeImageHandleNonResidentARB:
+        ::std::option::Option<unsafe extern "C" fn(handle: GLuint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMakeImageHandleNonResidentNV"]
+    pub static mut epoxy_glMakeImageHandleNonResidentNV:
+        ::std::option::Option<unsafe extern "C" fn(handle: GLuint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMakeImageHandleResidentARB"]
+    pub static mut epoxy_glMakeImageHandleResidentARB:
+        ::std::option::Option<unsafe extern "C" fn(handle: GLuint64, access: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMakeImageHandleResidentNV"]
+    pub static mut epoxy_glMakeImageHandleResidentNV:
+        ::std::option::Option<unsafe extern "C" fn(handle: GLuint64, access: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMakeNamedBufferNonResidentNV"]
+    pub static mut epoxy_glMakeNamedBufferNonResidentNV:
+        ::std::option::Option<unsafe extern "C" fn(buffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMakeNamedBufferResidentNV"]
+    pub static mut epoxy_glMakeNamedBufferResidentNV:
+        ::std::option::Option<unsafe extern "C" fn(buffer: GLuint, access: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMakeTextureHandleNonResidentARB"]
+    pub static mut epoxy_glMakeTextureHandleNonResidentARB:
+        ::std::option::Option<unsafe extern "C" fn(handle: GLuint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMakeTextureHandleNonResidentNV"]
+    pub static mut epoxy_glMakeTextureHandleNonResidentNV:
+        ::std::option::Option<unsafe extern "C" fn(handle: GLuint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMakeTextureHandleResidentARB"]
+    pub static mut epoxy_glMakeTextureHandleResidentARB:
+        ::std::option::Option<unsafe extern "C" fn(handle: GLuint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMakeTextureHandleResidentNV"]
+    pub static mut epoxy_glMakeTextureHandleResidentNV:
+        ::std::option::Option<unsafe extern "C" fn(handle: GLuint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMap1d"]
+    pub static mut epoxy_glMap1d: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            u1: GLdouble,
+            u2: GLdouble,
+            stride: GLint,
+            order: GLint,
+            points: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMap1f"]
+    pub static mut epoxy_glMap1f: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            u1: GLfloat,
+            u2: GLfloat,
+            stride: GLint,
+            order: GLint,
+            points: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMap1xOES"]
+    pub static mut epoxy_glMap1xOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            u1: GLfixed,
+            u2: GLfixed,
+            stride: GLint,
+            order: GLint,
+            points: GLfixed,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMap2d"]
+    pub static mut epoxy_glMap2d: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            u1: GLdouble,
+            u2: GLdouble,
+            ustride: GLint,
+            uorder: GLint,
+            v1: GLdouble,
+            v2: GLdouble,
+            vstride: GLint,
+            vorder: GLint,
+            points: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMap2f"]
+    pub static mut epoxy_glMap2f: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            u1: GLfloat,
+            u2: GLfloat,
+            ustride: GLint,
+            uorder: GLint,
+            v1: GLfloat,
+            v2: GLfloat,
+            vstride: GLint,
+            vorder: GLint,
+            points: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMap2xOES"]
+    pub static mut epoxy_glMap2xOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            u1: GLfixed,
+            u2: GLfixed,
+            ustride: GLint,
+            uorder: GLint,
+            v1: GLfixed,
+            v2: GLfixed,
+            vstride: GLint,
+            vorder: GLint,
+            points: GLfixed,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapBuffer"]
+    pub static mut epoxy_glMapBuffer: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, access: GLenum) -> *mut ::std::os::raw::c_void,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapBufferARB"]
+    pub static mut epoxy_glMapBufferARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, access: GLenum) -> *mut ::std::os::raw::c_void,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapBufferOES"]
+    pub static mut epoxy_glMapBufferOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, access: GLenum) -> *mut ::std::os::raw::c_void,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapBufferRange"]
+    pub static mut epoxy_glMapBufferRange: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            offset: GLintptr,
+            length: GLsizeiptr,
+            access: GLbitfield,
+        ) -> *mut ::std::os::raw::c_void,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapBufferRangeEXT"]
+    pub static mut epoxy_glMapBufferRangeEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            offset: GLintptr,
+            length: GLsizeiptr,
+            access: GLbitfield,
+        ) -> *mut ::std::os::raw::c_void,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapControlPointsNV"]
+    pub static mut epoxy_glMapControlPointsNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            index: GLuint,
+            type_: GLenum,
+            ustride: GLsizei,
+            vstride: GLsizei,
+            uorder: GLint,
+            vorder: GLint,
+            packed: GLboolean,
+            points: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapGrid1d"]
+    pub static mut epoxy_glMapGrid1d:
+        ::std::option::Option<unsafe extern "C" fn(un: GLint, u1: GLdouble, u2: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapGrid1f"]
+    pub static mut epoxy_glMapGrid1f:
+        ::std::option::Option<unsafe extern "C" fn(un: GLint, u1: GLfloat, u2: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapGrid1xOES"]
+    pub static mut epoxy_glMapGrid1xOES:
+        ::std::option::Option<unsafe extern "C" fn(n: GLint, u1: GLfixed, u2: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapGrid2d"]
+    pub static mut epoxy_glMapGrid2d: ::std::option::Option<
+        unsafe extern "C" fn(
+            un: GLint,
+            u1: GLdouble,
+            u2: GLdouble,
+            vn: GLint,
+            v1: GLdouble,
+            v2: GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapGrid2f"]
+    pub static mut epoxy_glMapGrid2f: ::std::option::Option<
+        unsafe extern "C" fn(
+            un: GLint,
+            u1: GLfloat,
+            u2: GLfloat,
+            vn: GLint,
+            v1: GLfloat,
+            v2: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapGrid2xOES"]
+    pub static mut epoxy_glMapGrid2xOES: ::std::option::Option<
+        unsafe extern "C" fn(n: GLint, u1: GLfixed, u2: GLfixed, v1: GLfixed, v2: GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapNamedBuffer"]
+    pub static mut epoxy_glMapNamedBuffer: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLuint, access: GLenum) -> *mut ::std::os::raw::c_void,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapNamedBufferEXT"]
+    pub static mut epoxy_glMapNamedBufferEXT: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLuint, access: GLenum) -> *mut ::std::os::raw::c_void,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapNamedBufferRange"]
+    pub static mut epoxy_glMapNamedBufferRange: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            offset: GLintptr,
+            length: GLsizeiptr,
+            access: GLbitfield,
+        ) -> *mut ::std::os::raw::c_void,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapNamedBufferRangeEXT"]
+    pub static mut epoxy_glMapNamedBufferRangeEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            offset: GLintptr,
+            length: GLsizeiptr,
+            access: GLbitfield,
+        ) -> *mut ::std::os::raw::c_void,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapObjectBufferATI"]
+    pub static mut epoxy_glMapObjectBufferATI:
+        ::std::option::Option<unsafe extern "C" fn(buffer: GLuint) -> *mut ::std::os::raw::c_void>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapParameterfvNV"]
+    pub static mut epoxy_glMapParameterfvNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapParameterivNV"]
+    pub static mut epoxy_glMapParameterivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapTexture2DINTEL"]
+    pub static mut epoxy_glMapTexture2DINTEL: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            access: GLbitfield,
+            stride: *mut GLint,
+            layout: *mut GLenum,
+        ) -> *mut ::std::os::raw::c_void,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapVertexAttrib1dAPPLE"]
+    pub static mut epoxy_glMapVertexAttrib1dAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            size: GLuint,
+            u1: GLdouble,
+            u2: GLdouble,
+            stride: GLint,
+            order: GLint,
+            points: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapVertexAttrib1fAPPLE"]
+    pub static mut epoxy_glMapVertexAttrib1fAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            size: GLuint,
+            u1: GLfloat,
+            u2: GLfloat,
+            stride: GLint,
+            order: GLint,
+            points: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapVertexAttrib2dAPPLE"]
+    pub static mut epoxy_glMapVertexAttrib2dAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            size: GLuint,
+            u1: GLdouble,
+            u2: GLdouble,
+            ustride: GLint,
+            uorder: GLint,
+            v1: GLdouble,
+            v2: GLdouble,
+            vstride: GLint,
+            vorder: GLint,
+            points: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMapVertexAttrib2fAPPLE"]
+    pub static mut epoxy_glMapVertexAttrib2fAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            size: GLuint,
+            u1: GLfloat,
+            u2: GLfloat,
+            ustride: GLint,
+            uorder: GLint,
+            v1: GLfloat,
+            v2: GLfloat,
+            vstride: GLint,
+            vorder: GLint,
+            points: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMaterialf"]
+    pub static mut epoxy_glMaterialf:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMaterialfv"]
+    pub static mut epoxy_glMaterialfv: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMateriali"]
+    pub static mut epoxy_glMateriali:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMaterialiv"]
+    pub static mut epoxy_glMaterialiv: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMaterialx"]
+    pub static mut epoxy_glMaterialx:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMaterialxOES"]
+    pub static mut epoxy_glMaterialxOES:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMaterialxv"]
+    pub static mut epoxy_glMaterialxv: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, pname: GLenum, param: *const GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMaterialxvOES"]
+    pub static mut epoxy_glMaterialxvOES: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, pname: GLenum, param: *const GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixFrustumEXT"]
+    pub static mut epoxy_glMatrixFrustumEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            left: GLdouble,
+            right: GLdouble,
+            bottom: GLdouble,
+            top: GLdouble,
+            zNear: GLdouble,
+            zFar: GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixIndexPointerARB"]
+    pub static mut epoxy_glMatrixIndexPointerARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixIndexPointerOES"]
+    pub static mut epoxy_glMatrixIndexPointerOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixIndexubvARB"]
+    pub static mut epoxy_glMatrixIndexubvARB:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, indices: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixIndexuivARB"]
+    pub static mut epoxy_glMatrixIndexuivARB:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, indices: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixIndexusvARB"]
+    pub static mut epoxy_glMatrixIndexusvARB:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, indices: *const GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixLoad3x2fNV"]
+    pub static mut epoxy_glMatrixLoad3x2fNV:
+        ::std::option::Option<unsafe extern "C" fn(matrixMode: GLenum, m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixLoad3x3fNV"]
+    pub static mut epoxy_glMatrixLoad3x3fNV:
+        ::std::option::Option<unsafe extern "C" fn(matrixMode: GLenum, m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixLoadIdentityEXT"]
+    pub static mut epoxy_glMatrixLoadIdentityEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixLoadTranspose3x3fNV"]
+    pub static mut epoxy_glMatrixLoadTranspose3x3fNV:
+        ::std::option::Option<unsafe extern "C" fn(matrixMode: GLenum, m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixLoadTransposedEXT"]
+    pub static mut epoxy_glMatrixLoadTransposedEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, m: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixLoadTransposefEXT"]
+    pub static mut epoxy_glMatrixLoadTransposefEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixLoaddEXT"]
+    pub static mut epoxy_glMatrixLoaddEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, m: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixLoadfEXT"]
+    pub static mut epoxy_glMatrixLoadfEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixMode"]
+    pub static mut epoxy_glMatrixMode: ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixMult3x2fNV"]
+    pub static mut epoxy_glMatrixMult3x2fNV:
+        ::std::option::Option<unsafe extern "C" fn(matrixMode: GLenum, m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixMult3x3fNV"]
+    pub static mut epoxy_glMatrixMult3x3fNV:
+        ::std::option::Option<unsafe extern "C" fn(matrixMode: GLenum, m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixMultTranspose3x3fNV"]
+    pub static mut epoxy_glMatrixMultTranspose3x3fNV:
+        ::std::option::Option<unsafe extern "C" fn(matrixMode: GLenum, m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixMultTransposedEXT"]
+    pub static mut epoxy_glMatrixMultTransposedEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, m: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixMultTransposefEXT"]
+    pub static mut epoxy_glMatrixMultTransposefEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixMultdEXT"]
+    pub static mut epoxy_glMatrixMultdEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, m: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixMultfEXT"]
+    pub static mut epoxy_glMatrixMultfEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum, m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixOrthoEXT"]
+    pub static mut epoxy_glMatrixOrthoEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            left: GLdouble,
+            right: GLdouble,
+            bottom: GLdouble,
+            top: GLdouble,
+            zNear: GLdouble,
+            zFar: GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixPopEXT"]
+    pub static mut epoxy_glMatrixPopEXT: ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixPushEXT"]
+    pub static mut epoxy_glMatrixPushEXT: ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixRotatedEXT"]
+    pub static mut epoxy_glMatrixRotatedEXT: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, angle: GLdouble, x: GLdouble, y: GLdouble, z: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixRotatefEXT"]
+    pub static mut epoxy_glMatrixRotatefEXT: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, angle: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixScaledEXT"]
+    pub static mut epoxy_glMatrixScaledEXT: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, x: GLdouble, y: GLdouble, z: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixScalefEXT"]
+    pub static mut epoxy_glMatrixScalefEXT: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, x: GLfloat, y: GLfloat, z: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixTranslatedEXT"]
+    pub static mut epoxy_glMatrixTranslatedEXT: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, x: GLdouble, y: GLdouble, z: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMatrixTranslatefEXT"]
+    pub static mut epoxy_glMatrixTranslatefEXT: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, x: GLfloat, y: GLfloat, z: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMaxShaderCompilerThreadsARB"]
+    pub static mut epoxy_glMaxShaderCompilerThreadsARB:
+        ::std::option::Option<unsafe extern "C" fn(count: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMemoryBarrier"]
+    pub static mut epoxy_glMemoryBarrier:
+        ::std::option::Option<unsafe extern "C" fn(barriers: GLbitfield)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMemoryBarrierByRegion"]
+    pub static mut epoxy_glMemoryBarrierByRegion:
+        ::std::option::Option<unsafe extern "C" fn(barriers: GLbitfield)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMemoryBarrierEXT"]
+    pub static mut epoxy_glMemoryBarrierEXT:
+        ::std::option::Option<unsafe extern "C" fn(barriers: GLbitfield)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMinSampleShading"]
+    pub static mut epoxy_glMinSampleShading:
+        ::std::option::Option<unsafe extern "C" fn(value: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMinSampleShadingARB"]
+    pub static mut epoxy_glMinSampleShadingARB:
+        ::std::option::Option<unsafe extern "C" fn(value: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMinSampleShadingOES"]
+    pub static mut epoxy_glMinSampleShadingOES:
+        ::std::option::Option<unsafe extern "C" fn(value: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMinmax"]
+    pub static mut epoxy_glMinmax: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, internalformat: GLenum, sink: GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMinmaxEXT"]
+    pub static mut epoxy_glMinmaxEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, internalformat: GLenum, sink: GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultMatrixd"]
+    pub static mut epoxy_glMultMatrixd:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultMatrixf"]
+    pub static mut epoxy_glMultMatrixf:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultMatrixx"]
+    pub static mut epoxy_glMultMatrixx:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultMatrixxOES"]
+    pub static mut epoxy_glMultMatrixxOES:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultTransposeMatrixd"]
+    pub static mut epoxy_glMultTransposeMatrixd:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultTransposeMatrixdARB"]
+    pub static mut epoxy_glMultTransposeMatrixdARB:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultTransposeMatrixf"]
+    pub static mut epoxy_glMultTransposeMatrixf:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultTransposeMatrixfARB"]
+    pub static mut epoxy_glMultTransposeMatrixfARB:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultTransposeMatrixxOES"]
+    pub static mut epoxy_glMultTransposeMatrixxOES:
+        ::std::option::Option<unsafe extern "C" fn(m: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawArrays"]
+    pub static mut epoxy_glMultiDrawArrays: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            first: *const GLint,
+            count: *const GLsizei,
+            drawcount: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawArraysEXT"]
+    pub static mut epoxy_glMultiDrawArraysEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            first: *const GLint,
+            count: *const GLsizei,
+            primcount: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawArraysIndirect"]
+    pub static mut epoxy_glMultiDrawArraysIndirect: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            indirect: *const ::std::os::raw::c_void,
+            drawcount: GLsizei,
+            stride: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawArraysIndirectAMD"]
+    pub static mut epoxy_glMultiDrawArraysIndirectAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            indirect: *const ::std::os::raw::c_void,
+            primcount: GLsizei,
+            stride: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawArraysIndirectBindlessCountNV"]
+    pub static mut epoxy_glMultiDrawArraysIndirectBindlessCountNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            indirect: *const ::std::os::raw::c_void,
+            drawCount: GLsizei,
+            maxDrawCount: GLsizei,
+            stride: GLsizei,
+            vertexBufferCount: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawArraysIndirectBindlessNV"]
+    pub static mut epoxy_glMultiDrawArraysIndirectBindlessNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            indirect: *const ::std::os::raw::c_void,
+            drawCount: GLsizei,
+            stride: GLsizei,
+            vertexBufferCount: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawArraysIndirectCountARB"]
+    pub static mut epoxy_glMultiDrawArraysIndirectCountARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            indirect: GLintptr,
+            drawcount: GLintptr,
+            maxdrawcount: GLsizei,
+            stride: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawArraysIndirectEXT"]
+    pub static mut epoxy_glMultiDrawArraysIndirectEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            indirect: *const ::std::os::raw::c_void,
+            drawcount: GLsizei,
+            stride: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawElementArrayAPPLE"]
+    pub static mut epoxy_glMultiDrawElementArrayAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            first: *const GLint,
+            count: *const GLsizei,
+            primcount: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawElements"]
+    pub static mut epoxy_glMultiDrawElements: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: *const GLsizei,
+            type_: GLenum,
+            indices: *const *const ::std::os::raw::c_void,
+            drawcount: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawElementsBaseVertex"]
+    pub static mut epoxy_glMultiDrawElementsBaseVertex: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: *const GLsizei,
+            type_: GLenum,
+            indices: *const *const ::std::os::raw::c_void,
+            drawcount: GLsizei,
+            basevertex: *const GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawElementsBaseVertexEXT"]
+    pub static mut epoxy_glMultiDrawElementsBaseVertexEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: *const GLsizei,
+            type_: GLenum,
+            indices: *const *const ::std::os::raw::c_void,
+            primcount: GLsizei,
+            basevertex: *const GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawElementsBaseVertexOES"]
+    pub static mut epoxy_glMultiDrawElementsBaseVertexOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: *const GLsizei,
+            type_: GLenum,
+            indices: *const *const ::std::os::raw::c_void,
+            primcount: GLsizei,
+            basevertex: *const GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawElementsEXT"]
+    pub static mut epoxy_glMultiDrawElementsEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            count: *const GLsizei,
+            type_: GLenum,
+            indices: *const *const ::std::os::raw::c_void,
+            primcount: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawElementsIndirect"]
+    pub static mut epoxy_glMultiDrawElementsIndirect: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            type_: GLenum,
+            indirect: *const ::std::os::raw::c_void,
+            drawcount: GLsizei,
+            stride: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawElementsIndirectAMD"]
+    pub static mut epoxy_glMultiDrawElementsIndirectAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            type_: GLenum,
+            indirect: *const ::std::os::raw::c_void,
+            primcount: GLsizei,
+            stride: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawElementsIndirectBindlessCountNV"]
+    pub static mut epoxy_glMultiDrawElementsIndirectBindlessCountNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            type_: GLenum,
+            indirect: *const ::std::os::raw::c_void,
+            drawCount: GLsizei,
+            maxDrawCount: GLsizei,
+            stride: GLsizei,
+            vertexBufferCount: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawElementsIndirectBindlessNV"]
+    pub static mut epoxy_glMultiDrawElementsIndirectBindlessNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            type_: GLenum,
+            indirect: *const ::std::os::raw::c_void,
+            drawCount: GLsizei,
+            stride: GLsizei,
+            vertexBufferCount: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawElementsIndirectCountARB"]
+    pub static mut epoxy_glMultiDrawElementsIndirectCountARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            type_: GLenum,
+            indirect: GLintptr,
+            drawcount: GLintptr,
+            maxdrawcount: GLsizei,
+            stride: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawElementsIndirectEXT"]
+    pub static mut epoxy_glMultiDrawElementsIndirectEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            type_: GLenum,
+            indirect: *const ::std::os::raw::c_void,
+            drawcount: GLsizei,
+            stride: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiDrawRangeElementArrayAPPLE"]
+    pub static mut epoxy_glMultiDrawRangeElementArrayAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: GLenum,
+            start: GLuint,
+            end: GLuint,
+            first: *const GLint,
+            count: *const GLsizei,
+            primcount: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiModeDrawArraysIBM"]
+    pub static mut epoxy_glMultiModeDrawArraysIBM: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: *const GLenum,
+            first: *const GLint,
+            count: *const GLsizei,
+            primcount: GLsizei,
+            modestride: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiModeDrawElementsIBM"]
+    pub static mut epoxy_glMultiModeDrawElementsIBM: ::std::option::Option<
+        unsafe extern "C" fn(
+            mode: *const GLenum,
+            count: *const GLsizei,
+            type_: GLenum,
+            indices: *const *const ::std::os::raw::c_void,
+            primcount: GLsizei,
+            modestride: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexBufferEXT"]
+    pub static mut epoxy_glMultiTexBufferEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            internalformat: GLenum,
+            buffer: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1bOES"]
+    pub static mut epoxy_glMultiTexCoord1bOES:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, s: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1bvOES"]
+    pub static mut epoxy_glMultiTexCoord1bvOES:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, coords: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1d"]
+    pub static mut epoxy_glMultiTexCoord1d:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1dARB"]
+    pub static mut epoxy_glMultiTexCoord1dARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1dv"]
+    pub static mut epoxy_glMultiTexCoord1dv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1dvARB"]
+    pub static mut epoxy_glMultiTexCoord1dvARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1f"]
+    pub static mut epoxy_glMultiTexCoord1f:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1fARB"]
+    pub static mut epoxy_glMultiTexCoord1fARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1fv"]
+    pub static mut epoxy_glMultiTexCoord1fv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1fvARB"]
+    pub static mut epoxy_glMultiTexCoord1fvARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1hNV"]
+    pub static mut epoxy_glMultiTexCoord1hNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1hvNV"]
+    pub static mut epoxy_glMultiTexCoord1hvNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1i"]
+    pub static mut epoxy_glMultiTexCoord1i:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1iARB"]
+    pub static mut epoxy_glMultiTexCoord1iARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1iv"]
+    pub static mut epoxy_glMultiTexCoord1iv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1ivARB"]
+    pub static mut epoxy_glMultiTexCoord1ivARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1s"]
+    pub static mut epoxy_glMultiTexCoord1s:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1sARB"]
+    pub static mut epoxy_glMultiTexCoord1sARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1sv"]
+    pub static mut epoxy_glMultiTexCoord1sv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1svARB"]
+    pub static mut epoxy_glMultiTexCoord1svARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1xOES"]
+    pub static mut epoxy_glMultiTexCoord1xOES:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, s: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord1xvOES"]
+    pub static mut epoxy_glMultiTexCoord1xvOES:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2bOES"]
+    pub static mut epoxy_glMultiTexCoord2bOES:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, s: GLbyte, t: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2bvOES"]
+    pub static mut epoxy_glMultiTexCoord2bvOES:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, coords: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2d"]
+    pub static mut epoxy_glMultiTexCoord2d:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLdouble, t: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2dARB"]
+    pub static mut epoxy_glMultiTexCoord2dARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLdouble, t: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2dv"]
+    pub static mut epoxy_glMultiTexCoord2dv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2dvARB"]
+    pub static mut epoxy_glMultiTexCoord2dvARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2f"]
+    pub static mut epoxy_glMultiTexCoord2f:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLfloat, t: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2fARB"]
+    pub static mut epoxy_glMultiTexCoord2fARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLfloat, t: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2fv"]
+    pub static mut epoxy_glMultiTexCoord2fv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2fvARB"]
+    pub static mut epoxy_glMultiTexCoord2fvARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2hNV"]
+    pub static mut epoxy_glMultiTexCoord2hNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLhalfNV, t: GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2hvNV"]
+    pub static mut epoxy_glMultiTexCoord2hvNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2i"]
+    pub static mut epoxy_glMultiTexCoord2i:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLint, t: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2iARB"]
+    pub static mut epoxy_glMultiTexCoord2iARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLint, t: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2iv"]
+    pub static mut epoxy_glMultiTexCoord2iv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2ivARB"]
+    pub static mut epoxy_glMultiTexCoord2ivARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2s"]
+    pub static mut epoxy_glMultiTexCoord2s:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLshort, t: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2sARB"]
+    pub static mut epoxy_glMultiTexCoord2sARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLshort, t: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2sv"]
+    pub static mut epoxy_glMultiTexCoord2sv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2svARB"]
+    pub static mut epoxy_glMultiTexCoord2svARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2xOES"]
+    pub static mut epoxy_glMultiTexCoord2xOES:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, s: GLfixed, t: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord2xvOES"]
+    pub static mut epoxy_glMultiTexCoord2xvOES:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3bOES"]
+    pub static mut epoxy_glMultiTexCoord3bOES: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLenum, s: GLbyte, t: GLbyte, r: GLbyte),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3bvOES"]
+    pub static mut epoxy_glMultiTexCoord3bvOES:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, coords: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3d"]
+    pub static mut epoxy_glMultiTexCoord3d: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLdouble, t: GLdouble, r: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3dARB"]
+    pub static mut epoxy_glMultiTexCoord3dARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLdouble, t: GLdouble, r: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3dv"]
+    pub static mut epoxy_glMultiTexCoord3dv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3dvARB"]
+    pub static mut epoxy_glMultiTexCoord3dvARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3f"]
+    pub static mut epoxy_glMultiTexCoord3f: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLfloat, t: GLfloat, r: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3fARB"]
+    pub static mut epoxy_glMultiTexCoord3fARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLfloat, t: GLfloat, r: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3fv"]
+    pub static mut epoxy_glMultiTexCoord3fv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3fvARB"]
+    pub static mut epoxy_glMultiTexCoord3fvARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3hNV"]
+    pub static mut epoxy_glMultiTexCoord3hNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLhalfNV, t: GLhalfNV, r: GLhalfNV),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3hvNV"]
+    pub static mut epoxy_glMultiTexCoord3hvNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3i"]
+    pub static mut epoxy_glMultiTexCoord3i:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLint, t: GLint, r: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3iARB"]
+    pub static mut epoxy_glMultiTexCoord3iARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, s: GLint, t: GLint, r: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3iv"]
+    pub static mut epoxy_glMultiTexCoord3iv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3ivARB"]
+    pub static mut epoxy_glMultiTexCoord3ivARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3s"]
+    pub static mut epoxy_glMultiTexCoord3s: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLshort, t: GLshort, r: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3sARB"]
+    pub static mut epoxy_glMultiTexCoord3sARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLshort, t: GLshort, r: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3sv"]
+    pub static mut epoxy_glMultiTexCoord3sv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3svARB"]
+    pub static mut epoxy_glMultiTexCoord3svARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3xOES"]
+    pub static mut epoxy_glMultiTexCoord3xOES: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLenum, s: GLfixed, t: GLfixed, r: GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord3xvOES"]
+    pub static mut epoxy_glMultiTexCoord3xvOES:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4bOES"]
+    pub static mut epoxy_glMultiTexCoord4bOES: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLenum, s: GLbyte, t: GLbyte, r: GLbyte, q: GLbyte),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4bvOES"]
+    pub static mut epoxy_glMultiTexCoord4bvOES:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, coords: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4d"]
+    pub static mut epoxy_glMultiTexCoord4d: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLdouble, t: GLdouble, r: GLdouble, q: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4dARB"]
+    pub static mut epoxy_glMultiTexCoord4dARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLdouble, t: GLdouble, r: GLdouble, q: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4dv"]
+    pub static mut epoxy_glMultiTexCoord4dv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4dvARB"]
+    pub static mut epoxy_glMultiTexCoord4dvARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4f"]
+    pub static mut epoxy_glMultiTexCoord4f: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLfloat, t: GLfloat, r: GLfloat, q: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4fARB"]
+    pub static mut epoxy_glMultiTexCoord4fARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLfloat, t: GLfloat, r: GLfloat, q: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4fv"]
+    pub static mut epoxy_glMultiTexCoord4fv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4fvARB"]
+    pub static mut epoxy_glMultiTexCoord4fvARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4hNV"]
+    pub static mut epoxy_glMultiTexCoord4hNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLhalfNV, t: GLhalfNV, r: GLhalfNV, q: GLhalfNV),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4hvNV"]
+    pub static mut epoxy_glMultiTexCoord4hvNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4i"]
+    pub static mut epoxy_glMultiTexCoord4i: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLint, t: GLint, r: GLint, q: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4iARB"]
+    pub static mut epoxy_glMultiTexCoord4iARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLint, t: GLint, r: GLint, q: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4iv"]
+    pub static mut epoxy_glMultiTexCoord4iv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4ivARB"]
+    pub static mut epoxy_glMultiTexCoord4ivARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4s"]
+    pub static mut epoxy_glMultiTexCoord4s: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLshort, t: GLshort, r: GLshort, q: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4sARB"]
+    pub static mut epoxy_glMultiTexCoord4sARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, s: GLshort, t: GLshort, r: GLshort, q: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4sv"]
+    pub static mut epoxy_glMultiTexCoord4sv:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4svARB"]
+    pub static mut epoxy_glMultiTexCoord4svARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4x"]
+    pub static mut epoxy_glMultiTexCoord4x: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLenum, s: GLfixed, t: GLfixed, r: GLfixed, q: GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4xOES"]
+    pub static mut epoxy_glMultiTexCoord4xOES: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLenum, s: GLfixed, t: GLfixed, r: GLfixed, q: GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoord4xvOES"]
+    pub static mut epoxy_glMultiTexCoord4xvOES:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoordP1ui"]
+    pub static mut epoxy_glMultiTexCoordP1ui:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, type_: GLenum, coords: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoordP1uiv"]
+    pub static mut epoxy_glMultiTexCoordP1uiv: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLenum, type_: GLenum, coords: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoordP2ui"]
+    pub static mut epoxy_glMultiTexCoordP2ui:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, type_: GLenum, coords: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoordP2uiv"]
+    pub static mut epoxy_glMultiTexCoordP2uiv: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLenum, type_: GLenum, coords: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoordP3ui"]
+    pub static mut epoxy_glMultiTexCoordP3ui:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, type_: GLenum, coords: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoordP3uiv"]
+    pub static mut epoxy_glMultiTexCoordP3uiv: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLenum, type_: GLenum, coords: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoordP4ui"]
+    pub static mut epoxy_glMultiTexCoordP4ui:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLenum, type_: GLenum, coords: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoordP4uiv"]
+    pub static mut epoxy_glMultiTexCoordP4uiv: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLenum, type_: GLenum, coords: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexCoordPointerEXT"]
+    pub static mut epoxy_glMultiTexCoordPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexEnvfEXT"]
+    pub static mut epoxy_glMultiTexEnvfEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, pname: GLenum, param: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexEnvfvEXT"]
+    pub static mut epoxy_glMultiTexEnvfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            pname: GLenum,
+            params: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexEnviEXT"]
+    pub static mut epoxy_glMultiTexEnviEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, pname: GLenum, param: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexEnvivEXT"]
+    pub static mut epoxy_glMultiTexEnvivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexGendEXT"]
+    pub static mut epoxy_glMultiTexGendEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, coord: GLenum, pname: GLenum, param: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexGendvEXT"]
+    pub static mut epoxy_glMultiTexGendvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            coord: GLenum,
+            pname: GLenum,
+            params: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexGenfEXT"]
+    pub static mut epoxy_glMultiTexGenfEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, coord: GLenum, pname: GLenum, param: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexGenfvEXT"]
+    pub static mut epoxy_glMultiTexGenfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, coord: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexGeniEXT"]
+    pub static mut epoxy_glMultiTexGeniEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, coord: GLenum, pname: GLenum, param: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexGenivEXT"]
+    pub static mut epoxy_glMultiTexGenivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, coord: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexImage1DEXT"]
+    pub static mut epoxy_glMultiTexImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLint,
+            width: GLsizei,
+            border: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexImage2DEXT"]
+    pub static mut epoxy_glMultiTexImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            border: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexImage3DEXT"]
+    pub static mut epoxy_glMultiTexImage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            border: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexParameterIivEXT"]
+    pub static mut epoxy_glMultiTexParameterIivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexParameterIuivEXT"]
+    pub static mut epoxy_glMultiTexParameterIuivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, pname: GLenum, params: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexParameterfEXT"]
+    pub static mut epoxy_glMultiTexParameterfEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, pname: GLenum, param: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexParameterfvEXT"]
+    pub static mut epoxy_glMultiTexParameterfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            pname: GLenum,
+            params: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexParameteriEXT"]
+    pub static mut epoxy_glMultiTexParameteriEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, pname: GLenum, param: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexParameterivEXT"]
+    pub static mut epoxy_glMultiTexParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexRenderbufferEXT"]
+    pub static mut epoxy_glMultiTexRenderbufferEXT: ::std::option::Option<
+        unsafe extern "C" fn(texunit: GLenum, target: GLenum, renderbuffer: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexSubImage1DEXT"]
+    pub static mut epoxy_glMultiTexSubImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            width: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexSubImage2DEXT"]
+    pub static mut epoxy_glMultiTexSubImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glMultiTexSubImage3DEXT"]
+    pub static mut epoxy_glMultiTexSubImage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texunit: GLenum,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedBufferData"]
+    pub static mut epoxy_glNamedBufferData: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            size: GLsizeiptr,
+            data: *const ::std::os::raw::c_void,
+            usage: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedBufferDataEXT"]
+    pub static mut epoxy_glNamedBufferDataEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            size: GLsizeiptr,
+            data: *const ::std::os::raw::c_void,
+            usage: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedBufferPageCommitmentARB"]
+    pub static mut epoxy_glNamedBufferPageCommitmentARB: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLuint, offset: GLintptr, size: GLsizeiptr, commit: GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedBufferPageCommitmentEXT"]
+    pub static mut epoxy_glNamedBufferPageCommitmentEXT: ::std::option::Option<
+        unsafe extern "C" fn(buffer: GLuint, offset: GLintptr, size: GLsizeiptr, commit: GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedBufferStorage"]
+    pub static mut epoxy_glNamedBufferStorage: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            size: GLsizeiptr,
+            data: *const ::std::os::raw::c_void,
+            flags: GLbitfield,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedBufferStorageEXT"]
+    pub static mut epoxy_glNamedBufferStorageEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            size: GLsizeiptr,
+            data: *const ::std::os::raw::c_void,
+            flags: GLbitfield,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedBufferSubData"]
+    pub static mut epoxy_glNamedBufferSubData: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            offset: GLintptr,
+            size: GLsizeiptr,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedBufferSubDataEXT"]
+    pub static mut epoxy_glNamedBufferSubDataEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            offset: GLintptr,
+            size: GLsizeiptr,
+            data: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedCopyBufferSubDataEXT"]
+    pub static mut epoxy_glNamedCopyBufferSubDataEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            readBuffer: GLuint,
+            writeBuffer: GLuint,
+            readOffset: GLintptr,
+            writeOffset: GLintptr,
+            size: GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferDrawBuffer"]
+    pub static mut epoxy_glNamedFramebufferDrawBuffer:
+        ::std::option::Option<unsafe extern "C" fn(framebuffer: GLuint, buf: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferDrawBuffers"]
+    pub static mut epoxy_glNamedFramebufferDrawBuffers: ::std::option::Option<
+        unsafe extern "C" fn(framebuffer: GLuint, n: GLsizei, bufs: *const GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferParameteri"]
+    pub static mut epoxy_glNamedFramebufferParameteri: ::std::option::Option<
+        unsafe extern "C" fn(framebuffer: GLuint, pname: GLenum, param: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferParameteriEXT"]
+    pub static mut epoxy_glNamedFramebufferParameteriEXT: ::std::option::Option<
+        unsafe extern "C" fn(framebuffer: GLuint, pname: GLenum, param: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferReadBuffer"]
+    pub static mut epoxy_glNamedFramebufferReadBuffer:
+        ::std::option::Option<unsafe extern "C" fn(framebuffer: GLuint, src: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferRenderbuffer"]
+    pub static mut epoxy_glNamedFramebufferRenderbuffer: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            attachment: GLenum,
+            renderbuffertarget: GLenum,
+            renderbuffer: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferRenderbufferEXT"]
+    pub static mut epoxy_glNamedFramebufferRenderbufferEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            attachment: GLenum,
+            renderbuffertarget: GLenum,
+            renderbuffer: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferSampleLocationsfvARB"]
+    pub static mut epoxy_glNamedFramebufferSampleLocationsfvARB: ::std::option::Option<
+        unsafe extern "C" fn(framebuffer: GLuint, start: GLuint, count: GLsizei, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferSampleLocationsfvNV"]
+    pub static mut epoxy_glNamedFramebufferSampleLocationsfvNV: ::std::option::Option<
+        unsafe extern "C" fn(framebuffer: GLuint, start: GLuint, count: GLsizei, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferSamplePositionsfvAMD"]
+    pub static mut epoxy_glNamedFramebufferSamplePositionsfvAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            numsamples: GLuint,
+            pixelindex: GLuint,
+            values: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferTexture"]
+    pub static mut epoxy_glNamedFramebufferTexture: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            attachment: GLenum,
+            texture: GLuint,
+            level: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferTexture1DEXT"]
+    pub static mut epoxy_glNamedFramebufferTexture1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            attachment: GLenum,
+            textarget: GLenum,
+            texture: GLuint,
+            level: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferTexture2DEXT"]
+    pub static mut epoxy_glNamedFramebufferTexture2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            attachment: GLenum,
+            textarget: GLenum,
+            texture: GLuint,
+            level: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferTexture3DEXT"]
+    pub static mut epoxy_glNamedFramebufferTexture3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            attachment: GLenum,
+            textarget: GLenum,
+            texture: GLuint,
+            level: GLint,
+            zoffset: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferTextureEXT"]
+    pub static mut epoxy_glNamedFramebufferTextureEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            attachment: GLenum,
+            texture: GLuint,
+            level: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferTextureFaceEXT"]
+    pub static mut epoxy_glNamedFramebufferTextureFaceEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            attachment: GLenum,
+            texture: GLuint,
+            level: GLint,
+            face: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferTextureLayer"]
+    pub static mut epoxy_glNamedFramebufferTextureLayer: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            attachment: GLenum,
+            texture: GLuint,
+            level: GLint,
+            layer: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedFramebufferTextureLayerEXT"]
+    pub static mut epoxy_glNamedFramebufferTextureLayerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            framebuffer: GLuint,
+            attachment: GLenum,
+            texture: GLuint,
+            level: GLint,
+            layer: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedProgramLocalParameter4dEXT"]
+    pub static mut epoxy_glNamedProgramLocalParameter4dEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            target: GLenum,
+            index: GLuint,
+            x: GLdouble,
+            y: GLdouble,
+            z: GLdouble,
+            w: GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedProgramLocalParameter4dvEXT"]
+    pub static mut epoxy_glNamedProgramLocalParameter4dvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            target: GLenum,
+            index: GLuint,
+            params: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedProgramLocalParameter4fEXT"]
+    pub static mut epoxy_glNamedProgramLocalParameter4fEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            target: GLenum,
+            index: GLuint,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+            w: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedProgramLocalParameter4fvEXT"]
+    pub static mut epoxy_glNamedProgramLocalParameter4fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            target: GLenum,
+            index: GLuint,
+            params: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedProgramLocalParameterI4iEXT"]
+    pub static mut epoxy_glNamedProgramLocalParameterI4iEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            target: GLenum,
+            index: GLuint,
+            x: GLint,
+            y: GLint,
+            z: GLint,
+            w: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedProgramLocalParameterI4ivEXT"]
+    pub static mut epoxy_glNamedProgramLocalParameterI4ivEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, target: GLenum, index: GLuint, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedProgramLocalParameterI4uiEXT"]
+    pub static mut epoxy_glNamedProgramLocalParameterI4uiEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            target: GLenum,
+            index: GLuint,
+            x: GLuint,
+            y: GLuint,
+            z: GLuint,
+            w: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedProgramLocalParameterI4uivEXT"]
+    pub static mut epoxy_glNamedProgramLocalParameterI4uivEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, target: GLenum, index: GLuint, params: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedProgramLocalParameters4fvEXT"]
+    pub static mut epoxy_glNamedProgramLocalParameters4fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            target: GLenum,
+            index: GLuint,
+            count: GLsizei,
+            params: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedProgramLocalParametersI4ivEXT"]
+    pub static mut epoxy_glNamedProgramLocalParametersI4ivEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            target: GLenum,
+            index: GLuint,
+            count: GLsizei,
+            params: *const GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedProgramLocalParametersI4uivEXT"]
+    pub static mut epoxy_glNamedProgramLocalParametersI4uivEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            target: GLenum,
+            index: GLuint,
+            count: GLsizei,
+            params: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedProgramStringEXT"]
+    pub static mut epoxy_glNamedProgramStringEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            target: GLenum,
+            format: GLenum,
+            len: GLsizei,
+            string: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedRenderbufferStorage"]
+    pub static mut epoxy_glNamedRenderbufferStorage: ::std::option::Option<
+        unsafe extern "C" fn(
+            renderbuffer: GLuint,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedRenderbufferStorageEXT"]
+    pub static mut epoxy_glNamedRenderbufferStorageEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            renderbuffer: GLuint,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedRenderbufferStorageMultisample"]
+    pub static mut epoxy_glNamedRenderbufferStorageMultisample: ::std::option::Option<
+        unsafe extern "C" fn(
+            renderbuffer: GLuint,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedRenderbufferStorageMultisampleCoverageEXT"]
+    pub static mut epoxy_glNamedRenderbufferStorageMultisampleCoverageEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            renderbuffer: GLuint,
+            coverageSamples: GLsizei,
+            colorSamples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedRenderbufferStorageMultisampleEXT"]
+    pub static mut epoxy_glNamedRenderbufferStorageMultisampleEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            renderbuffer: GLuint,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNamedStringARB"]
+    pub static mut epoxy_glNamedStringARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            namelen: GLint,
+            name: *const GLchar,
+            stringlen: GLint,
+            string: *const GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNewList"]
+    pub static mut epoxy_glNewList:
+        ::std::option::Option<unsafe extern "C" fn(list: GLuint, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNewObjectBufferATI"]
+    pub static mut epoxy_glNewObjectBufferATI: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+            usage: GLenum,
+        ) -> GLuint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3b"]
+    pub static mut epoxy_glNormal3b:
+        ::std::option::Option<unsafe extern "C" fn(nx: GLbyte, ny: GLbyte, nz: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3bv"]
+    pub static mut epoxy_glNormal3bv: ::std::option::Option<unsafe extern "C" fn(v: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3d"]
+    pub static mut epoxy_glNormal3d:
+        ::std::option::Option<unsafe extern "C" fn(nx: GLdouble, ny: GLdouble, nz: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3dv"]
+    pub static mut epoxy_glNormal3dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3f"]
+    pub static mut epoxy_glNormal3f:
+        ::std::option::Option<unsafe extern "C" fn(nx: GLfloat, ny: GLfloat, nz: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3fVertex3fSUN"]
+    pub static mut epoxy_glNormal3fVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            nx: GLfloat,
+            ny: GLfloat,
+            nz: GLfloat,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3fVertex3fvSUN"]
+    pub static mut epoxy_glNormal3fVertex3fvSUN:
+        ::std::option::Option<unsafe extern "C" fn(n: *const GLfloat, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3fv"]
+    pub static mut epoxy_glNormal3fv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3hNV"]
+    pub static mut epoxy_glNormal3hNV:
+        ::std::option::Option<unsafe extern "C" fn(nx: GLhalfNV, ny: GLhalfNV, nz: GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3hvNV"]
+    pub static mut epoxy_glNormal3hvNV:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3i"]
+    pub static mut epoxy_glNormal3i:
+        ::std::option::Option<unsafe extern "C" fn(nx: GLint, ny: GLint, nz: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3iv"]
+    pub static mut epoxy_glNormal3iv: ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3s"]
+    pub static mut epoxy_glNormal3s:
+        ::std::option::Option<unsafe extern "C" fn(nx: GLshort, ny: GLshort, nz: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3sv"]
+    pub static mut epoxy_glNormal3sv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3x"]
+    pub static mut epoxy_glNormal3x:
+        ::std::option::Option<unsafe extern "C" fn(nx: GLfixed, ny: GLfixed, nz: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3xOES"]
+    pub static mut epoxy_glNormal3xOES:
+        ::std::option::Option<unsafe extern "C" fn(nx: GLfixed, ny: GLfixed, nz: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormal3xvOES"]
+    pub static mut epoxy_glNormal3xvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalFormatNV"]
+    pub static mut epoxy_glNormalFormatNV:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, stride: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalP3ui"]
+    pub static mut epoxy_glNormalP3ui:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, coords: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalP3uiv"]
+    pub static mut epoxy_glNormalP3uiv:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, coords: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalPointer"]
+    pub static mut epoxy_glNormalPointer: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalPointerEXT"]
+    pub static mut epoxy_glNormalPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            stride: GLsizei,
+            count: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalPointerListIBM"]
+    pub static mut epoxy_glNormalPointerListIBM: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            stride: GLint,
+            pointer: *mut *const ::std::os::raw::c_void,
+            ptrstride: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalPointervINTEL"]
+    pub static mut epoxy_glNormalPointervINTEL: ::std::option::Option<
+        unsafe extern "C" fn(type_: GLenum, pointer: *mut *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalStream3bATI"]
+    pub static mut epoxy_glNormalStream3bATI: ::std::option::Option<
+        unsafe extern "C" fn(stream: GLenum, nx: GLbyte, ny: GLbyte, nz: GLbyte),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalStream3bvATI"]
+    pub static mut epoxy_glNormalStream3bvATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalStream3dATI"]
+    pub static mut epoxy_glNormalStream3dATI: ::std::option::Option<
+        unsafe extern "C" fn(stream: GLenum, nx: GLdouble, ny: GLdouble, nz: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalStream3dvATI"]
+    pub static mut epoxy_glNormalStream3dvATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalStream3fATI"]
+    pub static mut epoxy_glNormalStream3fATI: ::std::option::Option<
+        unsafe extern "C" fn(stream: GLenum, nx: GLfloat, ny: GLfloat, nz: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalStream3fvATI"]
+    pub static mut epoxy_glNormalStream3fvATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalStream3iATI"]
+    pub static mut epoxy_glNormalStream3iATI: ::std::option::Option<
+        unsafe extern "C" fn(stream: GLenum, nx: GLint, ny: GLint, nz: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalStream3ivATI"]
+    pub static mut epoxy_glNormalStream3ivATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalStream3sATI"]
+    pub static mut epoxy_glNormalStream3sATI: ::std::option::Option<
+        unsafe extern "C" fn(stream: GLenum, nx: GLshort, ny: GLshort, nz: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glNormalStream3svATI"]
+    pub static mut epoxy_glNormalStream3svATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glObjectLabel"]
+    pub static mut epoxy_glObjectLabel: ::std::option::Option<
+        unsafe extern "C" fn(
+            identifier: GLenum,
+            name: GLuint,
+            length: GLsizei,
+            label: *const GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glObjectLabelKHR"]
+    pub static mut epoxy_glObjectLabelKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            identifier: GLenum,
+            name: GLuint,
+            length: GLsizei,
+            label: *const GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glObjectPtrLabel"]
+    pub static mut epoxy_glObjectPtrLabel: ::std::option::Option<
+        unsafe extern "C" fn(
+            ptr: *const ::std::os::raw::c_void,
+            length: GLsizei,
+            label: *const GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glObjectPtrLabelKHR"]
+    pub static mut epoxy_glObjectPtrLabelKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            ptr: *const ::std::os::raw::c_void,
+            length: GLsizei,
+            label: *const GLchar,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glObjectPurgeableAPPLE"]
+    pub static mut epoxy_glObjectPurgeableAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(objectType: GLenum, name: GLuint, option: GLenum) -> GLenum,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glObjectUnpurgeableAPPLE"]
+    pub static mut epoxy_glObjectUnpurgeableAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(objectType: GLenum, name: GLuint, option: GLenum) -> GLenum,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glOrtho"]
+    pub static mut epoxy_glOrtho: ::std::option::Option<
+        unsafe extern "C" fn(
+            left: GLdouble,
+            right: GLdouble,
+            bottom: GLdouble,
+            top: GLdouble,
+            zNear: GLdouble,
+            zFar: GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glOrthof"]
+    pub static mut epoxy_glOrthof: ::std::option::Option<
+        unsafe extern "C" fn(
+            l: GLfloat,
+            r: GLfloat,
+            b: GLfloat,
+            t: GLfloat,
+            n: GLfloat,
+            f: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glOrthofOES"]
+    pub static mut epoxy_glOrthofOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            l: GLfloat,
+            r: GLfloat,
+            b: GLfloat,
+            t: GLfloat,
+            n: GLfloat,
+            f: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glOrthox"]
+    pub static mut epoxy_glOrthox: ::std::option::Option<
+        unsafe extern "C" fn(
+            l: GLfixed,
+            r: GLfixed,
+            b: GLfixed,
+            t: GLfixed,
+            n: GLfixed,
+            f: GLfixed,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glOrthoxOES"]
+    pub static mut epoxy_glOrthoxOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            l: GLfixed,
+            r: GLfixed,
+            b: GLfixed,
+            t: GLfixed,
+            n: GLfixed,
+            f: GLfixed,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPNTrianglesfATI"]
+    pub static mut epoxy_glPNTrianglesfATI:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPNTrianglesiATI"]
+    pub static mut epoxy_glPNTrianglesiATI:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPassTexCoordATI"]
+    pub static mut epoxy_glPassTexCoordATI:
+        ::std::option::Option<unsafe extern "C" fn(dst: GLuint, coord: GLuint, swizzle: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPassThrough"]
+    pub static mut epoxy_glPassThrough: ::std::option::Option<unsafe extern "C" fn(token: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPassThroughxOES"]
+    pub static mut epoxy_glPassThroughxOES:
+        ::std::option::Option<unsafe extern "C" fn(token: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPatchParameterfv"]
+    pub static mut epoxy_glPatchParameterfv:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, values: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPatchParameteri"]
+    pub static mut epoxy_glPatchParameteri:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, value: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPatchParameteriEXT"]
+    pub static mut epoxy_glPatchParameteriEXT:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, value: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPatchParameteriOES"]
+    pub static mut epoxy_glPatchParameteriOES:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, value: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathColorGenNV"]
+    pub static mut epoxy_glPathColorGenNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            color: GLenum,
+            genMode: GLenum,
+            colorFormat: GLenum,
+            coeffs: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathCommandsNV"]
+    pub static mut epoxy_glPathCommandsNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            path: GLuint,
+            numCommands: GLsizei,
+            commands: *const GLubyte,
+            numCoords: GLsizei,
+            coordType: GLenum,
+            coords: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathCoordsNV"]
+    pub static mut epoxy_glPathCoordsNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            path: GLuint,
+            numCoords: GLsizei,
+            coordType: GLenum,
+            coords: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathCoverDepthFuncNV"]
+    pub static mut epoxy_glPathCoverDepthFuncNV:
+        ::std::option::Option<unsafe extern "C" fn(func: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathDashArrayNV"]
+    pub static mut epoxy_glPathDashArrayNV: ::std::option::Option<
+        unsafe extern "C" fn(path: GLuint, dashCount: GLsizei, dashArray: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathFogGenNV"]
+    pub static mut epoxy_glPathFogGenNV:
+        ::std::option::Option<unsafe extern "C" fn(genMode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathGlyphIndexArrayNV"]
+    pub static mut epoxy_glPathGlyphIndexArrayNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            firstPathName: GLuint,
+            fontTarget: GLenum,
+            fontName: *const ::std::os::raw::c_void,
+            fontStyle: GLbitfield,
+            firstGlyphIndex: GLuint,
+            numGlyphs: GLsizei,
+            pathParameterTemplate: GLuint,
+            emScale: GLfloat,
+        ) -> GLenum,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathGlyphIndexRangeNV"]
+    pub static mut epoxy_glPathGlyphIndexRangeNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            fontTarget: GLenum,
+            fontName: *const ::std::os::raw::c_void,
+            fontStyle: GLbitfield,
+            pathParameterTemplate: GLuint,
+            emScale: GLfloat,
+            baseAndCount: GLuint,
+        ) -> GLenum,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathGlyphRangeNV"]
+    pub static mut epoxy_glPathGlyphRangeNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            firstPathName: GLuint,
+            fontTarget: GLenum,
+            fontName: *const ::std::os::raw::c_void,
+            fontStyle: GLbitfield,
+            firstGlyph: GLuint,
+            numGlyphs: GLsizei,
+            handleMissingGlyphs: GLenum,
+            pathParameterTemplate: GLuint,
+            emScale: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathGlyphsNV"]
+    pub static mut epoxy_glPathGlyphsNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            firstPathName: GLuint,
+            fontTarget: GLenum,
+            fontName: *const ::std::os::raw::c_void,
+            fontStyle: GLbitfield,
+            numGlyphs: GLsizei,
+            type_: GLenum,
+            charcodes: *const ::std::os::raw::c_void,
+            handleMissingGlyphs: GLenum,
+            pathParameterTemplate: GLuint,
+            emScale: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathMemoryGlyphIndexArrayNV"]
+    pub static mut epoxy_glPathMemoryGlyphIndexArrayNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            firstPathName: GLuint,
+            fontTarget: GLenum,
+            fontSize: GLsizeiptr,
+            fontData: *const ::std::os::raw::c_void,
+            faceIndex: GLsizei,
+            firstGlyphIndex: GLuint,
+            numGlyphs: GLsizei,
+            pathParameterTemplate: GLuint,
+            emScale: GLfloat,
+        ) -> GLenum,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathParameterfNV"]
+    pub static mut epoxy_glPathParameterfNV:
+        ::std::option::Option<unsafe extern "C" fn(path: GLuint, pname: GLenum, value: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathParameterfvNV"]
+    pub static mut epoxy_glPathParameterfvNV: ::std::option::Option<
+        unsafe extern "C" fn(path: GLuint, pname: GLenum, value: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathParameteriNV"]
+    pub static mut epoxy_glPathParameteriNV:
+        ::std::option::Option<unsafe extern "C" fn(path: GLuint, pname: GLenum, value: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathParameterivNV"]
+    pub static mut epoxy_glPathParameterivNV: ::std::option::Option<
+        unsafe extern "C" fn(path: GLuint, pname: GLenum, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathStencilDepthOffsetNV"]
+    pub static mut epoxy_glPathStencilDepthOffsetNV:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLfloat, units: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathStencilFuncNV"]
+    pub static mut epoxy_glPathStencilFuncNV:
+        ::std::option::Option<unsafe extern "C" fn(func: GLenum, ref_: GLint, mask: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathStringNV"]
+    pub static mut epoxy_glPathStringNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            path: GLuint,
+            format: GLenum,
+            length: GLsizei,
+            pathString: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathSubCommandsNV"]
+    pub static mut epoxy_glPathSubCommandsNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            path: GLuint,
+            commandStart: GLsizei,
+            commandsToDelete: GLsizei,
+            numCommands: GLsizei,
+            commands: *const GLubyte,
+            numCoords: GLsizei,
+            coordType: GLenum,
+            coords: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathSubCoordsNV"]
+    pub static mut epoxy_glPathSubCoordsNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            path: GLuint,
+            coordStart: GLsizei,
+            numCoords: GLsizei,
+            coordType: GLenum,
+            coords: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPathTexGenNV"]
+    pub static mut epoxy_glPathTexGenNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            texCoordSet: GLenum,
+            genMode: GLenum,
+            components: GLint,
+            coeffs: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPauseTransformFeedback"]
+    pub static mut epoxy_glPauseTransformFeedback: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPauseTransformFeedbackNV"]
+    pub static mut epoxy_glPauseTransformFeedbackNV: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelDataRangeNV"]
+    pub static mut epoxy_glPixelDataRangeNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            length: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelMapfv"]
+    pub static mut epoxy_glPixelMapfv: ::std::option::Option<
+        unsafe extern "C" fn(map: GLenum, mapsize: GLsizei, values: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelMapuiv"]
+    pub static mut epoxy_glPixelMapuiv: ::std::option::Option<
+        unsafe extern "C" fn(map: GLenum, mapsize: GLsizei, values: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelMapusv"]
+    pub static mut epoxy_glPixelMapusv: ::std::option::Option<
+        unsafe extern "C" fn(map: GLenum, mapsize: GLsizei, values: *const GLushort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelMapx"]
+    pub static mut epoxy_glPixelMapx: ::std::option::Option<
+        unsafe extern "C" fn(map: GLenum, size: GLint, values: *const GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelStoref"]
+    pub static mut epoxy_glPixelStoref:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelStorei"]
+    pub static mut epoxy_glPixelStorei:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelStorex"]
+    pub static mut epoxy_glPixelStorex:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelTexGenParameterfSGIS"]
+    pub static mut epoxy_glPixelTexGenParameterfSGIS:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelTexGenParameterfvSGIS"]
+    pub static mut epoxy_glPixelTexGenParameterfvSGIS:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelTexGenParameteriSGIS"]
+    pub static mut epoxy_glPixelTexGenParameteriSGIS:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelTexGenParameterivSGIS"]
+    pub static mut epoxy_glPixelTexGenParameterivSGIS:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelTexGenSGIX"]
+    pub static mut epoxy_glPixelTexGenSGIX:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelTransferf"]
+    pub static mut epoxy_glPixelTransferf:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelTransferi"]
+    pub static mut epoxy_glPixelTransferi:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelTransferxOES"]
+    pub static mut epoxy_glPixelTransferxOES:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelTransformParameterfEXT"]
+    pub static mut epoxy_glPixelTransformParameterfEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelTransformParameterfvEXT"]
+    pub static mut epoxy_glPixelTransformParameterfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelTransformParameteriEXT"]
+    pub static mut epoxy_glPixelTransformParameteriEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelTransformParameterivEXT"]
+    pub static mut epoxy_glPixelTransformParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelZoom"]
+    pub static mut epoxy_glPixelZoom:
+        ::std::option::Option<unsafe extern "C" fn(xfactor: GLfloat, yfactor: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPixelZoomxOES"]
+    pub static mut epoxy_glPixelZoomxOES:
+        ::std::option::Option<unsafe extern "C" fn(xfactor: GLfixed, yfactor: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointAlongPathNV"]
+    pub static mut epoxy_glPointAlongPathNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            path: GLuint,
+            startSegment: GLsizei,
+            numSegments: GLsizei,
+            distance: GLfloat,
+            x: *mut GLfloat,
+            y: *mut GLfloat,
+            tangentX: *mut GLfloat,
+            tangentY: *mut GLfloat,
+        ) -> GLboolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameterf"]
+    pub static mut epoxy_glPointParameterf:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameterfARB"]
+    pub static mut epoxy_glPointParameterfARB:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameterfEXT"]
+    pub static mut epoxy_glPointParameterfEXT:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameterfSGIS"]
+    pub static mut epoxy_glPointParameterfSGIS:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameterfv"]
+    pub static mut epoxy_glPointParameterfv:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameterfvARB"]
+    pub static mut epoxy_glPointParameterfvARB:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameterfvEXT"]
+    pub static mut epoxy_glPointParameterfvEXT:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameterfvSGIS"]
+    pub static mut epoxy_glPointParameterfvSGIS:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameteri"]
+    pub static mut epoxy_glPointParameteri:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameteriNV"]
+    pub static mut epoxy_glPointParameteriNV:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameteriv"]
+    pub static mut epoxy_glPointParameteriv:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameterivNV"]
+    pub static mut epoxy_glPointParameterivNV:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameterx"]
+    pub static mut epoxy_glPointParameterx:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameterxOES"]
+    pub static mut epoxy_glPointParameterxOES:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameterxv"]
+    pub static mut epoxy_glPointParameterxv:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointParameterxvOES"]
+    pub static mut epoxy_glPointParameterxvOES:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointSize"]
+    pub static mut epoxy_glPointSize: ::std::option::Option<unsafe extern "C" fn(size: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointSizePointerOES"]
+    pub static mut epoxy_glPointSizePointerOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointSizex"]
+    pub static mut epoxy_glPointSizex: ::std::option::Option<unsafe extern "C" fn(size: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPointSizexOES"]
+    pub static mut epoxy_glPointSizexOES:
+        ::std::option::Option<unsafe extern "C" fn(size: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPollAsyncSGIX"]
+    pub static mut epoxy_glPollAsyncSGIX:
+        ::std::option::Option<unsafe extern "C" fn(markerp: *mut GLuint) -> GLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPollInstrumentsSGIX"]
+    pub static mut epoxy_glPollInstrumentsSGIX:
+        ::std::option::Option<unsafe extern "C" fn(marker_p: *mut GLint) -> GLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPolygonMode"]
+    pub static mut epoxy_glPolygonMode:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPolygonModeNV"]
+    pub static mut epoxy_glPolygonModeNV:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPolygonOffset"]
+    pub static mut epoxy_glPolygonOffset:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLfloat, units: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPolygonOffsetClampEXT"]
+    pub static mut epoxy_glPolygonOffsetClampEXT: ::std::option::Option<
+        unsafe extern "C" fn(factor: GLfloat, units: GLfloat, clamp: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPolygonOffsetEXT"]
+    pub static mut epoxy_glPolygonOffsetEXT:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLfloat, bias: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPolygonOffsetx"]
+    pub static mut epoxy_glPolygonOffsetx:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLfixed, units: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPolygonOffsetxOES"]
+    pub static mut epoxy_glPolygonOffsetxOES:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLfixed, units: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPolygonStipple"]
+    pub static mut epoxy_glPolygonStipple:
+        ::std::option::Option<unsafe extern "C" fn(mask: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPopAttrib"]
+    pub static mut epoxy_glPopAttrib: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPopClientAttrib"]
+    pub static mut epoxy_glPopClientAttrib: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPopDebugGroup"]
+    pub static mut epoxy_glPopDebugGroup: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPopDebugGroupKHR"]
+    pub static mut epoxy_glPopDebugGroupKHR: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPopGroupMarkerEXT"]
+    pub static mut epoxy_glPopGroupMarkerEXT: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPopMatrix"]
+    pub static mut epoxy_glPopMatrix: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPopName"]
+    pub static mut epoxy_glPopName: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPresentFrameDualFillNV"]
+    pub static mut epoxy_glPresentFrameDualFillNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            video_slot: GLuint,
+            minPresentTime: GLuint64EXT,
+            beginPresentTimeId: GLuint,
+            presentDurationId: GLuint,
+            type_: GLenum,
+            target0: GLenum,
+            fill0: GLuint,
+            target1: GLenum,
+            fill1: GLuint,
+            target2: GLenum,
+            fill2: GLuint,
+            target3: GLenum,
+            fill3: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPresentFrameKeyedNV"]
+    pub static mut epoxy_glPresentFrameKeyedNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            video_slot: GLuint,
+            minPresentTime: GLuint64EXT,
+            beginPresentTimeId: GLuint,
+            presentDurationId: GLuint,
+            type_: GLenum,
+            target0: GLenum,
+            fill0: GLuint,
+            key0: GLuint,
+            target1: GLenum,
+            fill1: GLuint,
+            key1: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPrimitiveBoundingBox"]
+    pub static mut epoxy_glPrimitiveBoundingBox: ::std::option::Option<
+        unsafe extern "C" fn(
+            minX: GLfloat,
+            minY: GLfloat,
+            minZ: GLfloat,
+            minW: GLfloat,
+            maxX: GLfloat,
+            maxY: GLfloat,
+            maxZ: GLfloat,
+            maxW: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPrimitiveBoundingBoxARB"]
+    pub static mut epoxy_glPrimitiveBoundingBoxARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            minX: GLfloat,
+            minY: GLfloat,
+            minZ: GLfloat,
+            minW: GLfloat,
+            maxX: GLfloat,
+            maxY: GLfloat,
+            maxZ: GLfloat,
+            maxW: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPrimitiveBoundingBoxEXT"]
+    pub static mut epoxy_glPrimitiveBoundingBoxEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            minX: GLfloat,
+            minY: GLfloat,
+            minZ: GLfloat,
+            minW: GLfloat,
+            maxX: GLfloat,
+            maxY: GLfloat,
+            maxZ: GLfloat,
+            maxW: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPrimitiveBoundingBoxOES"]
+    pub static mut epoxy_glPrimitiveBoundingBoxOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            minX: GLfloat,
+            minY: GLfloat,
+            minZ: GLfloat,
+            minW: GLfloat,
+            maxX: GLfloat,
+            maxY: GLfloat,
+            maxZ: GLfloat,
+            maxW: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPrimitiveRestartIndex"]
+    pub static mut epoxy_glPrimitiveRestartIndex:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPrimitiveRestartIndexNV"]
+    pub static mut epoxy_glPrimitiveRestartIndexNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPrimitiveRestartNV"]
+    pub static mut epoxy_glPrimitiveRestartNV: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPrioritizeTextures"]
+    pub static mut epoxy_glPrioritizeTextures: ::std::option::Option<
+        unsafe extern "C" fn(n: GLsizei, textures: *const GLuint, priorities: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPrioritizeTexturesEXT"]
+    pub static mut epoxy_glPrioritizeTexturesEXT: ::std::option::Option<
+        unsafe extern "C" fn(n: GLsizei, textures: *const GLuint, priorities: *const GLclampf),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPrioritizeTexturesxOES"]
+    pub static mut epoxy_glPrioritizeTexturesxOES: ::std::option::Option<
+        unsafe extern "C" fn(n: GLsizei, textures: *const GLuint, priorities: *const GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramBinary"]
+    pub static mut epoxy_glProgramBinary: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            binaryFormat: GLenum,
+            binary: *const ::std::os::raw::c_void,
+            length: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramBinaryOES"]
+    pub static mut epoxy_glProgramBinaryOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            binaryFormat: GLenum,
+            binary: *const ::std::os::raw::c_void,
+            length: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramBufferParametersIivNV"]
+    pub static mut epoxy_glProgramBufferParametersIivNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            bindingIndex: GLuint,
+            wordIndex: GLuint,
+            count: GLsizei,
+            params: *const GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramBufferParametersIuivNV"]
+    pub static mut epoxy_glProgramBufferParametersIuivNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            bindingIndex: GLuint,
+            wordIndex: GLuint,
+            count: GLsizei,
+            params: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramBufferParametersfvNV"]
+    pub static mut epoxy_glProgramBufferParametersfvNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            bindingIndex: GLuint,
+            wordIndex: GLuint,
+            count: GLsizei,
+            params: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramEnvParameter4dARB"]
+    pub static mut epoxy_glProgramEnvParameter4dARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            index: GLuint,
+            x: GLdouble,
+            y: GLdouble,
+            z: GLdouble,
+            w: GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramEnvParameter4dvARB"]
+    pub static mut epoxy_glProgramEnvParameter4dvARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramEnvParameter4fARB"]
+    pub static mut epoxy_glProgramEnvParameter4fARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            index: GLuint,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+            w: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramEnvParameter4fvARB"]
+    pub static mut epoxy_glProgramEnvParameter4fvARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramEnvParameterI4iNV"]
+    pub static mut epoxy_glProgramEnvParameterI4iNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, x: GLint, y: GLint, z: GLint, w: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramEnvParameterI4ivNV"]
+    pub static mut epoxy_glProgramEnvParameterI4ivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramEnvParameterI4uiNV"]
+    pub static mut epoxy_glProgramEnvParameterI4uiNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            index: GLuint,
+            x: GLuint,
+            y: GLuint,
+            z: GLuint,
+            w: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramEnvParameterI4uivNV"]
+    pub static mut epoxy_glProgramEnvParameterI4uivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramEnvParameters4fvEXT"]
+    pub static mut epoxy_glProgramEnvParameters4fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, count: GLsizei, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramEnvParametersI4ivNV"]
+    pub static mut epoxy_glProgramEnvParametersI4ivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, count: GLsizei, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramEnvParametersI4uivNV"]
+    pub static mut epoxy_glProgramEnvParametersI4uivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, count: GLsizei, params: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramLocalParameter4dARB"]
+    pub static mut epoxy_glProgramLocalParameter4dARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            index: GLuint,
+            x: GLdouble,
+            y: GLdouble,
+            z: GLdouble,
+            w: GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramLocalParameter4dvARB"]
+    pub static mut epoxy_glProgramLocalParameter4dvARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramLocalParameter4fARB"]
+    pub static mut epoxy_glProgramLocalParameter4fARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            index: GLuint,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+            w: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramLocalParameter4fvARB"]
+    pub static mut epoxy_glProgramLocalParameter4fvARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramLocalParameterI4iNV"]
+    pub static mut epoxy_glProgramLocalParameterI4iNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, x: GLint, y: GLint, z: GLint, w: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramLocalParameterI4ivNV"]
+    pub static mut epoxy_glProgramLocalParameterI4ivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramLocalParameterI4uiNV"]
+    pub static mut epoxy_glProgramLocalParameterI4uiNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            index: GLuint,
+            x: GLuint,
+            y: GLuint,
+            z: GLuint,
+            w: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramLocalParameterI4uivNV"]
+    pub static mut epoxy_glProgramLocalParameterI4uivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, params: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramLocalParameters4fvEXT"]
+    pub static mut epoxy_glProgramLocalParameters4fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, count: GLsizei, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramLocalParametersI4ivNV"]
+    pub static mut epoxy_glProgramLocalParametersI4ivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, count: GLsizei, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramLocalParametersI4uivNV"]
+    pub static mut epoxy_glProgramLocalParametersI4uivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, count: GLsizei, params: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramNamedParameter4dNV"]
+    pub static mut epoxy_glProgramNamedParameter4dNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            id: GLuint,
+            len: GLsizei,
+            name: *const GLubyte,
+            x: GLdouble,
+            y: GLdouble,
+            z: GLdouble,
+            w: GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramNamedParameter4dvNV"]
+    pub static mut epoxy_glProgramNamedParameter4dvNV: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, len: GLsizei, name: *const GLubyte, v: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramNamedParameter4fNV"]
+    pub static mut epoxy_glProgramNamedParameter4fNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            id: GLuint,
+            len: GLsizei,
+            name: *const GLubyte,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+            w: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramNamedParameter4fvNV"]
+    pub static mut epoxy_glProgramNamedParameter4fvNV: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, len: GLsizei, name: *const GLubyte, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramParameter4dNV"]
+    pub static mut epoxy_glProgramParameter4dNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            index: GLuint,
+            x: GLdouble,
+            y: GLdouble,
+            z: GLdouble,
+            w: GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramParameter4dvNV"]
+    pub static mut epoxy_glProgramParameter4dvNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, v: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramParameter4fNV"]
+    pub static mut epoxy_glProgramParameter4fNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            index: GLuint,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+            w: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramParameter4fvNV"]
+    pub static mut epoxy_glProgramParameter4fvNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramParameteri"]
+    pub static mut epoxy_glProgramParameteri:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, pname: GLenum, value: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramParameteriARB"]
+    pub static mut epoxy_glProgramParameteriARB:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, pname: GLenum, value: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramParameteriEXT"]
+    pub static mut epoxy_glProgramParameteriEXT:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, pname: GLenum, value: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramParameters4dvNV"]
+    pub static mut epoxy_glProgramParameters4dvNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, count: GLsizei, v: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramParameters4fvNV"]
+    pub static mut epoxy_glProgramParameters4fvNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, index: GLuint, count: GLsizei, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramPathFragmentInputGenNV"]
+    pub static mut epoxy_glProgramPathFragmentInputGenNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            genMode: GLenum,
+            components: GLint,
+            coeffs: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramStringARB"]
+    pub static mut epoxy_glProgramStringARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            format: GLenum,
+            len: GLsizei,
+            string: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramSubroutineParametersuivNV"]
+    pub static mut epoxy_glProgramSubroutineParametersuivNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, count: GLsizei, params: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1d"]
+    pub static mut epoxy_glProgramUniform1d:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1dEXT"]
+    pub static mut epoxy_glProgramUniform1dEXT:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, location: GLint, x: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1dv"]
+    pub static mut epoxy_glProgramUniform1dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1dvEXT"]
+    pub static mut epoxy_glProgramUniform1dvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1f"]
+    pub static mut epoxy_glProgramUniform1f:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1fEXT"]
+    pub static mut epoxy_glProgramUniform1fEXT:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1fv"]
+    pub static mut epoxy_glProgramUniform1fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1fvEXT"]
+    pub static mut epoxy_glProgramUniform1fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1i"]
+    pub static mut epoxy_glProgramUniform1i:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1i64ARB"]
+    pub static mut epoxy_glProgramUniform1i64ARB:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, location: GLint, x: GLint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1i64NV"]
+    pub static mut epoxy_glProgramUniform1i64NV: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, x: GLint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1i64vARB"]
+    pub static mut epoxy_glProgramUniform1i64vARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1i64vNV"]
+    pub static mut epoxy_glProgramUniform1i64vNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1iEXT"]
+    pub static mut epoxy_glProgramUniform1iEXT:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1iv"]
+    pub static mut epoxy_glProgramUniform1iv: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1ivEXT"]
+    pub static mut epoxy_glProgramUniform1ivEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1ui"]
+    pub static mut epoxy_glProgramUniform1ui:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1ui64ARB"]
+    pub static mut epoxy_glProgramUniform1ui64ARB:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, location: GLint, x: GLuint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1ui64NV"]
+    pub static mut epoxy_glProgramUniform1ui64NV: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, x: GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1ui64vARB"]
+    pub static mut epoxy_glProgramUniform1ui64vARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1ui64vNV"]
+    pub static mut epoxy_glProgramUniform1ui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1uiEXT"]
+    pub static mut epoxy_glProgramUniform1uiEXT:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1uiv"]
+    pub static mut epoxy_glProgramUniform1uiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform1uivEXT"]
+    pub static mut epoxy_glProgramUniform1uivEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2d"]
+    pub static mut epoxy_glProgramUniform2d: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLdouble, v1: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2dEXT"]
+    pub static mut epoxy_glProgramUniform2dEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, x: GLdouble, y: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2dv"]
+    pub static mut epoxy_glProgramUniform2dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2dvEXT"]
+    pub static mut epoxy_glProgramUniform2dvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2f"]
+    pub static mut epoxy_glProgramUniform2f: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLfloat, v1: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2fEXT"]
+    pub static mut epoxy_glProgramUniform2fEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLfloat, v1: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2fv"]
+    pub static mut epoxy_glProgramUniform2fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2fvEXT"]
+    pub static mut epoxy_glProgramUniform2fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2i"]
+    pub static mut epoxy_glProgramUniform2i: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLint, v1: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2i64ARB"]
+    pub static mut epoxy_glProgramUniform2i64ARB: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, x: GLint64, y: GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2i64NV"]
+    pub static mut epoxy_glProgramUniform2i64NV: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, x: GLint64EXT, y: GLint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2i64vARB"]
+    pub static mut epoxy_glProgramUniform2i64vARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2i64vNV"]
+    pub static mut epoxy_glProgramUniform2i64vNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2iEXT"]
+    pub static mut epoxy_glProgramUniform2iEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLint, v1: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2iv"]
+    pub static mut epoxy_glProgramUniform2iv: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2ivEXT"]
+    pub static mut epoxy_glProgramUniform2ivEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2ui"]
+    pub static mut epoxy_glProgramUniform2ui: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLuint, v1: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2ui64ARB"]
+    pub static mut epoxy_glProgramUniform2ui64ARB: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, x: GLuint64, y: GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2ui64NV"]
+    pub static mut epoxy_glProgramUniform2ui64NV: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, x: GLuint64EXT, y: GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2ui64vARB"]
+    pub static mut epoxy_glProgramUniform2ui64vARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2ui64vNV"]
+    pub static mut epoxy_glProgramUniform2ui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2uiEXT"]
+    pub static mut epoxy_glProgramUniform2uiEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLuint, v1: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2uiv"]
+    pub static mut epoxy_glProgramUniform2uiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform2uivEXT"]
+    pub static mut epoxy_glProgramUniform2uivEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3d"]
+    pub static mut epoxy_glProgramUniform3d: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            v0: GLdouble,
+            v1: GLdouble,
+            v2: GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3dEXT"]
+    pub static mut epoxy_glProgramUniform3dEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            x: GLdouble,
+            y: GLdouble,
+            z: GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3dv"]
+    pub static mut epoxy_glProgramUniform3dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3dvEXT"]
+    pub static mut epoxy_glProgramUniform3dvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3f"]
+    pub static mut epoxy_glProgramUniform3f: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            v0: GLfloat,
+            v1: GLfloat,
+            v2: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3fEXT"]
+    pub static mut epoxy_glProgramUniform3fEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            v0: GLfloat,
+            v1: GLfloat,
+            v2: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3fv"]
+    pub static mut epoxy_glProgramUniform3fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3fvEXT"]
+    pub static mut epoxy_glProgramUniform3fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3i"]
+    pub static mut epoxy_glProgramUniform3i: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLint, v1: GLint, v2: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3i64ARB"]
+    pub static mut epoxy_glProgramUniform3i64ARB: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, x: GLint64, y: GLint64, z: GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3i64NV"]
+    pub static mut epoxy_glProgramUniform3i64NV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            x: GLint64EXT,
+            y: GLint64EXT,
+            z: GLint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3i64vARB"]
+    pub static mut epoxy_glProgramUniform3i64vARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3i64vNV"]
+    pub static mut epoxy_glProgramUniform3i64vNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3iEXT"]
+    pub static mut epoxy_glProgramUniform3iEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLint, v1: GLint, v2: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3iv"]
+    pub static mut epoxy_glProgramUniform3iv: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3ivEXT"]
+    pub static mut epoxy_glProgramUniform3ivEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3ui"]
+    pub static mut epoxy_glProgramUniform3ui: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3ui64ARB"]
+    pub static mut epoxy_glProgramUniform3ui64ARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            x: GLuint64,
+            y: GLuint64,
+            z: GLuint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3ui64NV"]
+    pub static mut epoxy_glProgramUniform3ui64NV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            x: GLuint64EXT,
+            y: GLuint64EXT,
+            z: GLuint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3ui64vARB"]
+    pub static mut epoxy_glProgramUniform3ui64vARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3ui64vNV"]
+    pub static mut epoxy_glProgramUniform3ui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3uiEXT"]
+    pub static mut epoxy_glProgramUniform3uiEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3uiv"]
+    pub static mut epoxy_glProgramUniform3uiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform3uivEXT"]
+    pub static mut epoxy_glProgramUniform3uivEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4d"]
+    pub static mut epoxy_glProgramUniform4d: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            v0: GLdouble,
+            v1: GLdouble,
+            v2: GLdouble,
+            v3: GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4dEXT"]
+    pub static mut epoxy_glProgramUniform4dEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            x: GLdouble,
+            y: GLdouble,
+            z: GLdouble,
+            w: GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4dv"]
+    pub static mut epoxy_glProgramUniform4dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4dvEXT"]
+    pub static mut epoxy_glProgramUniform4dvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4f"]
+    pub static mut epoxy_glProgramUniform4f: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            v0: GLfloat,
+            v1: GLfloat,
+            v2: GLfloat,
+            v3: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4fEXT"]
+    pub static mut epoxy_glProgramUniform4fEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            v0: GLfloat,
+            v1: GLfloat,
+            v2: GLfloat,
+            v3: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4fv"]
+    pub static mut epoxy_glProgramUniform4fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4fvEXT"]
+    pub static mut epoxy_glProgramUniform4fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4i"]
+    pub static mut epoxy_glProgramUniform4i: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            v0: GLint,
+            v1: GLint,
+            v2: GLint,
+            v3: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4i64ARB"]
+    pub static mut epoxy_glProgramUniform4i64ARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            x: GLint64,
+            y: GLint64,
+            z: GLint64,
+            w: GLint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4i64NV"]
+    pub static mut epoxy_glProgramUniform4i64NV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            x: GLint64EXT,
+            y: GLint64EXT,
+            z: GLint64EXT,
+            w: GLint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4i64vARB"]
+    pub static mut epoxy_glProgramUniform4i64vARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4i64vNV"]
+    pub static mut epoxy_glProgramUniform4i64vNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4iEXT"]
+    pub static mut epoxy_glProgramUniform4iEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            v0: GLint,
+            v1: GLint,
+            v2: GLint,
+            v3: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4iv"]
+    pub static mut epoxy_glProgramUniform4iv: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4ivEXT"]
+    pub static mut epoxy_glProgramUniform4ivEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4ui"]
+    pub static mut epoxy_glProgramUniform4ui: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            v0: GLuint,
+            v1: GLuint,
+            v2: GLuint,
+            v3: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4ui64ARB"]
+    pub static mut epoxy_glProgramUniform4ui64ARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            x: GLuint64,
+            y: GLuint64,
+            z: GLuint64,
+            w: GLuint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4ui64NV"]
+    pub static mut epoxy_glProgramUniform4ui64NV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            x: GLuint64EXT,
+            y: GLuint64EXT,
+            z: GLuint64EXT,
+            w: GLuint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4ui64vARB"]
+    pub static mut epoxy_glProgramUniform4ui64vARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4ui64vNV"]
+    pub static mut epoxy_glProgramUniform4ui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4uiEXT"]
+    pub static mut epoxy_glProgramUniform4uiEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            v0: GLuint,
+            v1: GLuint,
+            v2: GLuint,
+            v3: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4uiv"]
+    pub static mut epoxy_glProgramUniform4uiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniform4uivEXT"]
+    pub static mut epoxy_glProgramUniform4uivEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformHandleui64ARB"]
+    pub static mut epoxy_glProgramUniformHandleui64ARB: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, value: GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformHandleui64IMG"]
+    pub static mut epoxy_glProgramUniformHandleui64IMG: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, value: GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformHandleui64NV"]
+    pub static mut epoxy_glProgramUniformHandleui64NV: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, value: GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformHandleui64vARB"]
+    pub static mut epoxy_glProgramUniformHandleui64vARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            values: *const GLuint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformHandleui64vIMG"]
+    pub static mut epoxy_glProgramUniformHandleui64vIMG: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            values: *const GLuint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformHandleui64vNV"]
+    pub static mut epoxy_glProgramUniformHandleui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            values: *const GLuint64,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix2dv"]
+    pub static mut epoxy_glProgramUniformMatrix2dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix2dvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix2dvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix2fv"]
+    pub static mut epoxy_glProgramUniformMatrix2fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix2fvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix2fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix2x3dv"]
+    pub static mut epoxy_glProgramUniformMatrix2x3dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix2x3dvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix2x3dvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix2x3fv"]
+    pub static mut epoxy_glProgramUniformMatrix2x3fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix2x3fvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix2x3fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix2x4dv"]
+    pub static mut epoxy_glProgramUniformMatrix2x4dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix2x4dvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix2x4dvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix2x4fv"]
+    pub static mut epoxy_glProgramUniformMatrix2x4fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix2x4fvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix2x4fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix3dv"]
+    pub static mut epoxy_glProgramUniformMatrix3dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix3dvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix3dvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix3fv"]
+    pub static mut epoxy_glProgramUniformMatrix3fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix3fvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix3fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix3x2dv"]
+    pub static mut epoxy_glProgramUniformMatrix3x2dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix3x2dvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix3x2dvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix3x2fv"]
+    pub static mut epoxy_glProgramUniformMatrix3x2fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix3x2fvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix3x2fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix3x4dv"]
+    pub static mut epoxy_glProgramUniformMatrix3x4dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix3x4dvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix3x4dvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix3x4fv"]
+    pub static mut epoxy_glProgramUniformMatrix3x4fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix3x4fvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix3x4fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix4dv"]
+    pub static mut epoxy_glProgramUniformMatrix4dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix4dvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix4dvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix4fv"]
+    pub static mut epoxy_glProgramUniformMatrix4fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix4fvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix4fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix4x2dv"]
+    pub static mut epoxy_glProgramUniformMatrix4x2dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix4x2dvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix4x2dvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix4x2fv"]
+    pub static mut epoxy_glProgramUniformMatrix4x2fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix4x2fvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix4x2fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix4x3dv"]
+    pub static mut epoxy_glProgramUniformMatrix4x3dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix4x3dvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix4x3dvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix4x3fv"]
+    pub static mut epoxy_glProgramUniformMatrix4x3fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformMatrix4x3fvEXT"]
+    pub static mut epoxy_glProgramUniformMatrix4x3fvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformui64NV"]
+    pub static mut epoxy_glProgramUniformui64NV: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, value: GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramUniformui64vNV"]
+    pub static mut epoxy_glProgramUniformui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            location: GLint,
+            count: GLsizei,
+            value: *const GLuint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProgramVertexLimitNV"]
+    pub static mut epoxy_glProgramVertexLimitNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, limit: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProvokingVertex"]
+    pub static mut epoxy_glProvokingVertex:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glProvokingVertexEXT"]
+    pub static mut epoxy_glProvokingVertexEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPushAttrib"]
+    pub static mut epoxy_glPushAttrib:
+        ::std::option::Option<unsafe extern "C" fn(mask: GLbitfield)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPushClientAttrib"]
+    pub static mut epoxy_glPushClientAttrib:
+        ::std::option::Option<unsafe extern "C" fn(mask: GLbitfield)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPushClientAttribDefaultEXT"]
+    pub static mut epoxy_glPushClientAttribDefaultEXT:
+        ::std::option::Option<unsafe extern "C" fn(mask: GLbitfield)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPushDebugGroup"]
+    pub static mut epoxy_glPushDebugGroup: ::std::option::Option<
+        unsafe extern "C" fn(source: GLenum, id: GLuint, length: GLsizei, message: *const GLchar),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPushDebugGroupKHR"]
+    pub static mut epoxy_glPushDebugGroupKHR: ::std::option::Option<
+        unsafe extern "C" fn(source: GLenum, id: GLuint, length: GLsizei, message: *const GLchar),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPushGroupMarkerEXT"]
+    pub static mut epoxy_glPushGroupMarkerEXT:
+        ::std::option::Option<unsafe extern "C" fn(length: GLsizei, marker: *const GLchar)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPushMatrix"]
+    pub static mut epoxy_glPushMatrix: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glPushName"]
+    pub static mut epoxy_glPushName: ::std::option::Option<unsafe extern "C" fn(name: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glQueryCounter"]
+    pub static mut epoxy_glQueryCounter:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glQueryCounterEXT"]
+    pub static mut epoxy_glQueryCounterEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glQueryMatrixxOES"]
+    pub static mut epoxy_glQueryMatrixxOES: ::std::option::Option<
+        unsafe extern "C" fn(mantissa: *mut GLfixed, exponent: *mut GLint) -> GLbitfield,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glQueryObjectParameteruiAMD"]
+    pub static mut epoxy_glQueryObjectParameteruiAMD: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, id: GLuint, pname: GLenum, param: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos2d"]
+    pub static mut epoxy_glRasterPos2d:
+        ::std::option::Option<unsafe extern "C" fn(x: GLdouble, y: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos2dv"]
+    pub static mut epoxy_glRasterPos2dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos2f"]
+    pub static mut epoxy_glRasterPos2f:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos2fv"]
+    pub static mut epoxy_glRasterPos2fv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos2i"]
+    pub static mut epoxy_glRasterPos2i:
+        ::std::option::Option<unsafe extern "C" fn(x: GLint, y: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos2iv"]
+    pub static mut epoxy_glRasterPos2iv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos2s"]
+    pub static mut epoxy_glRasterPos2s:
+        ::std::option::Option<unsafe extern "C" fn(x: GLshort, y: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos2sv"]
+    pub static mut epoxy_glRasterPos2sv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos2xOES"]
+    pub static mut epoxy_glRasterPos2xOES:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfixed, y: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos2xvOES"]
+    pub static mut epoxy_glRasterPos2xvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos3d"]
+    pub static mut epoxy_glRasterPos3d:
+        ::std::option::Option<unsafe extern "C" fn(x: GLdouble, y: GLdouble, z: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos3dv"]
+    pub static mut epoxy_glRasterPos3dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos3f"]
+    pub static mut epoxy_glRasterPos3f:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat, z: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos3fv"]
+    pub static mut epoxy_glRasterPos3fv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos3i"]
+    pub static mut epoxy_glRasterPos3i:
+        ::std::option::Option<unsafe extern "C" fn(x: GLint, y: GLint, z: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos3iv"]
+    pub static mut epoxy_glRasterPos3iv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos3s"]
+    pub static mut epoxy_glRasterPos3s:
+        ::std::option::Option<unsafe extern "C" fn(x: GLshort, y: GLshort, z: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos3sv"]
+    pub static mut epoxy_glRasterPos3sv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos3xOES"]
+    pub static mut epoxy_glRasterPos3xOES:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfixed, y: GLfixed, z: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos3xvOES"]
+    pub static mut epoxy_glRasterPos3xvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos4d"]
+    pub static mut epoxy_glRasterPos4d: ::std::option::Option<
+        unsafe extern "C" fn(x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos4dv"]
+    pub static mut epoxy_glRasterPos4dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos4f"]
+    pub static mut epoxy_glRasterPos4f:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos4fv"]
+    pub static mut epoxy_glRasterPos4fv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos4i"]
+    pub static mut epoxy_glRasterPos4i:
+        ::std::option::Option<unsafe extern "C" fn(x: GLint, y: GLint, z: GLint, w: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos4iv"]
+    pub static mut epoxy_glRasterPos4iv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos4s"]
+    pub static mut epoxy_glRasterPos4s:
+        ::std::option::Option<unsafe extern "C" fn(x: GLshort, y: GLshort, z: GLshort, w: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos4sv"]
+    pub static mut epoxy_glRasterPos4sv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos4xOES"]
+    pub static mut epoxy_glRasterPos4xOES:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfixed, y: GLfixed, z: GLfixed, w: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterPos4xvOES"]
+    pub static mut epoxy_glRasterPos4xvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRasterSamplesEXT"]
+    pub static mut epoxy_glRasterSamplesEXT: ::std::option::Option<
+        unsafe extern "C" fn(samples: GLuint, fixedsamplelocations: GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReadBuffer"]
+    pub static mut epoxy_glReadBuffer: ::std::option::Option<unsafe extern "C" fn(src: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReadBufferIndexedEXT"]
+    pub static mut epoxy_glReadBufferIndexedEXT:
+        ::std::option::Option<unsafe extern "C" fn(src: GLenum, index: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReadBufferNV"]
+    pub static mut epoxy_glReadBufferNV: ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReadInstrumentsSGIX"]
+    pub static mut epoxy_glReadInstrumentsSGIX:
+        ::std::option::Option<unsafe extern "C" fn(marker: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReadPixels"]
+    pub static mut epoxy_glReadPixels: ::std::option::Option<
+        unsafe extern "C" fn(
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReadnPixels"]
+    pub static mut epoxy_glReadnPixels: ::std::option::Option<
+        unsafe extern "C" fn(
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            data: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReadnPixelsARB"]
+    pub static mut epoxy_glReadnPixelsARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            data: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReadnPixelsEXT"]
+    pub static mut epoxy_glReadnPixelsEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            data: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReadnPixelsKHR"]
+    pub static mut epoxy_glReadnPixelsKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            x: GLint,
+            y: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            bufSize: GLsizei,
+            data: *mut ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRectd"]
+    pub static mut epoxy_glRectd: ::std::option::Option<
+        unsafe extern "C" fn(x1: GLdouble, y1: GLdouble, x2: GLdouble, y2: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRectdv"]
+    pub static mut epoxy_glRectdv:
+        ::std::option::Option<unsafe extern "C" fn(v1: *const GLdouble, v2: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRectf"]
+    pub static mut epoxy_glRectf: ::std::option::Option<
+        unsafe extern "C" fn(x1: GLfloat, y1: GLfloat, x2: GLfloat, y2: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRectfv"]
+    pub static mut epoxy_glRectfv:
+        ::std::option::Option<unsafe extern "C" fn(v1: *const GLfloat, v2: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRecti"]
+    pub static mut epoxy_glRecti:
+        ::std::option::Option<unsafe extern "C" fn(x1: GLint, y1: GLint, x2: GLint, y2: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRectiv"]
+    pub static mut epoxy_glRectiv:
+        ::std::option::Option<unsafe extern "C" fn(v1: *const GLint, v2: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRects"]
+    pub static mut epoxy_glRects: ::std::option::Option<
+        unsafe extern "C" fn(x1: GLshort, y1: GLshort, x2: GLshort, y2: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRectsv"]
+    pub static mut epoxy_glRectsv:
+        ::std::option::Option<unsafe extern "C" fn(v1: *const GLshort, v2: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRectxOES"]
+    pub static mut epoxy_glRectxOES: ::std::option::Option<
+        unsafe extern "C" fn(x1: GLfixed, y1: GLfixed, x2: GLfixed, y2: GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRectxvOES"]
+    pub static mut epoxy_glRectxvOES:
+        ::std::option::Option<unsafe extern "C" fn(v1: *const GLfixed, v2: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReferencePlaneSGIX"]
+    pub static mut epoxy_glReferencePlaneSGIX:
+        ::std::option::Option<unsafe extern "C" fn(equation: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReleaseShaderCompiler"]
+    pub static mut epoxy_glReleaseShaderCompiler: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRenderMode"]
+    pub static mut epoxy_glRenderMode:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum) -> GLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRenderbufferStorage"]
+    pub static mut epoxy_glRenderbufferStorage: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRenderbufferStorageEXT"]
+    pub static mut epoxy_glRenderbufferStorageEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRenderbufferStorageMultisample"]
+    pub static mut epoxy_glRenderbufferStorageMultisample: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRenderbufferStorageMultisampleANGLE"]
+    pub static mut epoxy_glRenderbufferStorageMultisampleANGLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRenderbufferStorageMultisampleAPPLE"]
+    pub static mut epoxy_glRenderbufferStorageMultisampleAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRenderbufferStorageMultisampleCoverageNV"]
+    pub static mut epoxy_glRenderbufferStorageMultisampleCoverageNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            coverageSamples: GLsizei,
+            colorSamples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRenderbufferStorageMultisampleEXT"]
+    pub static mut epoxy_glRenderbufferStorageMultisampleEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRenderbufferStorageMultisampleIMG"]
+    pub static mut epoxy_glRenderbufferStorageMultisampleIMG: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRenderbufferStorageMultisampleNV"]
+    pub static mut epoxy_glRenderbufferStorageMultisampleNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRenderbufferStorageOES"]
+    pub static mut epoxy_glRenderbufferStorageOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodePointerSUN"]
+    pub static mut epoxy_glReplacementCodePointerSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *mut *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeubSUN"]
+    pub static mut epoxy_glReplacementCodeubSUN:
+        ::std::option::Option<unsafe extern "C" fn(code: GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeubvSUN"]
+    pub static mut epoxy_glReplacementCodeubvSUN:
+        ::std::option::Option<unsafe extern "C" fn(code: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiColor3fVertex3fSUN"]
+    pub static mut epoxy_glReplacementCodeuiColor3fVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            rc: GLuint,
+            r: GLfloat,
+            g: GLfloat,
+            b: GLfloat,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiColor3fVertex3fvSUN"]
+    pub static mut epoxy_glReplacementCodeuiColor3fVertex3fvSUN: ::std::option::Option<
+        unsafe extern "C" fn(rc: *const GLuint, c: *const GLfloat, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiColor4fNormal3fVertex3fSUN"]
+    pub static mut epoxy_glReplacementCodeuiColor4fNormal3fVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            rc: GLuint,
+            r: GLfloat,
+            g: GLfloat,
+            b: GLfloat,
+            a: GLfloat,
+            nx: GLfloat,
+            ny: GLfloat,
+            nz: GLfloat,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiColor4fNormal3fVertex3fvSUN"]
+    pub static mut epoxy_glReplacementCodeuiColor4fNormal3fVertex3fvSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            rc: *const GLuint,
+            c: *const GLfloat,
+            n: *const GLfloat,
+            v: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiColor4ubVertex3fSUN"]
+    pub static mut epoxy_glReplacementCodeuiColor4ubVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            rc: GLuint,
+            r: GLubyte,
+            g: GLubyte,
+            b: GLubyte,
+            a: GLubyte,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiColor4ubVertex3fvSUN"]
+    pub static mut epoxy_glReplacementCodeuiColor4ubVertex3fvSUN: ::std::option::Option<
+        unsafe extern "C" fn(rc: *const GLuint, c: *const GLubyte, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiNormal3fVertex3fSUN"]
+    pub static mut epoxy_glReplacementCodeuiNormal3fVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            rc: GLuint,
+            nx: GLfloat,
+            ny: GLfloat,
+            nz: GLfloat,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiNormal3fVertex3fvSUN"]
+    pub static mut epoxy_glReplacementCodeuiNormal3fVertex3fvSUN: ::std::option::Option<
+        unsafe extern "C" fn(rc: *const GLuint, n: *const GLfloat, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiSUN"]
+    pub static mut epoxy_glReplacementCodeuiSUN:
+        ::std::option::Option<unsafe extern "C" fn(code: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN"]
+    pub static mut epoxy_glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN:
+        ::std::option::Option<
+            unsafe extern "C" fn(
+                rc: GLuint,
+                s: GLfloat,
+                t: GLfloat,
+                r: GLfloat,
+                g: GLfloat,
+                b: GLfloat,
+                a: GLfloat,
+                nx: GLfloat,
+                ny: GLfloat,
+                nz: GLfloat,
+                x: GLfloat,
+                y: GLfloat,
+                z: GLfloat,
+            ),
+        >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN"]
+    pub static mut epoxy_glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN:
+        ::std::option::Option<
+            unsafe extern "C" fn(
+                rc: *const GLuint,
+                tc: *const GLfloat,
+                c: *const GLfloat,
+                n: *const GLfloat,
+                v: *const GLfloat,
+            ),
+        >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN"]
+    pub static mut epoxy_glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            rc: GLuint,
+            s: GLfloat,
+            t: GLfloat,
+            nx: GLfloat,
+            ny: GLfloat,
+            nz: GLfloat,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN"]
+    pub static mut epoxy_glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            rc: *const GLuint,
+            tc: *const GLfloat,
+            n: *const GLfloat,
+            v: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiTexCoord2fVertex3fSUN"]
+    pub static mut epoxy_glReplacementCodeuiTexCoord2fVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            rc: GLuint,
+            s: GLfloat,
+            t: GLfloat,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiTexCoord2fVertex3fvSUN"]
+    pub static mut epoxy_glReplacementCodeuiTexCoord2fVertex3fvSUN: ::std::option::Option<
+        unsafe extern "C" fn(rc: *const GLuint, tc: *const GLfloat, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiVertex3fSUN"]
+    pub static mut epoxy_glReplacementCodeuiVertex3fSUN:
+        ::std::option::Option<unsafe extern "C" fn(rc: GLuint, x: GLfloat, y: GLfloat, z: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuiVertex3fvSUN"]
+    pub static mut epoxy_glReplacementCodeuiVertex3fvSUN:
+        ::std::option::Option<unsafe extern "C" fn(rc: *const GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeuivSUN"]
+    pub static mut epoxy_glReplacementCodeuivSUN:
+        ::std::option::Option<unsafe extern "C" fn(code: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeusSUN"]
+    pub static mut epoxy_glReplacementCodeusSUN:
+        ::std::option::Option<unsafe extern "C" fn(code: GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glReplacementCodeusvSUN"]
+    pub static mut epoxy_glReplacementCodeusvSUN:
+        ::std::option::Option<unsafe extern "C" fn(code: *const GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRequestResidentProgramsNV"]
+    pub static mut epoxy_glRequestResidentProgramsNV:
+        ::std::option::Option<unsafe extern "C" fn(n: GLsizei, programs: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glResetHistogram"]
+    pub static mut epoxy_glResetHistogram:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glResetHistogramEXT"]
+    pub static mut epoxy_glResetHistogramEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glResetMinmax"]
+    pub static mut epoxy_glResetMinmax: ::std::option::Option<unsafe extern "C" fn(target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glResetMinmaxEXT"]
+    pub static mut epoxy_glResetMinmaxEXT:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glResizeBuffersMESA"]
+    pub static mut epoxy_glResizeBuffersMESA: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glResolveDepthValuesNV"]
+    pub static mut epoxy_glResolveDepthValuesNV: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glResolveMultisampleFramebufferAPPLE"]
+    pub static mut epoxy_glResolveMultisampleFramebufferAPPLE:
+        ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glResumeTransformFeedback"]
+    pub static mut epoxy_glResumeTransformFeedback: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glResumeTransformFeedbackNV"]
+    pub static mut epoxy_glResumeTransformFeedbackNV: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRotated"]
+    pub static mut epoxy_glRotated: ::std::option::Option<
+        unsafe extern "C" fn(angle: GLdouble, x: GLdouble, y: GLdouble, z: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRotatef"]
+    pub static mut epoxy_glRotatef: ::std::option::Option<
+        unsafe extern "C" fn(angle: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRotatex"]
+    pub static mut epoxy_glRotatex: ::std::option::Option<
+        unsafe extern "C" fn(angle: GLfixed, x: GLfixed, y: GLfixed, z: GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glRotatexOES"]
+    pub static mut epoxy_glRotatexOES: ::std::option::Option<
+        unsafe extern "C" fn(angle: GLfixed, x: GLfixed, y: GLfixed, z: GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSampleCoverage"]
+    pub static mut epoxy_glSampleCoverage:
+        ::std::option::Option<unsafe extern "C" fn(value: GLfloat, invert: GLboolean)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSampleCoverageARB"]
+    pub static mut epoxy_glSampleCoverageARB:
+        ::std::option::Option<unsafe extern "C" fn(value: GLfloat, invert: GLboolean)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSampleCoveragex"]
+    pub static mut epoxy_glSampleCoveragex:
+        ::std::option::Option<unsafe extern "C" fn(value: GLclampx, invert: GLboolean)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSampleCoveragexOES"]
+    pub static mut epoxy_glSampleCoveragexOES:
+        ::std::option::Option<unsafe extern "C" fn(value: GLclampx, invert: GLboolean)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSampleMapATI"]
+    pub static mut epoxy_glSampleMapATI:
+        ::std::option::Option<unsafe extern "C" fn(dst: GLuint, interp: GLuint, swizzle: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSampleMaskEXT"]
+    pub static mut epoxy_glSampleMaskEXT:
+        ::std::option::Option<unsafe extern "C" fn(value: GLclampf, invert: GLboolean)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSampleMaskIndexedNV"]
+    pub static mut epoxy_glSampleMaskIndexedNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, mask: GLbitfield)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSampleMaskSGIS"]
+    pub static mut epoxy_glSampleMaskSGIS:
+        ::std::option::Option<unsafe extern "C" fn(value: GLclampf, invert: GLboolean)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSampleMaski"]
+    pub static mut epoxy_glSampleMaski:
+        ::std::option::Option<unsafe extern "C" fn(maskNumber: GLuint, mask: GLbitfield)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSamplePatternEXT"]
+    pub static mut epoxy_glSamplePatternEXT:
+        ::std::option::Option<unsafe extern "C" fn(pattern: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSamplePatternSGIS"]
+    pub static mut epoxy_glSamplePatternSGIS:
+        ::std::option::Option<unsafe extern "C" fn(pattern: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSamplerParameterIiv"]
+    pub static mut epoxy_glSamplerParameterIiv: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, param: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSamplerParameterIivEXT"]
+    pub static mut epoxy_glSamplerParameterIivEXT: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, param: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSamplerParameterIivOES"]
+    pub static mut epoxy_glSamplerParameterIivOES: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, param: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSamplerParameterIuiv"]
+    pub static mut epoxy_glSamplerParameterIuiv: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, param: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSamplerParameterIuivEXT"]
+    pub static mut epoxy_glSamplerParameterIuivEXT: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, param: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSamplerParameterIuivOES"]
+    pub static mut epoxy_glSamplerParameterIuivOES: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, param: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSamplerParameterf"]
+    pub static mut epoxy_glSamplerParameterf:
+        ::std::option::Option<unsafe extern "C" fn(sampler: GLuint, pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSamplerParameterfv"]
+    pub static mut epoxy_glSamplerParameterfv: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, param: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSamplerParameteri"]
+    pub static mut epoxy_glSamplerParameteri:
+        ::std::option::Option<unsafe extern "C" fn(sampler: GLuint, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSamplerParameteriv"]
+    pub static mut epoxy_glSamplerParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(sampler: GLuint, pname: GLenum, param: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glScaled"]
+    pub static mut epoxy_glScaled:
+        ::std::option::Option<unsafe extern "C" fn(x: GLdouble, y: GLdouble, z: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glScalef"]
+    pub static mut epoxy_glScalef:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat, z: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glScalex"]
+    pub static mut epoxy_glScalex:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfixed, y: GLfixed, z: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glScalexOES"]
+    pub static mut epoxy_glScalexOES:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfixed, y: GLfixed, z: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glScissor"]
+    pub static mut epoxy_glScissor: ::std::option::Option<
+        unsafe extern "C" fn(x: GLint, y: GLint, width: GLsizei, height: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glScissorArrayv"]
+    pub static mut epoxy_glScissorArrayv:
+        ::std::option::Option<unsafe extern "C" fn(first: GLuint, count: GLsizei, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glScissorArrayvNV"]
+    pub static mut epoxy_glScissorArrayvNV:
+        ::std::option::Option<unsafe extern "C" fn(first: GLuint, count: GLsizei, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glScissorArrayvOES"]
+    pub static mut epoxy_glScissorArrayvOES:
+        ::std::option::Option<unsafe extern "C" fn(first: GLuint, count: GLsizei, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glScissorIndexed"]
+    pub static mut epoxy_glScissorIndexed: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            left: GLint,
+            bottom: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glScissorIndexedNV"]
+    pub static mut epoxy_glScissorIndexedNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            left: GLint,
+            bottom: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glScissorIndexedOES"]
+    pub static mut epoxy_glScissorIndexedOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            left: GLint,
+            bottom: GLint,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glScissorIndexedv"]
+    pub static mut epoxy_glScissorIndexedv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glScissorIndexedvNV"]
+    pub static mut epoxy_glScissorIndexedvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glScissorIndexedvOES"]
+    pub static mut epoxy_glScissorIndexedvOES:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3b"]
+    pub static mut epoxy_glSecondaryColor3b:
+        ::std::option::Option<unsafe extern "C" fn(red: GLbyte, green: GLbyte, blue: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3bEXT"]
+    pub static mut epoxy_glSecondaryColor3bEXT:
+        ::std::option::Option<unsafe extern "C" fn(red: GLbyte, green: GLbyte, blue: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3bv"]
+    pub static mut epoxy_glSecondaryColor3bv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3bvEXT"]
+    pub static mut epoxy_glSecondaryColor3bvEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3d"]
+    pub static mut epoxy_glSecondaryColor3d:
+        ::std::option::Option<unsafe extern "C" fn(red: GLdouble, green: GLdouble, blue: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3dEXT"]
+    pub static mut epoxy_glSecondaryColor3dEXT:
+        ::std::option::Option<unsafe extern "C" fn(red: GLdouble, green: GLdouble, blue: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3dv"]
+    pub static mut epoxy_glSecondaryColor3dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3dvEXT"]
+    pub static mut epoxy_glSecondaryColor3dvEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3f"]
+    pub static mut epoxy_glSecondaryColor3f:
+        ::std::option::Option<unsafe extern "C" fn(red: GLfloat, green: GLfloat, blue: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3fEXT"]
+    pub static mut epoxy_glSecondaryColor3fEXT:
+        ::std::option::Option<unsafe extern "C" fn(red: GLfloat, green: GLfloat, blue: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3fv"]
+    pub static mut epoxy_glSecondaryColor3fv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3fvEXT"]
+    pub static mut epoxy_glSecondaryColor3fvEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3hNV"]
+    pub static mut epoxy_glSecondaryColor3hNV:
+        ::std::option::Option<unsafe extern "C" fn(red: GLhalfNV, green: GLhalfNV, blue: GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3hvNV"]
+    pub static mut epoxy_glSecondaryColor3hvNV:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3i"]
+    pub static mut epoxy_glSecondaryColor3i:
+        ::std::option::Option<unsafe extern "C" fn(red: GLint, green: GLint, blue: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3iEXT"]
+    pub static mut epoxy_glSecondaryColor3iEXT:
+        ::std::option::Option<unsafe extern "C" fn(red: GLint, green: GLint, blue: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3iv"]
+    pub static mut epoxy_glSecondaryColor3iv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3ivEXT"]
+    pub static mut epoxy_glSecondaryColor3ivEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3s"]
+    pub static mut epoxy_glSecondaryColor3s:
+        ::std::option::Option<unsafe extern "C" fn(red: GLshort, green: GLshort, blue: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3sEXT"]
+    pub static mut epoxy_glSecondaryColor3sEXT:
+        ::std::option::Option<unsafe extern "C" fn(red: GLshort, green: GLshort, blue: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3sv"]
+    pub static mut epoxy_glSecondaryColor3sv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3svEXT"]
+    pub static mut epoxy_glSecondaryColor3svEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3ub"]
+    pub static mut epoxy_glSecondaryColor3ub:
+        ::std::option::Option<unsafe extern "C" fn(red: GLubyte, green: GLubyte, blue: GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3ubEXT"]
+    pub static mut epoxy_glSecondaryColor3ubEXT:
+        ::std::option::Option<unsafe extern "C" fn(red: GLubyte, green: GLubyte, blue: GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3ubv"]
+    pub static mut epoxy_glSecondaryColor3ubv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3ubvEXT"]
+    pub static mut epoxy_glSecondaryColor3ubvEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3ui"]
+    pub static mut epoxy_glSecondaryColor3ui:
+        ::std::option::Option<unsafe extern "C" fn(red: GLuint, green: GLuint, blue: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3uiEXT"]
+    pub static mut epoxy_glSecondaryColor3uiEXT:
+        ::std::option::Option<unsafe extern "C" fn(red: GLuint, green: GLuint, blue: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3uiv"]
+    pub static mut epoxy_glSecondaryColor3uiv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3uivEXT"]
+    pub static mut epoxy_glSecondaryColor3uivEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3us"]
+    pub static mut epoxy_glSecondaryColor3us:
+        ::std::option::Option<unsafe extern "C" fn(red: GLushort, green: GLushort, blue: GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3usEXT"]
+    pub static mut epoxy_glSecondaryColor3usEXT:
+        ::std::option::Option<unsafe extern "C" fn(red: GLushort, green: GLushort, blue: GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3usv"]
+    pub static mut epoxy_glSecondaryColor3usv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColor3usvEXT"]
+    pub static mut epoxy_glSecondaryColor3usvEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColorFormatNV"]
+    pub static mut epoxy_glSecondaryColorFormatNV:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, type_: GLenum, stride: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColorP3ui"]
+    pub static mut epoxy_glSecondaryColorP3ui:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, color: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColorP3uiv"]
+    pub static mut epoxy_glSecondaryColorP3uiv:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, color: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColorPointer"]
+    pub static mut epoxy_glSecondaryColorPointer: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColorPointerEXT"]
+    pub static mut epoxy_glSecondaryColorPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSecondaryColorPointerListIBM"]
+    pub static mut epoxy_glSecondaryColorPointerListIBM: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLint,
+            pointer: *mut *const ::std::os::raw::c_void,
+            ptrstride: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSelectBuffer"]
+    pub static mut epoxy_glSelectBuffer:
+        ::std::option::Option<unsafe extern "C" fn(size: GLsizei, buffer: *mut GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSelectPerfMonitorCountersAMD"]
+    pub static mut epoxy_glSelectPerfMonitorCountersAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            monitor: GLuint,
+            enable: GLboolean,
+            group: GLuint,
+            numCounters: GLint,
+            counterList: *mut GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSeparableFilter2D"]
+    pub static mut epoxy_glSeparableFilter2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            row: *const ::std::os::raw::c_void,
+            column: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSeparableFilter2DEXT"]
+    pub static mut epoxy_glSeparableFilter2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            row: *const ::std::os::raw::c_void,
+            column: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSetFenceAPPLE"]
+    pub static mut epoxy_glSetFenceAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(fence: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSetFenceNV"]
+    pub static mut epoxy_glSetFenceNV:
+        ::std::option::Option<unsafe extern "C" fn(fence: GLuint, condition: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSetFragmentShaderConstantATI"]
+    pub static mut epoxy_glSetFragmentShaderConstantATI:
+        ::std::option::Option<unsafe extern "C" fn(dst: GLuint, value: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSetInvariantEXT"]
+    pub static mut epoxy_glSetInvariantEXT: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, type_: GLenum, addr: *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSetLocalConstantEXT"]
+    pub static mut epoxy_glSetLocalConstantEXT: ::std::option::Option<
+        unsafe extern "C" fn(id: GLuint, type_: GLenum, addr: *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSetMultisamplefvAMD"]
+    pub static mut epoxy_glSetMultisamplefvAMD: ::std::option::Option<
+        unsafe extern "C" fn(pname: GLenum, index: GLuint, val: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glShadeModel"]
+    pub static mut epoxy_glShadeModel: ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glShaderBinary"]
+    pub static mut epoxy_glShaderBinary: ::std::option::Option<
+        unsafe extern "C" fn(
+            count: GLsizei,
+            shaders: *const GLuint,
+            binaryformat: GLenum,
+            binary: *const ::std::os::raw::c_void,
+            length: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glShaderOp1EXT"]
+    pub static mut epoxy_glShaderOp1EXT:
+        ::std::option::Option<unsafe extern "C" fn(op: GLenum, res: GLuint, arg1: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glShaderOp2EXT"]
+    pub static mut epoxy_glShaderOp2EXT: ::std::option::Option<
+        unsafe extern "C" fn(op: GLenum, res: GLuint, arg1: GLuint, arg2: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glShaderOp3EXT"]
+    pub static mut epoxy_glShaderOp3EXT: ::std::option::Option<
+        unsafe extern "C" fn(op: GLenum, res: GLuint, arg1: GLuint, arg2: GLuint, arg3: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glShaderSource"]
+    pub static mut epoxy_glShaderSource: ::std::option::Option<
+        unsafe extern "C" fn(
+            shader: GLuint,
+            count: GLsizei,
+            string: *const *const GLchar,
+            length: *const GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glShaderSourceARB"]
+    pub static mut epoxy_glShaderSourceARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            shaderObj: GLhandleARB,
+            count: GLsizei,
+            string: *mut *const GLcharARB,
+            length: *const GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glShaderStorageBlockBinding"]
+    pub static mut epoxy_glShaderStorageBlockBinding: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            storageBlockIndex: GLuint,
+            storageBlockBinding: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSharpenTexFuncSGIS"]
+    pub static mut epoxy_glSharpenTexFuncSGIS: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, n: GLsizei, points: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSpriteParameterfSGIX"]
+    pub static mut epoxy_glSpriteParameterfSGIX:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSpriteParameterfvSGIX"]
+    pub static mut epoxy_glSpriteParameterfvSGIX:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSpriteParameteriSGIX"]
+    pub static mut epoxy_glSpriteParameteriSGIX:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSpriteParameterivSGIX"]
+    pub static mut epoxy_glSpriteParameterivSGIX:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, params: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStartInstrumentsSGIX"]
+    pub static mut epoxy_glStartInstrumentsSGIX: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStartTilingQCOM"]
+    pub static mut epoxy_glStartTilingQCOM: ::std::option::Option<
+        unsafe extern "C" fn(
+            x: GLuint,
+            y: GLuint,
+            width: GLuint,
+            height: GLuint,
+            preserveMask: GLbitfield,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStateCaptureNV"]
+    pub static mut epoxy_glStateCaptureNV:
+        ::std::option::Option<unsafe extern "C" fn(state: GLuint, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilClearTagEXT"]
+    pub static mut epoxy_glStencilClearTagEXT: ::std::option::Option<
+        unsafe extern "C" fn(stencilTagBits: GLsizei, stencilClearTag: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilFillPathInstancedNV"]
+    pub static mut epoxy_glStencilFillPathInstancedNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            numPaths: GLsizei,
+            pathNameType: GLenum,
+            paths: *const ::std::os::raw::c_void,
+            pathBase: GLuint,
+            fillMode: GLenum,
+            mask: GLuint,
+            transformType: GLenum,
+            transformValues: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilFillPathNV"]
+    pub static mut epoxy_glStencilFillPathNV:
+        ::std::option::Option<unsafe extern "C" fn(path: GLuint, fillMode: GLenum, mask: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilFunc"]
+    pub static mut epoxy_glStencilFunc:
+        ::std::option::Option<unsafe extern "C" fn(func: GLenum, ref_: GLint, mask: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilFuncSeparate"]
+    pub static mut epoxy_glStencilFuncSeparate: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, func: GLenum, ref_: GLint, mask: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilFuncSeparateATI"]
+    pub static mut epoxy_glStencilFuncSeparateATI: ::std::option::Option<
+        unsafe extern "C" fn(frontfunc: GLenum, backfunc: GLenum, ref_: GLint, mask: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilMask"]
+    pub static mut epoxy_glStencilMask: ::std::option::Option<unsafe extern "C" fn(mask: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilMaskSeparate"]
+    pub static mut epoxy_glStencilMaskSeparate:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, mask: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilOp"]
+    pub static mut epoxy_glStencilOp:
+        ::std::option::Option<unsafe extern "C" fn(fail: GLenum, zfail: GLenum, zpass: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilOpSeparate"]
+    pub static mut epoxy_glStencilOpSeparate: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, sfail: GLenum, dpfail: GLenum, dppass: GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilOpSeparateATI"]
+    pub static mut epoxy_glStencilOpSeparateATI: ::std::option::Option<
+        unsafe extern "C" fn(face: GLenum, sfail: GLenum, dpfail: GLenum, dppass: GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilOpValueAMD"]
+    pub static mut epoxy_glStencilOpValueAMD:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, value: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilStrokePathInstancedNV"]
+    pub static mut epoxy_glStencilStrokePathInstancedNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            numPaths: GLsizei,
+            pathNameType: GLenum,
+            paths: *const ::std::os::raw::c_void,
+            pathBase: GLuint,
+            reference: GLint,
+            mask: GLuint,
+            transformType: GLenum,
+            transformValues: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilStrokePathNV"]
+    pub static mut epoxy_glStencilStrokePathNV:
+        ::std::option::Option<unsafe extern "C" fn(path: GLuint, reference: GLint, mask: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilThenCoverFillPathInstancedNV"]
+    pub static mut epoxy_glStencilThenCoverFillPathInstancedNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            numPaths: GLsizei,
+            pathNameType: GLenum,
+            paths: *const ::std::os::raw::c_void,
+            pathBase: GLuint,
+            fillMode: GLenum,
+            mask: GLuint,
+            coverMode: GLenum,
+            transformType: GLenum,
+            transformValues: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilThenCoverFillPathNV"]
+    pub static mut epoxy_glStencilThenCoverFillPathNV: ::std::option::Option<
+        unsafe extern "C" fn(path: GLuint, fillMode: GLenum, mask: GLuint, coverMode: GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilThenCoverStrokePathInstancedNV"]
+    pub static mut epoxy_glStencilThenCoverStrokePathInstancedNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            numPaths: GLsizei,
+            pathNameType: GLenum,
+            paths: *const ::std::os::raw::c_void,
+            pathBase: GLuint,
+            reference: GLint,
+            mask: GLuint,
+            coverMode: GLenum,
+            transformType: GLenum,
+            transformValues: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStencilThenCoverStrokePathNV"]
+    pub static mut epoxy_glStencilThenCoverStrokePathNV: ::std::option::Option<
+        unsafe extern "C" fn(path: GLuint, reference: GLint, mask: GLuint, coverMode: GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStopInstrumentsSGIX"]
+    pub static mut epoxy_glStopInstrumentsSGIX:
+        ::std::option::Option<unsafe extern "C" fn(marker: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glStringMarkerGREMEDY"]
+    pub static mut epoxy_glStringMarkerGREMEDY: ::std::option::Option<
+        unsafe extern "C" fn(len: GLsizei, string: *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSubpixelPrecisionBiasNV"]
+    pub static mut epoxy_glSubpixelPrecisionBiasNV:
+        ::std::option::Option<unsafe extern "C" fn(xbits: GLuint, ybits: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSwizzleEXT"]
+    pub static mut epoxy_glSwizzleEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            res: GLuint,
+            in_: GLuint,
+            outX: GLenum,
+            outY: GLenum,
+            outZ: GLenum,
+            outW: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glSyncTextureINTEL"]
+    pub static mut epoxy_glSyncTextureINTEL:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTagSampleBufferSGIX"]
+    pub static mut epoxy_glTagSampleBufferSGIX: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTangent3bEXT"]
+    pub static mut epoxy_glTangent3bEXT:
+        ::std::option::Option<unsafe extern "C" fn(tx: GLbyte, ty: GLbyte, tz: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTangent3bvEXT"]
+    pub static mut epoxy_glTangent3bvEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTangent3dEXT"]
+    pub static mut epoxy_glTangent3dEXT:
+        ::std::option::Option<unsafe extern "C" fn(tx: GLdouble, ty: GLdouble, tz: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTangent3dvEXT"]
+    pub static mut epoxy_glTangent3dvEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTangent3fEXT"]
+    pub static mut epoxy_glTangent3fEXT:
+        ::std::option::Option<unsafe extern "C" fn(tx: GLfloat, ty: GLfloat, tz: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTangent3fvEXT"]
+    pub static mut epoxy_glTangent3fvEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTangent3iEXT"]
+    pub static mut epoxy_glTangent3iEXT:
+        ::std::option::Option<unsafe extern "C" fn(tx: GLint, ty: GLint, tz: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTangent3ivEXT"]
+    pub static mut epoxy_glTangent3ivEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTangent3sEXT"]
+    pub static mut epoxy_glTangent3sEXT:
+        ::std::option::Option<unsafe extern "C" fn(tx: GLshort, ty: GLshort, tz: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTangent3svEXT"]
+    pub static mut epoxy_glTangent3svEXT:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTangentPointerEXT"]
+    pub static mut epoxy_glTangentPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTbufferMask3DFX"]
+    pub static mut epoxy_glTbufferMask3DFX:
+        ::std::option::Option<unsafe extern "C" fn(mask: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTessellationFactorAMD"]
+    pub static mut epoxy_glTessellationFactorAMD:
+        ::std::option::Option<unsafe extern "C" fn(factor: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTessellationModeAMD"]
+    pub static mut epoxy_glTessellationModeAMD:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTestFenceAPPLE"]
+    pub static mut epoxy_glTestFenceAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(fence: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTestFenceNV"]
+    pub static mut epoxy_glTestFenceNV:
+        ::std::option::Option<unsafe extern "C" fn(fence: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTestObjectAPPLE"]
+    pub static mut epoxy_glTestObjectAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(object: GLenum, name: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexBuffer"]
+    pub static mut epoxy_glTexBuffer: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, internalformat: GLenum, buffer: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexBufferARB"]
+    pub static mut epoxy_glTexBufferARB: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, internalformat: GLenum, buffer: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexBufferEXT"]
+    pub static mut epoxy_glTexBufferEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, internalformat: GLenum, buffer: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexBufferOES"]
+    pub static mut epoxy_glTexBufferOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, internalformat: GLenum, buffer: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexBufferRange"]
+    pub static mut epoxy_glTexBufferRange: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            buffer: GLuint,
+            offset: GLintptr,
+            size: GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexBufferRangeEXT"]
+    pub static mut epoxy_glTexBufferRangeEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            buffer: GLuint,
+            offset: GLintptr,
+            size: GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexBufferRangeOES"]
+    pub static mut epoxy_glTexBufferRangeOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalformat: GLenum,
+            buffer: GLuint,
+            offset: GLintptr,
+            size: GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexBumpParameterfvATI"]
+    pub static mut epoxy_glTexBumpParameterfvATI:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexBumpParameterivATI"]
+    pub static mut epoxy_glTexBumpParameterivATI:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord1bOES"]
+    pub static mut epoxy_glTexCoord1bOES: ::std::option::Option<unsafe extern "C" fn(s: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord1bvOES"]
+    pub static mut epoxy_glTexCoord1bvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord1d"]
+    pub static mut epoxy_glTexCoord1d: ::std::option::Option<unsafe extern "C" fn(s: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord1dv"]
+    pub static mut epoxy_glTexCoord1dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord1f"]
+    pub static mut epoxy_glTexCoord1f: ::std::option::Option<unsafe extern "C" fn(s: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord1fv"]
+    pub static mut epoxy_glTexCoord1fv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord1hNV"]
+    pub static mut epoxy_glTexCoord1hNV: ::std::option::Option<unsafe extern "C" fn(s: GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord1hvNV"]
+    pub static mut epoxy_glTexCoord1hvNV:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord1i"]
+    pub static mut epoxy_glTexCoord1i: ::std::option::Option<unsafe extern "C" fn(s: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord1iv"]
+    pub static mut epoxy_glTexCoord1iv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord1s"]
+    pub static mut epoxy_glTexCoord1s: ::std::option::Option<unsafe extern "C" fn(s: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord1sv"]
+    pub static mut epoxy_glTexCoord1sv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord1xOES"]
+    pub static mut epoxy_glTexCoord1xOES: ::std::option::Option<unsafe extern "C" fn(s: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord1xvOES"]
+    pub static mut epoxy_glTexCoord1xvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2bOES"]
+    pub static mut epoxy_glTexCoord2bOES:
+        ::std::option::Option<unsafe extern "C" fn(s: GLbyte, t: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2bvOES"]
+    pub static mut epoxy_glTexCoord2bvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2d"]
+    pub static mut epoxy_glTexCoord2d:
+        ::std::option::Option<unsafe extern "C" fn(s: GLdouble, t: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2dv"]
+    pub static mut epoxy_glTexCoord2dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2f"]
+    pub static mut epoxy_glTexCoord2f:
+        ::std::option::Option<unsafe extern "C" fn(s: GLfloat, t: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2fColor3fVertex3fSUN"]
+    pub static mut epoxy_glTexCoord2fColor3fVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            s: GLfloat,
+            t: GLfloat,
+            r: GLfloat,
+            g: GLfloat,
+            b: GLfloat,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2fColor3fVertex3fvSUN"]
+    pub static mut epoxy_glTexCoord2fColor3fVertex3fvSUN: ::std::option::Option<
+        unsafe extern "C" fn(tc: *const GLfloat, c: *const GLfloat, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2fColor4fNormal3fVertex3fSUN"]
+    pub static mut epoxy_glTexCoord2fColor4fNormal3fVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            s: GLfloat,
+            t: GLfloat,
+            r: GLfloat,
+            g: GLfloat,
+            b: GLfloat,
+            a: GLfloat,
+            nx: GLfloat,
+            ny: GLfloat,
+            nz: GLfloat,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2fColor4fNormal3fVertex3fvSUN"]
+    pub static mut epoxy_glTexCoord2fColor4fNormal3fVertex3fvSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            tc: *const GLfloat,
+            c: *const GLfloat,
+            n: *const GLfloat,
+            v: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2fColor4ubVertex3fSUN"]
+    pub static mut epoxy_glTexCoord2fColor4ubVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            s: GLfloat,
+            t: GLfloat,
+            r: GLubyte,
+            g: GLubyte,
+            b: GLubyte,
+            a: GLubyte,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2fColor4ubVertex3fvSUN"]
+    pub static mut epoxy_glTexCoord2fColor4ubVertex3fvSUN: ::std::option::Option<
+        unsafe extern "C" fn(tc: *const GLfloat, c: *const GLubyte, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2fNormal3fVertex3fSUN"]
+    pub static mut epoxy_glTexCoord2fNormal3fVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            s: GLfloat,
+            t: GLfloat,
+            nx: GLfloat,
+            ny: GLfloat,
+            nz: GLfloat,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2fNormal3fVertex3fvSUN"]
+    pub static mut epoxy_glTexCoord2fNormal3fVertex3fvSUN: ::std::option::Option<
+        unsafe extern "C" fn(tc: *const GLfloat, n: *const GLfloat, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2fVertex3fSUN"]
+    pub static mut epoxy_glTexCoord2fVertex3fSUN: ::std::option::Option<
+        unsafe extern "C" fn(s: GLfloat, t: GLfloat, x: GLfloat, y: GLfloat, z: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2fVertex3fvSUN"]
+    pub static mut epoxy_glTexCoord2fVertex3fvSUN:
+        ::std::option::Option<unsafe extern "C" fn(tc: *const GLfloat, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2fv"]
+    pub static mut epoxy_glTexCoord2fv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2hNV"]
+    pub static mut epoxy_glTexCoord2hNV:
+        ::std::option::Option<unsafe extern "C" fn(s: GLhalfNV, t: GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2hvNV"]
+    pub static mut epoxy_glTexCoord2hvNV:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2i"]
+    pub static mut epoxy_glTexCoord2i:
+        ::std::option::Option<unsafe extern "C" fn(s: GLint, t: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2iv"]
+    pub static mut epoxy_glTexCoord2iv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2s"]
+    pub static mut epoxy_glTexCoord2s:
+        ::std::option::Option<unsafe extern "C" fn(s: GLshort, t: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2sv"]
+    pub static mut epoxy_glTexCoord2sv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2xOES"]
+    pub static mut epoxy_glTexCoord2xOES:
+        ::std::option::Option<unsafe extern "C" fn(s: GLfixed, t: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord2xvOES"]
+    pub static mut epoxy_glTexCoord2xvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord3bOES"]
+    pub static mut epoxy_glTexCoord3bOES:
+        ::std::option::Option<unsafe extern "C" fn(s: GLbyte, t: GLbyte, r: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord3bvOES"]
+    pub static mut epoxy_glTexCoord3bvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord3d"]
+    pub static mut epoxy_glTexCoord3d:
+        ::std::option::Option<unsafe extern "C" fn(s: GLdouble, t: GLdouble, r: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord3dv"]
+    pub static mut epoxy_glTexCoord3dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord3f"]
+    pub static mut epoxy_glTexCoord3f:
+        ::std::option::Option<unsafe extern "C" fn(s: GLfloat, t: GLfloat, r: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord3fv"]
+    pub static mut epoxy_glTexCoord3fv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord3hNV"]
+    pub static mut epoxy_glTexCoord3hNV:
+        ::std::option::Option<unsafe extern "C" fn(s: GLhalfNV, t: GLhalfNV, r: GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord3hvNV"]
+    pub static mut epoxy_glTexCoord3hvNV:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord3i"]
+    pub static mut epoxy_glTexCoord3i:
+        ::std::option::Option<unsafe extern "C" fn(s: GLint, t: GLint, r: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord3iv"]
+    pub static mut epoxy_glTexCoord3iv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord3s"]
+    pub static mut epoxy_glTexCoord3s:
+        ::std::option::Option<unsafe extern "C" fn(s: GLshort, t: GLshort, r: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord3sv"]
+    pub static mut epoxy_glTexCoord3sv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord3xOES"]
+    pub static mut epoxy_glTexCoord3xOES:
+        ::std::option::Option<unsafe extern "C" fn(s: GLfixed, t: GLfixed, r: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord3xvOES"]
+    pub static mut epoxy_glTexCoord3xvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4bOES"]
+    pub static mut epoxy_glTexCoord4bOES:
+        ::std::option::Option<unsafe extern "C" fn(s: GLbyte, t: GLbyte, r: GLbyte, q: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4bvOES"]
+    pub static mut epoxy_glTexCoord4bvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4d"]
+    pub static mut epoxy_glTexCoord4d: ::std::option::Option<
+        unsafe extern "C" fn(s: GLdouble, t: GLdouble, r: GLdouble, q: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4dv"]
+    pub static mut epoxy_glTexCoord4dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4f"]
+    pub static mut epoxy_glTexCoord4f:
+        ::std::option::Option<unsafe extern "C" fn(s: GLfloat, t: GLfloat, r: GLfloat, q: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4fColor4fNormal3fVertex4fSUN"]
+    pub static mut epoxy_glTexCoord4fColor4fNormal3fVertex4fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            s: GLfloat,
+            t: GLfloat,
+            p: GLfloat,
+            q: GLfloat,
+            r: GLfloat,
+            g: GLfloat,
+            b: GLfloat,
+            a: GLfloat,
+            nx: GLfloat,
+            ny: GLfloat,
+            nz: GLfloat,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+            w: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4fColor4fNormal3fVertex4fvSUN"]
+    pub static mut epoxy_glTexCoord4fColor4fNormal3fVertex4fvSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            tc: *const GLfloat,
+            c: *const GLfloat,
+            n: *const GLfloat,
+            v: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4fVertex4fSUN"]
+    pub static mut epoxy_glTexCoord4fVertex4fSUN: ::std::option::Option<
+        unsafe extern "C" fn(
+            s: GLfloat,
+            t: GLfloat,
+            p: GLfloat,
+            q: GLfloat,
+            x: GLfloat,
+            y: GLfloat,
+            z: GLfloat,
+            w: GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4fVertex4fvSUN"]
+    pub static mut epoxy_glTexCoord4fVertex4fvSUN:
+        ::std::option::Option<unsafe extern "C" fn(tc: *const GLfloat, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4fv"]
+    pub static mut epoxy_glTexCoord4fv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4hNV"]
+    pub static mut epoxy_glTexCoord4hNV: ::std::option::Option<
+        unsafe extern "C" fn(s: GLhalfNV, t: GLhalfNV, r: GLhalfNV, q: GLhalfNV),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4hvNV"]
+    pub static mut epoxy_glTexCoord4hvNV:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4i"]
+    pub static mut epoxy_glTexCoord4i:
+        ::std::option::Option<unsafe extern "C" fn(s: GLint, t: GLint, r: GLint, q: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4iv"]
+    pub static mut epoxy_glTexCoord4iv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4s"]
+    pub static mut epoxy_glTexCoord4s:
+        ::std::option::Option<unsafe extern "C" fn(s: GLshort, t: GLshort, r: GLshort, q: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4sv"]
+    pub static mut epoxy_glTexCoord4sv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4xOES"]
+    pub static mut epoxy_glTexCoord4xOES:
+        ::std::option::Option<unsafe extern "C" fn(s: GLfixed, t: GLfixed, r: GLfixed, q: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoord4xvOES"]
+    pub static mut epoxy_glTexCoord4xvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoordFormatNV"]
+    pub static mut epoxy_glTexCoordFormatNV:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, type_: GLenum, stride: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoordP1ui"]
+    pub static mut epoxy_glTexCoordP1ui:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, coords: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoordP1uiv"]
+    pub static mut epoxy_glTexCoordP1uiv:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, coords: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoordP2ui"]
+    pub static mut epoxy_glTexCoordP2ui:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, coords: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoordP2uiv"]
+    pub static mut epoxy_glTexCoordP2uiv:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, coords: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoordP3ui"]
+    pub static mut epoxy_glTexCoordP3ui:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, coords: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoordP3uiv"]
+    pub static mut epoxy_glTexCoordP3uiv:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, coords: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoordP4ui"]
+    pub static mut epoxy_glTexCoordP4ui:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, coords: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoordP4uiv"]
+    pub static mut epoxy_glTexCoordP4uiv:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, coords: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoordPointer"]
+    pub static mut epoxy_glTexCoordPointer: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoordPointerEXT"]
+    pub static mut epoxy_glTexCoordPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            count: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoordPointerListIBM"]
+    pub static mut epoxy_glTexCoordPointerListIBM: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLint,
+            pointer: *mut *const ::std::os::raw::c_void,
+            ptrstride: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexCoordPointervINTEL"]
+    pub static mut epoxy_glTexCoordPointervINTEL: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            pointer: *mut *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexEnvf"]
+    pub static mut epoxy_glTexEnvf:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexEnvfv"]
+    pub static mut epoxy_glTexEnvfv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexEnvi"]
+    pub static mut epoxy_glTexEnvi:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexEnviv"]
+    pub static mut epoxy_glTexEnviv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexEnvx"]
+    pub static mut epoxy_glTexEnvx:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexEnvxOES"]
+    pub static mut epoxy_glTexEnvxOES:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexEnvxv"]
+    pub static mut epoxy_glTexEnvxv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexEnvxvOES"]
+    pub static mut epoxy_glTexEnvxvOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexFilterFuncSGIS"]
+    pub static mut epoxy_glTexFilterFuncSGIS: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, filter: GLenum, n: GLsizei, weights: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexGend"]
+    pub static mut epoxy_glTexGend:
+        ::std::option::Option<unsafe extern "C" fn(coord: GLenum, pname: GLenum, param: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexGendv"]
+    pub static mut epoxy_glTexGendv: ::std::option::Option<
+        unsafe extern "C" fn(coord: GLenum, pname: GLenum, params: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexGenf"]
+    pub static mut epoxy_glTexGenf:
+        ::std::option::Option<unsafe extern "C" fn(coord: GLenum, pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexGenfOES"]
+    pub static mut epoxy_glTexGenfOES:
+        ::std::option::Option<unsafe extern "C" fn(coord: GLenum, pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexGenfv"]
+    pub static mut epoxy_glTexGenfv: ::std::option::Option<
+        unsafe extern "C" fn(coord: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexGenfvOES"]
+    pub static mut epoxy_glTexGenfvOES: ::std::option::Option<
+        unsafe extern "C" fn(coord: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexGeni"]
+    pub static mut epoxy_glTexGeni:
+        ::std::option::Option<unsafe extern "C" fn(coord: GLenum, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexGeniOES"]
+    pub static mut epoxy_glTexGeniOES:
+        ::std::option::Option<unsafe extern "C" fn(coord: GLenum, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexGeniv"]
+    pub static mut epoxy_glTexGeniv: ::std::option::Option<
+        unsafe extern "C" fn(coord: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexGenivOES"]
+    pub static mut epoxy_glTexGenivOES: ::std::option::Option<
+        unsafe extern "C" fn(coord: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexGenxOES"]
+    pub static mut epoxy_glTexGenxOES:
+        ::std::option::Option<unsafe extern "C" fn(coord: GLenum, pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexGenxvOES"]
+    pub static mut epoxy_glTexGenxvOES: ::std::option::Option<
+        unsafe extern "C" fn(coord: GLenum, pname: GLenum, params: *const GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexImage1D"]
+    pub static mut epoxy_glTexImage1D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLint,
+            width: GLsizei,
+            border: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexImage2D"]
+    pub static mut epoxy_glTexImage2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            border: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexImage2DMultisample"]
+    pub static mut epoxy_glTexImage2DMultisample: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            fixedsamplelocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexImage2DMultisampleCoverageNV"]
+    pub static mut epoxy_glTexImage2DMultisampleCoverageNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            coverageSamples: GLsizei,
+            colorSamples: GLsizei,
+            internalFormat: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            fixedSampleLocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexImage3D"]
+    pub static mut epoxy_glTexImage3D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            border: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexImage3DEXT"]
+    pub static mut epoxy_glTexImage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            border: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexImage3DMultisample"]
+    pub static mut epoxy_glTexImage3DMultisample: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            fixedsamplelocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexImage3DMultisampleCoverageNV"]
+    pub static mut epoxy_glTexImage3DMultisampleCoverageNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            coverageSamples: GLsizei,
+            colorSamples: GLsizei,
+            internalFormat: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            fixedSampleLocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexImage3DOES"]
+    pub static mut epoxy_glTexImage3DOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            border: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexImage4DSGIS"]
+    pub static mut epoxy_glTexImage4DSGIS: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            size4d: GLsizei,
+            border: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexPageCommitmentARB"]
+    pub static mut epoxy_glTexPageCommitmentARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            commit: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexPageCommitmentEXT"]
+    pub static mut epoxy_glTexPageCommitmentEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            commit: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexParameterIiv"]
+    pub static mut epoxy_glTexParameterIiv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexParameterIivEXT"]
+    pub static mut epoxy_glTexParameterIivEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexParameterIivOES"]
+    pub static mut epoxy_glTexParameterIivOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexParameterIuiv"]
+    pub static mut epoxy_glTexParameterIuiv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexParameterIuivEXT"]
+    pub static mut epoxy_glTexParameterIuivEXT: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexParameterIuivOES"]
+    pub static mut epoxy_glTexParameterIuivOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexParameterf"]
+    pub static mut epoxy_glTexParameterf:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexParameterfv"]
+    pub static mut epoxy_glTexParameterfv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexParameteri"]
+    pub static mut epoxy_glTexParameteri:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexParameteriv"]
+    pub static mut epoxy_glTexParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexParameterx"]
+    pub static mut epoxy_glTexParameterx:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexParameterxOES"]
+    pub static mut epoxy_glTexParameterxOES:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, pname: GLenum, param: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexParameterxv"]
+    pub static mut epoxy_glTexParameterxv: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexParameterxvOES"]
+    pub static mut epoxy_glTexParameterxvOES: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, pname: GLenum, params: *const GLfixed),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexRenderbufferNV"]
+    pub static mut epoxy_glTexRenderbufferNV:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum, renderbuffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexStorage1D"]
+    pub static mut epoxy_glTexStorage1D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            levels: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexStorage1DEXT"]
+    pub static mut epoxy_glTexStorage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            levels: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexStorage2D"]
+    pub static mut epoxy_glTexStorage2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            levels: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexStorage2DEXT"]
+    pub static mut epoxy_glTexStorage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            levels: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexStorage2DMultisample"]
+    pub static mut epoxy_glTexStorage2DMultisample: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            fixedsamplelocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexStorage3D"]
+    pub static mut epoxy_glTexStorage3D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            levels: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexStorage3DEXT"]
+    pub static mut epoxy_glTexStorage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            levels: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexStorage3DMultisample"]
+    pub static mut epoxy_glTexStorage3DMultisample: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            fixedsamplelocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexStorage3DMultisampleOES"]
+    pub static mut epoxy_glTexStorage3DMultisampleOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            fixedsamplelocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexStorageSparseAMD"]
+    pub static mut epoxy_glTexStorageSparseAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            internalFormat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            layers: GLsizei,
+            flags: GLbitfield,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexSubImage1D"]
+    pub static mut epoxy_glTexSubImage1D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            width: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexSubImage1DEXT"]
+    pub static mut epoxy_glTexSubImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            width: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexSubImage2D"]
+    pub static mut epoxy_glTexSubImage2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexSubImage2DEXT"]
+    pub static mut epoxy_glTexSubImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexSubImage3D"]
+    pub static mut epoxy_glTexSubImage3D: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexSubImage3DEXT"]
+    pub static mut epoxy_glTexSubImage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexSubImage3DOES"]
+    pub static mut epoxy_glTexSubImage3DOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexSubImage4DSGIS"]
+    pub static mut epoxy_glTexSubImage4DSGIS: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            woffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            size4d: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureBarrier"]
+    pub static mut epoxy_glTextureBarrier: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureBarrierNV"]
+    pub static mut epoxy_glTextureBarrierNV: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureBuffer"]
+    pub static mut epoxy_glTextureBuffer: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, internalformat: GLenum, buffer: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureBufferEXT"]
+    pub static mut epoxy_glTextureBufferEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            internalformat: GLenum,
+            buffer: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureBufferRange"]
+    pub static mut epoxy_glTextureBufferRange: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            internalformat: GLenum,
+            buffer: GLuint,
+            offset: GLintptr,
+            size: GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureBufferRangeEXT"]
+    pub static mut epoxy_glTextureBufferRangeEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            internalformat: GLenum,
+            buffer: GLuint,
+            offset: GLintptr,
+            size: GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureColorMaskSGIS"]
+    pub static mut epoxy_glTextureColorMaskSGIS: ::std::option::Option<
+        unsafe extern "C" fn(red: GLboolean, green: GLboolean, blue: GLboolean, alpha: GLboolean),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureImage1DEXT"]
+    pub static mut epoxy_glTextureImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLint,
+            width: GLsizei,
+            border: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureImage2DEXT"]
+    pub static mut epoxy_glTextureImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            border: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureImage2DMultisampleCoverageNV"]
+    pub static mut epoxy_glTextureImage2DMultisampleCoverageNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            coverageSamples: GLsizei,
+            colorSamples: GLsizei,
+            internalFormat: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            fixedSampleLocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureImage2DMultisampleNV"]
+    pub static mut epoxy_glTextureImage2DMultisampleNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            samples: GLsizei,
+            internalFormat: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            fixedSampleLocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureImage3DEXT"]
+    pub static mut epoxy_glTextureImage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            internalformat: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            border: GLint,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureImage3DMultisampleCoverageNV"]
+    pub static mut epoxy_glTextureImage3DMultisampleCoverageNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            coverageSamples: GLsizei,
+            colorSamples: GLsizei,
+            internalFormat: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            fixedSampleLocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureImage3DMultisampleNV"]
+    pub static mut epoxy_glTextureImage3DMultisampleNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            samples: GLsizei,
+            internalFormat: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            fixedSampleLocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureLightEXT"]
+    pub static mut epoxy_glTextureLightEXT:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureMaterialEXT"]
+    pub static mut epoxy_glTextureMaterialEXT:
+        ::std::option::Option<unsafe extern "C" fn(face: GLenum, mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureNormalEXT"]
+    pub static mut epoxy_glTextureNormalEXT:
+        ::std::option::Option<unsafe extern "C" fn(mode: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTexturePageCommitmentEXT"]
+    pub static mut epoxy_glTexturePageCommitmentEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            commit: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureParameterIiv"]
+    pub static mut epoxy_glTextureParameterIiv: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureParameterIivEXT"]
+    pub static mut epoxy_glTextureParameterIivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureParameterIuiv"]
+    pub static mut epoxy_glTextureParameterIuiv: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, pname: GLenum, params: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureParameterIuivEXT"]
+    pub static mut epoxy_glTextureParameterIuivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, target: GLenum, pname: GLenum, params: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureParameterf"]
+    pub static mut epoxy_glTextureParameterf:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint, pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureParameterfEXT"]
+    pub static mut epoxy_glTextureParameterfEXT: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, target: GLenum, pname: GLenum, param: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureParameterfv"]
+    pub static mut epoxy_glTextureParameterfv: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, pname: GLenum, param: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureParameterfvEXT"]
+    pub static mut epoxy_glTextureParameterfvEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            pname: GLenum,
+            params: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureParameteri"]
+    pub static mut epoxy_glTextureParameteri:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureParameteriEXT"]
+    pub static mut epoxy_glTextureParameteriEXT: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, target: GLenum, pname: GLenum, param: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureParameteriv"]
+    pub static mut epoxy_glTextureParameteriv: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, pname: GLenum, param: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureParameterivEXT"]
+    pub static mut epoxy_glTextureParameterivEXT: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, target: GLenum, pname: GLenum, params: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureRangeAPPLE"]
+    pub static mut epoxy_glTextureRangeAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            target: GLenum,
+            length: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureRenderbufferEXT"]
+    pub static mut epoxy_glTextureRenderbufferEXT: ::std::option::Option<
+        unsafe extern "C" fn(texture: GLuint, target: GLenum, renderbuffer: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureStorage1D"]
+    pub static mut epoxy_glTextureStorage1D: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            levels: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureStorage1DEXT"]
+    pub static mut epoxy_glTextureStorage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            levels: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureStorage2D"]
+    pub static mut epoxy_glTextureStorage2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            levels: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureStorage2DEXT"]
+    pub static mut epoxy_glTextureStorage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            levels: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureStorage2DMultisample"]
+    pub static mut epoxy_glTextureStorage2DMultisample: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            fixedsamplelocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureStorage2DMultisampleEXT"]
+    pub static mut epoxy_glTextureStorage2DMultisampleEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            fixedsamplelocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureStorage3D"]
+    pub static mut epoxy_glTextureStorage3D: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            levels: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureStorage3DEXT"]
+    pub static mut epoxy_glTextureStorage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            levels: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureStorage3DMultisample"]
+    pub static mut epoxy_glTextureStorage3DMultisample: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            fixedsamplelocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureStorage3DMultisampleEXT"]
+    pub static mut epoxy_glTextureStorage3DMultisampleEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            samples: GLsizei,
+            internalformat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            fixedsamplelocations: GLboolean,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureStorageSparseAMD"]
+    pub static mut epoxy_glTextureStorageSparseAMD: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            internalFormat: GLenum,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            layers: GLsizei,
+            flags: GLbitfield,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureSubImage1D"]
+    pub static mut epoxy_glTextureSubImage1D: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            width: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureSubImage1DEXT"]
+    pub static mut epoxy_glTextureSubImage1DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            width: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureSubImage2D"]
+    pub static mut epoxy_glTextureSubImage2D: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureSubImage2DEXT"]
+    pub static mut epoxy_glTextureSubImage2DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureSubImage3D"]
+    pub static mut epoxy_glTextureSubImage3D: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureSubImage3DEXT"]
+    pub static mut epoxy_glTextureSubImage3DEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            level: GLint,
+            xoffset: GLint,
+            yoffset: GLint,
+            zoffset: GLint,
+            width: GLsizei,
+            height: GLsizei,
+            depth: GLsizei,
+            format: GLenum,
+            type_: GLenum,
+            pixels: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureView"]
+    pub static mut epoxy_glTextureView: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            origtexture: GLuint,
+            internalformat: GLenum,
+            minlevel: GLuint,
+            numlevels: GLuint,
+            minlayer: GLuint,
+            numlayers: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureViewEXT"]
+    pub static mut epoxy_glTextureViewEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            origtexture: GLuint,
+            internalformat: GLenum,
+            minlevel: GLuint,
+            numlevels: GLuint,
+            minlayer: GLuint,
+            numlayers: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTextureViewOES"]
+    pub static mut epoxy_glTextureViewOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            texture: GLuint,
+            target: GLenum,
+            origtexture: GLuint,
+            internalformat: GLenum,
+            minlevel: GLuint,
+            numlevels: GLuint,
+            minlayer: GLuint,
+            numlayers: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTrackMatrixNV"]
+    pub static mut epoxy_glTrackMatrixNV: ::std::option::Option<
+        unsafe extern "C" fn(target: GLenum, address: GLuint, matrix: GLenum, transform: GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTransformFeedbackAttribsNV"]
+    pub static mut epoxy_glTransformFeedbackAttribsNV: ::std::option::Option<
+        unsafe extern "C" fn(count: GLsizei, attribs: *const GLint, bufferMode: GLenum),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTransformFeedbackBufferBase"]
+    pub static mut epoxy_glTransformFeedbackBufferBase:
+        ::std::option::Option<unsafe extern "C" fn(xfb: GLuint, index: GLuint, buffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTransformFeedbackBufferRange"]
+    pub static mut epoxy_glTransformFeedbackBufferRange: ::std::option::Option<
+        unsafe extern "C" fn(
+            xfb: GLuint,
+            index: GLuint,
+            buffer: GLuint,
+            offset: GLintptr,
+            size: GLsizeiptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTransformFeedbackStreamAttribsNV"]
+    pub static mut epoxy_glTransformFeedbackStreamAttribsNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            count: GLsizei,
+            attribs: *const GLint,
+            nbuffers: GLsizei,
+            bufstreams: *const GLint,
+            bufferMode: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTransformFeedbackVaryings"]
+    pub static mut epoxy_glTransformFeedbackVaryings: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            count: GLsizei,
+            varyings: *const *const GLchar,
+            bufferMode: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTransformFeedbackVaryingsEXT"]
+    pub static mut epoxy_glTransformFeedbackVaryingsEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            count: GLsizei,
+            varyings: *const *const GLchar,
+            bufferMode: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTransformFeedbackVaryingsNV"]
+    pub static mut epoxy_glTransformFeedbackVaryingsNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            count: GLsizei,
+            locations: *const GLint,
+            bufferMode: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTransformPathNV"]
+    pub static mut epoxy_glTransformPathNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            resultPath: GLuint,
+            srcPath: GLuint,
+            transformType: GLenum,
+            transformValues: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTranslated"]
+    pub static mut epoxy_glTranslated:
+        ::std::option::Option<unsafe extern "C" fn(x: GLdouble, y: GLdouble, z: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTranslatef"]
+    pub static mut epoxy_glTranslatef:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat, z: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTranslatex"]
+    pub static mut epoxy_glTranslatex:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfixed, y: GLfixed, z: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glTranslatexOES"]
+    pub static mut epoxy_glTranslatexOES:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfixed, y: GLfixed, z: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1d"]
+    pub static mut epoxy_glUniform1d:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, x: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1dv"]
+    pub static mut epoxy_glUniform1dv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1f"]
+    pub static mut epoxy_glUniform1f:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, v0: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1fARB"]
+    pub static mut epoxy_glUniform1fARB:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, v0: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1fv"]
+    pub static mut epoxy_glUniform1fv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1fvARB"]
+    pub static mut epoxy_glUniform1fvARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1i"]
+    pub static mut epoxy_glUniform1i:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, v0: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1i64ARB"]
+    pub static mut epoxy_glUniform1i64ARB:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, x: GLint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1i64NV"]
+    pub static mut epoxy_glUniform1i64NV:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, x: GLint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1i64vARB"]
+    pub static mut epoxy_glUniform1i64vARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1i64vNV"]
+    pub static mut epoxy_glUniform1i64vNV: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1iARB"]
+    pub static mut epoxy_glUniform1iARB:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, v0: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1iv"]
+    pub static mut epoxy_glUniform1iv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1ivARB"]
+    pub static mut epoxy_glUniform1ivARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1ui"]
+    pub static mut epoxy_glUniform1ui:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, v0: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1ui64ARB"]
+    pub static mut epoxy_glUniform1ui64ARB:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, x: GLuint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1ui64NV"]
+    pub static mut epoxy_glUniform1ui64NV:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, x: GLuint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1ui64vARB"]
+    pub static mut epoxy_glUniform1ui64vARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1ui64vNV"]
+    pub static mut epoxy_glUniform1ui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1uiEXT"]
+    pub static mut epoxy_glUniform1uiEXT:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, v0: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1uiv"]
+    pub static mut epoxy_glUniform1uiv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform1uivEXT"]
+    pub static mut epoxy_glUniform1uivEXT: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2d"]
+    pub static mut epoxy_glUniform2d:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, x: GLdouble, y: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2dv"]
+    pub static mut epoxy_glUniform2dv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2f"]
+    pub static mut epoxy_glUniform2f:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, v0: GLfloat, v1: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2fARB"]
+    pub static mut epoxy_glUniform2fARB:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, v0: GLfloat, v1: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2fv"]
+    pub static mut epoxy_glUniform2fv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2fvARB"]
+    pub static mut epoxy_glUniform2fvARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2i"]
+    pub static mut epoxy_glUniform2i:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, v0: GLint, v1: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2i64ARB"]
+    pub static mut epoxy_glUniform2i64ARB:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, x: GLint64, y: GLint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2i64NV"]
+    pub static mut epoxy_glUniform2i64NV:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, x: GLint64EXT, y: GLint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2i64vARB"]
+    pub static mut epoxy_glUniform2i64vARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2i64vNV"]
+    pub static mut epoxy_glUniform2i64vNV: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2iARB"]
+    pub static mut epoxy_glUniform2iARB:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, v0: GLint, v1: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2iv"]
+    pub static mut epoxy_glUniform2iv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2ivARB"]
+    pub static mut epoxy_glUniform2ivARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2ui"]
+    pub static mut epoxy_glUniform2ui:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, v0: GLuint, v1: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2ui64ARB"]
+    pub static mut epoxy_glUniform2ui64ARB:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, x: GLuint64, y: GLuint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2ui64NV"]
+    pub static mut epoxy_glUniform2ui64NV: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, x: GLuint64EXT, y: GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2ui64vARB"]
+    pub static mut epoxy_glUniform2ui64vARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2ui64vNV"]
+    pub static mut epoxy_glUniform2ui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2uiEXT"]
+    pub static mut epoxy_glUniform2uiEXT:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, v0: GLuint, v1: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2uiv"]
+    pub static mut epoxy_glUniform2uiv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform2uivEXT"]
+    pub static mut epoxy_glUniform2uivEXT: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3d"]
+    pub static mut epoxy_glUniform3d: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, x: GLdouble, y: GLdouble, z: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3dv"]
+    pub static mut epoxy_glUniform3dv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3f"]
+    pub static mut epoxy_glUniform3f: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3fARB"]
+    pub static mut epoxy_glUniform3fARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3fv"]
+    pub static mut epoxy_glUniform3fv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3fvARB"]
+    pub static mut epoxy_glUniform3fvARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3i"]
+    pub static mut epoxy_glUniform3i: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, v0: GLint, v1: GLint, v2: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3i64ARB"]
+    pub static mut epoxy_glUniform3i64ARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, x: GLint64, y: GLint64, z: GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3i64NV"]
+    pub static mut epoxy_glUniform3i64NV: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, x: GLint64EXT, y: GLint64EXT, z: GLint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3i64vARB"]
+    pub static mut epoxy_glUniform3i64vARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3i64vNV"]
+    pub static mut epoxy_glUniform3i64vNV: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3iARB"]
+    pub static mut epoxy_glUniform3iARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, v0: GLint, v1: GLint, v2: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3iv"]
+    pub static mut epoxy_glUniform3iv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3ivARB"]
+    pub static mut epoxy_glUniform3ivARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3ui"]
+    pub static mut epoxy_glUniform3ui: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, v0: GLuint, v1: GLuint, v2: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3ui64ARB"]
+    pub static mut epoxy_glUniform3ui64ARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, x: GLuint64, y: GLuint64, z: GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3ui64NV"]
+    pub static mut epoxy_glUniform3ui64NV: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, x: GLuint64EXT, y: GLuint64EXT, z: GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3ui64vARB"]
+    pub static mut epoxy_glUniform3ui64vARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3ui64vNV"]
+    pub static mut epoxy_glUniform3ui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3uiEXT"]
+    pub static mut epoxy_glUniform3uiEXT: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, v0: GLuint, v1: GLuint, v2: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3uiv"]
+    pub static mut epoxy_glUniform3uiv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform3uivEXT"]
+    pub static mut epoxy_glUniform3uivEXT: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4d"]
+    pub static mut epoxy_glUniform4d: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4dv"]
+    pub static mut epoxy_glUniform4dv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4f"]
+    pub static mut epoxy_glUniform4f: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat, v3: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4fARB"]
+    pub static mut epoxy_glUniform4fARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat, v3: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4fv"]
+    pub static mut epoxy_glUniform4fv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4fvARB"]
+    pub static mut epoxy_glUniform4fvARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4i"]
+    pub static mut epoxy_glUniform4i: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, v0: GLint, v1: GLint, v2: GLint, v3: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4i64ARB"]
+    pub static mut epoxy_glUniform4i64ARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, x: GLint64, y: GLint64, z: GLint64, w: GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4i64NV"]
+    pub static mut epoxy_glUniform4i64NV: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            x: GLint64EXT,
+            y: GLint64EXT,
+            z: GLint64EXT,
+            w: GLint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4i64vARB"]
+    pub static mut epoxy_glUniform4i64vARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4i64vNV"]
+    pub static mut epoxy_glUniform4i64vNV: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4iARB"]
+    pub static mut epoxy_glUniform4iARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, v0: GLint, v1: GLint, v2: GLint, v3: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4iv"]
+    pub static mut epoxy_glUniform4iv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4ivARB"]
+    pub static mut epoxy_glUniform4ivARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4ui"]
+    pub static mut epoxy_glUniform4ui: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, v0: GLuint, v1: GLuint, v2: GLuint, v3: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4ui64ARB"]
+    pub static mut epoxy_glUniform4ui64ARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, x: GLuint64, y: GLuint64, z: GLuint64, w: GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4ui64NV"]
+    pub static mut epoxy_glUniform4ui64NV: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            x: GLuint64EXT,
+            y: GLuint64EXT,
+            z: GLuint64EXT,
+            w: GLuint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4ui64vARB"]
+    pub static mut epoxy_glUniform4ui64vARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4ui64vNV"]
+    pub static mut epoxy_glUniform4ui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4uiEXT"]
+    pub static mut epoxy_glUniform4uiEXT: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, v0: GLuint, v1: GLuint, v2: GLuint, v3: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4uiv"]
+    pub static mut epoxy_glUniform4uiv: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniform4uivEXT"]
+    pub static mut epoxy_glUniform4uivEXT: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformBlockBinding"]
+    pub static mut epoxy_glUniformBlockBinding: ::std::option::Option<
+        unsafe extern "C" fn(
+            program: GLuint,
+            uniformBlockIndex: GLuint,
+            uniformBlockBinding: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformBufferEXT"]
+    pub static mut epoxy_glUniformBufferEXT: ::std::option::Option<
+        unsafe extern "C" fn(program: GLuint, location: GLint, buffer: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformHandleui64ARB"]
+    pub static mut epoxy_glUniformHandleui64ARB:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, value: GLuint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformHandleui64IMG"]
+    pub static mut epoxy_glUniformHandleui64IMG:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, value: GLuint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformHandleui64NV"]
+    pub static mut epoxy_glUniformHandleui64NV:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, value: GLuint64)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformHandleui64vARB"]
+    pub static mut epoxy_glUniformHandleui64vARB: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformHandleui64vIMG"]
+    pub static mut epoxy_glUniformHandleui64vIMG: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformHandleui64vNV"]
+    pub static mut epoxy_glUniformHandleui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix2dv"]
+    pub static mut epoxy_glUniformMatrix2dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix2fv"]
+    pub static mut epoxy_glUniformMatrix2fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix2fvARB"]
+    pub static mut epoxy_glUniformMatrix2fvARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix2x3dv"]
+    pub static mut epoxy_glUniformMatrix2x3dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix2x3fv"]
+    pub static mut epoxy_glUniformMatrix2x3fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix2x3fvNV"]
+    pub static mut epoxy_glUniformMatrix2x3fvNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix2x4dv"]
+    pub static mut epoxy_glUniformMatrix2x4dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix2x4fv"]
+    pub static mut epoxy_glUniformMatrix2x4fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix2x4fvNV"]
+    pub static mut epoxy_glUniformMatrix2x4fvNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix3dv"]
+    pub static mut epoxy_glUniformMatrix3dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix3fv"]
+    pub static mut epoxy_glUniformMatrix3fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix3fvARB"]
+    pub static mut epoxy_glUniformMatrix3fvARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix3x2dv"]
+    pub static mut epoxy_glUniformMatrix3x2dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix3x2fv"]
+    pub static mut epoxy_glUniformMatrix3x2fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix3x2fvNV"]
+    pub static mut epoxy_glUniformMatrix3x2fvNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix3x4dv"]
+    pub static mut epoxy_glUniformMatrix3x4dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix3x4fv"]
+    pub static mut epoxy_glUniformMatrix3x4fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix3x4fvNV"]
+    pub static mut epoxy_glUniformMatrix3x4fvNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix4dv"]
+    pub static mut epoxy_glUniformMatrix4dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix4fv"]
+    pub static mut epoxy_glUniformMatrix4fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix4fvARB"]
+    pub static mut epoxy_glUniformMatrix4fvARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix4x2dv"]
+    pub static mut epoxy_glUniformMatrix4x2dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix4x2fv"]
+    pub static mut epoxy_glUniformMatrix4x2fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix4x2fvNV"]
+    pub static mut epoxy_glUniformMatrix4x2fvNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix4x3dv"]
+    pub static mut epoxy_glUniformMatrix4x3dv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix4x3fv"]
+    pub static mut epoxy_glUniformMatrix4x3fv: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformMatrix4x3fvNV"]
+    pub static mut epoxy_glUniformMatrix4x3fvNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            location: GLint,
+            count: GLsizei,
+            transpose: GLboolean,
+            value: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformSubroutinesuiv"]
+    pub static mut epoxy_glUniformSubroutinesuiv: ::std::option::Option<
+        unsafe extern "C" fn(shadertype: GLenum, count: GLsizei, indices: *const GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformui64NV"]
+    pub static mut epoxy_glUniformui64NV:
+        ::std::option::Option<unsafe extern "C" fn(location: GLint, value: GLuint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUniformui64vNV"]
+    pub static mut epoxy_glUniformui64vNV: ::std::option::Option<
+        unsafe extern "C" fn(location: GLint, count: GLsizei, value: *const GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUnlockArraysEXT"]
+    pub static mut epoxy_glUnlockArraysEXT: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUnmapBuffer"]
+    pub static mut epoxy_glUnmapBuffer:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUnmapBufferARB"]
+    pub static mut epoxy_glUnmapBufferARB:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUnmapBufferOES"]
+    pub static mut epoxy_glUnmapBufferOES:
+        ::std::option::Option<unsafe extern "C" fn(target: GLenum) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUnmapNamedBuffer"]
+    pub static mut epoxy_glUnmapNamedBuffer:
+        ::std::option::Option<unsafe extern "C" fn(buffer: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUnmapNamedBufferEXT"]
+    pub static mut epoxy_glUnmapNamedBufferEXT:
+        ::std::option::Option<unsafe extern "C" fn(buffer: GLuint) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUnmapObjectBufferATI"]
+    pub static mut epoxy_glUnmapObjectBufferATI:
+        ::std::option::Option<unsafe extern "C" fn(buffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUnmapTexture2DINTEL"]
+    pub static mut epoxy_glUnmapTexture2DINTEL:
+        ::std::option::Option<unsafe extern "C" fn(texture: GLuint, level: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUpdateObjectBufferATI"]
+    pub static mut epoxy_glUpdateObjectBufferATI: ::std::option::Option<
+        unsafe extern "C" fn(
+            buffer: GLuint,
+            offset: GLuint,
+            size: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+            preserve: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUseProgram"]
+    pub static mut epoxy_glUseProgram: ::std::option::Option<unsafe extern "C" fn(program: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUseProgramObjectARB"]
+    pub static mut epoxy_glUseProgramObjectARB:
+        ::std::option::Option<unsafe extern "C" fn(programObj: GLhandleARB)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUseProgramStages"]
+    pub static mut epoxy_glUseProgramStages: ::std::option::Option<
+        unsafe extern "C" fn(pipeline: GLuint, stages: GLbitfield, program: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUseProgramStagesEXT"]
+    pub static mut epoxy_glUseProgramStagesEXT: ::std::option::Option<
+        unsafe extern "C" fn(pipeline: GLuint, stages: GLbitfield, program: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glUseShaderProgramEXT"]
+    pub static mut epoxy_glUseShaderProgramEXT:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, program: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVDPAUFiniNV"]
+    pub static mut epoxy_glVDPAUFiniNV: ::std::option::Option<unsafe extern "C" fn()>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVDPAUGetSurfaceivNV"]
+    pub static mut epoxy_glVDPAUGetSurfaceivNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            surface: GLvdpauSurfaceNV,
+            pname: GLenum,
+            bufSize: GLsizei,
+            length: *mut GLsizei,
+            values: *mut GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVDPAUInitNV"]
+    pub static mut epoxy_glVDPAUInitNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            vdpDevice: *const ::std::os::raw::c_void,
+            getProcAddress: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVDPAUIsSurfaceNV"]
+    pub static mut epoxy_glVDPAUIsSurfaceNV:
+        ::std::option::Option<unsafe extern "C" fn(surface: GLvdpauSurfaceNV) -> GLboolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVDPAUMapSurfacesNV"]
+    pub static mut epoxy_glVDPAUMapSurfacesNV: ::std::option::Option<
+        unsafe extern "C" fn(numSurfaces: GLsizei, surfaces: *const GLvdpauSurfaceNV),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVDPAURegisterOutputSurfaceNV"]
+    pub static mut epoxy_glVDPAURegisterOutputSurfaceNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            vdpSurface: *const ::std::os::raw::c_void,
+            target: GLenum,
+            numTextureNames: GLsizei,
+            textureNames: *const GLuint,
+        ) -> GLvdpauSurfaceNV,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVDPAURegisterVideoSurfaceNV"]
+    pub static mut epoxy_glVDPAURegisterVideoSurfaceNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            vdpSurface: *const ::std::os::raw::c_void,
+            target: GLenum,
+            numTextureNames: GLsizei,
+            textureNames: *const GLuint,
+        ) -> GLvdpauSurfaceNV,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVDPAUSurfaceAccessNV"]
+    pub static mut epoxy_glVDPAUSurfaceAccessNV:
+        ::std::option::Option<unsafe extern "C" fn(surface: GLvdpauSurfaceNV, access: GLenum)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVDPAUUnmapSurfacesNV"]
+    pub static mut epoxy_glVDPAUUnmapSurfacesNV: ::std::option::Option<
+        unsafe extern "C" fn(numSurface: GLsizei, surfaces: *const GLvdpauSurfaceNV),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVDPAUUnregisterSurfaceNV"]
+    pub static mut epoxy_glVDPAUUnregisterSurfaceNV:
+        ::std::option::Option<unsafe extern "C" fn(surface: GLvdpauSurfaceNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glValidateProgram"]
+    pub static mut epoxy_glValidateProgram:
+        ::std::option::Option<unsafe extern "C" fn(program: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glValidateProgramARB"]
+    pub static mut epoxy_glValidateProgramARB:
+        ::std::option::Option<unsafe extern "C" fn(programObj: GLhandleARB)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glValidateProgramPipeline"]
+    pub static mut epoxy_glValidateProgramPipeline:
+        ::std::option::Option<unsafe extern "C" fn(pipeline: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glValidateProgramPipelineEXT"]
+    pub static mut epoxy_glValidateProgramPipelineEXT:
+        ::std::option::Option<unsafe extern "C" fn(pipeline: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVariantArrayObjectATI"]
+    pub static mut epoxy_glVariantArrayObjectATI: ::std::option::Option<
+        unsafe extern "C" fn(
+            id: GLuint,
+            type_: GLenum,
+            stride: GLsizei,
+            buffer: GLuint,
+            offset: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVariantPointerEXT"]
+    pub static mut epoxy_glVariantPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            id: GLuint,
+            type_: GLenum,
+            stride: GLuint,
+            addr: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVariantbvEXT"]
+    pub static mut epoxy_glVariantbvEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, addr: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVariantdvEXT"]
+    pub static mut epoxy_glVariantdvEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, addr: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVariantfvEXT"]
+    pub static mut epoxy_glVariantfvEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, addr: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVariantivEXT"]
+    pub static mut epoxy_glVariantivEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, addr: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVariantsvEXT"]
+    pub static mut epoxy_glVariantsvEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, addr: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVariantubvEXT"]
+    pub static mut epoxy_glVariantubvEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, addr: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVariantuivEXT"]
+    pub static mut epoxy_glVariantuivEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, addr: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVariantusvEXT"]
+    pub static mut epoxy_glVariantusvEXT:
+        ::std::option::Option<unsafe extern "C" fn(id: GLuint, addr: *const GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex2bOES"]
+    pub static mut epoxy_glVertex2bOES:
+        ::std::option::Option<unsafe extern "C" fn(x: GLbyte, y: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex2bvOES"]
+    pub static mut epoxy_glVertex2bvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex2d"]
+    pub static mut epoxy_glVertex2d:
+        ::std::option::Option<unsafe extern "C" fn(x: GLdouble, y: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex2dv"]
+    pub static mut epoxy_glVertex2dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex2f"]
+    pub static mut epoxy_glVertex2f:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex2fv"]
+    pub static mut epoxy_glVertex2fv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex2hNV"]
+    pub static mut epoxy_glVertex2hNV:
+        ::std::option::Option<unsafe extern "C" fn(x: GLhalfNV, y: GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex2hvNV"]
+    pub static mut epoxy_glVertex2hvNV:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex2i"]
+    pub static mut epoxy_glVertex2i:
+        ::std::option::Option<unsafe extern "C" fn(x: GLint, y: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex2iv"]
+    pub static mut epoxy_glVertex2iv: ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex2s"]
+    pub static mut epoxy_glVertex2s:
+        ::std::option::Option<unsafe extern "C" fn(x: GLshort, y: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex2sv"]
+    pub static mut epoxy_glVertex2sv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex2xOES"]
+    pub static mut epoxy_glVertex2xOES: ::std::option::Option<unsafe extern "C" fn(x: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex2xvOES"]
+    pub static mut epoxy_glVertex2xvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex3bOES"]
+    pub static mut epoxy_glVertex3bOES:
+        ::std::option::Option<unsafe extern "C" fn(x: GLbyte, y: GLbyte, z: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex3bvOES"]
+    pub static mut epoxy_glVertex3bvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex3d"]
+    pub static mut epoxy_glVertex3d:
+        ::std::option::Option<unsafe extern "C" fn(x: GLdouble, y: GLdouble, z: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex3dv"]
+    pub static mut epoxy_glVertex3dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex3f"]
+    pub static mut epoxy_glVertex3f:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat, z: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex3fv"]
+    pub static mut epoxy_glVertex3fv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex3hNV"]
+    pub static mut epoxy_glVertex3hNV:
+        ::std::option::Option<unsafe extern "C" fn(x: GLhalfNV, y: GLhalfNV, z: GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex3hvNV"]
+    pub static mut epoxy_glVertex3hvNV:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex3i"]
+    pub static mut epoxy_glVertex3i:
+        ::std::option::Option<unsafe extern "C" fn(x: GLint, y: GLint, z: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex3iv"]
+    pub static mut epoxy_glVertex3iv: ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex3s"]
+    pub static mut epoxy_glVertex3s:
+        ::std::option::Option<unsafe extern "C" fn(x: GLshort, y: GLshort, z: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex3sv"]
+    pub static mut epoxy_glVertex3sv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex3xOES"]
+    pub static mut epoxy_glVertex3xOES:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfixed, y: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex3xvOES"]
+    pub static mut epoxy_glVertex3xvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex4bOES"]
+    pub static mut epoxy_glVertex4bOES:
+        ::std::option::Option<unsafe extern "C" fn(x: GLbyte, y: GLbyte, z: GLbyte, w: GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex4bvOES"]
+    pub static mut epoxy_glVertex4bvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex4d"]
+    pub static mut epoxy_glVertex4d: ::std::option::Option<
+        unsafe extern "C" fn(x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex4dv"]
+    pub static mut epoxy_glVertex4dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex4f"]
+    pub static mut epoxy_glVertex4f:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex4fv"]
+    pub static mut epoxy_glVertex4fv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex4hNV"]
+    pub static mut epoxy_glVertex4hNV: ::std::option::Option<
+        unsafe extern "C" fn(x: GLhalfNV, y: GLhalfNV, z: GLhalfNV, w: GLhalfNV),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex4hvNV"]
+    pub static mut epoxy_glVertex4hvNV:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex4i"]
+    pub static mut epoxy_glVertex4i:
+        ::std::option::Option<unsafe extern "C" fn(x: GLint, y: GLint, z: GLint, w: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex4iv"]
+    pub static mut epoxy_glVertex4iv: ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex4s"]
+    pub static mut epoxy_glVertex4s:
+        ::std::option::Option<unsafe extern "C" fn(x: GLshort, y: GLshort, z: GLshort, w: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex4sv"]
+    pub static mut epoxy_glVertex4sv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex4xOES"]
+    pub static mut epoxy_glVertex4xOES:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfixed, y: GLfixed, z: GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertex4xvOES"]
+    pub static mut epoxy_glVertex4xvOES:
+        ::std::option::Option<unsafe extern "C" fn(coords: *const GLfixed)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayAttribBinding"]
+    pub static mut epoxy_glVertexArrayAttribBinding: ::std::option::Option<
+        unsafe extern "C" fn(vaobj: GLuint, attribindex: GLuint, bindingindex: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayAttribFormat"]
+    pub static mut epoxy_glVertexArrayAttribFormat: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            attribindex: GLuint,
+            size: GLint,
+            type_: GLenum,
+            normalized: GLboolean,
+            relativeoffset: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayAttribIFormat"]
+    pub static mut epoxy_glVertexArrayAttribIFormat: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            attribindex: GLuint,
+            size: GLint,
+            type_: GLenum,
+            relativeoffset: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayAttribLFormat"]
+    pub static mut epoxy_glVertexArrayAttribLFormat: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            attribindex: GLuint,
+            size: GLint,
+            type_: GLenum,
+            relativeoffset: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayBindVertexBufferEXT"]
+    pub static mut epoxy_glVertexArrayBindVertexBufferEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            bindingindex: GLuint,
+            buffer: GLuint,
+            offset: GLintptr,
+            stride: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayBindingDivisor"]
+    pub static mut epoxy_glVertexArrayBindingDivisor: ::std::option::Option<
+        unsafe extern "C" fn(vaobj: GLuint, bindingindex: GLuint, divisor: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayColorOffsetEXT"]
+    pub static mut epoxy_glVertexArrayColorOffsetEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            buffer: GLuint,
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            offset: GLintptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayEdgeFlagOffsetEXT"]
+    pub static mut epoxy_glVertexArrayEdgeFlagOffsetEXT: ::std::option::Option<
+        unsafe extern "C" fn(vaobj: GLuint, buffer: GLuint, stride: GLsizei, offset: GLintptr),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayElementBuffer"]
+    pub static mut epoxy_glVertexArrayElementBuffer:
+        ::std::option::Option<unsafe extern "C" fn(vaobj: GLuint, buffer: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayFogCoordOffsetEXT"]
+    pub static mut epoxy_glVertexArrayFogCoordOffsetEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            buffer: GLuint,
+            type_: GLenum,
+            stride: GLsizei,
+            offset: GLintptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayIndexOffsetEXT"]
+    pub static mut epoxy_glVertexArrayIndexOffsetEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            buffer: GLuint,
+            type_: GLenum,
+            stride: GLsizei,
+            offset: GLintptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayMultiTexCoordOffsetEXT"]
+    pub static mut epoxy_glVertexArrayMultiTexCoordOffsetEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            buffer: GLuint,
+            texunit: GLenum,
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            offset: GLintptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayNormalOffsetEXT"]
+    pub static mut epoxy_glVertexArrayNormalOffsetEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            buffer: GLuint,
+            type_: GLenum,
+            stride: GLsizei,
+            offset: GLintptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayParameteriAPPLE"]
+    pub static mut epoxy_glVertexArrayParameteriAPPLE:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayRangeAPPLE"]
+    pub static mut epoxy_glVertexArrayRangeAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(length: GLsizei, pointer: *mut ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayRangeNV"]
+    pub static mut epoxy_glVertexArrayRangeNV: ::std::option::Option<
+        unsafe extern "C" fn(length: GLsizei, pointer: *const ::std::os::raw::c_void),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArraySecondaryColorOffsetEXT"]
+    pub static mut epoxy_glVertexArraySecondaryColorOffsetEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            buffer: GLuint,
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            offset: GLintptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayTexCoordOffsetEXT"]
+    pub static mut epoxy_glVertexArrayTexCoordOffsetEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            buffer: GLuint,
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            offset: GLintptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayVertexAttribBindingEXT"]
+    pub static mut epoxy_glVertexArrayVertexAttribBindingEXT: ::std::option::Option<
+        unsafe extern "C" fn(vaobj: GLuint, attribindex: GLuint, bindingindex: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayVertexAttribDivisorEXT"]
+    pub static mut epoxy_glVertexArrayVertexAttribDivisorEXT:
+        ::std::option::Option<unsafe extern "C" fn(vaobj: GLuint, index: GLuint, divisor: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayVertexAttribFormatEXT"]
+    pub static mut epoxy_glVertexArrayVertexAttribFormatEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            attribindex: GLuint,
+            size: GLint,
+            type_: GLenum,
+            normalized: GLboolean,
+            relativeoffset: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayVertexAttribIFormatEXT"]
+    pub static mut epoxy_glVertexArrayVertexAttribIFormatEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            attribindex: GLuint,
+            size: GLint,
+            type_: GLenum,
+            relativeoffset: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayVertexAttribIOffsetEXT"]
+    pub static mut epoxy_glVertexArrayVertexAttribIOffsetEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            buffer: GLuint,
+            index: GLuint,
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            offset: GLintptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayVertexAttribLFormatEXT"]
+    pub static mut epoxy_glVertexArrayVertexAttribLFormatEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            attribindex: GLuint,
+            size: GLint,
+            type_: GLenum,
+            relativeoffset: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayVertexAttribLOffsetEXT"]
+    pub static mut epoxy_glVertexArrayVertexAttribLOffsetEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            buffer: GLuint,
+            index: GLuint,
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            offset: GLintptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayVertexAttribOffsetEXT"]
+    pub static mut epoxy_glVertexArrayVertexAttribOffsetEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            buffer: GLuint,
+            index: GLuint,
+            size: GLint,
+            type_: GLenum,
+            normalized: GLboolean,
+            stride: GLsizei,
+            offset: GLintptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayVertexBindingDivisorEXT"]
+    pub static mut epoxy_glVertexArrayVertexBindingDivisorEXT: ::std::option::Option<
+        unsafe extern "C" fn(vaobj: GLuint, bindingindex: GLuint, divisor: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayVertexBuffer"]
+    pub static mut epoxy_glVertexArrayVertexBuffer: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            bindingindex: GLuint,
+            buffer: GLuint,
+            offset: GLintptr,
+            stride: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayVertexBuffers"]
+    pub static mut epoxy_glVertexArrayVertexBuffers: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            first: GLuint,
+            count: GLsizei,
+            buffers: *const GLuint,
+            offsets: *const GLintptr,
+            strides: *const GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexArrayVertexOffsetEXT"]
+    pub static mut epoxy_glVertexArrayVertexOffsetEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            vaobj: GLuint,
+            buffer: GLuint,
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            offset: GLintptr,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1d"]
+    pub static mut epoxy_glVertexAttrib1d:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1dARB"]
+    pub static mut epoxy_glVertexAttrib1dARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1dNV"]
+    pub static mut epoxy_glVertexAttrib1dNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1dv"]
+    pub static mut epoxy_glVertexAttrib1dv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1dvARB"]
+    pub static mut epoxy_glVertexAttrib1dvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1dvNV"]
+    pub static mut epoxy_glVertexAttrib1dvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1f"]
+    pub static mut epoxy_glVertexAttrib1f:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1fARB"]
+    pub static mut epoxy_glVertexAttrib1fARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1fNV"]
+    pub static mut epoxy_glVertexAttrib1fNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1fv"]
+    pub static mut epoxy_glVertexAttrib1fv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1fvARB"]
+    pub static mut epoxy_glVertexAttrib1fvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1fvNV"]
+    pub static mut epoxy_glVertexAttrib1fvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1hNV"]
+    pub static mut epoxy_glVertexAttrib1hNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1hvNV"]
+    pub static mut epoxy_glVertexAttrib1hvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1s"]
+    pub static mut epoxy_glVertexAttrib1s:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1sARB"]
+    pub static mut epoxy_glVertexAttrib1sARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1sNV"]
+    pub static mut epoxy_glVertexAttrib1sNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1sv"]
+    pub static mut epoxy_glVertexAttrib1sv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1svARB"]
+    pub static mut epoxy_glVertexAttrib1svARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib1svNV"]
+    pub static mut epoxy_glVertexAttrib1svNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2d"]
+    pub static mut epoxy_glVertexAttrib2d:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2dARB"]
+    pub static mut epoxy_glVertexAttrib2dARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2dNV"]
+    pub static mut epoxy_glVertexAttrib2dNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2dv"]
+    pub static mut epoxy_glVertexAttrib2dv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2dvARB"]
+    pub static mut epoxy_glVertexAttrib2dvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2dvNV"]
+    pub static mut epoxy_glVertexAttrib2dvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2f"]
+    pub static mut epoxy_glVertexAttrib2f:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLfloat, y: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2fARB"]
+    pub static mut epoxy_glVertexAttrib2fARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLfloat, y: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2fNV"]
+    pub static mut epoxy_glVertexAttrib2fNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLfloat, y: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2fv"]
+    pub static mut epoxy_glVertexAttrib2fv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2fvARB"]
+    pub static mut epoxy_glVertexAttrib2fvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2fvNV"]
+    pub static mut epoxy_glVertexAttrib2fvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2hNV"]
+    pub static mut epoxy_glVertexAttrib2hNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLhalfNV, y: GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2hvNV"]
+    pub static mut epoxy_glVertexAttrib2hvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2s"]
+    pub static mut epoxy_glVertexAttrib2s:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLshort, y: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2sARB"]
+    pub static mut epoxy_glVertexAttrib2sARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLshort, y: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2sNV"]
+    pub static mut epoxy_glVertexAttrib2sNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLshort, y: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2sv"]
+    pub static mut epoxy_glVertexAttrib2sv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2svARB"]
+    pub static mut epoxy_glVertexAttrib2svARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib2svNV"]
+    pub static mut epoxy_glVertexAttrib2svNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3d"]
+    pub static mut epoxy_glVertexAttrib3d: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3dARB"]
+    pub static mut epoxy_glVertexAttrib3dARB: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3dNV"]
+    pub static mut epoxy_glVertexAttrib3dNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3dv"]
+    pub static mut epoxy_glVertexAttrib3dv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3dvARB"]
+    pub static mut epoxy_glVertexAttrib3dvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3dvNV"]
+    pub static mut epoxy_glVertexAttrib3dvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3f"]
+    pub static mut epoxy_glVertexAttrib3f: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3fARB"]
+    pub static mut epoxy_glVertexAttrib3fARB: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3fNV"]
+    pub static mut epoxy_glVertexAttrib3fNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3fv"]
+    pub static mut epoxy_glVertexAttrib3fv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3fvARB"]
+    pub static mut epoxy_glVertexAttrib3fvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3fvNV"]
+    pub static mut epoxy_glVertexAttrib3fvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3hNV"]
+    pub static mut epoxy_glVertexAttrib3hNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLhalfNV, y: GLhalfNV, z: GLhalfNV),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3hvNV"]
+    pub static mut epoxy_glVertexAttrib3hvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3s"]
+    pub static mut epoxy_glVertexAttrib3s: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLshort, y: GLshort, z: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3sARB"]
+    pub static mut epoxy_glVertexAttrib3sARB: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLshort, y: GLshort, z: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3sNV"]
+    pub static mut epoxy_glVertexAttrib3sNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLshort, y: GLshort, z: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3sv"]
+    pub static mut epoxy_glVertexAttrib3sv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3svARB"]
+    pub static mut epoxy_glVertexAttrib3svARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib3svNV"]
+    pub static mut epoxy_glVertexAttrib3svNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4Nbv"]
+    pub static mut epoxy_glVertexAttrib4Nbv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4NbvARB"]
+    pub static mut epoxy_glVertexAttrib4NbvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4Niv"]
+    pub static mut epoxy_glVertexAttrib4Niv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4NivARB"]
+    pub static mut epoxy_glVertexAttrib4NivARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4Nsv"]
+    pub static mut epoxy_glVertexAttrib4Nsv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4NsvARB"]
+    pub static mut epoxy_glVertexAttrib4NsvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4Nub"]
+    pub static mut epoxy_glVertexAttrib4Nub: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLubyte, y: GLubyte, z: GLubyte, w: GLubyte),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4NubARB"]
+    pub static mut epoxy_glVertexAttrib4NubARB: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLubyte, y: GLubyte, z: GLubyte, w: GLubyte),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4Nubv"]
+    pub static mut epoxy_glVertexAttrib4Nubv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4NubvARB"]
+    pub static mut epoxy_glVertexAttrib4NubvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4Nuiv"]
+    pub static mut epoxy_glVertexAttrib4Nuiv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4NuivARB"]
+    pub static mut epoxy_glVertexAttrib4NuivARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4Nusv"]
+    pub static mut epoxy_glVertexAttrib4Nusv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4NusvARB"]
+    pub static mut epoxy_glVertexAttrib4NusvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4bv"]
+    pub static mut epoxy_glVertexAttrib4bv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4bvARB"]
+    pub static mut epoxy_glVertexAttrib4bvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4d"]
+    pub static mut epoxy_glVertexAttrib4d: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4dARB"]
+    pub static mut epoxy_glVertexAttrib4dARB: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4dNV"]
+    pub static mut epoxy_glVertexAttrib4dNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4dv"]
+    pub static mut epoxy_glVertexAttrib4dv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4dvARB"]
+    pub static mut epoxy_glVertexAttrib4dvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4dvNV"]
+    pub static mut epoxy_glVertexAttrib4dvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4f"]
+    pub static mut epoxy_glVertexAttrib4f: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4fARB"]
+    pub static mut epoxy_glVertexAttrib4fARB: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4fNV"]
+    pub static mut epoxy_glVertexAttrib4fNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4fv"]
+    pub static mut epoxy_glVertexAttrib4fv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4fvARB"]
+    pub static mut epoxy_glVertexAttrib4fvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4fvNV"]
+    pub static mut epoxy_glVertexAttrib4fvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4hNV"]
+    pub static mut epoxy_glVertexAttrib4hNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLhalfNV, y: GLhalfNV, z: GLhalfNV, w: GLhalfNV),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4hvNV"]
+    pub static mut epoxy_glVertexAttrib4hvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4iv"]
+    pub static mut epoxy_glVertexAttrib4iv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4ivARB"]
+    pub static mut epoxy_glVertexAttrib4ivARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4s"]
+    pub static mut epoxy_glVertexAttrib4s: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLshort, y: GLshort, z: GLshort, w: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4sARB"]
+    pub static mut epoxy_glVertexAttrib4sARB: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLshort, y: GLshort, z: GLshort, w: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4sNV"]
+    pub static mut epoxy_glVertexAttrib4sNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLshort, y: GLshort, z: GLshort, w: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4sv"]
+    pub static mut epoxy_glVertexAttrib4sv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4svARB"]
+    pub static mut epoxy_glVertexAttrib4svARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4svNV"]
+    pub static mut epoxy_glVertexAttrib4svNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4ubNV"]
+    pub static mut epoxy_glVertexAttrib4ubNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLubyte, y: GLubyte, z: GLubyte, w: GLubyte),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4ubv"]
+    pub static mut epoxy_glVertexAttrib4ubv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4ubvARB"]
+    pub static mut epoxy_glVertexAttrib4ubvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4ubvNV"]
+    pub static mut epoxy_glVertexAttrib4ubvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4uiv"]
+    pub static mut epoxy_glVertexAttrib4uiv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4uivARB"]
+    pub static mut epoxy_glVertexAttrib4uivARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4usv"]
+    pub static mut epoxy_glVertexAttrib4usv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttrib4usvARB"]
+    pub static mut epoxy_glVertexAttrib4usvARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribArrayObjectATI"]
+    pub static mut epoxy_glVertexAttribArrayObjectATI: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            size: GLint,
+            type_: GLenum,
+            normalized: GLboolean,
+            stride: GLsizei,
+            buffer: GLuint,
+            offset: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribBinding"]
+    pub static mut epoxy_glVertexAttribBinding:
+        ::std::option::Option<unsafe extern "C" fn(attribindex: GLuint, bindingindex: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribDivisor"]
+    pub static mut epoxy_glVertexAttribDivisor:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, divisor: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribDivisorANGLE"]
+    pub static mut epoxy_glVertexAttribDivisorANGLE:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, divisor: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribDivisorARB"]
+    pub static mut epoxy_glVertexAttribDivisorARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, divisor: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribDivisorEXT"]
+    pub static mut epoxy_glVertexAttribDivisorEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, divisor: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribDivisorNV"]
+    pub static mut epoxy_glVertexAttribDivisorNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, divisor: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribFormat"]
+    pub static mut epoxy_glVertexAttribFormat: ::std::option::Option<
+        unsafe extern "C" fn(
+            attribindex: GLuint,
+            size: GLint,
+            type_: GLenum,
+            normalized: GLboolean,
+            relativeoffset: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribFormatNV"]
+    pub static mut epoxy_glVertexAttribFormatNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            size: GLint,
+            type_: GLenum,
+            normalized: GLboolean,
+            stride: GLsizei,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI1i"]
+    pub static mut epoxy_glVertexAttribI1i:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI1iEXT"]
+    pub static mut epoxy_glVertexAttribI1iEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI1iv"]
+    pub static mut epoxy_glVertexAttribI1iv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI1ivEXT"]
+    pub static mut epoxy_glVertexAttribI1ivEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI1ui"]
+    pub static mut epoxy_glVertexAttribI1ui:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI1uiEXT"]
+    pub static mut epoxy_glVertexAttribI1uiEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI1uiv"]
+    pub static mut epoxy_glVertexAttribI1uiv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI1uivEXT"]
+    pub static mut epoxy_glVertexAttribI1uivEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI2i"]
+    pub static mut epoxy_glVertexAttribI2i:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLint, y: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI2iEXT"]
+    pub static mut epoxy_glVertexAttribI2iEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLint, y: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI2iv"]
+    pub static mut epoxy_glVertexAttribI2iv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI2ivEXT"]
+    pub static mut epoxy_glVertexAttribI2ivEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI2ui"]
+    pub static mut epoxy_glVertexAttribI2ui:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLuint, y: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI2uiEXT"]
+    pub static mut epoxy_glVertexAttribI2uiEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLuint, y: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI2uiv"]
+    pub static mut epoxy_glVertexAttribI2uiv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI2uivEXT"]
+    pub static mut epoxy_glVertexAttribI2uivEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI3i"]
+    pub static mut epoxy_glVertexAttribI3i:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLint, y: GLint, z: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI3iEXT"]
+    pub static mut epoxy_glVertexAttribI3iEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLint, y: GLint, z: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI3iv"]
+    pub static mut epoxy_glVertexAttribI3iv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI3ivEXT"]
+    pub static mut epoxy_glVertexAttribI3ivEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI3ui"]
+    pub static mut epoxy_glVertexAttribI3ui:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLuint, y: GLuint, z: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI3uiEXT"]
+    pub static mut epoxy_glVertexAttribI3uiEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLuint, y: GLuint, z: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI3uiv"]
+    pub static mut epoxy_glVertexAttribI3uiv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI3uivEXT"]
+    pub static mut epoxy_glVertexAttribI3uivEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4bv"]
+    pub static mut epoxy_glVertexAttribI4bv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4bvEXT"]
+    pub static mut epoxy_glVertexAttribI4bvEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4i"]
+    pub static mut epoxy_glVertexAttribI4i: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLint, y: GLint, z: GLint, w: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4iEXT"]
+    pub static mut epoxy_glVertexAttribI4iEXT: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLint, y: GLint, z: GLint, w: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4iv"]
+    pub static mut epoxy_glVertexAttribI4iv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4ivEXT"]
+    pub static mut epoxy_glVertexAttribI4ivEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4sv"]
+    pub static mut epoxy_glVertexAttribI4sv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4svEXT"]
+    pub static mut epoxy_glVertexAttribI4svEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4ubv"]
+    pub static mut epoxy_glVertexAttribI4ubv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4ubvEXT"]
+    pub static mut epoxy_glVertexAttribI4ubvEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4ui"]
+    pub static mut epoxy_glVertexAttribI4ui: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLuint, y: GLuint, z: GLuint, w: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4uiEXT"]
+    pub static mut epoxy_glVertexAttribI4uiEXT: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLuint, y: GLuint, z: GLuint, w: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4uiv"]
+    pub static mut epoxy_glVertexAttribI4uiv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4uivEXT"]
+    pub static mut epoxy_glVertexAttribI4uivEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4usv"]
+    pub static mut epoxy_glVertexAttribI4usv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribI4usvEXT"]
+    pub static mut epoxy_glVertexAttribI4usvEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribIFormat"]
+    pub static mut epoxy_glVertexAttribIFormat: ::std::option::Option<
+        unsafe extern "C" fn(
+            attribindex: GLuint,
+            size: GLint,
+            type_: GLenum,
+            relativeoffset: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribIFormatNV"]
+    pub static mut epoxy_glVertexAttribIFormatNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, size: GLint, type_: GLenum, stride: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribIPointer"]
+    pub static mut epoxy_glVertexAttribIPointer: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribIPointerEXT"]
+    pub static mut epoxy_glVertexAttribIPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL1d"]
+    pub static mut epoxy_glVertexAttribL1d:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL1dEXT"]
+    pub static mut epoxy_glVertexAttribL1dEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL1dv"]
+    pub static mut epoxy_glVertexAttribL1dv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL1dvEXT"]
+    pub static mut epoxy_glVertexAttribL1dvEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL1i64NV"]
+    pub static mut epoxy_glVertexAttribL1i64NV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL1i64vNV"]
+    pub static mut epoxy_glVertexAttribL1i64vNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL1ui64ARB"]
+    pub static mut epoxy_glVertexAttribL1ui64ARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLuint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL1ui64NV"]
+    pub static mut epoxy_glVertexAttribL1ui64NV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLuint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL1ui64vARB"]
+    pub static mut epoxy_glVertexAttribL1ui64vARB:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL1ui64vNV"]
+    pub static mut epoxy_glVertexAttribL1ui64vNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL2d"]
+    pub static mut epoxy_glVertexAttribL2d:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL2dEXT"]
+    pub static mut epoxy_glVertexAttribL2dEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL2dv"]
+    pub static mut epoxy_glVertexAttribL2dv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL2dvEXT"]
+    pub static mut epoxy_glVertexAttribL2dvEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL2i64NV"]
+    pub static mut epoxy_glVertexAttribL2i64NV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLint64EXT, y: GLint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL2i64vNV"]
+    pub static mut epoxy_glVertexAttribL2i64vNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL2ui64NV"]
+    pub static mut epoxy_glVertexAttribL2ui64NV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, x: GLuint64EXT, y: GLuint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL2ui64vNV"]
+    pub static mut epoxy_glVertexAttribL2ui64vNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL3d"]
+    pub static mut epoxy_glVertexAttribL3d: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL3dEXT"]
+    pub static mut epoxy_glVertexAttribL3dEXT: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL3dv"]
+    pub static mut epoxy_glVertexAttribL3dv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL3dvEXT"]
+    pub static mut epoxy_glVertexAttribL3dvEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL3i64NV"]
+    pub static mut epoxy_glVertexAttribL3i64NV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLint64EXT, y: GLint64EXT, z: GLint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL3i64vNV"]
+    pub static mut epoxy_glVertexAttribL3i64vNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL3ui64NV"]
+    pub static mut epoxy_glVertexAttribL3ui64NV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLuint64EXT, y: GLuint64EXT, z: GLuint64EXT),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL3ui64vNV"]
+    pub static mut epoxy_glVertexAttribL3ui64vNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL4d"]
+    pub static mut epoxy_glVertexAttribL4d: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL4dEXT"]
+    pub static mut epoxy_glVertexAttribL4dEXT: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL4dv"]
+    pub static mut epoxy_glVertexAttribL4dv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL4dvEXT"]
+    pub static mut epoxy_glVertexAttribL4dvEXT:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL4i64NV"]
+    pub static mut epoxy_glVertexAttribL4i64NV: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            x: GLint64EXT,
+            y: GLint64EXT,
+            z: GLint64EXT,
+            w: GLint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL4i64vNV"]
+    pub static mut epoxy_glVertexAttribL4i64vNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL4ui64NV"]
+    pub static mut epoxy_glVertexAttribL4ui64NV: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            x: GLuint64EXT,
+            y: GLuint64EXT,
+            z: GLuint64EXT,
+            w: GLuint64EXT,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribL4ui64vNV"]
+    pub static mut epoxy_glVertexAttribL4ui64vNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLuint64EXT)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribLFormat"]
+    pub static mut epoxy_glVertexAttribLFormat: ::std::option::Option<
+        unsafe extern "C" fn(
+            attribindex: GLuint,
+            size: GLint,
+            type_: GLenum,
+            relativeoffset: GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribLFormatNV"]
+    pub static mut epoxy_glVertexAttribLFormatNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, size: GLint, type_: GLenum, stride: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribLPointer"]
+    pub static mut epoxy_glVertexAttribLPointer: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribLPointerEXT"]
+    pub static mut epoxy_glVertexAttribLPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribP1ui"]
+    pub static mut epoxy_glVertexAttribP1ui: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, type_: GLenum, normalized: GLboolean, value: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribP1uiv"]
+    pub static mut epoxy_glVertexAttribP1uiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            type_: GLenum,
+            normalized: GLboolean,
+            value: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribP2ui"]
+    pub static mut epoxy_glVertexAttribP2ui: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, type_: GLenum, normalized: GLboolean, value: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribP2uiv"]
+    pub static mut epoxy_glVertexAttribP2uiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            type_: GLenum,
+            normalized: GLboolean,
+            value: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribP3ui"]
+    pub static mut epoxy_glVertexAttribP3ui: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, type_: GLenum, normalized: GLboolean, value: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribP3uiv"]
+    pub static mut epoxy_glVertexAttribP3uiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            type_: GLenum,
+            normalized: GLboolean,
+            value: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribP4ui"]
+    pub static mut epoxy_glVertexAttribP4ui: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, type_: GLenum, normalized: GLboolean, value: GLuint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribP4uiv"]
+    pub static mut epoxy_glVertexAttribP4uiv: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            type_: GLenum,
+            normalized: GLboolean,
+            value: *const GLuint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribParameteriAMD"]
+    pub static mut epoxy_glVertexAttribParameteriAMD:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribPointer"]
+    pub static mut epoxy_glVertexAttribPointer: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            size: GLint,
+            type_: GLenum,
+            normalized: GLboolean,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribPointerARB"]
+    pub static mut epoxy_glVertexAttribPointerARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            size: GLint,
+            type_: GLenum,
+            normalized: GLboolean,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribPointerNV"]
+    pub static mut epoxy_glVertexAttribPointerNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            fsize: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs1dvNV"]
+    pub static mut epoxy_glVertexAttribs1dvNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, count: GLsizei, v: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs1fvNV"]
+    pub static mut epoxy_glVertexAttribs1fvNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, count: GLsizei, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs1hvNV"]
+    pub static mut epoxy_glVertexAttribs1hvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, n: GLsizei, v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs1svNV"]
+    pub static mut epoxy_glVertexAttribs1svNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, count: GLsizei, v: *const GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs2dvNV"]
+    pub static mut epoxy_glVertexAttribs2dvNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, count: GLsizei, v: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs2fvNV"]
+    pub static mut epoxy_glVertexAttribs2fvNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, count: GLsizei, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs2hvNV"]
+    pub static mut epoxy_glVertexAttribs2hvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, n: GLsizei, v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs2svNV"]
+    pub static mut epoxy_glVertexAttribs2svNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, count: GLsizei, v: *const GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs3dvNV"]
+    pub static mut epoxy_glVertexAttribs3dvNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, count: GLsizei, v: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs3fvNV"]
+    pub static mut epoxy_glVertexAttribs3fvNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, count: GLsizei, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs3hvNV"]
+    pub static mut epoxy_glVertexAttribs3hvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, n: GLsizei, v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs3svNV"]
+    pub static mut epoxy_glVertexAttribs3svNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, count: GLsizei, v: *const GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs4dvNV"]
+    pub static mut epoxy_glVertexAttribs4dvNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, count: GLsizei, v: *const GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs4fvNV"]
+    pub static mut epoxy_glVertexAttribs4fvNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, count: GLsizei, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs4hvNV"]
+    pub static mut epoxy_glVertexAttribs4hvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, n: GLsizei, v: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs4svNV"]
+    pub static mut epoxy_glVertexAttribs4svNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, count: GLsizei, v: *const GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexAttribs4ubvNV"]
+    pub static mut epoxy_glVertexAttribs4ubvNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, count: GLsizei, v: *const GLubyte),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexBindingDivisor"]
+    pub static mut epoxy_glVertexBindingDivisor:
+        ::std::option::Option<unsafe extern "C" fn(bindingindex: GLuint, divisor: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexBlendARB"]
+    pub static mut epoxy_glVertexBlendARB:
+        ::std::option::Option<unsafe extern "C" fn(count: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexBlendEnvfATI"]
+    pub static mut epoxy_glVertexBlendEnvfATI:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexBlendEnviATI"]
+    pub static mut epoxy_glVertexBlendEnviATI:
+        ::std::option::Option<unsafe extern "C" fn(pname: GLenum, param: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexFormatNV"]
+    pub static mut epoxy_glVertexFormatNV:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, type_: GLenum, stride: GLsizei)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexP2ui"]
+    pub static mut epoxy_glVertexP2ui:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, value: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexP2uiv"]
+    pub static mut epoxy_glVertexP2uiv:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, value: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexP3ui"]
+    pub static mut epoxy_glVertexP3ui:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, value: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexP3uiv"]
+    pub static mut epoxy_glVertexP3uiv:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, value: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexP4ui"]
+    pub static mut epoxy_glVertexP4ui:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, value: GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexP4uiv"]
+    pub static mut epoxy_glVertexP4uiv:
+        ::std::option::Option<unsafe extern "C" fn(type_: GLenum, value: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexPointer"]
+    pub static mut epoxy_glVertexPointer: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexPointerEXT"]
+    pub static mut epoxy_glVertexPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            count: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexPointerListIBM"]
+    pub static mut epoxy_glVertexPointerListIBM: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLint,
+            pointer: *mut *const ::std::os::raw::c_void,
+            ptrstride: GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexPointervINTEL"]
+    pub static mut epoxy_glVertexPointervINTEL: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            pointer: *mut *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream1dATI"]
+    pub static mut epoxy_glVertexStream1dATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, x: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream1dvATI"]
+    pub static mut epoxy_glVertexStream1dvATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream1fATI"]
+    pub static mut epoxy_glVertexStream1fATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, x: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream1fvATI"]
+    pub static mut epoxy_glVertexStream1fvATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream1iATI"]
+    pub static mut epoxy_glVertexStream1iATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, x: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream1ivATI"]
+    pub static mut epoxy_glVertexStream1ivATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream1sATI"]
+    pub static mut epoxy_glVertexStream1sATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, x: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream1svATI"]
+    pub static mut epoxy_glVertexStream1svATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream2dATI"]
+    pub static mut epoxy_glVertexStream2dATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, x: GLdouble, y: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream2dvATI"]
+    pub static mut epoxy_glVertexStream2dvATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream2fATI"]
+    pub static mut epoxy_glVertexStream2fATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, x: GLfloat, y: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream2fvATI"]
+    pub static mut epoxy_glVertexStream2fvATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream2iATI"]
+    pub static mut epoxy_glVertexStream2iATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, x: GLint, y: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream2ivATI"]
+    pub static mut epoxy_glVertexStream2ivATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream2sATI"]
+    pub static mut epoxy_glVertexStream2sATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, x: GLshort, y: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream2svATI"]
+    pub static mut epoxy_glVertexStream2svATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream3dATI"]
+    pub static mut epoxy_glVertexStream3dATI: ::std::option::Option<
+        unsafe extern "C" fn(stream: GLenum, x: GLdouble, y: GLdouble, z: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream3dvATI"]
+    pub static mut epoxy_glVertexStream3dvATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream3fATI"]
+    pub static mut epoxy_glVertexStream3fATI: ::std::option::Option<
+        unsafe extern "C" fn(stream: GLenum, x: GLfloat, y: GLfloat, z: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream3fvATI"]
+    pub static mut epoxy_glVertexStream3fvATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream3iATI"]
+    pub static mut epoxy_glVertexStream3iATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, x: GLint, y: GLint, z: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream3ivATI"]
+    pub static mut epoxy_glVertexStream3ivATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream3sATI"]
+    pub static mut epoxy_glVertexStream3sATI: ::std::option::Option<
+        unsafe extern "C" fn(stream: GLenum, x: GLshort, y: GLshort, z: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream3svATI"]
+    pub static mut epoxy_glVertexStream3svATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream4dATI"]
+    pub static mut epoxy_glVertexStream4dATI: ::std::option::Option<
+        unsafe extern "C" fn(stream: GLenum, x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream4dvATI"]
+    pub static mut epoxy_glVertexStream4dvATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream4fATI"]
+    pub static mut epoxy_glVertexStream4fATI: ::std::option::Option<
+        unsafe extern "C" fn(stream: GLenum, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream4fvATI"]
+    pub static mut epoxy_glVertexStream4fvATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream4iATI"]
+    pub static mut epoxy_glVertexStream4iATI: ::std::option::Option<
+        unsafe extern "C" fn(stream: GLenum, x: GLint, y: GLint, z: GLint, w: GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream4ivATI"]
+    pub static mut epoxy_glVertexStream4ivATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream4sATI"]
+    pub static mut epoxy_glVertexStream4sATI: ::std::option::Option<
+        unsafe extern "C" fn(stream: GLenum, x: GLshort, y: GLshort, z: GLshort, w: GLshort),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexStream4svATI"]
+    pub static mut epoxy_glVertexStream4svATI:
+        ::std::option::Option<unsafe extern "C" fn(stream: GLenum, coords: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexWeightPointerEXT"]
+    pub static mut epoxy_glVertexWeightPointerEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexWeightfEXT"]
+    pub static mut epoxy_glVertexWeightfEXT:
+        ::std::option::Option<unsafe extern "C" fn(weight: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexWeightfvEXT"]
+    pub static mut epoxy_glVertexWeightfvEXT:
+        ::std::option::Option<unsafe extern "C" fn(weight: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexWeighthNV"]
+    pub static mut epoxy_glVertexWeighthNV:
+        ::std::option::Option<unsafe extern "C" fn(weight: GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVertexWeighthvNV"]
+    pub static mut epoxy_glVertexWeighthvNV:
+        ::std::option::Option<unsafe extern "C" fn(weight: *const GLhalfNV)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVideoCaptureNV"]
+    pub static mut epoxy_glVideoCaptureNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            video_capture_slot: GLuint,
+            sequence_num: *mut GLuint,
+            capture_time: *mut GLuint64EXT,
+        ) -> GLenum,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVideoCaptureStreamParameterdvNV"]
+    pub static mut epoxy_glVideoCaptureStreamParameterdvNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            video_capture_slot: GLuint,
+            stream: GLuint,
+            pname: GLenum,
+            params: *const GLdouble,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVideoCaptureStreamParameterfvNV"]
+    pub static mut epoxy_glVideoCaptureStreamParameterfvNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            video_capture_slot: GLuint,
+            stream: GLuint,
+            pname: GLenum,
+            params: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glVideoCaptureStreamParameterivNV"]
+    pub static mut epoxy_glVideoCaptureStreamParameterivNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            video_capture_slot: GLuint,
+            stream: GLuint,
+            pname: GLenum,
+            params: *const GLint,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glViewport"]
+    pub static mut epoxy_glViewport: ::std::option::Option<
+        unsafe extern "C" fn(x: GLint, y: GLint, width: GLsizei, height: GLsizei),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glViewportArrayv"]
+    pub static mut epoxy_glViewportArrayv: ::std::option::Option<
+        unsafe extern "C" fn(first: GLuint, count: GLsizei, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glViewportArrayvNV"]
+    pub static mut epoxy_glViewportArrayvNV: ::std::option::Option<
+        unsafe extern "C" fn(first: GLuint, count: GLsizei, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glViewportArrayvOES"]
+    pub static mut epoxy_glViewportArrayvOES: ::std::option::Option<
+        unsafe extern "C" fn(first: GLuint, count: GLsizei, v: *const GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glViewportIndexedf"]
+    pub static mut epoxy_glViewportIndexedf: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLfloat, y: GLfloat, w: GLfloat, h: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glViewportIndexedfNV"]
+    pub static mut epoxy_glViewportIndexedfNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLfloat, y: GLfloat, w: GLfloat, h: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glViewportIndexedfOES"]
+    pub static mut epoxy_glViewportIndexedfOES: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, x: GLfloat, y: GLfloat, w: GLfloat, h: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glViewportIndexedfv"]
+    pub static mut epoxy_glViewportIndexedfv:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glViewportIndexedfvNV"]
+    pub static mut epoxy_glViewportIndexedfvNV:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glViewportIndexedfvOES"]
+    pub static mut epoxy_glViewportIndexedfvOES:
+        ::std::option::Option<unsafe extern "C" fn(index: GLuint, v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glViewportPositionWScaleNV"]
+    pub static mut epoxy_glViewportPositionWScaleNV: ::std::option::Option<
+        unsafe extern "C" fn(index: GLuint, xcoeff: GLfloat, ycoeff: GLfloat),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glViewportSwizzleNV"]
+    pub static mut epoxy_glViewportSwizzleNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            index: GLuint,
+            swizzlex: GLenum,
+            swizzley: GLenum,
+            swizzlez: GLenum,
+            swizzlew: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWaitSync"]
+    pub static mut epoxy_glWaitSync: ::std::option::Option<
+        unsafe extern "C" fn(sync: GLsync, flags: GLbitfield, timeout: GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWaitSyncAPPLE"]
+    pub static mut epoxy_glWaitSyncAPPLE: ::std::option::Option<
+        unsafe extern "C" fn(sync: GLsync, flags: GLbitfield, timeout: GLuint64),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWeightPathsNV"]
+    pub static mut epoxy_glWeightPathsNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            resultPath: GLuint,
+            numPaths: GLsizei,
+            paths: *const GLuint,
+            weights: *const GLfloat,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWeightPointerARB"]
+    pub static mut epoxy_glWeightPointerARB: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWeightPointerOES"]
+    pub static mut epoxy_glWeightPointerOES: ::std::option::Option<
+        unsafe extern "C" fn(
+            size: GLint,
+            type_: GLenum,
+            stride: GLsizei,
+            pointer: *const ::std::os::raw::c_void,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWeightbvARB"]
+    pub static mut epoxy_glWeightbvARB:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, weights: *const GLbyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWeightdvARB"]
+    pub static mut epoxy_glWeightdvARB:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, weights: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWeightfvARB"]
+    pub static mut epoxy_glWeightfvARB:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, weights: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWeightivARB"]
+    pub static mut epoxy_glWeightivARB:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, weights: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWeightsvARB"]
+    pub static mut epoxy_glWeightsvARB:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, weights: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWeightubvARB"]
+    pub static mut epoxy_glWeightubvARB:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, weights: *const GLubyte)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWeightuivARB"]
+    pub static mut epoxy_glWeightuivARB:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, weights: *const GLuint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWeightusvARB"]
+    pub static mut epoxy_glWeightusvARB:
+        ::std::option::Option<unsafe extern "C" fn(size: GLint, weights: *const GLushort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2d"]
+    pub static mut epoxy_glWindowPos2d:
+        ::std::option::Option<unsafe extern "C" fn(x: GLdouble, y: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2dARB"]
+    pub static mut epoxy_glWindowPos2dARB:
+        ::std::option::Option<unsafe extern "C" fn(x: GLdouble, y: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2dMESA"]
+    pub static mut epoxy_glWindowPos2dMESA:
+        ::std::option::Option<unsafe extern "C" fn(x: GLdouble, y: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2dv"]
+    pub static mut epoxy_glWindowPos2dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2dvARB"]
+    pub static mut epoxy_glWindowPos2dvARB:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2dvMESA"]
+    pub static mut epoxy_glWindowPos2dvMESA:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2f"]
+    pub static mut epoxy_glWindowPos2f:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2fARB"]
+    pub static mut epoxy_glWindowPos2fARB:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2fMESA"]
+    pub static mut epoxy_glWindowPos2fMESA:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2fv"]
+    pub static mut epoxy_glWindowPos2fv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2fvARB"]
+    pub static mut epoxy_glWindowPos2fvARB:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2fvMESA"]
+    pub static mut epoxy_glWindowPos2fvMESA:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2i"]
+    pub static mut epoxy_glWindowPos2i:
+        ::std::option::Option<unsafe extern "C" fn(x: GLint, y: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2iARB"]
+    pub static mut epoxy_glWindowPos2iARB:
+        ::std::option::Option<unsafe extern "C" fn(x: GLint, y: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2iMESA"]
+    pub static mut epoxy_glWindowPos2iMESA:
+        ::std::option::Option<unsafe extern "C" fn(x: GLint, y: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2iv"]
+    pub static mut epoxy_glWindowPos2iv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2ivARB"]
+    pub static mut epoxy_glWindowPos2ivARB:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2ivMESA"]
+    pub static mut epoxy_glWindowPos2ivMESA:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2s"]
+    pub static mut epoxy_glWindowPos2s:
+        ::std::option::Option<unsafe extern "C" fn(x: GLshort, y: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2sARB"]
+    pub static mut epoxy_glWindowPos2sARB:
+        ::std::option::Option<unsafe extern "C" fn(x: GLshort, y: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2sMESA"]
+    pub static mut epoxy_glWindowPos2sMESA:
+        ::std::option::Option<unsafe extern "C" fn(x: GLshort, y: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2sv"]
+    pub static mut epoxy_glWindowPos2sv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2svARB"]
+    pub static mut epoxy_glWindowPos2svARB:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos2svMESA"]
+    pub static mut epoxy_glWindowPos2svMESA:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3d"]
+    pub static mut epoxy_glWindowPos3d:
+        ::std::option::Option<unsafe extern "C" fn(x: GLdouble, y: GLdouble, z: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3dARB"]
+    pub static mut epoxy_glWindowPos3dARB:
+        ::std::option::Option<unsafe extern "C" fn(x: GLdouble, y: GLdouble, z: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3dMESA"]
+    pub static mut epoxy_glWindowPos3dMESA:
+        ::std::option::Option<unsafe extern "C" fn(x: GLdouble, y: GLdouble, z: GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3dv"]
+    pub static mut epoxy_glWindowPos3dv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3dvARB"]
+    pub static mut epoxy_glWindowPos3dvARB:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3dvMESA"]
+    pub static mut epoxy_glWindowPos3dvMESA:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3f"]
+    pub static mut epoxy_glWindowPos3f:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat, z: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3fARB"]
+    pub static mut epoxy_glWindowPos3fARB:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat, z: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3fMESA"]
+    pub static mut epoxy_glWindowPos3fMESA:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat, z: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3fv"]
+    pub static mut epoxy_glWindowPos3fv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3fvARB"]
+    pub static mut epoxy_glWindowPos3fvARB:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3fvMESA"]
+    pub static mut epoxy_glWindowPos3fvMESA:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3i"]
+    pub static mut epoxy_glWindowPos3i:
+        ::std::option::Option<unsafe extern "C" fn(x: GLint, y: GLint, z: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3iARB"]
+    pub static mut epoxy_glWindowPos3iARB:
+        ::std::option::Option<unsafe extern "C" fn(x: GLint, y: GLint, z: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3iMESA"]
+    pub static mut epoxy_glWindowPos3iMESA:
+        ::std::option::Option<unsafe extern "C" fn(x: GLint, y: GLint, z: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3iv"]
+    pub static mut epoxy_glWindowPos3iv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3ivARB"]
+    pub static mut epoxy_glWindowPos3ivARB:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3ivMESA"]
+    pub static mut epoxy_glWindowPos3ivMESA:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3s"]
+    pub static mut epoxy_glWindowPos3s:
+        ::std::option::Option<unsafe extern "C" fn(x: GLshort, y: GLshort, z: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3sARB"]
+    pub static mut epoxy_glWindowPos3sARB:
+        ::std::option::Option<unsafe extern "C" fn(x: GLshort, y: GLshort, z: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3sMESA"]
+    pub static mut epoxy_glWindowPos3sMESA:
+        ::std::option::Option<unsafe extern "C" fn(x: GLshort, y: GLshort, z: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3sv"]
+    pub static mut epoxy_glWindowPos3sv:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3svARB"]
+    pub static mut epoxy_glWindowPos3svARB:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos3svMESA"]
+    pub static mut epoxy_glWindowPos3svMESA:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos4dMESA"]
+    pub static mut epoxy_glWindowPos4dMESA: ::std::option::Option<
+        unsafe extern "C" fn(x: GLdouble, y: GLdouble, z: GLdouble, w: GLdouble),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos4dvMESA"]
+    pub static mut epoxy_glWindowPos4dvMESA:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLdouble)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos4fMESA"]
+    pub static mut epoxy_glWindowPos4fMESA:
+        ::std::option::Option<unsafe extern "C" fn(x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos4fvMESA"]
+    pub static mut epoxy_glWindowPos4fvMESA:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLfloat)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos4iMESA"]
+    pub static mut epoxy_glWindowPos4iMESA:
+        ::std::option::Option<unsafe extern "C" fn(x: GLint, y: GLint, z: GLint, w: GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos4ivMESA"]
+    pub static mut epoxy_glWindowPos4ivMESA:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLint)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos4sMESA"]
+    pub static mut epoxy_glWindowPos4sMESA:
+        ::std::option::Option<unsafe extern "C" fn(x: GLshort, y: GLshort, z: GLshort, w: GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowPos4svMESA"]
+    pub static mut epoxy_glWindowPos4svMESA:
+        ::std::option::Option<unsafe extern "C" fn(v: *const GLshort)>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWindowRectanglesEXT"]
+    pub static mut epoxy_glWindowRectanglesEXT: ::std::option::Option<
+        unsafe extern "C" fn(mode: GLenum, count: GLsizei, box_: *const GLint),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_glWriteMaskEXT"]
+    pub static mut epoxy_glWriteMaskEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            res: GLuint,
+            in_: GLuint,
+            outX: GLenum,
+            outY: GLenum,
+            outZ: GLenum,
+            outW: GLenum,
+        ),
+    >;
+}
+extern "C" {
+    pub fn epoxy_has_gl_extension(extension: *const ::std::os::raw::c_char) -> bool;
+}
+extern "C" {
+    pub fn epoxy_is_desktop_gl() -> bool;
+}
+extern "C" {
+    pub fn epoxy_gl_version() -> ::std::os::raw::c_int;
+}
+pub type XID = ::std::os::raw::c_ulong;
+pub type Window = XID;
+pub type Pixmap = XID;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct _XDisplay {
+    _unused: [u8; 0],
+}
+pub type Display = _XDisplay;
+pub type EGLNativeDisplayType = *mut Display;
+pub type EGLNativePixmapType = Pixmap;
+pub type EGLNativeWindowType = Window;
+pub type EGLint = khronos_int32_t;
+pub type EGLBoolean = ::std::os::raw::c_uint;
+pub type EGLenum = ::std::os::raw::c_uint;
+pub type EGLAttribKHR = isize;
+pub type EGLAttrib = isize;
+pub type EGLClientBuffer = *mut ::std::os::raw::c_void;
+pub type EGLConfig = *mut ::std::os::raw::c_void;
+pub type EGLContext = *mut ::std::os::raw::c_void;
+pub type EGLDeviceEXT = *mut ::std::os::raw::c_void;
+pub type EGLDisplay = *mut ::std::os::raw::c_void;
+pub type EGLImage = *mut ::std::os::raw::c_void;
+pub type EGLImageKHR = *mut ::std::os::raw::c_void;
+pub type EGLLabelKHR = *mut ::std::os::raw::c_void;
+pub type EGLObjectKHR = *mut ::std::os::raw::c_void;
+pub type EGLOutputLayerEXT = *mut ::std::os::raw::c_void;
+pub type EGLOutputPortEXT = *mut ::std::os::raw::c_void;
+pub type EGLStreamKHR = *mut ::std::os::raw::c_void;
+pub type EGLSurface = *mut ::std::os::raw::c_void;
+pub type EGLSync = *mut ::std::os::raw::c_void;
+pub type EGLSyncKHR = *mut ::std::os::raw::c_void;
+pub type EGLSyncNV = *mut ::std::os::raw::c_void;
+pub type __eglMustCastToProperFunctionPointerType = ::std::option::Option<unsafe extern "C" fn()>;
+pub type EGLTimeKHR = khronos_utime_nanoseconds_t;
+pub type EGLTime = khronos_utime_nanoseconds_t;
+pub type EGLTimeNV = khronos_utime_nanoseconds_t;
+pub type EGLuint64NV = khronos_utime_nanoseconds_t;
+pub type EGLuint64KHR = khronos_uint64_t;
+pub type EGLnsecsANDROID = khronos_stime_nanoseconds_t;
+pub type EGLNativeFileDescriptorKHR = ::std::os::raw::c_int;
+pub type EGLsizeiANDROID = khronos_ssize_t;
+pub type EGLSetBlobFuncANDROID = ::std::option::Option<
+    unsafe extern "C" fn(
+        key: *const ::std::os::raw::c_void,
+        keySize: EGLsizeiANDROID,
+        value: *const ::std::os::raw::c_void,
+        valueSize: EGLsizeiANDROID,
+    ),
+>;
+pub type EGLGetBlobFuncANDROID = ::std::option::Option<
+    unsafe extern "C" fn(
+        key: *const ::std::os::raw::c_void,
+        keySize: EGLsizeiANDROID,
+        value: *mut ::std::os::raw::c_void,
+        valueSize: EGLsizeiANDROID,
+    ) -> EGLsizeiANDROID,
+>;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct EGLClientPixmapHI {
+    pub pData: *mut ::std::os::raw::c_void,
+    pub iWidth: EGLint,
+    pub iHeight: EGLint,
+    pub iStride: EGLint,
+}
+pub type EGLDEBUGPROCKHR = ::std::option::Option<
+    unsafe extern "C" fn(
+        error: EGLenum,
+        command: *const ::std::os::raw::c_char,
+        messageType: EGLint,
+        threadLabel: EGLLabelKHR,
+        objectLabel: EGLLabelKHR,
+        message: *const ::std::os::raw::c_char,
+    ),
+>;
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglBindAPI"]
+    pub static mut epoxy_eglBindAPI:
+        ::std::option::Option<unsafe extern "C" fn(api: EGLenum) -> EGLBoolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglBindTexImage"]
+    pub static mut epoxy_eglBindTexImage: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, surface: EGLSurface, buffer: EGLint) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglChooseConfig"]
+    pub static mut epoxy_eglChooseConfig: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            attrib_list: *const EGLint,
+            configs: *mut EGLConfig,
+            config_size: EGLint,
+            num_config: *mut EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglClientWaitSync"]
+    pub static mut epoxy_eglClientWaitSync: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            sync: EGLSync,
+            flags: EGLint,
+            timeout: EGLTime,
+        ) -> EGLint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglClientWaitSyncKHR"]
+    pub static mut epoxy_eglClientWaitSyncKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            sync: EGLSyncKHR,
+            flags: EGLint,
+            timeout: EGLTimeKHR,
+        ) -> EGLint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglClientWaitSyncNV"]
+    pub static mut epoxy_eglClientWaitSyncNV: ::std::option::Option<
+        unsafe extern "C" fn(sync: EGLSyncNV, flags: EGLint, timeout: EGLTimeNV) -> EGLint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCopyBuffers"]
+    pub static mut epoxy_eglCopyBuffers: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surface: EGLSurface,
+            target: EGLNativePixmapType,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateContext"]
+    pub static mut epoxy_eglCreateContext: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            config: EGLConfig,
+            share_context: EGLContext,
+            attrib_list: *const EGLint,
+        ) -> EGLContext,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateDRMImageMESA"]
+    pub static mut epoxy_eglCreateDRMImageMESA: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, attrib_list: *const EGLint) -> EGLImageKHR,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateFenceSyncNV"]
+    pub static mut epoxy_eglCreateFenceSyncNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            condition: EGLenum,
+            attrib_list: *const EGLint,
+        ) -> EGLSyncNV,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateImage"]
+    pub static mut epoxy_eglCreateImage: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            ctx: EGLContext,
+            target: EGLenum,
+            buffer: EGLClientBuffer,
+            attrib_list: *const EGLAttrib,
+        ) -> EGLImage,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateImageKHR"]
+    pub static mut epoxy_eglCreateImageKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            ctx: EGLContext,
+            target: EGLenum,
+            buffer: EGLClientBuffer,
+            attrib_list: *const EGLint,
+        ) -> EGLImageKHR,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateNativeClientBufferANDROID"]
+    pub static mut epoxy_eglCreateNativeClientBufferANDROID:
+        ::std::option::Option<unsafe extern "C" fn(attrib_list: *const EGLint) -> EGLClientBuffer>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreatePbufferFromClientBuffer"]
+    pub static mut epoxy_eglCreatePbufferFromClientBuffer: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            buftype: EGLenum,
+            buffer: EGLClientBuffer,
+            config: EGLConfig,
+            attrib_list: *const EGLint,
+        ) -> EGLSurface,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreatePbufferSurface"]
+    pub static mut epoxy_eglCreatePbufferSurface: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            config: EGLConfig,
+            attrib_list: *const EGLint,
+        ) -> EGLSurface,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreatePixmapSurface"]
+    pub static mut epoxy_eglCreatePixmapSurface: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            config: EGLConfig,
+            pixmap: EGLNativePixmapType,
+            attrib_list: *const EGLint,
+        ) -> EGLSurface,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreatePixmapSurfaceHI"]
+    pub static mut epoxy_eglCreatePixmapSurfaceHI: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            config: EGLConfig,
+            pixmap: *mut EGLClientPixmapHI,
+        ) -> EGLSurface,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreatePlatformPixmapSurface"]
+    pub static mut epoxy_eglCreatePlatformPixmapSurface: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            config: EGLConfig,
+            native_pixmap: *mut ::std::os::raw::c_void,
+            attrib_list: *const EGLAttrib,
+        ) -> EGLSurface,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreatePlatformPixmapSurfaceEXT"]
+    pub static mut epoxy_eglCreatePlatformPixmapSurfaceEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            config: EGLConfig,
+            native_pixmap: *mut ::std::os::raw::c_void,
+            attrib_list: *const EGLint,
+        ) -> EGLSurface,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreatePlatformWindowSurface"]
+    pub static mut epoxy_eglCreatePlatformWindowSurface: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            config: EGLConfig,
+            native_window: *mut ::std::os::raw::c_void,
+            attrib_list: *const EGLAttrib,
+        ) -> EGLSurface,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreatePlatformWindowSurfaceEXT"]
+    pub static mut epoxy_eglCreatePlatformWindowSurfaceEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            config: EGLConfig,
+            native_window: *mut ::std::os::raw::c_void,
+            attrib_list: *const EGLint,
+        ) -> EGLSurface,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateStreamAttribKHR"]
+    pub static mut epoxy_eglCreateStreamAttribKHR: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, attrib_list: *const EGLAttrib) -> EGLStreamKHR,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateStreamFromFileDescriptorKHR"]
+    pub static mut epoxy_eglCreateStreamFromFileDescriptorKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            file_descriptor: EGLNativeFileDescriptorKHR,
+        ) -> EGLStreamKHR,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateStreamKHR"]
+    pub static mut epoxy_eglCreateStreamKHR: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, attrib_list: *const EGLint) -> EGLStreamKHR,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateStreamProducerSurfaceKHR"]
+    pub static mut epoxy_eglCreateStreamProducerSurfaceKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            config: EGLConfig,
+            stream: EGLStreamKHR,
+            attrib_list: *const EGLint,
+        ) -> EGLSurface,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateStreamSyncNV"]
+    pub static mut epoxy_eglCreateStreamSyncNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            stream: EGLStreamKHR,
+            type_: EGLenum,
+            attrib_list: *const EGLint,
+        ) -> EGLSyncKHR,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateSync"]
+    pub static mut epoxy_eglCreateSync: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            type_: EGLenum,
+            attrib_list: *const EGLAttrib,
+        ) -> EGLSync,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateSync64KHR"]
+    pub static mut epoxy_eglCreateSync64KHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            type_: EGLenum,
+            attrib_list: *const EGLAttribKHR,
+        ) -> EGLSyncKHR,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateSyncKHR"]
+    pub static mut epoxy_eglCreateSyncKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            type_: EGLenum,
+            attrib_list: *const EGLint,
+        ) -> EGLSyncKHR,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglCreateWindowSurface"]
+    pub static mut epoxy_eglCreateWindowSurface: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            config: EGLConfig,
+            win: EGLNativeWindowType,
+            attrib_list: *const EGLint,
+        ) -> EGLSurface,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglDebugMessageControlKHR"]
+    pub static mut epoxy_eglDebugMessageControlKHR: ::std::option::Option<
+        unsafe extern "C" fn(callback: EGLDEBUGPROCKHR, attrib_list: *const EGLAttrib) -> EGLint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglDestroyContext"]
+    pub static mut epoxy_eglDestroyContext:
+        ::std::option::Option<unsafe extern "C" fn(dpy: EGLDisplay, ctx: EGLContext) -> EGLBoolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglDestroyImage"]
+    pub static mut epoxy_eglDestroyImage:
+        ::std::option::Option<unsafe extern "C" fn(dpy: EGLDisplay, image: EGLImage) -> EGLBoolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglDestroyImageKHR"]
+    pub static mut epoxy_eglDestroyImageKHR: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, image: EGLImageKHR) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglDestroyStreamKHR"]
+    pub static mut epoxy_eglDestroyStreamKHR: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, stream: EGLStreamKHR) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglDestroySurface"]
+    pub static mut epoxy_eglDestroySurface: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, surface: EGLSurface) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglDestroySync"]
+    pub static mut epoxy_eglDestroySync:
+        ::std::option::Option<unsafe extern "C" fn(dpy: EGLDisplay, sync: EGLSync) -> EGLBoolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglDestroySyncKHR"]
+    pub static mut epoxy_eglDestroySyncKHR: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, sync: EGLSyncKHR) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglDestroySyncNV"]
+    pub static mut epoxy_eglDestroySyncNV:
+        ::std::option::Option<unsafe extern "C" fn(sync: EGLSyncNV) -> EGLBoolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglDupNativeFenceFDANDROID"]
+    pub static mut epoxy_eglDupNativeFenceFDANDROID:
+        ::std::option::Option<unsafe extern "C" fn(dpy: EGLDisplay, sync: EGLSyncKHR) -> EGLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglExportDMABUFImageMESA"]
+    pub static mut epoxy_eglExportDMABUFImageMESA: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            image: EGLImageKHR,
+            fds: *mut ::std::os::raw::c_int,
+            strides: *mut EGLint,
+            offsets: *mut EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglExportDMABUFImageQueryMESA"]
+    pub static mut epoxy_eglExportDMABUFImageQueryMESA: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            image: EGLImageKHR,
+            fourcc: *mut ::std::os::raw::c_int,
+            num_planes: *mut ::std::os::raw::c_int,
+            modifiers: *mut EGLuint64KHR,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglExportDRMImageMESA"]
+    pub static mut epoxy_eglExportDRMImageMESA: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            image: EGLImageKHR,
+            name: *mut EGLint,
+            handle: *mut EGLint,
+            stride: *mut EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglFenceNV"]
+    pub static mut epoxy_eglFenceNV:
+        ::std::option::Option<unsafe extern "C" fn(sync: EGLSyncNV) -> EGLBoolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetConfigAttrib"]
+    pub static mut epoxy_eglGetConfigAttrib: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            config: EGLConfig,
+            attribute: EGLint,
+            value: *mut EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetConfigs"]
+    pub static mut epoxy_eglGetConfigs: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            configs: *mut EGLConfig,
+            config_size: EGLint,
+            num_config: *mut EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetCurrentContext"]
+    pub static mut epoxy_eglGetCurrentContext:
+        ::std::option::Option<unsafe extern "C" fn() -> EGLContext>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetCurrentDisplay"]
+    pub static mut epoxy_eglGetCurrentDisplay:
+        ::std::option::Option<unsafe extern "C" fn() -> EGLDisplay>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetCurrentSurface"]
+    pub static mut epoxy_eglGetCurrentSurface:
+        ::std::option::Option<unsafe extern "C" fn(readdraw: EGLint) -> EGLSurface>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetDisplay"]
+    pub static mut epoxy_eglGetDisplay:
+        ::std::option::Option<unsafe extern "C" fn(display_id: EGLNativeDisplayType) -> EGLDisplay>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetError"]
+    pub static mut epoxy_eglGetError: ::std::option::Option<unsafe extern "C" fn() -> EGLint>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetOutputLayersEXT"]
+    pub static mut epoxy_eglGetOutputLayersEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            attrib_list: *const EGLAttrib,
+            layers: *mut EGLOutputLayerEXT,
+            max_layers: EGLint,
+            num_layers: *mut EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetOutputPortsEXT"]
+    pub static mut epoxy_eglGetOutputPortsEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            attrib_list: *const EGLAttrib,
+            ports: *mut EGLOutputPortEXT,
+            max_ports: EGLint,
+            num_ports: *mut EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetPlatformDisplay"]
+    pub static mut epoxy_eglGetPlatformDisplay: ::std::option::Option<
+        unsafe extern "C" fn(
+            platform: EGLenum,
+            native_display: *mut ::std::os::raw::c_void,
+            attrib_list: *const EGLAttrib,
+        ) -> EGLDisplay,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetPlatformDisplayEXT"]
+    pub static mut epoxy_eglGetPlatformDisplayEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            platform: EGLenum,
+            native_display: *mut ::std::os::raw::c_void,
+            attrib_list: *const EGLint,
+        ) -> EGLDisplay,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetProcAddress"]
+    pub static mut epoxy_eglGetProcAddress: ::std::option::Option<
+        unsafe extern "C" fn(
+            procname: *const ::std::os::raw::c_char,
+        ) -> __eglMustCastToProperFunctionPointerType,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetStreamFileDescriptorKHR"]
+    pub static mut epoxy_eglGetStreamFileDescriptorKHR: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, stream: EGLStreamKHR) -> EGLNativeFileDescriptorKHR,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetSyncAttrib"]
+    pub static mut epoxy_eglGetSyncAttrib: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            sync: EGLSync,
+            attribute: EGLint,
+            value: *mut EGLAttrib,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetSyncAttribKHR"]
+    pub static mut epoxy_eglGetSyncAttribKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            sync: EGLSyncKHR,
+            attribute: EGLint,
+            value: *mut EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetSyncAttribNV"]
+    pub static mut epoxy_eglGetSyncAttribNV: ::std::option::Option<
+        unsafe extern "C" fn(sync: EGLSyncNV, attribute: EGLint, value: *mut EGLint) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetSystemTimeFrequencyNV"]
+    pub static mut epoxy_eglGetSystemTimeFrequencyNV:
+        ::std::option::Option<unsafe extern "C" fn() -> EGLuint64NV>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglGetSystemTimeNV"]
+    pub static mut epoxy_eglGetSystemTimeNV:
+        ::std::option::Option<unsafe extern "C" fn() -> EGLuint64NV>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglInitialize"]
+    pub static mut epoxy_eglInitialize: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, major: *mut EGLint, minor: *mut EGLint) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglLabelObjectKHR"]
+    pub static mut epoxy_eglLabelObjectKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            display: EGLDisplay,
+            objectType: EGLenum,
+            object: EGLObjectKHR,
+            label: EGLLabelKHR,
+        ) -> EGLint,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglLockSurfaceKHR"]
+    pub static mut epoxy_eglLockSurfaceKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surface: EGLSurface,
+            attrib_list: *const EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglMakeCurrent"]
+    pub static mut epoxy_eglMakeCurrent: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            draw: EGLSurface,
+            read: EGLSurface,
+            ctx: EGLContext,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglOutputLayerAttribEXT"]
+    pub static mut epoxy_eglOutputLayerAttribEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            layer: EGLOutputLayerEXT,
+            attribute: EGLint,
+            value: EGLAttrib,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglOutputPortAttribEXT"]
+    pub static mut epoxy_eglOutputPortAttribEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            port: EGLOutputPortEXT,
+            attribute: EGLint,
+            value: EGLAttrib,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglPostSubBufferNV"]
+    pub static mut epoxy_eglPostSubBufferNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surface: EGLSurface,
+            x: EGLint,
+            y: EGLint,
+            width: EGLint,
+            height: EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglPresentationTimeANDROID"]
+    pub static mut epoxy_eglPresentationTimeANDROID: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surface: EGLSurface,
+            time: EGLnsecsANDROID,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryAPI"]
+    pub static mut epoxy_eglQueryAPI: ::std::option::Option<unsafe extern "C" fn() -> EGLenum>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryContext"]
+    pub static mut epoxy_eglQueryContext: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            ctx: EGLContext,
+            attribute: EGLint,
+            value: *mut EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryDebugKHR"]
+    pub static mut epoxy_eglQueryDebugKHR: ::std::option::Option<
+        unsafe extern "C" fn(attribute: EGLint, value: *mut EGLAttrib) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryDeviceAttribEXT"]
+    pub static mut epoxy_eglQueryDeviceAttribEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            device: EGLDeviceEXT,
+            attribute: EGLint,
+            value: *mut EGLAttrib,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryDeviceStringEXT"]
+    pub static mut epoxy_eglQueryDeviceStringEXT: ::std::option::Option<
+        unsafe extern "C" fn(device: EGLDeviceEXT, name: EGLint) -> *const ::std::os::raw::c_char,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryDevicesEXT"]
+    pub static mut epoxy_eglQueryDevicesEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            max_devices: EGLint,
+            devices: *mut EGLDeviceEXT,
+            num_devices: *mut EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryDisplayAttribEXT"]
+    pub static mut epoxy_eglQueryDisplayAttribEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            attribute: EGLint,
+            value: *mut EGLAttrib,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryDisplayAttribNV"]
+    pub static mut epoxy_eglQueryDisplayAttribNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            attribute: EGLint,
+            value: *mut EGLAttrib,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryDmaBufFormatsEXT"]
+    pub static mut epoxy_eglQueryDmaBufFormatsEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            max_formats: EGLint,
+            formats: *mut EGLint,
+            num_formats: *mut EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryDmaBufModifiersEXT"]
+    pub static mut epoxy_eglQueryDmaBufModifiersEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            format: EGLint,
+            max_modifiers: EGLint,
+            modifiers: *mut EGLuint64KHR,
+            external_only: *mut EGLBoolean,
+            num_modifiers: *mut EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryNativeDisplayNV"]
+    pub static mut epoxy_eglQueryNativeDisplayNV: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, display_id: *mut EGLNativeDisplayType) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryNativePixmapNV"]
+    pub static mut epoxy_eglQueryNativePixmapNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surf: EGLSurface,
+            pixmap: *mut EGLNativePixmapType,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryNativeWindowNV"]
+    pub static mut epoxy_eglQueryNativeWindowNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surf: EGLSurface,
+            window: *mut EGLNativeWindowType,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryOutputLayerAttribEXT"]
+    pub static mut epoxy_eglQueryOutputLayerAttribEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            layer: EGLOutputLayerEXT,
+            attribute: EGLint,
+            value: *mut EGLAttrib,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryOutputLayerStringEXT"]
+    pub static mut epoxy_eglQueryOutputLayerStringEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            layer: EGLOutputLayerEXT,
+            name: EGLint,
+        ) -> *const ::std::os::raw::c_char,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryOutputPortAttribEXT"]
+    pub static mut epoxy_eglQueryOutputPortAttribEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            port: EGLOutputPortEXT,
+            attribute: EGLint,
+            value: *mut EGLAttrib,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryOutputPortStringEXT"]
+    pub static mut epoxy_eglQueryOutputPortStringEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            port: EGLOutputPortEXT,
+            name: EGLint,
+        ) -> *const ::std::os::raw::c_char,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryStreamAttribKHR"]
+    pub static mut epoxy_eglQueryStreamAttribKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            stream: EGLStreamKHR,
+            attribute: EGLenum,
+            value: *mut EGLAttrib,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryStreamKHR"]
+    pub static mut epoxy_eglQueryStreamKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            stream: EGLStreamKHR,
+            attribute: EGLenum,
+            value: *mut EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryStreamMetadataNV"]
+    pub static mut epoxy_eglQueryStreamMetadataNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            stream: EGLStreamKHR,
+            name: EGLenum,
+            n: EGLint,
+            offset: EGLint,
+            size: EGLint,
+            data: *mut ::std::os::raw::c_void,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryStreamTimeKHR"]
+    pub static mut epoxy_eglQueryStreamTimeKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            stream: EGLStreamKHR,
+            attribute: EGLenum,
+            value: *mut EGLTimeKHR,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryStreamu64KHR"]
+    pub static mut epoxy_eglQueryStreamu64KHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            stream: EGLStreamKHR,
+            attribute: EGLenum,
+            value: *mut EGLuint64KHR,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQueryString"]
+    pub static mut epoxy_eglQueryString: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, name: EGLint) -> *const ::std::os::raw::c_char,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQuerySurface"]
+    pub static mut epoxy_eglQuerySurface: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surface: EGLSurface,
+            attribute: EGLint,
+            value: *mut EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQuerySurface64KHR"]
+    pub static mut epoxy_eglQuerySurface64KHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surface: EGLSurface,
+            attribute: EGLint,
+            value: *mut EGLAttribKHR,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglQuerySurfacePointerANGLE"]
+    pub static mut epoxy_eglQuerySurfacePointerANGLE: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surface: EGLSurface,
+            attribute: EGLint,
+            value: *mut *mut ::std::os::raw::c_void,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglReleaseTexImage"]
+    pub static mut epoxy_eglReleaseTexImage: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, surface: EGLSurface, buffer: EGLint) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglReleaseThread"]
+    pub static mut epoxy_eglReleaseThread:
+        ::std::option::Option<unsafe extern "C" fn() -> EGLBoolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglResetStreamNV"]
+    pub static mut epoxy_eglResetStreamNV: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, stream: EGLStreamKHR) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglSetBlobCacheFuncsANDROID"]
+    pub static mut epoxy_eglSetBlobCacheFuncsANDROID: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            set: EGLSetBlobFuncANDROID,
+            get: EGLGetBlobFuncANDROID,
+        ),
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglSetDamageRegionKHR"]
+    pub static mut epoxy_eglSetDamageRegionKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surface: EGLSurface,
+            rects: *mut EGLint,
+            n_rects: EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglSetStreamAttribKHR"]
+    pub static mut epoxy_eglSetStreamAttribKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            stream: EGLStreamKHR,
+            attribute: EGLenum,
+            value: EGLAttrib,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglSetStreamMetadataNV"]
+    pub static mut epoxy_eglSetStreamMetadataNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            stream: EGLStreamKHR,
+            n: EGLint,
+            offset: EGLint,
+            size: EGLint,
+            data: *const ::std::os::raw::c_void,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglSignalSyncKHR"]
+    pub static mut epoxy_eglSignalSyncKHR: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, sync: EGLSyncKHR, mode: EGLenum) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglSignalSyncNV"]
+    pub static mut epoxy_eglSignalSyncNV:
+        ::std::option::Option<unsafe extern "C" fn(sync: EGLSyncNV, mode: EGLenum) -> EGLBoolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglStreamAttribKHR"]
+    pub static mut epoxy_eglStreamAttribKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            stream: EGLStreamKHR,
+            attribute: EGLenum,
+            value: EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglStreamConsumerAcquireAttribKHR"]
+    pub static mut epoxy_eglStreamConsumerAcquireAttribKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            stream: EGLStreamKHR,
+            attrib_list: *const EGLAttrib,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglStreamConsumerAcquireKHR"]
+    pub static mut epoxy_eglStreamConsumerAcquireKHR: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, stream: EGLStreamKHR) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglStreamConsumerGLTextureExternalAttribsNV"]
+    pub static mut epoxy_eglStreamConsumerGLTextureExternalAttribsNV: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            stream: EGLStreamKHR,
+            attrib_list: *mut EGLAttrib,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglStreamConsumerGLTextureExternalKHR"]
+    pub static mut epoxy_eglStreamConsumerGLTextureExternalKHR: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, stream: EGLStreamKHR) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglStreamConsumerOutputEXT"]
+    pub static mut epoxy_eglStreamConsumerOutputEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            stream: EGLStreamKHR,
+            layer: EGLOutputLayerEXT,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglStreamConsumerReleaseAttribKHR"]
+    pub static mut epoxy_eglStreamConsumerReleaseAttribKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            stream: EGLStreamKHR,
+            attrib_list: *const EGLAttrib,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglStreamConsumerReleaseKHR"]
+    pub static mut epoxy_eglStreamConsumerReleaseKHR: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, stream: EGLStreamKHR) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglSurfaceAttrib"]
+    pub static mut epoxy_eglSurfaceAttrib: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surface: EGLSurface,
+            attribute: EGLint,
+            value: EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglSwapBuffers"]
+    pub static mut epoxy_eglSwapBuffers: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, surface: EGLSurface) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglSwapBuffersRegion2NOK"]
+    pub static mut epoxy_eglSwapBuffersRegion2NOK: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surface: EGLSurface,
+            numRects: EGLint,
+            rects: *const EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglSwapBuffersRegionNOK"]
+    pub static mut epoxy_eglSwapBuffersRegionNOK: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surface: EGLSurface,
+            numRects: EGLint,
+            rects: *const EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglSwapBuffersWithDamageEXT"]
+    pub static mut epoxy_eglSwapBuffersWithDamageEXT: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surface: EGLSurface,
+            rects: *mut EGLint,
+            n_rects: EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglSwapBuffersWithDamageKHR"]
+    pub static mut epoxy_eglSwapBuffersWithDamageKHR: ::std::option::Option<
+        unsafe extern "C" fn(
+            dpy: EGLDisplay,
+            surface: EGLSurface,
+            rects: *mut EGLint,
+            n_rects: EGLint,
+        ) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglSwapInterval"]
+    pub static mut epoxy_eglSwapInterval: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, interval: EGLint) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglTerminate"]
+    pub static mut epoxy_eglTerminate:
+        ::std::option::Option<unsafe extern "C" fn(dpy: EGLDisplay) -> EGLBoolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglUnlockSurfaceKHR"]
+    pub static mut epoxy_eglUnlockSurfaceKHR: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, surface: EGLSurface) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglWaitClient"]
+    pub static mut epoxy_eglWaitClient: ::std::option::Option<unsafe extern "C" fn() -> EGLBoolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglWaitGL"]
+    pub static mut epoxy_eglWaitGL: ::std::option::Option<unsafe extern "C" fn() -> EGLBoolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglWaitNative"]
+    pub static mut epoxy_eglWaitNative:
+        ::std::option::Option<unsafe extern "C" fn(engine: EGLint) -> EGLBoolean>;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglWaitSync"]
+    pub static mut epoxy_eglWaitSync: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, sync: EGLSync, flags: EGLint) -> EGLBoolean,
+    >;
+}
+extern "C" {
+    #[link_name = "\u{1}epoxy_eglWaitSyncKHR"]
+    pub static mut epoxy_eglWaitSyncKHR: ::std::option::Option<
+        unsafe extern "C" fn(dpy: EGLDisplay, sync: EGLSyncKHR, flags: EGLint) -> EGLint,
+    >;
+}
+extern "C" {
+    pub fn epoxy_has_egl_extension(
+        dpy: EGLDisplay,
+        extension: *const ::std::os::raw::c_char,
+    ) -> bool;
+}
+extern "C" {
+    pub fn epoxy_egl_version(dpy: EGLDisplay) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn epoxy_has_egl() -> bool;
+}
diff --git a/gpu_renderer/src/generated/generate b/gpu_renderer/src/generated/generate
new file mode 120000
index 0000000..d4bb1f1
--- /dev/null
+++ b/gpu_renderer/src/generated/generate
@@ -0,0 +1 @@
+generate.py
\ No newline at end of file
diff --git a/gpu_renderer/src/generated/generate.py b/gpu_renderer/src/generated/generate.py
new file mode 100755
index 0000000..923cd70
--- /dev/null
+++ b/gpu_renderer/src/generated/generate.py
@@ -0,0 +1,182 @@
+#!/usr/bin/env python3
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generates bindings that are used gpu_renderer.
+
+A sysroot and virglrenderer source checkout is required. The defaults to the
+root directory.
+"""
+
+from __future__ import print_function
+import argparse
+import multiprocessing.pool
+import os
+import subprocess
+import sys
+import tempfile
+
+# Bright green.
+PASS_COLOR = '\033[1;32m'
+# Bright red.
+FAIL_COLOR = '\033[1;31m'
+# Default color.
+END_COLOR = '\033[0m'
+
+verbose = False
+
+def generate_module(module_name, whitelist, header, clang_args, lib_name):
+  args = [
+    'bindgen',
+    '--no-layout-tests',
+    '--whitelist-function', whitelist,
+    '--whitelist-var', whitelist,
+    '--whitelist-type', whitelist,
+    '--no-prepend-enum-name',
+    '--no-rustfmt-bindings',
+    '-o', module_name + '.rs',
+  ];
+
+  if lib_name:
+    args.extend(['--raw-line',
+                 '#[link(name = "{}")] extern {{}}'.format(lib_name)])
+
+  args.extend([header, '--'])
+  args.extend(clang_args)
+
+  if verbose:
+    print(' '.join(args))
+
+  if subprocess.Popen(args).wait() == 0:
+    return 'pass'
+  else:
+    return 'bindgen failed'
+
+
+def download_virgl(src, dst, branch):
+  virgl_src = tempfile.TemporaryDirectory(prefix='virglrenderer-src')
+
+  args = ['git', 'clone']
+
+  if branch:
+    args.extend(['-b', branch])
+
+  args.extend([src, dst])
+  
+  if verbose:
+    print(' '.join(args))
+
+  if subprocess.Popen(args).wait() == 0:
+    return True
+  else:
+    
+    return False
+
+
+def get_parser():
+  """Gets the argument parser"""
+  parser = argparse.ArgumentParser(description=__doc__)
+  parser.add_argument('--sysroot',
+                      default='/',
+                      help='sysroot directory (default=%(default)s)')
+  parser.add_argument('--virglrenderer',
+                      default='git://git.freedesktop.org/git/virglrenderer',
+                      help='virglrenderer src dir/repo (default=%(default)s)')
+  parser.add_argument('--virgl_branch',
+                      default='master',
+                      help='virglrenderer branch name (default=%(default)s)')
+  parser.add_argument('--verbose', '-v',
+                      action='store_true',
+                      help='enable verbose output (default=%(default)s)')
+  return parser
+
+
+def main(argv):
+  global verbose
+  os.chdir(os.path.dirname(sys.argv[0]))
+  opts = get_parser().parse_args(argv)
+  if opts.verbose:
+    verbose = True
+
+  virgl_src_dir = opts.virglrenderer
+  virgl_src_dir_temp = None
+  if '://' in opts.virglrenderer:
+    virgl_src_dir_temp = tempfile.TemporaryDirectory(prefix='virglrenderer-src')
+    virgl_src_dir = virgl_src_dir_temp.name
+    if not download_virgl(opts.virglrenderer, virgl_src_dir, opts.virgl_branch):
+      print('failed to clone \'{}\' to \'{}\''.format(virgl_src_dir,
+                                                      opts.virgl_branch))
+      sys.exit(1)
+
+  clang_args = ['-I', os.path.join(opts.sysroot, 'usr/include')]
+
+  modules = (
+    (
+      'virglrenderer',
+      '(virgl|VIRGL)_.+',
+      os.path.join(opts.sysroot, 'usr/include/virgl/virglrenderer.h'),
+      clang_args,
+      'virglrenderer',
+    ),
+    (
+      'epoxy_egl',
+      '(E?GL)|(epoxy)_.+',
+      os.path.join(opts.sysroot, 'usr/include/epoxy/egl.h'),
+      clang_args,
+      'epoxy',
+    ),
+    (
+      'virgl_protocol',
+      '(virgl)|(VIRGL)_.+',
+      os.path.join(virgl_src_dir, 'src/virgl_protocol.h'),
+      clang_args,
+      None,
+    ),
+    (
+      'p_defines',
+      '(pipe)|(PIPE).+',
+      os.path.join(virgl_src_dir, 'src/gallium/include/pipe/p_defines.h'),
+      clang_args,
+      None,
+    ),
+    (
+      'p_format',
+      'pipe_format',
+      os.path.join(virgl_src_dir, 'src/gallium/include/pipe/p_format.h'),
+      clang_args,
+      None,
+    ),
+  )
+
+  pool = multiprocessing.pool.Pool(len(modules))
+  results = pool.starmap(generate_module, modules, 1)
+
+  return_fail = False
+  print('---')
+  print('generate module summary:')
+  for module, result in zip(modules, results):
+    result_color = FAIL_COLOR
+    if result == 'pass':
+      result_color = PASS_COLOR
+    else:
+      return_fail = True
+
+    print('%15s: %s%s%s' %
+          (module[0], result_color, result, END_COLOR))
+
+  if return_fail:
+    sys.exit(1)
+
+  with open('mod.rs', 'w') as f:
+    print('/* generated by generate.py */', file=f)
+    print('#![allow(dead_code)]', file=f)
+    print('#![allow(non_camel_case_types)]', file=f)
+    print('#![allow(non_snake_case)]', file=f)
+    print('#![allow(non_upper_case_globals)]', file=f)
+    for module in modules:
+      print('pub mod', module[0] + ';', file=f)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/gpu_renderer/src/generated/mod.rs b/gpu_renderer/src/generated/mod.rs
new file mode 100644
index 0000000..d35ed8d
--- /dev/null
+++ b/gpu_renderer/src/generated/mod.rs
@@ -0,0 +1,14 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* generated by generate.py */
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(non_upper_case_globals)]
+pub mod epoxy_egl;
+pub mod p_defines;
+pub mod p_format;
+pub mod virgl_protocol;
+pub mod virglrenderer;
diff --git a/gpu_renderer/src/generated/p_defines.rs b/gpu_renderer/src/generated/p_defines.rs
new file mode 100644
index 0000000..637179a
--- /dev/null
+++ b/gpu_renderer/src/generated/p_defines.rs
@@ -0,0 +1,634 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+pub const _POSIX_PIPE_BUF: u32 = 512;
+pub const PIPE_BUF: u32 = 4096;
+pub const PIPE_BLENDFACTOR_ONE: u32 = 1;
+pub const PIPE_BLENDFACTOR_SRC_COLOR: u32 = 2;
+pub const PIPE_BLENDFACTOR_SRC_ALPHA: u32 = 3;
+pub const PIPE_BLENDFACTOR_DST_ALPHA: u32 = 4;
+pub const PIPE_BLENDFACTOR_DST_COLOR: u32 = 5;
+pub const PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: u32 = 6;
+pub const PIPE_BLENDFACTOR_CONST_COLOR: u32 = 7;
+pub const PIPE_BLENDFACTOR_CONST_ALPHA: u32 = 8;
+pub const PIPE_BLENDFACTOR_SRC1_COLOR: u32 = 9;
+pub const PIPE_BLENDFACTOR_SRC1_ALPHA: u32 = 10;
+pub const PIPE_BLENDFACTOR_ZERO: u32 = 17;
+pub const PIPE_BLENDFACTOR_INV_SRC_COLOR: u32 = 18;
+pub const PIPE_BLENDFACTOR_INV_SRC_ALPHA: u32 = 19;
+pub const PIPE_BLENDFACTOR_INV_DST_ALPHA: u32 = 20;
+pub const PIPE_BLENDFACTOR_INV_DST_COLOR: u32 = 21;
+pub const PIPE_BLENDFACTOR_INV_CONST_COLOR: u32 = 23;
+pub const PIPE_BLENDFACTOR_INV_CONST_ALPHA: u32 = 24;
+pub const PIPE_BLENDFACTOR_INV_SRC1_COLOR: u32 = 25;
+pub const PIPE_BLENDFACTOR_INV_SRC1_ALPHA: u32 = 26;
+pub const PIPE_BLEND_ADD: u32 = 0;
+pub const PIPE_BLEND_SUBTRACT: u32 = 1;
+pub const PIPE_BLEND_REVERSE_SUBTRACT: u32 = 2;
+pub const PIPE_BLEND_MIN: u32 = 3;
+pub const PIPE_BLEND_MAX: u32 = 4;
+pub const PIPE_LOGICOP_CLEAR: u32 = 0;
+pub const PIPE_LOGICOP_NOR: u32 = 1;
+pub const PIPE_LOGICOP_AND_INVERTED: u32 = 2;
+pub const PIPE_LOGICOP_COPY_INVERTED: u32 = 3;
+pub const PIPE_LOGICOP_AND_REVERSE: u32 = 4;
+pub const PIPE_LOGICOP_INVERT: u32 = 5;
+pub const PIPE_LOGICOP_XOR: u32 = 6;
+pub const PIPE_LOGICOP_NAND: u32 = 7;
+pub const PIPE_LOGICOP_AND: u32 = 8;
+pub const PIPE_LOGICOP_EQUIV: u32 = 9;
+pub const PIPE_LOGICOP_NOOP: u32 = 10;
+pub const PIPE_LOGICOP_OR_INVERTED: u32 = 11;
+pub const PIPE_LOGICOP_COPY: u32 = 12;
+pub const PIPE_LOGICOP_OR_REVERSE: u32 = 13;
+pub const PIPE_LOGICOP_OR: u32 = 14;
+pub const PIPE_LOGICOP_SET: u32 = 15;
+pub const PIPE_MASK_R: u32 = 1;
+pub const PIPE_MASK_G: u32 = 2;
+pub const PIPE_MASK_B: u32 = 4;
+pub const PIPE_MASK_A: u32 = 8;
+pub const PIPE_MASK_RGBA: u32 = 15;
+pub const PIPE_MASK_Z: u32 = 16;
+pub const PIPE_MASK_S: u32 = 32;
+pub const PIPE_MASK_ZS: u32 = 48;
+pub const PIPE_MASK_RGBAZS: u32 = 63;
+pub const PIPE_FUNC_NEVER: u32 = 0;
+pub const PIPE_FUNC_LESS: u32 = 1;
+pub const PIPE_FUNC_EQUAL: u32 = 2;
+pub const PIPE_FUNC_LEQUAL: u32 = 3;
+pub const PIPE_FUNC_GREATER: u32 = 4;
+pub const PIPE_FUNC_NOTEQUAL: u32 = 5;
+pub const PIPE_FUNC_GEQUAL: u32 = 6;
+pub const PIPE_FUNC_ALWAYS: u32 = 7;
+pub const PIPE_POLYGON_MODE_FILL: u32 = 0;
+pub const PIPE_POLYGON_MODE_LINE: u32 = 1;
+pub const PIPE_POLYGON_MODE_POINT: u32 = 2;
+pub const PIPE_FACE_NONE: u32 = 0;
+pub const PIPE_FACE_FRONT: u32 = 1;
+pub const PIPE_FACE_BACK: u32 = 2;
+pub const PIPE_FACE_FRONT_AND_BACK: u32 = 3;
+pub const PIPE_STENCIL_OP_KEEP: u32 = 0;
+pub const PIPE_STENCIL_OP_ZERO: u32 = 1;
+pub const PIPE_STENCIL_OP_REPLACE: u32 = 2;
+pub const PIPE_STENCIL_OP_INCR: u32 = 3;
+pub const PIPE_STENCIL_OP_DECR: u32 = 4;
+pub const PIPE_STENCIL_OP_INCR_WRAP: u32 = 5;
+pub const PIPE_STENCIL_OP_DECR_WRAP: u32 = 6;
+pub const PIPE_STENCIL_OP_INVERT: u32 = 7;
+pub const PIPE_TEX_FACE_POS_X: u32 = 0;
+pub const PIPE_TEX_FACE_NEG_X: u32 = 1;
+pub const PIPE_TEX_FACE_POS_Y: u32 = 2;
+pub const PIPE_TEX_FACE_NEG_Y: u32 = 3;
+pub const PIPE_TEX_FACE_POS_Z: u32 = 4;
+pub const PIPE_TEX_FACE_NEG_Z: u32 = 5;
+pub const PIPE_TEX_FACE_MAX: u32 = 6;
+pub const PIPE_TEX_WRAP_REPEAT: u32 = 0;
+pub const PIPE_TEX_WRAP_CLAMP: u32 = 1;
+pub const PIPE_TEX_WRAP_CLAMP_TO_EDGE: u32 = 2;
+pub const PIPE_TEX_WRAP_CLAMP_TO_BORDER: u32 = 3;
+pub const PIPE_TEX_WRAP_MIRROR_REPEAT: u32 = 4;
+pub const PIPE_TEX_WRAP_MIRROR_CLAMP: u32 = 5;
+pub const PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: u32 = 6;
+pub const PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: u32 = 7;
+pub const PIPE_TEX_MIPFILTER_NEAREST: u32 = 0;
+pub const PIPE_TEX_MIPFILTER_LINEAR: u32 = 1;
+pub const PIPE_TEX_MIPFILTER_NONE: u32 = 2;
+pub const PIPE_TEX_FILTER_NEAREST: u32 = 0;
+pub const PIPE_TEX_FILTER_LINEAR: u32 = 1;
+pub const PIPE_TEX_COMPARE_NONE: u32 = 0;
+pub const PIPE_TEX_COMPARE_R_TO_TEXTURE: u32 = 1;
+pub const PIPE_CLEAR_DEPTH: u32 = 1;
+pub const PIPE_CLEAR_STENCIL: u32 = 2;
+pub const PIPE_CLEAR_COLOR0: u32 = 4;
+pub const PIPE_CLEAR_COLOR1: u32 = 8;
+pub const PIPE_CLEAR_COLOR2: u32 = 16;
+pub const PIPE_CLEAR_COLOR3: u32 = 32;
+pub const PIPE_CLEAR_COLOR4: u32 = 64;
+pub const PIPE_CLEAR_COLOR5: u32 = 128;
+pub const PIPE_CLEAR_COLOR6: u32 = 256;
+pub const PIPE_CLEAR_COLOR7: u32 = 512;
+pub const PIPE_CLEAR_COLOR: u32 = 1020;
+pub const PIPE_CLEAR_DEPTHSTENCIL: u32 = 3;
+pub const PIPE_BARRIER_MAPPED_BUFFER: u32 = 1;
+pub const PIPE_BARRIER_SHADER_BUFFER: u32 = 2;
+pub const PIPE_BARRIER_QUERY_BUFFER: u32 = 4;
+pub const PIPE_BARRIER_VERTEX_BUFFER: u32 = 8;
+pub const PIPE_BARRIER_INDEX_BUFFER: u32 = 16;
+pub const PIPE_BARRIER_CONSTANT_BUFFER: u32 = 32;
+pub const PIPE_BARRIER_INDIRECT_BUFFER: u32 = 64;
+pub const PIPE_BARRIER_TEXTURE: u32 = 128;
+pub const PIPE_BARRIER_IMAGE: u32 = 256;
+pub const PIPE_BARRIER_FRAMEBUFFER: u32 = 512;
+pub const PIPE_BARRIER_STREAMOUT_BUFFER: u32 = 1024;
+pub const PIPE_BARRIER_GLOBAL_BUFFER: u32 = 2048;
+pub const PIPE_BARRIER_ALL: u32 = 4095;
+pub const PIPE_TEXTURE_BARRIER_SAMPLER: u32 = 1;
+pub const PIPE_TEXTURE_BARRIER_FRAMEBUFFER: u32 = 2;
+pub const PIPE_BIND_DEPTH_STENCIL: u32 = 1;
+pub const PIPE_BIND_RENDER_TARGET: u32 = 2;
+pub const PIPE_BIND_BLENDABLE: u32 = 4;
+pub const PIPE_BIND_SAMPLER_VIEW: u32 = 8;
+pub const PIPE_BIND_VERTEX_BUFFER: u32 = 16;
+pub const PIPE_BIND_INDEX_BUFFER: u32 = 32;
+pub const PIPE_BIND_CONSTANT_BUFFER: u32 = 64;
+pub const PIPE_BIND_DISPLAY_TARGET: u32 = 256;
+pub const PIPE_BIND_TRANSFER_WRITE: u32 = 512;
+pub const PIPE_BIND_TRANSFER_READ: u32 = 1024;
+pub const PIPE_BIND_STREAM_OUTPUT: u32 = 2048;
+pub const PIPE_BIND_CURSOR: u32 = 65536;
+pub const PIPE_BIND_CUSTOM: u32 = 131072;
+pub const PIPE_BIND_GLOBAL: u32 = 262144;
+pub const PIPE_BIND_SHADER_RESOURCE: u32 = 524288;
+pub const PIPE_BIND_COMPUTE_RESOURCE: u32 = 1048576;
+pub const PIPE_BIND_COMMAND_ARGS_BUFFER: u32 = 2097152;
+pub const PIPE_BIND_QUERY_BUFFER: u32 = 4194304;
+pub const PIPE_BIND_SCANOUT: u32 = 16384;
+pub const PIPE_BIND_SHARED: u32 = 32768;
+pub const PIPE_BIND_LINEAR: u32 = 2097152;
+pub const PIPE_RESOURCE_FLAG_MAP_PERSISTENT: u32 = 1;
+pub const PIPE_RESOURCE_FLAG_MAP_COHERENT: u32 = 2;
+pub const PIPE_RESOURCE_FLAG_DRV_PRIV: u32 = 65536;
+pub const PIPE_RESOURCE_FLAG_ST_PRIV: u32 = 16777216;
+pub const PIPE_USAGE_DEFAULT: u32 = 0;
+pub const PIPE_USAGE_IMMUTABLE: u32 = 1;
+pub const PIPE_USAGE_DYNAMIC: u32 = 2;
+pub const PIPE_USAGE_STREAM: u32 = 3;
+pub const PIPE_USAGE_STAGING: u32 = 4;
+pub const PIPE_SHADER_VERTEX: u32 = 0;
+pub const PIPE_SHADER_FRAGMENT: u32 = 1;
+pub const PIPE_SHADER_GEOMETRY: u32 = 2;
+pub const PIPE_SHADER_TESS_CTRL: u32 = 3;
+pub const PIPE_SHADER_TESS_EVAL: u32 = 4;
+pub const PIPE_SHADER_COMPUTE: u32 = 5;
+pub const PIPE_SHADER_TYPES: u32 = 6;
+pub const PIPE_PRIM_POINTS: u32 = 0;
+pub const PIPE_PRIM_LINES: u32 = 1;
+pub const PIPE_PRIM_LINE_LOOP: u32 = 2;
+pub const PIPE_PRIM_LINE_STRIP: u32 = 3;
+pub const PIPE_PRIM_TRIANGLES: u32 = 4;
+pub const PIPE_PRIM_TRIANGLE_STRIP: u32 = 5;
+pub const PIPE_PRIM_TRIANGLE_FAN: u32 = 6;
+pub const PIPE_PRIM_QUADS: u32 = 7;
+pub const PIPE_PRIM_QUAD_STRIP: u32 = 8;
+pub const PIPE_PRIM_POLYGON: u32 = 9;
+pub const PIPE_PRIM_LINES_ADJACENCY: u32 = 10;
+pub const PIPE_PRIM_LINE_STRIP_ADJACENCY: u32 = 11;
+pub const PIPE_PRIM_TRIANGLES_ADJACENCY: u32 = 12;
+pub const PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: u32 = 13;
+pub const PIPE_PRIM_PATCHES: u32 = 14;
+pub const PIPE_PRIM_MAX: u32 = 15;
+pub const PIPE_TESS_SPACING_FRACTIONAL_ODD: u32 = 0;
+pub const PIPE_TESS_SPACING_FRACTIONAL_EVEN: u32 = 1;
+pub const PIPE_TESS_SPACING_EQUAL: u32 = 2;
+pub const PIPE_QUERY_OCCLUSION_COUNTER: u32 = 0;
+pub const PIPE_QUERY_OCCLUSION_PREDICATE: u32 = 1;
+pub const PIPE_QUERY_TIMESTAMP: u32 = 2;
+pub const PIPE_QUERY_TIMESTAMP_DISJOINT: u32 = 3;
+pub const PIPE_QUERY_TIME_ELAPSED: u32 = 4;
+pub const PIPE_QUERY_PRIMITIVES_GENERATED: u32 = 5;
+pub const PIPE_QUERY_PRIMITIVES_EMITTED: u32 = 6;
+pub const PIPE_QUERY_SO_STATISTICS: u32 = 7;
+pub const PIPE_QUERY_SO_OVERFLOW_PREDICATE: u32 = 8;
+pub const PIPE_QUERY_GPU_FINISHED: u32 = 9;
+pub const PIPE_QUERY_PIPELINE_STATISTICS: u32 = 10;
+pub const PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: u32 = 11;
+pub const PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE: u32 = 12;
+pub const PIPE_QUERY_TYPES: u32 = 13;
+pub const PIPE_QUERY_DRIVER_SPECIFIC: u32 = 256;
+pub const PIPE_RENDER_COND_WAIT: u32 = 0;
+pub const PIPE_RENDER_COND_NO_WAIT: u32 = 1;
+pub const PIPE_RENDER_COND_BY_REGION_WAIT: u32 = 2;
+pub const PIPE_RENDER_COND_BY_REGION_NO_WAIT: u32 = 3;
+pub const PIPE_SPRITE_COORD_UPPER_LEFT: u32 = 0;
+pub const PIPE_SPRITE_COORD_LOWER_LEFT: u32 = 1;
+pub const PIPE_SWIZZLE_RED: u32 = 0;
+pub const PIPE_SWIZZLE_GREEN: u32 = 1;
+pub const PIPE_SWIZZLE_BLUE: u32 = 2;
+pub const PIPE_SWIZZLE_ALPHA: u32 = 3;
+pub const PIPE_SWIZZLE_ZERO: u32 = 4;
+pub const PIPE_SWIZZLE_ONE: u32 = 5;
+pub const PIPE_TIMEOUT_INFINITE: i32 = -1;
+pub const PIPE_IMAGE_ACCESS_READ: u32 = 1;
+pub const PIPE_IMAGE_ACCESS_WRITE: u32 = 2;
+pub const PIPE_IMAGE_ACCESS_READ_WRITE: u32 = 3;
+pub const PIPE_QUIRK_TEXTURE_BORDER_COLOR_SWIZZLE_NV50: u32 = 1;
+pub const PIPE_QUIRK_TEXTURE_BORDER_COLOR_SWIZZLE_R600: u32 = 2;
+pub type __uint64_t = ::std::os::raw::c_ulong;
+pub type boolean = ::std::os::raw::c_uchar;
+pub const PIPE_OK: pipe_error = 0;
+/// < Generic error
+pub const PIPE_ERROR: pipe_error = -1;
+pub const PIPE_ERROR_BAD_INPUT: pipe_error = -2;
+pub const PIPE_ERROR_OUT_OF_MEMORY: pipe_error = -3;
+pub const PIPE_ERROR_RETRY: pipe_error = -4;
+/// Gallium error codes.
+///
+/// - A zero value always means success.
+/// - A negative value always means failure.
+/// - The meaning of a positive value is function dependent.
+pub type pipe_error = i32;
+pub const PIPE_BUFFER: pipe_texture_target = 0;
+pub const PIPE_TEXTURE_1D: pipe_texture_target = 1;
+pub const PIPE_TEXTURE_2D: pipe_texture_target = 2;
+pub const PIPE_TEXTURE_3D: pipe_texture_target = 3;
+pub const PIPE_TEXTURE_CUBE: pipe_texture_target = 4;
+pub const PIPE_TEXTURE_RECT: pipe_texture_target = 5;
+pub const PIPE_TEXTURE_1D_ARRAY: pipe_texture_target = 6;
+pub const PIPE_TEXTURE_2D_ARRAY: pipe_texture_target = 7;
+pub const PIPE_TEXTURE_CUBE_ARRAY: pipe_texture_target = 8;
+pub const PIPE_MAX_TEXTURE_TYPES: pipe_texture_target = 9;
+/// Texture types.
+/// See the documentation for info on PIPE_TEXTURE_RECT vs PIPE_TEXTURE_2D
+pub type pipe_texture_target = u32;
+/// Resource contents read back (or accessed directly) at transfer
+/// create time.
+pub const PIPE_TRANSFER_READ: pipe_transfer_usage = 1;
+/// Resource contents will be written back at transfer_unmap
+/// time (or modified as a result of being accessed directly).
+pub const PIPE_TRANSFER_WRITE: pipe_transfer_usage = 2;
+/// Read/modify/write
+pub const PIPE_TRANSFER_READ_WRITE: pipe_transfer_usage = 3;
+/// The transfer should map the texture storage directly. The driver may
+/// return NULL if that isn't possible, and the state tracker needs to cope
+/// with that and use an alternative path without this flag.
+///
+/// E.g. the state tracker could have a simpler path which maps textures and
+/// does read/modify/write cycles on them directly, and a more complicated
+/// path which uses minimal read and write transfers.
+pub const PIPE_TRANSFER_MAP_DIRECTLY: pipe_transfer_usage = 4;
+/// Discards the memory within the mapped region.
+///
+/// It should not be used with PIPE_TRANSFER_READ.
+///
+/// See also:
+/// - OpenGL's ARB_map_buffer_range extension, MAP_INVALIDATE_RANGE_BIT flag.
+pub const PIPE_TRANSFER_DISCARD_RANGE: pipe_transfer_usage = 256;
+/// Fail if the resource cannot be mapped immediately.
+///
+/// See also:
+/// - Direct3D's D3DLOCK_DONOTWAIT flag.
+/// - Mesa3D's MESA_MAP_NOWAIT_BIT flag.
+/// - WDDM's D3DDDICB_LOCKFLAGS.DonotWait flag.
+pub const PIPE_TRANSFER_DONTBLOCK: pipe_transfer_usage = 512;
+/// Do not attempt to synchronize pending operations on the resource when mapping.
+///
+/// It should not be used with PIPE_TRANSFER_READ.
+///
+/// See also:
+/// - OpenGL's ARB_map_buffer_range extension, MAP_UNSYNCHRONIZED_BIT flag.
+/// - Direct3D's D3DLOCK_NOOVERWRITE flag.
+/// - WDDM's D3DDDICB_LOCKFLAGS.IgnoreSync flag.
+pub const PIPE_TRANSFER_UNSYNCHRONIZED: pipe_transfer_usage = 1024;
+/// Written ranges will be notified later with
+/// pipe_context::transfer_flush_region.
+///
+/// It should not be used with PIPE_TRANSFER_READ.
+///
+/// See also:
+/// - pipe_context::transfer_flush_region
+/// - OpenGL's ARB_map_buffer_range extension, MAP_FLUSH_EXPLICIT_BIT flag.
+pub const PIPE_TRANSFER_FLUSH_EXPLICIT: pipe_transfer_usage = 2048;
+/// Discards all memory backing the resource.
+///
+/// It should not be used with PIPE_TRANSFER_READ.
+///
+/// This is equivalent to:
+/// - OpenGL's ARB_map_buffer_range extension, MAP_INVALIDATE_BUFFER_BIT
+/// - BufferData(NULL) on a GL buffer
+/// - Direct3D's D3DLOCK_DISCARD flag.
+/// - WDDM's D3DDDICB_LOCKFLAGS.Discard flag.
+/// - D3D10 DDI's D3D10_DDI_MAP_WRITE_DISCARD flag
+/// - D3D10's D3D10_MAP_WRITE_DISCARD flag.
+pub const PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE: pipe_transfer_usage = 4096;
+/// Allows the resource to be used for rendering while mapped.
+///
+/// PIPE_RESOURCE_FLAG_MAP_PERSISTENT must be set when creating
+/// the resource.
+///
+/// If COHERENT is not set, memory_barrier(PIPE_BARRIER_MAPPED_BUFFER)
+/// must be called to ensure the device can see what the CPU has written.
+pub const PIPE_TRANSFER_PERSISTENT: pipe_transfer_usage = 8192;
+/// If PERSISTENT is set, this ensures any writes done by the device are
+/// immediately visible to the CPU and vice versa.
+///
+/// PIPE_RESOURCE_FLAG_MAP_COHERENT must be set when creating
+/// the resource.
+pub const PIPE_TRANSFER_COHERENT: pipe_transfer_usage = 16384;
+/// Transfer object usage flags
+pub type pipe_transfer_usage = u32;
+pub const PIPE_FLUSH_END_OF_FRAME: pipe_flush_flags = 1;
+/// Flags for the flush function.
+pub type pipe_flush_flags = u32;
+pub const PIPE_CAP_NPOT_TEXTURES: pipe_cap = 1;
+pub const PIPE_CAP_TWO_SIDED_STENCIL: pipe_cap = 2;
+pub const PIPE_CAP_MAX_DUAL_SOURCE_RENDER_TARGETS: pipe_cap = 4;
+pub const PIPE_CAP_ANISOTROPIC_FILTER: pipe_cap = 5;
+pub const PIPE_CAP_POINT_SPRITE: pipe_cap = 6;
+pub const PIPE_CAP_MAX_RENDER_TARGETS: pipe_cap = 7;
+pub const PIPE_CAP_OCCLUSION_QUERY: pipe_cap = 8;
+pub const PIPE_CAP_QUERY_TIME_ELAPSED: pipe_cap = 9;
+pub const PIPE_CAP_TEXTURE_SHADOW_MAP: pipe_cap = 10;
+pub const PIPE_CAP_TEXTURE_SWIZZLE: pipe_cap = 11;
+pub const PIPE_CAP_MAX_TEXTURE_2D_LEVELS: pipe_cap = 12;
+pub const PIPE_CAP_MAX_TEXTURE_3D_LEVELS: pipe_cap = 13;
+pub const PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS: pipe_cap = 14;
+pub const PIPE_CAP_TEXTURE_MIRROR_CLAMP: pipe_cap = 25;
+pub const PIPE_CAP_BLEND_EQUATION_SEPARATE: pipe_cap = 28;
+pub const PIPE_CAP_SM3: pipe_cap = 29;
+pub const PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS: pipe_cap = 30;
+pub const PIPE_CAP_PRIMITIVE_RESTART: pipe_cap = 31;
+/// blend enables and write masks per rendertarget
+pub const PIPE_CAP_INDEP_BLEND_ENABLE: pipe_cap = 33;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_INDEP_BLEND_FUNC: pipe_cap = 34;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS: pipe_cap = 36;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT: pipe_cap = 37;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT: pipe_cap = 38;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER: pipe_cap = 39;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER: pipe_cap = 40;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_DEPTH_CLIP_DISABLE: pipe_cap = 41;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_SHADER_STENCIL_EXPORT: pipe_cap = 42;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TGSI_INSTANCEID: pipe_cap = 43;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_VERTEX_ELEMENT_INSTANCE_DIVISOR: pipe_cap = 44;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_FRAGMENT_COLOR_CLAMPED: pipe_cap = 45;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MIXED_COLORBUFFER_FORMATS: pipe_cap = 46;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_SEAMLESS_CUBE_MAP: pipe_cap = 47;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE: pipe_cap = 48;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MIN_TEXEL_OFFSET: pipe_cap = 50;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MAX_TEXEL_OFFSET: pipe_cap = 51;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_CONDITIONAL_RENDER: pipe_cap = 52;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TEXTURE_BARRIER: pipe_cap = 53;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_COMPONENTS: pipe_cap = 55;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MAX_STREAM_OUTPUT_INTERLEAVED_COMPONENTS: pipe_cap = 56;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_STREAM_OUTPUT_PAUSE_RESUME: pipe_cap = 57;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TGSI_CAN_COMPACT_CONSTANTS: pipe_cap = 59;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_VERTEX_COLOR_UNCLAMPED: pipe_cap = 60;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_VERTEX_COLOR_CLAMPED: pipe_cap = 61;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_GLSL_FEATURE_LEVEL: pipe_cap = 62;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION: pipe_cap = 63;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_USER_VERTEX_BUFFERS: pipe_cap = 64;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_VERTEX_BUFFER_OFFSET_4BYTE_ALIGNED_ONLY: pipe_cap = 65;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_VERTEX_BUFFER_STRIDE_4BYTE_ALIGNED_ONLY: pipe_cap = 66;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_VERTEX_ELEMENT_SRC_OFFSET_4BYTE_ALIGNED_ONLY: pipe_cap = 67;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_COMPUTE: pipe_cap = 68;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_USER_INDEX_BUFFERS: pipe_cap = 69;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_USER_CONSTANT_BUFFERS: pipe_cap = 70;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT: pipe_cap = 71;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_START_INSTANCE: pipe_cap = 72;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_QUERY_TIMESTAMP: pipe_cap = 73;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TEXTURE_MULTISAMPLE: pipe_cap = 74;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MIN_MAP_BUFFER_ALIGNMENT: pipe_cap = 75;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_CUBE_MAP_ARRAY: pipe_cap = 76;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TEXTURE_BUFFER_OBJECTS: pipe_cap = 77;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT: pipe_cap = 78;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TGSI_TEXCOORD: pipe_cap = 79;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER: pipe_cap = 80;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_QUERY_PIPELINE_STATISTICS: pipe_cap = 81;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TEXTURE_BORDER_COLOR_QUIRK: pipe_cap = 82;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MAX_TEXTURE_BUFFER_SIZE: pipe_cap = 83;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MAX_VIEWPORTS: pipe_cap = 84;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_ENDIANNESS: pipe_cap = 85;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MIXED_FRAMEBUFFER_SIZES: pipe_cap = 86;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TGSI_VS_LAYER_VIEWPORT: pipe_cap = 87;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MAX_GEOMETRY_OUTPUT_VERTICES: pipe_cap = 88;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS: pipe_cap = 89;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MAX_TEXTURE_GATHER_COMPONENTS: pipe_cap = 90;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TEXTURE_GATHER_SM5: pipe_cap = 91;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_BUFFER_MAP_PERSISTENT_COHERENT: pipe_cap = 92;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_FAKE_SW_MSAA: pipe_cap = 93;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TEXTURE_QUERY_LOD: pipe_cap = 94;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MIN_TEXTURE_GATHER_OFFSET: pipe_cap = 95;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MAX_TEXTURE_GATHER_OFFSET: pipe_cap = 96;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_SAMPLE_SHADING: pipe_cap = 97;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TEXTURE_GATHER_OFFSETS: pipe_cap = 98;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TGSI_VS_WINDOW_SPACE_POSITION: pipe_cap = 99;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MAX_VERTEX_STREAMS: pipe_cap = 100;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_DRAW_INDIRECT: pipe_cap = 101;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_TGSI_FS_FINE_DERIVATIVE: pipe_cap = 102;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_VENDOR_ID: pipe_cap = 103;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_DEVICE_ID: pipe_cap = 104;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_ACCELERATED: pipe_cap = 105;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_VIDEO_MEMORY: pipe_cap = 106;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_UMA: pipe_cap = 107;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_CONDITIONAL_RENDER_INVERTED: pipe_cap = 108;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_MAX_VERTEX_ATTRIB_STRIDE: pipe_cap = 109;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_SAMPLER_VIEW_TARGET: pipe_cap = 110;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_CLIP_HALFZ: pipe_cap = 111;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_VERTEXID_NOBASE: pipe_cap = 112;
+/// different blend funcs per rendertarget
+pub const PIPE_CAP_POLYGON_OFFSET_CLAMP: pipe_cap = 113;
+/// Implementation capabilities/limits which are queried through
+/// pipe_screen::get_param()
+pub type pipe_cap = u32;
+pub const PIPE_ENDIAN_LITTLE: pipe_endian = 0;
+pub const PIPE_ENDIAN_BIG: pipe_endian = 1;
+pub const PIPE_ENDIAN_NATIVE: pipe_endian = 0;
+pub type pipe_endian = u32;
+pub const PIPE_CAPF_MAX_LINE_WIDTH: pipe_capf = 0;
+pub const PIPE_CAPF_MAX_LINE_WIDTH_AA: pipe_capf = 1;
+pub const PIPE_CAPF_MAX_POINT_WIDTH: pipe_capf = 2;
+pub const PIPE_CAPF_MAX_POINT_WIDTH_AA: pipe_capf = 3;
+pub const PIPE_CAPF_MAX_TEXTURE_ANISOTROPY: pipe_capf = 4;
+pub const PIPE_CAPF_MAX_TEXTURE_LOD_BIAS: pipe_capf = 5;
+pub const PIPE_CAPF_GUARD_BAND_LEFT: pipe_capf = 6;
+pub const PIPE_CAPF_GUARD_BAND_TOP: pipe_capf = 7;
+pub const PIPE_CAPF_GUARD_BAND_RIGHT: pipe_capf = 8;
+pub const PIPE_CAPF_GUARD_BAND_BOTTOM: pipe_capf = 9;
+/// Implementation limits which are queried through
+/// pipe_screen::get_paramf()
+pub type pipe_capf = u32;
+pub const PIPE_SHADER_CAP_MAX_INSTRUCTIONS: pipe_shader_cap = 0;
+pub const PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS: pipe_shader_cap = 1;
+pub const PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS: pipe_shader_cap = 2;
+pub const PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS: pipe_shader_cap = 3;
+pub const PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH: pipe_shader_cap = 4;
+pub const PIPE_SHADER_CAP_MAX_INPUTS: pipe_shader_cap = 5;
+pub const PIPE_SHADER_CAP_MAX_OUTPUTS: pipe_shader_cap = 6;
+pub const PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE: pipe_shader_cap = 7;
+pub const PIPE_SHADER_CAP_MAX_CONST_BUFFERS: pipe_shader_cap = 8;
+pub const PIPE_SHADER_CAP_MAX_TEMPS: pipe_shader_cap = 9;
+pub const PIPE_SHADER_CAP_MAX_PREDS: pipe_shader_cap = 10;
+pub const PIPE_SHADER_CAP_TGSI_CONT_SUPPORTED: pipe_shader_cap = 11;
+pub const PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR: pipe_shader_cap = 12;
+pub const PIPE_SHADER_CAP_INDIRECT_OUTPUT_ADDR: pipe_shader_cap = 13;
+pub const PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR: pipe_shader_cap = 14;
+pub const PIPE_SHADER_CAP_INDIRECT_CONST_ADDR: pipe_shader_cap = 15;
+pub const PIPE_SHADER_CAP_SUBROUTINES: pipe_shader_cap = 16;
+pub const PIPE_SHADER_CAP_INTEGERS: pipe_shader_cap = 17;
+pub const PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS: pipe_shader_cap = 18;
+pub const PIPE_SHADER_CAP_PREFERRED_IR: pipe_shader_cap = 19;
+pub const PIPE_SHADER_CAP_TGSI_SQRT_SUPPORTED: pipe_shader_cap = 20;
+pub const PIPE_SHADER_CAP_MAX_SAMPLER_VIEWS: pipe_shader_cap = 21;
+pub const PIPE_SHADER_CAP_DOUBLES: pipe_shader_cap = 22;
+pub type pipe_shader_cap = u32;
+pub const PIPE_SHADER_IR_TGSI: pipe_shader_ir = 0;
+pub const PIPE_SHADER_IR_LLVM: pipe_shader_ir = 1;
+pub const PIPE_SHADER_IR_NATIVE: pipe_shader_ir = 2;
+/// Shader intermediate representation.
+pub type pipe_shader_ir = u32;
+pub const PIPE_COMPUTE_CAP_IR_TARGET: pipe_compute_cap = 0;
+pub const PIPE_COMPUTE_CAP_GRID_DIMENSION: pipe_compute_cap = 1;
+pub const PIPE_COMPUTE_CAP_MAX_GRID_SIZE: pipe_compute_cap = 2;
+pub const PIPE_COMPUTE_CAP_MAX_BLOCK_SIZE: pipe_compute_cap = 3;
+pub const PIPE_COMPUTE_CAP_MAX_THREADS_PER_BLOCK: pipe_compute_cap = 4;
+pub const PIPE_COMPUTE_CAP_MAX_GLOBAL_SIZE: pipe_compute_cap = 5;
+pub const PIPE_COMPUTE_CAP_MAX_LOCAL_SIZE: pipe_compute_cap = 6;
+pub const PIPE_COMPUTE_CAP_MAX_PRIVATE_SIZE: pipe_compute_cap = 7;
+pub const PIPE_COMPUTE_CAP_MAX_INPUT_SIZE: pipe_compute_cap = 8;
+pub const PIPE_COMPUTE_CAP_MAX_MEM_ALLOC_SIZE: pipe_compute_cap = 9;
+pub const PIPE_COMPUTE_CAP_MAX_CLOCK_FREQUENCY: pipe_compute_cap = 10;
+pub const PIPE_COMPUTE_CAP_MAX_COMPUTE_UNITS: pipe_compute_cap = 11;
+pub const PIPE_COMPUTE_CAP_IMAGES_SUPPORTED: pipe_compute_cap = 12;
+/// Compute-specific implementation capability.  They can be queried
+/// using pipe_screen::get_compute_param.
+pub type pipe_compute_cap = u32;
+/// Query result for PIPE_QUERY_SO_STATISTICS.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct pipe_query_data_so_statistics {
+    pub num_primitives_written: u64,
+    pub primitives_storage_needed: u64,
+}
+/// Query result for PIPE_QUERY_TIMESTAMP_DISJOINT.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct pipe_query_data_timestamp_disjoint {
+    pub frequency: u64,
+    pub disjoint: boolean,
+}
+/// Query result for PIPE_QUERY_PIPELINE_STATISTICS.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct pipe_query_data_pipeline_statistics {
+    /// < Num vertices read by the vertex fetcher.
+    pub ia_vertices: u64,
+    /// < Num primitives read by the vertex fetcher.
+    pub ia_primitives: u64,
+    /// < Num vertex shader invocations.
+    pub vs_invocations: u64,
+    /// < Num geometry shader invocations.
+    pub gs_invocations: u64,
+    /// < Num primitives output by a geometry shader.
+    pub gs_primitives: u64,
+    /// < Num primitives sent to the rasterizer.
+    pub c_invocations: u64,
+    /// < Num primitives that were rendered.
+    pub c_primitives: u64,
+    /// < Num pixel shader invocations.
+    pub ps_invocations: u64,
+    /// < Num hull shader invocations.
+    pub hs_invocations: u64,
+    /// < Num domain shader invocations.
+    pub ds_invocations: u64,
+    /// < Num compute shader invocations.
+    pub cs_invocations: u64,
+}
+/// Query result (returned by pipe_context::get_query_result).
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pipe_query_result {
+    pub b: boolean,
+    pub u64: u64,
+    pub so_statistics: pipe_query_data_so_statistics,
+    pub timestamp_disjoint: pipe_query_data_timestamp_disjoint,
+    pub pipeline_statistics: pipe_query_data_pipeline_statistics,
+    _bindgen_union_align: [u64; 11usize],
+}
+pub const PIPE_QUERY_TYPE_I32: pipe_query_value_type = 0;
+pub const PIPE_QUERY_TYPE_U32: pipe_query_value_type = 1;
+pub const PIPE_QUERY_TYPE_I64: pipe_query_value_type = 2;
+pub const PIPE_QUERY_TYPE_U64: pipe_query_value_type = 3;
+pub type pipe_query_value_type = u32;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pipe_color_union {
+    pub f: [f32; 4usize],
+    pub i: [::std::os::raw::c_int; 4usize],
+    pub ui: [::std::os::raw::c_uint; 4usize],
+    _bindgen_union_align: [u32; 4usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct pipe_driver_query_info {
+    pub name: *const ::std::os::raw::c_char,
+    pub query_type: ::std::os::raw::c_uint,
+    pub max_value: u64,
+    pub uses_byte_units: boolean,
+}
diff --git a/gpu_renderer/src/generated/p_format.rs b/gpu_renderer/src/generated/p_format.rs
new file mode 100644
index 0000000..709fa4d
--- /dev/null
+++ b/gpu_renderer/src/generated/p_format.rs
@@ -0,0 +1,323 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+pub const PIPE_FORMAT_NONE: pipe_format = 0;
+pub const PIPE_FORMAT_B8G8R8A8_UNORM: pipe_format = 1;
+pub const PIPE_FORMAT_B8G8R8X8_UNORM: pipe_format = 2;
+pub const PIPE_FORMAT_A8R8G8B8_UNORM: pipe_format = 3;
+pub const PIPE_FORMAT_X8R8G8B8_UNORM: pipe_format = 4;
+pub const PIPE_FORMAT_B5G5R5A1_UNORM: pipe_format = 5;
+pub const PIPE_FORMAT_B4G4R4A4_UNORM: pipe_format = 6;
+pub const PIPE_FORMAT_B5G6R5_UNORM: pipe_format = 7;
+pub const PIPE_FORMAT_R10G10B10A2_UNORM: pipe_format = 8;
+/// < ubyte luminance
+pub const PIPE_FORMAT_L8_UNORM: pipe_format = 9;
+/// < ubyte alpha
+pub const PIPE_FORMAT_A8_UNORM: pipe_format = 10;
+/// < ubyte intensity
+pub const PIPE_FORMAT_I8_UNORM: pipe_format = 11;
+/// < ubyte alpha, luminance
+pub const PIPE_FORMAT_L8A8_UNORM: pipe_format = 12;
+/// < ushort luminance
+pub const PIPE_FORMAT_L16_UNORM: pipe_format = 13;
+pub const PIPE_FORMAT_UYVY: pipe_format = 14;
+pub const PIPE_FORMAT_YUYV: pipe_format = 15;
+pub const PIPE_FORMAT_Z16_UNORM: pipe_format = 16;
+pub const PIPE_FORMAT_Z32_UNORM: pipe_format = 17;
+pub const PIPE_FORMAT_Z32_FLOAT: pipe_format = 18;
+pub const PIPE_FORMAT_Z24_UNORM_S8_UINT: pipe_format = 19;
+pub const PIPE_FORMAT_S8_UINT_Z24_UNORM: pipe_format = 20;
+pub const PIPE_FORMAT_Z24X8_UNORM: pipe_format = 21;
+pub const PIPE_FORMAT_X8Z24_UNORM: pipe_format = 22;
+/// < ubyte stencil
+pub const PIPE_FORMAT_S8_UINT: pipe_format = 23;
+pub const PIPE_FORMAT_R64_FLOAT: pipe_format = 24;
+pub const PIPE_FORMAT_R64G64_FLOAT: pipe_format = 25;
+pub const PIPE_FORMAT_R64G64B64_FLOAT: pipe_format = 26;
+pub const PIPE_FORMAT_R64G64B64A64_FLOAT: pipe_format = 27;
+pub const PIPE_FORMAT_R32_FLOAT: pipe_format = 28;
+pub const PIPE_FORMAT_R32G32_FLOAT: pipe_format = 29;
+pub const PIPE_FORMAT_R32G32B32_FLOAT: pipe_format = 30;
+pub const PIPE_FORMAT_R32G32B32A32_FLOAT: pipe_format = 31;
+pub const PIPE_FORMAT_R32_UNORM: pipe_format = 32;
+pub const PIPE_FORMAT_R32G32_UNORM: pipe_format = 33;
+pub const PIPE_FORMAT_R32G32B32_UNORM: pipe_format = 34;
+pub const PIPE_FORMAT_R32G32B32A32_UNORM: pipe_format = 35;
+pub const PIPE_FORMAT_R32_USCALED: pipe_format = 36;
+pub const PIPE_FORMAT_R32G32_USCALED: pipe_format = 37;
+pub const PIPE_FORMAT_R32G32B32_USCALED: pipe_format = 38;
+pub const PIPE_FORMAT_R32G32B32A32_USCALED: pipe_format = 39;
+pub const PIPE_FORMAT_R32_SNORM: pipe_format = 40;
+pub const PIPE_FORMAT_R32G32_SNORM: pipe_format = 41;
+pub const PIPE_FORMAT_R32G32B32_SNORM: pipe_format = 42;
+pub const PIPE_FORMAT_R32G32B32A32_SNORM: pipe_format = 43;
+pub const PIPE_FORMAT_R32_SSCALED: pipe_format = 44;
+pub const PIPE_FORMAT_R32G32_SSCALED: pipe_format = 45;
+pub const PIPE_FORMAT_R32G32B32_SSCALED: pipe_format = 46;
+pub const PIPE_FORMAT_R32G32B32A32_SSCALED: pipe_format = 47;
+pub const PIPE_FORMAT_R16_UNORM: pipe_format = 48;
+pub const PIPE_FORMAT_R16G16_UNORM: pipe_format = 49;
+pub const PIPE_FORMAT_R16G16B16_UNORM: pipe_format = 50;
+pub const PIPE_FORMAT_R16G16B16A16_UNORM: pipe_format = 51;
+pub const PIPE_FORMAT_R16_USCALED: pipe_format = 52;
+pub const PIPE_FORMAT_R16G16_USCALED: pipe_format = 53;
+pub const PIPE_FORMAT_R16G16B16_USCALED: pipe_format = 54;
+pub const PIPE_FORMAT_R16G16B16A16_USCALED: pipe_format = 55;
+pub const PIPE_FORMAT_R16_SNORM: pipe_format = 56;
+pub const PIPE_FORMAT_R16G16_SNORM: pipe_format = 57;
+pub const PIPE_FORMAT_R16G16B16_SNORM: pipe_format = 58;
+pub const PIPE_FORMAT_R16G16B16A16_SNORM: pipe_format = 59;
+pub const PIPE_FORMAT_R16_SSCALED: pipe_format = 60;
+pub const PIPE_FORMAT_R16G16_SSCALED: pipe_format = 61;
+pub const PIPE_FORMAT_R16G16B16_SSCALED: pipe_format = 62;
+pub const PIPE_FORMAT_R16G16B16A16_SSCALED: pipe_format = 63;
+pub const PIPE_FORMAT_R8_UNORM: pipe_format = 64;
+pub const PIPE_FORMAT_R8G8_UNORM: pipe_format = 65;
+pub const PIPE_FORMAT_R8G8B8_UNORM: pipe_format = 66;
+pub const PIPE_FORMAT_R8G8B8A8_UNORM: pipe_format = 67;
+pub const PIPE_FORMAT_X8B8G8R8_UNORM: pipe_format = 68;
+pub const PIPE_FORMAT_R8_USCALED: pipe_format = 69;
+pub const PIPE_FORMAT_R8G8_USCALED: pipe_format = 70;
+pub const PIPE_FORMAT_R8G8B8_USCALED: pipe_format = 71;
+pub const PIPE_FORMAT_R8G8B8A8_USCALED: pipe_format = 72;
+pub const PIPE_FORMAT_R8_SNORM: pipe_format = 74;
+pub const PIPE_FORMAT_R8G8_SNORM: pipe_format = 75;
+pub const PIPE_FORMAT_R8G8B8_SNORM: pipe_format = 76;
+pub const PIPE_FORMAT_R8G8B8A8_SNORM: pipe_format = 77;
+pub const PIPE_FORMAT_R8_SSCALED: pipe_format = 82;
+pub const PIPE_FORMAT_R8G8_SSCALED: pipe_format = 83;
+pub const PIPE_FORMAT_R8G8B8_SSCALED: pipe_format = 84;
+pub const PIPE_FORMAT_R8G8B8A8_SSCALED: pipe_format = 85;
+pub const PIPE_FORMAT_R32_FIXED: pipe_format = 87;
+pub const PIPE_FORMAT_R32G32_FIXED: pipe_format = 88;
+pub const PIPE_FORMAT_R32G32B32_FIXED: pipe_format = 89;
+pub const PIPE_FORMAT_R32G32B32A32_FIXED: pipe_format = 90;
+pub const PIPE_FORMAT_R16_FLOAT: pipe_format = 91;
+pub const PIPE_FORMAT_R16G16_FLOAT: pipe_format = 92;
+pub const PIPE_FORMAT_R16G16B16_FLOAT: pipe_format = 93;
+pub const PIPE_FORMAT_R16G16B16A16_FLOAT: pipe_format = 94;
+pub const PIPE_FORMAT_L8_SRGB: pipe_format = 95;
+pub const PIPE_FORMAT_L8A8_SRGB: pipe_format = 96;
+pub const PIPE_FORMAT_R8G8B8_SRGB: pipe_format = 97;
+pub const PIPE_FORMAT_A8B8G8R8_SRGB: pipe_format = 98;
+pub const PIPE_FORMAT_X8B8G8R8_SRGB: pipe_format = 99;
+pub const PIPE_FORMAT_B8G8R8A8_SRGB: pipe_format = 100;
+pub const PIPE_FORMAT_B8G8R8X8_SRGB: pipe_format = 101;
+pub const PIPE_FORMAT_A8R8G8B8_SRGB: pipe_format = 102;
+pub const PIPE_FORMAT_X8R8G8B8_SRGB: pipe_format = 103;
+pub const PIPE_FORMAT_R8G8B8A8_SRGB: pipe_format = 104;
+pub const PIPE_FORMAT_DXT1_RGB: pipe_format = 105;
+pub const PIPE_FORMAT_DXT1_RGBA: pipe_format = 106;
+pub const PIPE_FORMAT_DXT3_RGBA: pipe_format = 107;
+pub const PIPE_FORMAT_DXT5_RGBA: pipe_format = 108;
+pub const PIPE_FORMAT_DXT1_SRGB: pipe_format = 109;
+pub const PIPE_FORMAT_DXT1_SRGBA: pipe_format = 110;
+pub const PIPE_FORMAT_DXT3_SRGBA: pipe_format = 111;
+pub const PIPE_FORMAT_DXT5_SRGBA: pipe_format = 112;
+pub const PIPE_FORMAT_RGTC1_UNORM: pipe_format = 113;
+pub const PIPE_FORMAT_RGTC1_SNORM: pipe_format = 114;
+pub const PIPE_FORMAT_RGTC2_UNORM: pipe_format = 115;
+pub const PIPE_FORMAT_RGTC2_SNORM: pipe_format = 116;
+pub const PIPE_FORMAT_R8G8_B8G8_UNORM: pipe_format = 117;
+pub const PIPE_FORMAT_G8R8_G8B8_UNORM: pipe_format = 118;
+pub const PIPE_FORMAT_R8SG8SB8UX8U_NORM: pipe_format = 119;
+pub const PIPE_FORMAT_R5SG5SB6U_NORM: pipe_format = 120;
+pub const PIPE_FORMAT_A8B8G8R8_UNORM: pipe_format = 121;
+pub const PIPE_FORMAT_B5G5R5X1_UNORM: pipe_format = 122;
+pub const PIPE_FORMAT_R10G10B10A2_USCALED: pipe_format = 123;
+pub const PIPE_FORMAT_R11G11B10_FLOAT: pipe_format = 124;
+pub const PIPE_FORMAT_R9G9B9E5_FLOAT: pipe_format = 125;
+pub const PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: pipe_format = 126;
+pub const PIPE_FORMAT_R1_UNORM: pipe_format = 127;
+pub const PIPE_FORMAT_R10G10B10X2_USCALED: pipe_format = 128;
+pub const PIPE_FORMAT_R10G10B10X2_SNORM: pipe_format = 129;
+pub const PIPE_FORMAT_L4A4_UNORM: pipe_format = 130;
+pub const PIPE_FORMAT_B10G10R10A2_UNORM: pipe_format = 131;
+pub const PIPE_FORMAT_R10SG10SB10SA2U_NORM: pipe_format = 132;
+pub const PIPE_FORMAT_R8G8Bx_SNORM: pipe_format = 133;
+pub const PIPE_FORMAT_R8G8B8X8_UNORM: pipe_format = 134;
+pub const PIPE_FORMAT_B4G4R4X4_UNORM: pipe_format = 135;
+pub const PIPE_FORMAT_X24S8_UINT: pipe_format = 136;
+pub const PIPE_FORMAT_S8X24_UINT: pipe_format = 137;
+pub const PIPE_FORMAT_X32_S8X24_UINT: pipe_format = 138;
+pub const PIPE_FORMAT_B2G3R3_UNORM: pipe_format = 139;
+pub const PIPE_FORMAT_L16A16_UNORM: pipe_format = 140;
+pub const PIPE_FORMAT_A16_UNORM: pipe_format = 141;
+pub const PIPE_FORMAT_I16_UNORM: pipe_format = 142;
+pub const PIPE_FORMAT_LATC1_UNORM: pipe_format = 143;
+pub const PIPE_FORMAT_LATC1_SNORM: pipe_format = 144;
+pub const PIPE_FORMAT_LATC2_UNORM: pipe_format = 145;
+pub const PIPE_FORMAT_LATC2_SNORM: pipe_format = 146;
+pub const PIPE_FORMAT_A8_SNORM: pipe_format = 147;
+pub const PIPE_FORMAT_L8_SNORM: pipe_format = 148;
+pub const PIPE_FORMAT_L8A8_SNORM: pipe_format = 149;
+pub const PIPE_FORMAT_I8_SNORM: pipe_format = 150;
+pub const PIPE_FORMAT_A16_SNORM: pipe_format = 151;
+pub const PIPE_FORMAT_L16_SNORM: pipe_format = 152;
+pub const PIPE_FORMAT_L16A16_SNORM: pipe_format = 153;
+pub const PIPE_FORMAT_I16_SNORM: pipe_format = 154;
+pub const PIPE_FORMAT_A16_FLOAT: pipe_format = 155;
+pub const PIPE_FORMAT_L16_FLOAT: pipe_format = 156;
+pub const PIPE_FORMAT_L16A16_FLOAT: pipe_format = 157;
+pub const PIPE_FORMAT_I16_FLOAT: pipe_format = 158;
+pub const PIPE_FORMAT_A32_FLOAT: pipe_format = 159;
+pub const PIPE_FORMAT_L32_FLOAT: pipe_format = 160;
+pub const PIPE_FORMAT_L32A32_FLOAT: pipe_format = 161;
+pub const PIPE_FORMAT_I32_FLOAT: pipe_format = 162;
+pub const PIPE_FORMAT_YV12: pipe_format = 163;
+pub const PIPE_FORMAT_YV16: pipe_format = 164;
+/// < aka I420
+pub const PIPE_FORMAT_IYUV: pipe_format = 165;
+pub const PIPE_FORMAT_NV12: pipe_format = 166;
+pub const PIPE_FORMAT_NV21: pipe_format = 167;
+pub const PIPE_FORMAT_A4R4_UNORM: pipe_format = 168;
+pub const PIPE_FORMAT_R4A4_UNORM: pipe_format = 169;
+pub const PIPE_FORMAT_R8A8_UNORM: pipe_format = 170;
+pub const PIPE_FORMAT_A8R8_UNORM: pipe_format = 171;
+pub const PIPE_FORMAT_R10G10B10A2_SSCALED: pipe_format = 172;
+pub const PIPE_FORMAT_R10G10B10A2_SNORM: pipe_format = 173;
+pub const PIPE_FORMAT_B10G10R10A2_USCALED: pipe_format = 174;
+pub const PIPE_FORMAT_B10G10R10A2_SSCALED: pipe_format = 175;
+pub const PIPE_FORMAT_B10G10R10A2_SNORM: pipe_format = 176;
+pub const PIPE_FORMAT_R8_UINT: pipe_format = 177;
+pub const PIPE_FORMAT_R8G8_UINT: pipe_format = 178;
+pub const PIPE_FORMAT_R8G8B8_UINT: pipe_format = 179;
+pub const PIPE_FORMAT_R8G8B8A8_UINT: pipe_format = 180;
+pub const PIPE_FORMAT_R8_SINT: pipe_format = 181;
+pub const PIPE_FORMAT_R8G8_SINT: pipe_format = 182;
+pub const PIPE_FORMAT_R8G8B8_SINT: pipe_format = 183;
+pub const PIPE_FORMAT_R8G8B8A8_SINT: pipe_format = 184;
+pub const PIPE_FORMAT_R16_UINT: pipe_format = 185;
+pub const PIPE_FORMAT_R16G16_UINT: pipe_format = 186;
+pub const PIPE_FORMAT_R16G16B16_UINT: pipe_format = 187;
+pub const PIPE_FORMAT_R16G16B16A16_UINT: pipe_format = 188;
+pub const PIPE_FORMAT_R16_SINT: pipe_format = 189;
+pub const PIPE_FORMAT_R16G16_SINT: pipe_format = 190;
+pub const PIPE_FORMAT_R16G16B16_SINT: pipe_format = 191;
+pub const PIPE_FORMAT_R16G16B16A16_SINT: pipe_format = 192;
+pub const PIPE_FORMAT_R32_UINT: pipe_format = 193;
+pub const PIPE_FORMAT_R32G32_UINT: pipe_format = 194;
+pub const PIPE_FORMAT_R32G32B32_UINT: pipe_format = 195;
+pub const PIPE_FORMAT_R32G32B32A32_UINT: pipe_format = 196;
+pub const PIPE_FORMAT_R32_SINT: pipe_format = 197;
+pub const PIPE_FORMAT_R32G32_SINT: pipe_format = 198;
+pub const PIPE_FORMAT_R32G32B32_SINT: pipe_format = 199;
+pub const PIPE_FORMAT_R32G32B32A32_SINT: pipe_format = 200;
+pub const PIPE_FORMAT_A8_UINT: pipe_format = 201;
+pub const PIPE_FORMAT_I8_UINT: pipe_format = 202;
+pub const PIPE_FORMAT_L8_UINT: pipe_format = 203;
+pub const PIPE_FORMAT_L8A8_UINT: pipe_format = 204;
+pub const PIPE_FORMAT_A8_SINT: pipe_format = 205;
+pub const PIPE_FORMAT_I8_SINT: pipe_format = 206;
+pub const PIPE_FORMAT_L8_SINT: pipe_format = 207;
+pub const PIPE_FORMAT_L8A8_SINT: pipe_format = 208;
+pub const PIPE_FORMAT_A16_UINT: pipe_format = 209;
+pub const PIPE_FORMAT_I16_UINT: pipe_format = 210;
+pub const PIPE_FORMAT_L16_UINT: pipe_format = 211;
+pub const PIPE_FORMAT_L16A16_UINT: pipe_format = 212;
+pub const PIPE_FORMAT_A16_SINT: pipe_format = 213;
+pub const PIPE_FORMAT_I16_SINT: pipe_format = 214;
+pub const PIPE_FORMAT_L16_SINT: pipe_format = 215;
+pub const PIPE_FORMAT_L16A16_SINT: pipe_format = 216;
+pub const PIPE_FORMAT_A32_UINT: pipe_format = 217;
+pub const PIPE_FORMAT_I32_UINT: pipe_format = 218;
+pub const PIPE_FORMAT_L32_UINT: pipe_format = 219;
+pub const PIPE_FORMAT_L32A32_UINT: pipe_format = 220;
+pub const PIPE_FORMAT_A32_SINT: pipe_format = 221;
+pub const PIPE_FORMAT_I32_SINT: pipe_format = 222;
+pub const PIPE_FORMAT_L32_SINT: pipe_format = 223;
+pub const PIPE_FORMAT_L32A32_SINT: pipe_format = 224;
+pub const PIPE_FORMAT_B10G10R10A2_UINT: pipe_format = 225;
+pub const PIPE_FORMAT_ETC1_RGB8: pipe_format = 226;
+pub const PIPE_FORMAT_R8G8_R8B8_UNORM: pipe_format = 227;
+pub const PIPE_FORMAT_G8R8_B8R8_UNORM: pipe_format = 228;
+pub const PIPE_FORMAT_R8G8B8X8_SNORM: pipe_format = 229;
+pub const PIPE_FORMAT_R8G8B8X8_SRGB: pipe_format = 230;
+pub const PIPE_FORMAT_R8G8B8X8_UINT: pipe_format = 231;
+pub const PIPE_FORMAT_R8G8B8X8_SINT: pipe_format = 232;
+pub const PIPE_FORMAT_B10G10R10X2_UNORM: pipe_format = 233;
+pub const PIPE_FORMAT_R16G16B16X16_UNORM: pipe_format = 234;
+pub const PIPE_FORMAT_R16G16B16X16_SNORM: pipe_format = 235;
+pub const PIPE_FORMAT_R16G16B16X16_FLOAT: pipe_format = 236;
+pub const PIPE_FORMAT_R16G16B16X16_UINT: pipe_format = 237;
+pub const PIPE_FORMAT_R16G16B16X16_SINT: pipe_format = 238;
+pub const PIPE_FORMAT_R32G32B32X32_FLOAT: pipe_format = 239;
+pub const PIPE_FORMAT_R32G32B32X32_UINT: pipe_format = 240;
+pub const PIPE_FORMAT_R32G32B32X32_SINT: pipe_format = 241;
+pub const PIPE_FORMAT_R8A8_SNORM: pipe_format = 242;
+pub const PIPE_FORMAT_R16A16_UNORM: pipe_format = 243;
+pub const PIPE_FORMAT_R16A16_SNORM: pipe_format = 244;
+pub const PIPE_FORMAT_R16A16_FLOAT: pipe_format = 245;
+pub const PIPE_FORMAT_R32A32_FLOAT: pipe_format = 246;
+pub const PIPE_FORMAT_R8A8_UINT: pipe_format = 247;
+pub const PIPE_FORMAT_R8A8_SINT: pipe_format = 248;
+pub const PIPE_FORMAT_R16A16_UINT: pipe_format = 249;
+pub const PIPE_FORMAT_R16A16_SINT: pipe_format = 250;
+pub const PIPE_FORMAT_R32A32_UINT: pipe_format = 251;
+pub const PIPE_FORMAT_R32A32_SINT: pipe_format = 252;
+pub const PIPE_FORMAT_R10G10B10A2_UINT: pipe_format = 253;
+pub const PIPE_FORMAT_B5G6R5_SRGB: pipe_format = 254;
+pub const PIPE_FORMAT_BPTC_RGBA_UNORM: pipe_format = 255;
+pub const PIPE_FORMAT_BPTC_SRGBA: pipe_format = 256;
+pub const PIPE_FORMAT_BPTC_RGB_FLOAT: pipe_format = 257;
+pub const PIPE_FORMAT_BPTC_RGB_UFLOAT: pipe_format = 258;
+pub const PIPE_FORMAT_A8L8_UNORM: pipe_format = 259;
+pub const PIPE_FORMAT_A8L8_SNORM: pipe_format = 260;
+pub const PIPE_FORMAT_A8L8_SRGB: pipe_format = 261;
+pub const PIPE_FORMAT_A16L16_UNORM: pipe_format = 262;
+pub const PIPE_FORMAT_G8R8_UNORM: pipe_format = 263;
+pub const PIPE_FORMAT_G8R8_SNORM: pipe_format = 264;
+pub const PIPE_FORMAT_G16R16_UNORM: pipe_format = 265;
+pub const PIPE_FORMAT_G16R16_SNORM: pipe_format = 266;
+pub const PIPE_FORMAT_A8B8G8R8_SNORM: pipe_format = 267;
+pub const PIPE_FORMAT_X8B8G8R8_SNORM: pipe_format = 268;
+pub const PIPE_FORMAT_ETC2_RGB8: pipe_format = 269;
+pub const PIPE_FORMAT_ETC2_SRGB8: pipe_format = 270;
+pub const PIPE_FORMAT_ETC2_RGB8A1: pipe_format = 271;
+pub const PIPE_FORMAT_ETC2_SRGB8A1: pipe_format = 272;
+pub const PIPE_FORMAT_ETC2_RGBA8: pipe_format = 273;
+pub const PIPE_FORMAT_ETC2_SRGBA8: pipe_format = 274;
+pub const PIPE_FORMAT_ETC2_R11_UNORM: pipe_format = 275;
+pub const PIPE_FORMAT_ETC2_R11_SNORM: pipe_format = 276;
+pub const PIPE_FORMAT_ETC2_RG11_UNORM: pipe_format = 277;
+pub const PIPE_FORMAT_ETC2_RG11_SNORM: pipe_format = 278;
+pub const PIPE_FORMAT_ASTC_4x4: pipe_format = 279;
+pub const PIPE_FORMAT_ASTC_5x4: pipe_format = 280;
+pub const PIPE_FORMAT_ASTC_5x5: pipe_format = 281;
+pub const PIPE_FORMAT_ASTC_6x5: pipe_format = 282;
+pub const PIPE_FORMAT_ASTC_6x6: pipe_format = 283;
+pub const PIPE_FORMAT_ASTC_8x5: pipe_format = 284;
+pub const PIPE_FORMAT_ASTC_8x6: pipe_format = 285;
+pub const PIPE_FORMAT_ASTC_8x8: pipe_format = 286;
+pub const PIPE_FORMAT_ASTC_10x5: pipe_format = 287;
+pub const PIPE_FORMAT_ASTC_10x6: pipe_format = 288;
+pub const PIPE_FORMAT_ASTC_10x8: pipe_format = 289;
+pub const PIPE_FORMAT_ASTC_10x10: pipe_format = 290;
+pub const PIPE_FORMAT_ASTC_12x10: pipe_format = 291;
+pub const PIPE_FORMAT_ASTC_12x12: pipe_format = 292;
+pub const PIPE_FORMAT_ASTC_4x4_SRGB: pipe_format = 293;
+pub const PIPE_FORMAT_ASTC_5x4_SRGB: pipe_format = 294;
+pub const PIPE_FORMAT_ASTC_5x5_SRGB: pipe_format = 295;
+pub const PIPE_FORMAT_ASTC_6x5_SRGB: pipe_format = 296;
+pub const PIPE_FORMAT_ASTC_6x6_SRGB: pipe_format = 297;
+pub const PIPE_FORMAT_ASTC_8x5_SRGB: pipe_format = 298;
+pub const PIPE_FORMAT_ASTC_8x6_SRGB: pipe_format = 299;
+pub const PIPE_FORMAT_ASTC_8x8_SRGB: pipe_format = 300;
+pub const PIPE_FORMAT_ASTC_10x5_SRGB: pipe_format = 301;
+pub const PIPE_FORMAT_ASTC_10x6_SRGB: pipe_format = 302;
+pub const PIPE_FORMAT_ASTC_10x8_SRGB: pipe_format = 303;
+pub const PIPE_FORMAT_ASTC_10x10_SRGB: pipe_format = 304;
+pub const PIPE_FORMAT_ASTC_12x10_SRGB: pipe_format = 305;
+pub const PIPE_FORMAT_ASTC_12x12_SRGB: pipe_format = 306;
+pub const PIPE_FORMAT_P016: pipe_format = 307;
+pub const PIPE_FORMAT_R10G10B10X2_UNORM: pipe_format = 308;
+pub const PIPE_FORMAT_A1B5G5R5_UNORM: pipe_format = 309;
+pub const PIPE_FORMAT_X1B5G5R5_UNORM: pipe_format = 310;
+pub const PIPE_FORMAT_A4B4G4R4_UNORM: pipe_format = 311;
+pub const PIPE_FORMAT_R8_SRGB: pipe_format = 312;
+pub const PIPE_FORMAT_COUNT: pipe_format = 313;
+/// Formats for textures, surfaces and vertex data
+pub type pipe_format = u32;
diff --git a/gpu_renderer/src/generated/virgl_protocol.rs b/gpu_renderer/src/generated/virgl_protocol.rs
new file mode 100644
index 0000000..8d09d61
--- /dev/null
+++ b/gpu_renderer/src/generated/virgl_protocol.rs
@@ -0,0 +1,310 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+pub const VIRGL_QUERY_STATE_NEW: u32 = 0;
+pub const VIRGL_QUERY_STATE_DONE: u32 = 1;
+pub const VIRGL_QUERY_STATE_WAIT_HOST: u32 = 2;
+pub const VIRGL_MAX_COLOR_BUFS: u32 = 8;
+pub const VIRGL_MAX_CLIP_PLANES: u32 = 8;
+pub const VIRGL_OBJ_CREATE_HEADER: u32 = 0;
+pub const VIRGL_OBJ_CREATE_HANDLE: u32 = 1;
+pub const VIRGL_OBJ_BIND_HEADER: u32 = 0;
+pub const VIRGL_OBJ_BIND_HANDLE: u32 = 1;
+pub const VIRGL_OBJ_DESTROY_HANDLE: u32 = 1;
+pub const VIRGL_OBJ_BLEND_SIZE: u32 = 11;
+pub const VIRGL_OBJ_BLEND_HANDLE: u32 = 1;
+pub const VIRGL_OBJ_BLEND_S0: u32 = 2;
+pub const VIRGL_OBJ_BLEND_S1: u32 = 3;
+pub const VIRGL_OBJ_DSA_SIZE: u32 = 5;
+pub const VIRGL_OBJ_DSA_HANDLE: u32 = 1;
+pub const VIRGL_OBJ_DSA_S0: u32 = 2;
+pub const VIRGL_OBJ_DSA_S1: u32 = 3;
+pub const VIRGL_OBJ_DSA_S2: u32 = 4;
+pub const VIRGL_OBJ_DSA_ALPHA_REF: u32 = 5;
+pub const VIRGL_OBJ_RS_SIZE: u32 = 9;
+pub const VIRGL_OBJ_RS_HANDLE: u32 = 1;
+pub const VIRGL_OBJ_RS_S0: u32 = 2;
+pub const VIRGL_OBJ_RS_POINT_SIZE: u32 = 3;
+pub const VIRGL_OBJ_RS_SPRITE_COORD_ENABLE: u32 = 4;
+pub const VIRGL_OBJ_RS_S3: u32 = 5;
+pub const VIRGL_OBJ_RS_LINE_WIDTH: u32 = 6;
+pub const VIRGL_OBJ_RS_OFFSET_UNITS: u32 = 7;
+pub const VIRGL_OBJ_RS_OFFSET_SCALE: u32 = 8;
+pub const VIRGL_OBJ_RS_OFFSET_CLAMP: u32 = 9;
+pub const VIRGL_OBJ_CLEAR_SIZE: u32 = 8;
+pub const VIRGL_OBJ_CLEAR_BUFFERS: u32 = 1;
+pub const VIRGL_OBJ_CLEAR_COLOR_0: u32 = 2;
+pub const VIRGL_OBJ_CLEAR_COLOR_1: u32 = 3;
+pub const VIRGL_OBJ_CLEAR_COLOR_2: u32 = 4;
+pub const VIRGL_OBJ_CLEAR_COLOR_3: u32 = 5;
+pub const VIRGL_OBJ_CLEAR_DEPTH_0: u32 = 6;
+pub const VIRGL_OBJ_CLEAR_DEPTH_1: u32 = 7;
+pub const VIRGL_OBJ_CLEAR_STENCIL: u32 = 8;
+pub const VIRGL_OBJ_SHADER_HANDLE: u32 = 1;
+pub const VIRGL_OBJ_SHADER_TYPE: u32 = 2;
+pub const VIRGL_OBJ_SHADER_OFFSET: u32 = 3;
+pub const VIRGL_OBJ_SHADER_OFFSET_CONT: u32 = 2147483648;
+pub const VIRGL_OBJ_SHADER_NUM_TOKENS: u32 = 4;
+pub const VIRGL_OBJ_SHADER_SO_NUM_OUTPUTS: u32 = 5;
+pub const VIRGL_SET_VIEWPORT_START_SLOT: u32 = 1;
+pub const VIRGL_SET_FRAMEBUFFER_STATE_NR_CBUFS: u32 = 1;
+pub const VIRGL_SET_FRAMEBUFFER_STATE_NR_ZSURF_HANDLE: u32 = 2;
+pub const VIRGL_OBJ_VERTEX_ELEMENTS_HANDLE: u32 = 1;
+pub const VIRGL_SET_INDEX_BUFFER_HANDLE: u32 = 1;
+pub const VIRGL_SET_INDEX_BUFFER_INDEX_SIZE: u32 = 2;
+pub const VIRGL_SET_INDEX_BUFFER_OFFSET: u32 = 3;
+pub const VIRGL_SET_CONSTANT_BUFFER_SHADER_TYPE: u32 = 1;
+pub const VIRGL_SET_CONSTANT_BUFFER_INDEX: u32 = 2;
+pub const VIRGL_SET_CONSTANT_BUFFER_DATA_START: u32 = 3;
+pub const VIRGL_SET_UNIFORM_BUFFER_SIZE: u32 = 5;
+pub const VIRGL_SET_UNIFORM_BUFFER_SHADER_TYPE: u32 = 1;
+pub const VIRGL_SET_UNIFORM_BUFFER_INDEX: u32 = 2;
+pub const VIRGL_SET_UNIFORM_BUFFER_OFFSET: u32 = 3;
+pub const VIRGL_SET_UNIFORM_BUFFER_LENGTH: u32 = 4;
+pub const VIRGL_SET_UNIFORM_BUFFER_RES_HANDLE: u32 = 5;
+pub const VIRGL_DRAW_VBO_SIZE: u32 = 12;
+pub const VIRGL_DRAW_VBO_SIZE_TESS: u32 = 14;
+pub const VIRGL_DRAW_VBO_SIZE_INDIRECT: u32 = 20;
+pub const VIRGL_DRAW_VBO_START: u32 = 1;
+pub const VIRGL_DRAW_VBO_COUNT: u32 = 2;
+pub const VIRGL_DRAW_VBO_MODE: u32 = 3;
+pub const VIRGL_DRAW_VBO_INDEXED: u32 = 4;
+pub const VIRGL_DRAW_VBO_INSTANCE_COUNT: u32 = 5;
+pub const VIRGL_DRAW_VBO_INDEX_BIAS: u32 = 6;
+pub const VIRGL_DRAW_VBO_START_INSTANCE: u32 = 7;
+pub const VIRGL_DRAW_VBO_PRIMITIVE_RESTART: u32 = 8;
+pub const VIRGL_DRAW_VBO_RESTART_INDEX: u32 = 9;
+pub const VIRGL_DRAW_VBO_MIN_INDEX: u32 = 10;
+pub const VIRGL_DRAW_VBO_MAX_INDEX: u32 = 11;
+pub const VIRGL_DRAW_VBO_COUNT_FROM_SO: u32 = 12;
+pub const VIRGL_DRAW_VBO_VERTICES_PER_PATCH: u32 = 13;
+pub const VIRGL_DRAW_VBO_DRAWID: u32 = 14;
+pub const VIRGL_DRAW_VBO_INDIRECT_HANDLE: u32 = 15;
+pub const VIRGL_DRAW_VBO_INDIRECT_OFFSET: u32 = 16;
+pub const VIRGL_DRAW_VBO_INDIRECT_STRIDE: u32 = 17;
+pub const VIRGL_DRAW_VBO_INDIRECT_DRAW_COUNT: u32 = 18;
+pub const VIRGL_DRAW_VBO_INDIRECT_DRAW_COUNT_OFFSET: u32 = 19;
+pub const VIRGL_DRAW_VBO_INDIRECT_DRAW_COUNT_HANDLE: u32 = 20;
+pub const VIRGL_OBJ_SURFACE_SIZE: u32 = 5;
+pub const VIRGL_OBJ_SURFACE_HANDLE: u32 = 1;
+pub const VIRGL_OBJ_SURFACE_RES_HANDLE: u32 = 2;
+pub const VIRGL_OBJ_SURFACE_FORMAT: u32 = 3;
+pub const VIRGL_OBJ_SURFACE_BUFFER_FIRST_ELEMENT: u32 = 4;
+pub const VIRGL_OBJ_SURFACE_BUFFER_LAST_ELEMENT: u32 = 5;
+pub const VIRGL_OBJ_SURFACE_TEXTURE_LEVEL: u32 = 4;
+pub const VIRGL_OBJ_SURFACE_TEXTURE_LAYERS: u32 = 5;
+pub const VIRGL_OBJ_STREAMOUT_SIZE: u32 = 4;
+pub const VIRGL_OBJ_STREAMOUT_HANDLE: u32 = 1;
+pub const VIRGL_OBJ_STREAMOUT_RES_HANDLE: u32 = 2;
+pub const VIRGL_OBJ_STREAMOUT_BUFFER_OFFSET: u32 = 3;
+pub const VIRGL_OBJ_STREAMOUT_BUFFER_SIZE: u32 = 4;
+pub const VIRGL_OBJ_SAMPLER_STATE_SIZE: u32 = 9;
+pub const VIRGL_OBJ_SAMPLER_STATE_HANDLE: u32 = 1;
+pub const VIRGL_OBJ_SAMPLER_STATE_S0: u32 = 2;
+pub const VIRGL_OBJ_SAMPLER_STATE_LOD_BIAS: u32 = 3;
+pub const VIRGL_OBJ_SAMPLER_STATE_MIN_LOD: u32 = 4;
+pub const VIRGL_OBJ_SAMPLER_STATE_MAX_LOD: u32 = 5;
+pub const VIRGL_OBJ_SAMPLER_VIEW_SIZE: u32 = 6;
+pub const VIRGL_OBJ_SAMPLER_VIEW_HANDLE: u32 = 1;
+pub const VIRGL_OBJ_SAMPLER_VIEW_RES_HANDLE: u32 = 2;
+pub const VIRGL_OBJ_SAMPLER_VIEW_FORMAT: u32 = 3;
+pub const VIRGL_OBJ_SAMPLER_VIEW_BUFFER_FIRST_ELEMENT: u32 = 4;
+pub const VIRGL_OBJ_SAMPLER_VIEW_BUFFER_LAST_ELEMENT: u32 = 5;
+pub const VIRGL_OBJ_SAMPLER_VIEW_TEXTURE_LAYER: u32 = 4;
+pub const VIRGL_OBJ_SAMPLER_VIEW_TEXTURE_LEVEL: u32 = 5;
+pub const VIRGL_OBJ_SAMPLER_VIEW_SWIZZLE: u32 = 6;
+pub const VIRGL_SET_SAMPLER_VIEWS_SHADER_TYPE: u32 = 1;
+pub const VIRGL_SET_SAMPLER_VIEWS_START_SLOT: u32 = 2;
+pub const VIRGL_SET_SAMPLER_VIEWS_V0_HANDLE: u32 = 3;
+pub const VIRGL_BIND_SAMPLER_STATES_SHADER_TYPE: u32 = 1;
+pub const VIRGL_BIND_SAMPLER_STATES_START_SLOT: u32 = 2;
+pub const VIRGL_BIND_SAMPLER_STATES_S0_HANDLE: u32 = 3;
+pub const VIRGL_SET_STENCIL_REF_SIZE: u32 = 1;
+pub const VIRGL_SET_STENCIL_REF: u32 = 1;
+pub const VIRGL_SET_BLEND_COLOR_SIZE: u32 = 4;
+pub const VIRGL_SET_SCISSOR_START_SLOT: u32 = 1;
+pub const VIRGL_CMD_RESOURCE_COPY_REGION_SIZE: u32 = 13;
+pub const VIRGL_CMD_RCR_DST_RES_HANDLE: u32 = 1;
+pub const VIRGL_CMD_RCR_DST_LEVEL: u32 = 2;
+pub const VIRGL_CMD_RCR_DST_X: u32 = 3;
+pub const VIRGL_CMD_RCR_DST_Y: u32 = 4;
+pub const VIRGL_CMD_RCR_DST_Z: u32 = 5;
+pub const VIRGL_CMD_RCR_SRC_RES_HANDLE: u32 = 6;
+pub const VIRGL_CMD_RCR_SRC_LEVEL: u32 = 7;
+pub const VIRGL_CMD_RCR_SRC_X: u32 = 8;
+pub const VIRGL_CMD_RCR_SRC_Y: u32 = 9;
+pub const VIRGL_CMD_RCR_SRC_Z: u32 = 10;
+pub const VIRGL_CMD_RCR_SRC_W: u32 = 11;
+pub const VIRGL_CMD_RCR_SRC_H: u32 = 12;
+pub const VIRGL_CMD_RCR_SRC_D: u32 = 13;
+pub const VIRGL_CMD_BLIT_SIZE: u32 = 21;
+pub const VIRGL_CMD_BLIT_S0: u32 = 1;
+pub const VIRGL_CMD_BLIT_SCISSOR_MINX_MINY: u32 = 2;
+pub const VIRGL_CMD_BLIT_SCISSOR_MAXX_MAXY: u32 = 3;
+pub const VIRGL_CMD_BLIT_DST_RES_HANDLE: u32 = 4;
+pub const VIRGL_CMD_BLIT_DST_LEVEL: u32 = 5;
+pub const VIRGL_CMD_BLIT_DST_FORMAT: u32 = 6;
+pub const VIRGL_CMD_BLIT_DST_X: u32 = 7;
+pub const VIRGL_CMD_BLIT_DST_Y: u32 = 8;
+pub const VIRGL_CMD_BLIT_DST_Z: u32 = 9;
+pub const VIRGL_CMD_BLIT_DST_W: u32 = 10;
+pub const VIRGL_CMD_BLIT_DST_H: u32 = 11;
+pub const VIRGL_CMD_BLIT_DST_D: u32 = 12;
+pub const VIRGL_CMD_BLIT_SRC_RES_HANDLE: u32 = 13;
+pub const VIRGL_CMD_BLIT_SRC_LEVEL: u32 = 14;
+pub const VIRGL_CMD_BLIT_SRC_FORMAT: u32 = 15;
+pub const VIRGL_CMD_BLIT_SRC_X: u32 = 16;
+pub const VIRGL_CMD_BLIT_SRC_Y: u32 = 17;
+pub const VIRGL_CMD_BLIT_SRC_Z: u32 = 18;
+pub const VIRGL_CMD_BLIT_SRC_W: u32 = 19;
+pub const VIRGL_CMD_BLIT_SRC_H: u32 = 20;
+pub const VIRGL_CMD_BLIT_SRC_D: u32 = 21;
+pub const VIRGL_OBJ_QUERY_SIZE: u32 = 4;
+pub const VIRGL_OBJ_QUERY_HANDLE: u32 = 1;
+pub const VIRGL_OBJ_QUERY_TYPE_INDEX: u32 = 2;
+pub const VIRGL_OBJ_QUERY_OFFSET: u32 = 3;
+pub const VIRGL_OBJ_QUERY_RES_HANDLE: u32 = 4;
+pub const VIRGL_QUERY_BEGIN_HANDLE: u32 = 1;
+pub const VIRGL_QUERY_END_HANDLE: u32 = 1;
+pub const VIRGL_QUERY_RESULT_HANDLE: u32 = 1;
+pub const VIRGL_QUERY_RESULT_WAIT: u32 = 2;
+pub const VIRGL_RENDER_CONDITION_SIZE: u32 = 3;
+pub const VIRGL_RENDER_CONDITION_HANDLE: u32 = 1;
+pub const VIRGL_RENDER_CONDITION_CONDITION: u32 = 2;
+pub const VIRGL_RENDER_CONDITION_MODE: u32 = 3;
+pub const VIRGL_RESOURCE_IW_RES_HANDLE: u32 = 1;
+pub const VIRGL_RESOURCE_IW_LEVEL: u32 = 2;
+pub const VIRGL_RESOURCE_IW_USAGE: u32 = 3;
+pub const VIRGL_RESOURCE_IW_STRIDE: u32 = 4;
+pub const VIRGL_RESOURCE_IW_LAYER_STRIDE: u32 = 5;
+pub const VIRGL_RESOURCE_IW_X: u32 = 6;
+pub const VIRGL_RESOURCE_IW_Y: u32 = 7;
+pub const VIRGL_RESOURCE_IW_Z: u32 = 8;
+pub const VIRGL_RESOURCE_IW_W: u32 = 9;
+pub const VIRGL_RESOURCE_IW_H: u32 = 10;
+pub const VIRGL_RESOURCE_IW_D: u32 = 11;
+pub const VIRGL_RESOURCE_IW_DATA_START: u32 = 12;
+pub const VIRGL_SET_STREAMOUT_TARGETS_APPEND_BITMASK: u32 = 1;
+pub const VIRGL_SET_STREAMOUT_TARGETS_H0: u32 = 2;
+pub const VIRGL_SET_SAMPLE_MASK_SIZE: u32 = 1;
+pub const VIRGL_SET_SAMPLE_MASK_MASK: u32 = 1;
+pub const VIRGL_SET_CLIP_STATE_SIZE: u32 = 32;
+pub const VIRGL_SET_CLIP_STATE_C0: u32 = 1;
+pub const VIRGL_POLYGON_STIPPLE_SIZE: u32 = 32;
+pub const VIRGL_POLYGON_STIPPLE_P0: u32 = 1;
+pub const VIRGL_BIND_SHADER_SIZE: u32 = 2;
+pub const VIRGL_BIND_SHADER_HANDLE: u32 = 1;
+pub const VIRGL_BIND_SHADER_TYPE: u32 = 2;
+pub const VIRGL_TESS_STATE_SIZE: u32 = 6;
+pub const VIRGL_SET_MIN_SAMPLES_SIZE: u32 = 1;
+pub const VIRGL_SET_MIN_SAMPLES_MASK: u32 = 1;
+pub const VIRGL_SET_SHADER_BUFFER_ELEMENT_SIZE: u32 = 3;
+pub const VIRGL_SET_SHADER_BUFFER_SHADER_TYPE: u32 = 1;
+pub const VIRGL_SET_SHADER_BUFFER_START_SLOT: u32 = 2;
+pub const VIRGL_SET_SHADER_IMAGE_ELEMENT_SIZE: u32 = 5;
+pub const VIRGL_SET_SHADER_IMAGE_SHADER_TYPE: u32 = 1;
+pub const VIRGL_SET_SHADER_IMAGE_START_SLOT: u32 = 2;
+pub const VIRGL_MEMORY_BARRIER_SIZE: u32 = 1;
+pub const VIRGL_MEMORY_BARRIER_FLAGS: u32 = 1;
+pub const VIRGL_LAUNCH_GRID_SIZE: u32 = 8;
+pub const VIRGL_LAUNCH_BLOCK_X: u32 = 1;
+pub const VIRGL_LAUNCH_BLOCK_Y: u32 = 2;
+pub const VIRGL_LAUNCH_BLOCK_Z: u32 = 3;
+pub const VIRGL_LAUNCH_GRID_X: u32 = 4;
+pub const VIRGL_LAUNCH_GRID_Y: u32 = 5;
+pub const VIRGL_LAUNCH_GRID_Z: u32 = 6;
+pub const VIRGL_LAUNCH_INDIRECT_HANDLE: u32 = 7;
+pub const VIRGL_LAUNCH_INDIRECT_OFFSET: u32 = 8;
+pub const VIRGL_SET_FRAMEBUFFER_STATE_NO_ATTACH_SIZE: u32 = 2;
+pub const VIRGL_SET_FRAMEBUFFER_STATE_NO_ATTACH_WIDTH_HEIGHT: u32 = 1;
+pub const VIRGL_SET_FRAMEBUFFER_STATE_NO_ATTACH_LAYERS_SAMPLES: u32 = 2;
+pub const VIRGL_TEXTURE_BARRIER_SIZE: u32 = 1;
+pub const VIRGL_TEXTURE_BARRIER_FLAGS: u32 = 1;
+pub const VIRGL_SET_ATOMIC_BUFFER_ELEMENT_SIZE: u32 = 3;
+pub const VIRGL_SET_ATOMIC_BUFFER_START_SLOT: u32 = 1;
+pub const VIRGL_SET_DEBUG_FLAGS_MIN_SIZE: u32 = 2;
+pub const VIRGL_SET_DEBUG_FLAGSTRING_OFFSET: u32 = 1;
+pub const VIRGL_QUERY_RESULT_QBO_SIZE: u32 = 6;
+pub const VIRGL_QUERY_RESULT_QBO_HANDLE: u32 = 1;
+pub const VIRGL_QUERY_RESULT_QBO_QBO_HANDLE: u32 = 2;
+pub const VIRGL_QUERY_RESULT_QBO_WAIT: u32 = 3;
+pub const VIRGL_QUERY_RESULT_QBO_RESULT_TYPE: u32 = 4;
+pub const VIRGL_QUERY_RESULT_QBO_OFFSET: u32 = 5;
+pub const VIRGL_QUERY_RESULT_QBO_INDEX: u32 = 6;
+pub const VIRGL_TRANSFER_TO_HOST: u32 = 1;
+pub const VIRGL_TRANSFER_FROM_HOST: u32 = 2;
+pub const VIRGL_TRANSFER3D_SIZE: u32 = 13;
+pub const VIRGL_TRANSFER3D_DATA_OFFSET: u32 = 12;
+pub const VIRGL_TRANSFER3D_DIRECTION: u32 = 13;
+pub type __uint32_t = ::std::os::raw::c_uint;
+pub type __uint64_t = ::std::os::raw::c_ulong;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct virgl_host_query_state {
+    pub query_state: u32,
+    pub result_size: u32,
+    pub result: u64,
+}
+pub const VIRGL_OBJECT_NULL: virgl_object_type = 0;
+pub const VIRGL_OBJECT_BLEND: virgl_object_type = 1;
+pub const VIRGL_OBJECT_RASTERIZER: virgl_object_type = 2;
+pub const VIRGL_OBJECT_DSA: virgl_object_type = 3;
+pub const VIRGL_OBJECT_SHADER: virgl_object_type = 4;
+pub const VIRGL_OBJECT_VERTEX_ELEMENTS: virgl_object_type = 5;
+pub const VIRGL_OBJECT_SAMPLER_VIEW: virgl_object_type = 6;
+pub const VIRGL_OBJECT_SAMPLER_STATE: virgl_object_type = 7;
+pub const VIRGL_OBJECT_SURFACE: virgl_object_type = 8;
+pub const VIRGL_OBJECT_QUERY: virgl_object_type = 9;
+pub const VIRGL_OBJECT_STREAMOUT_TARGET: virgl_object_type = 10;
+pub const VIRGL_MAX_OBJECTS: virgl_object_type = 11;
+pub type virgl_object_type = u32;
+pub const VIRGL_CCMD_NOP: virgl_context_cmd = 0;
+pub const VIRGL_CCMD_CREATE_OBJECT: virgl_context_cmd = 1;
+pub const VIRGL_CCMD_BIND_OBJECT: virgl_context_cmd = 2;
+pub const VIRGL_CCMD_DESTROY_OBJECT: virgl_context_cmd = 3;
+pub const VIRGL_CCMD_SET_VIEWPORT_STATE: virgl_context_cmd = 4;
+pub const VIRGL_CCMD_SET_FRAMEBUFFER_STATE: virgl_context_cmd = 5;
+pub const VIRGL_CCMD_SET_VERTEX_BUFFERS: virgl_context_cmd = 6;
+pub const VIRGL_CCMD_CLEAR: virgl_context_cmd = 7;
+pub const VIRGL_CCMD_DRAW_VBO: virgl_context_cmd = 8;
+pub const VIRGL_CCMD_RESOURCE_INLINE_WRITE: virgl_context_cmd = 9;
+pub const VIRGL_CCMD_SET_SAMPLER_VIEWS: virgl_context_cmd = 10;
+pub const VIRGL_CCMD_SET_INDEX_BUFFER: virgl_context_cmd = 11;
+pub const VIRGL_CCMD_SET_CONSTANT_BUFFER: virgl_context_cmd = 12;
+pub const VIRGL_CCMD_SET_STENCIL_REF: virgl_context_cmd = 13;
+pub const VIRGL_CCMD_SET_BLEND_COLOR: virgl_context_cmd = 14;
+pub const VIRGL_CCMD_SET_SCISSOR_STATE: virgl_context_cmd = 15;
+pub const VIRGL_CCMD_BLIT: virgl_context_cmd = 16;
+pub const VIRGL_CCMD_RESOURCE_COPY_REGION: virgl_context_cmd = 17;
+pub const VIRGL_CCMD_BIND_SAMPLER_STATES: virgl_context_cmd = 18;
+pub const VIRGL_CCMD_BEGIN_QUERY: virgl_context_cmd = 19;
+pub const VIRGL_CCMD_END_QUERY: virgl_context_cmd = 20;
+pub const VIRGL_CCMD_GET_QUERY_RESULT: virgl_context_cmd = 21;
+pub const VIRGL_CCMD_SET_POLYGON_STIPPLE: virgl_context_cmd = 22;
+pub const VIRGL_CCMD_SET_CLIP_STATE: virgl_context_cmd = 23;
+pub const VIRGL_CCMD_SET_SAMPLE_MASK: virgl_context_cmd = 24;
+pub const VIRGL_CCMD_SET_STREAMOUT_TARGETS: virgl_context_cmd = 25;
+pub const VIRGL_CCMD_SET_RENDER_CONDITION: virgl_context_cmd = 26;
+pub const VIRGL_CCMD_SET_UNIFORM_BUFFER: virgl_context_cmd = 27;
+pub const VIRGL_CCMD_SET_SUB_CTX: virgl_context_cmd = 28;
+pub const VIRGL_CCMD_CREATE_SUB_CTX: virgl_context_cmd = 29;
+pub const VIRGL_CCMD_DESTROY_SUB_CTX: virgl_context_cmd = 30;
+pub const VIRGL_CCMD_BIND_SHADER: virgl_context_cmd = 31;
+pub const VIRGL_CCMD_SET_TESS_STATE: virgl_context_cmd = 32;
+pub const VIRGL_CCMD_SET_MIN_SAMPLES: virgl_context_cmd = 33;
+pub const VIRGL_CCMD_SET_SHADER_BUFFERS: virgl_context_cmd = 34;
+pub const VIRGL_CCMD_SET_SHADER_IMAGES: virgl_context_cmd = 35;
+pub const VIRGL_CCMD_MEMORY_BARRIER: virgl_context_cmd = 36;
+pub const VIRGL_CCMD_LAUNCH_GRID: virgl_context_cmd = 37;
+pub const VIRGL_CCMD_SET_FRAMEBUFFER_STATE_NO_ATTACH: virgl_context_cmd = 38;
+pub const VIRGL_CCMD_TEXTURE_BARRIER: virgl_context_cmd = 39;
+pub const VIRGL_CCMD_SET_ATOMIC_BUFFERS: virgl_context_cmd = 40;
+pub const VIRGL_CCMD_SET_DEBUG_FLAGS: virgl_context_cmd = 41;
+pub const VIRGL_CCMD_GET_QUERY_RESULT_QBO: virgl_context_cmd = 42;
+pub const VIRGL_CCMD_TRANSFER3D: virgl_context_cmd = 43;
+pub const VIRGL_CCMD_END_TRANSFERS: virgl_context_cmd = 44;
+pub const VIRGL_MAX_COMMANDS: virgl_context_cmd = 45;
+pub type virgl_context_cmd = u32;
diff --git a/gpu_renderer/src/generated/virglrenderer.rs b/gpu_renderer/src/generated/virglrenderer.rs
new file mode 100644
index 0000000..eb4d4d6
--- /dev/null
+++ b/gpu_renderer/src/generated/virglrenderer.rs
@@ -0,0 +1,282 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+#[link(name = "virglrenderer")]
+extern "C" {}
+
+pub const VIRGL_RENDERER_CALLBACKS_VERSION: u32 = 2;
+pub const VIRGL_RENDERER_USE_EGL: u32 = 1;
+pub const VIRGL_RENDERER_THREAD_SYNC: u32 = 2;
+pub const VIRGL_RENDERER_USE_GLX: u32 = 4;
+pub const VIRGL_RENDERER_USE_SURFACELESS: u32 = 8;
+pub const VIRGL_RENDERER_USE_GLES: u32 = 16;
+pub const VIRGL_RES_BIND_DEPTH_STENCIL: u32 = 1;
+pub const VIRGL_RES_BIND_RENDER_TARGET: u32 = 2;
+pub const VIRGL_RES_BIND_SAMPLER_VIEW: u32 = 8;
+pub const VIRGL_RES_BIND_VERTEX_BUFFER: u32 = 16;
+pub const VIRGL_RES_BIND_INDEX_BUFFER: u32 = 32;
+pub const VIRGL_RES_BIND_CONSTANT_BUFFER: u32 = 64;
+pub const VIRGL_RES_BIND_STREAM_OUTPUT: u32 = 2048;
+pub const VIRGL_RES_BIND_CURSOR: u32 = 65536;
+pub const VIRGL_RES_BIND_CUSTOM: u32 = 131072;
+pub const VIRGL_RES_BIND_SCANOUT: u32 = 262144;
+pub type __uint32_t = ::std::os::raw::c_uint;
+pub type __uint64_t = ::std::os::raw::c_ulong;
+pub type va_list = __builtin_va_list;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct virgl_box {
+    _unused: [u8; 0],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct iovec {
+    _unused: [u8; 0],
+}
+pub type virgl_renderer_gl_context = *mut ::std::os::raw::c_void;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct virgl_renderer_gl_ctx_param {
+    pub version: ::std::os::raw::c_int,
+    pub shared: bool,
+    pub major_ver: ::std::os::raw::c_int,
+    pub minor_ver: ::std::os::raw::c_int,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct virgl_renderer_callbacks {
+    pub version: ::std::os::raw::c_int,
+    pub write_fence: ::std::option::Option<
+        unsafe extern "C" fn(cookie: *mut ::std::os::raw::c_void, fence: u32),
+    >,
+    pub create_gl_context: ::std::option::Option<
+        unsafe extern "C" fn(
+            cookie: *mut ::std::os::raw::c_void,
+            scanout_idx: ::std::os::raw::c_int,
+            param: *mut virgl_renderer_gl_ctx_param,
+        ) -> virgl_renderer_gl_context,
+    >,
+    pub destroy_gl_context: ::std::option::Option<
+        unsafe extern "C" fn(cookie: *mut ::std::os::raw::c_void, ctx: virgl_renderer_gl_context),
+    >,
+    pub make_current: ::std::option::Option<
+        unsafe extern "C" fn(
+            cookie: *mut ::std::os::raw::c_void,
+            scanout_idx: ::std::os::raw::c_int,
+            ctx: virgl_renderer_gl_context,
+        ) -> ::std::os::raw::c_int,
+    >,
+    pub get_drm_fd: ::std::option::Option<
+        unsafe extern "C" fn(cookie: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int,
+    >,
+}
+extern "C" {
+    pub fn virgl_renderer_init(
+        cookie: *mut ::std::os::raw::c_void,
+        flags: ::std::os::raw::c_int,
+        cb: *mut virgl_renderer_callbacks,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn virgl_renderer_poll();
+}
+extern "C" {
+    pub fn virgl_renderer_get_cursor_data(
+        resource_id: u32,
+        width: *mut u32,
+        height: *mut u32,
+    ) -> *mut ::std::os::raw::c_void;
+}
+extern "C" {
+    pub fn virgl_renderer_get_rect(
+        resource_id: ::std::os::raw::c_int,
+        iov: *mut iovec,
+        num_iovs: ::std::os::raw::c_uint,
+        offset: u32,
+        x: ::std::os::raw::c_int,
+        y: ::std::os::raw::c_int,
+        width: ::std::os::raw::c_int,
+        height: ::std::os::raw::c_int,
+    );
+}
+extern "C" {
+    pub fn virgl_renderer_get_fd_for_texture(
+        tex_id: u32,
+        fd: *mut ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn virgl_renderer_get_fd_for_texture2(
+        tex_id: u32,
+        fd: *mut ::std::os::raw::c_int,
+        stride: *mut ::std::os::raw::c_int,
+        offset: *mut ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct virgl_renderer_resource_create_args {
+    pub handle: u32,
+    pub target: u32,
+    pub format: u32,
+    pub bind: u32,
+    pub width: u32,
+    pub height: u32,
+    pub depth: u32,
+    pub array_size: u32,
+    pub last_level: u32,
+    pub nr_samples: u32,
+    pub flags: u32,
+}
+pub type virgl_debug_callback_type = ::std::option::Option<
+    unsafe extern "C" fn(fmt: *const ::std::os::raw::c_char, ap: *mut __va_list_tag),
+>;
+extern "C" {
+    pub fn virgl_renderer_resource_create(
+        args: *mut virgl_renderer_resource_create_args,
+        iov: *mut iovec,
+        num_iovs: u32,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn virgl_renderer_resource_import_eglimage(
+        args: *mut virgl_renderer_resource_create_args,
+        image: *mut ::std::os::raw::c_void,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn virgl_renderer_resource_unref(res_handle: u32);
+}
+extern "C" {
+    pub fn virgl_renderer_resource_set_priv(res_handle: u32, priv_: *mut ::std::os::raw::c_void);
+}
+extern "C" {
+    pub fn virgl_renderer_resource_get_priv(res_handle: u32) -> *mut ::std::os::raw::c_void;
+}
+extern "C" {
+    pub fn virgl_renderer_context_create(
+        handle: u32,
+        nlen: u32,
+        name: *const ::std::os::raw::c_char,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn virgl_renderer_context_destroy(handle: u32);
+}
+extern "C" {
+    pub fn virgl_renderer_submit_cmd(
+        buffer: *mut ::std::os::raw::c_void,
+        ctx_id: ::std::os::raw::c_int,
+        ndw: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn virgl_renderer_transfer_read_iov(
+        handle: u32,
+        ctx_id: u32,
+        level: u32,
+        stride: u32,
+        layer_stride: u32,
+        box_: *mut virgl_box,
+        offset: u64,
+        iov: *mut iovec,
+        iovec_cnt: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn virgl_renderer_transfer_write_iov(
+        handle: u32,
+        ctx_id: u32,
+        level: ::std::os::raw::c_int,
+        stride: u32,
+        layer_stride: u32,
+        box_: *mut virgl_box,
+        offset: u64,
+        iovec: *mut iovec,
+        iovec_cnt: ::std::os::raw::c_uint,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn virgl_renderer_get_cap_set(set: u32, max_ver: *mut u32, max_size: *mut u32);
+}
+extern "C" {
+    pub fn virgl_renderer_fill_caps(set: u32, version: u32, caps: *mut ::std::os::raw::c_void);
+}
+extern "C" {
+    pub fn virgl_renderer_resource_attach_iov(
+        res_handle: ::std::os::raw::c_int,
+        iov: *mut iovec,
+        num_iovs: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn virgl_renderer_resource_detach_iov(
+        res_handle: ::std::os::raw::c_int,
+        iov: *mut *mut iovec,
+        num_iovs: *mut ::std::os::raw::c_int,
+    );
+}
+extern "C" {
+    pub fn virgl_renderer_create_fence(
+        client_fence_id: ::std::os::raw::c_int,
+        ctx_id: u32,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn virgl_renderer_force_ctx_0();
+}
+extern "C" {
+    pub fn virgl_renderer_ctx_attach_resource(
+        ctx_id: ::std::os::raw::c_int,
+        res_handle: ::std::os::raw::c_int,
+    );
+}
+extern "C" {
+    pub fn virgl_renderer_ctx_detach_resource(
+        ctx_id: ::std::os::raw::c_int,
+        res_handle: ::std::os::raw::c_int,
+    );
+}
+extern "C" {
+    pub fn virgl_set_debug_callback(cb: virgl_debug_callback_type) -> virgl_debug_callback_type;
+}
+#[repr(C)]
+#[derive(Default, Debug, Copy, Clone)]
+pub struct virgl_renderer_resource_info {
+    pub handle: u32,
+    pub virgl_format: u32,
+    pub width: u32,
+    pub height: u32,
+    pub depth: u32,
+    pub flags: u32,
+    pub tex_id: u32,
+    pub stride: u32,
+    pub drm_fourcc: ::std::os::raw::c_int,
+}
+extern "C" {
+    pub fn virgl_renderer_resource_get_info(
+        res_handle: ::std::os::raw::c_int,
+        info: *mut virgl_renderer_resource_info,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn virgl_renderer_cleanup(cookie: *mut ::std::os::raw::c_void);
+}
+extern "C" {
+    pub fn virgl_renderer_reset();
+}
+extern "C" {
+    pub fn virgl_renderer_get_poll_fd() -> ::std::os::raw::c_int;
+}
+pub type __builtin_va_list = [__va_list_tag; 1usize];
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __va_list_tag {
+    pub gp_offset: ::std::os::raw::c_uint,
+    pub fp_offset: ::std::os::raw::c_uint,
+    pub overflow_arg_area: *mut ::std::os::raw::c_void,
+    pub reg_save_area: *mut ::std::os::raw::c_void,
+}
diff --git a/gpu_renderer/src/lib.rs b/gpu_renderer/src/lib.rs
new file mode 100644
index 0000000..4b8274d
--- /dev/null
+++ b/gpu_renderer/src/lib.rs
@@ -0,0 +1,1009 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! A crate for using hardware acceleration to render virtio-gpu's virgl command streams.
+
+mod command_buffer;
+mod generated;
+mod pipe_format_fourcc;
+
+use std::cell::RefCell;
+use std::ffi::CStr;
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::marker::PhantomData;
+use std::mem::{size_of, transmute};
+use std::ops::Deref;
+use std::os::raw::{c_char, c_int, c_uint, c_void};
+use std::os::unix::io::{FromRawFd, RawFd};
+use std::ptr::{null, null_mut};
+use std::rc::Rc;
+use std::result;
+use std::sync::atomic::{AtomicBool, Ordering};
+
+use data_model::{VolatileMemory, VolatileSlice};
+use sys_util::{GuestAddress, GuestMemory};
+
+use crate::generated::epoxy_egl::{
+    EGLAttrib, EGLBoolean, EGLClientBuffer, EGLConfig, EGLContext, EGLDisplay, EGLImageKHR,
+    EGLNativeDisplayType, EGLSurface, EGLenum, EGLint, EGLuint64KHR, EGLDEBUGPROCKHR,
+    EGL_CONTEXT_CLIENT_VERSION, EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE0_OFFSET_EXT,
+    EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_GL_TEXTURE_2D_KHR, EGL_HEIGHT, EGL_LINUX_DMA_BUF_EXT,
+    EGL_LINUX_DRM_FOURCC_EXT, EGL_NONE, EGL_OPENGL_ES_API, EGL_SURFACE_TYPE, EGL_WIDTH,
+};
+use crate::generated::p_defines::{PIPE_BIND_SAMPLER_VIEW, PIPE_TEXTURE_1D, PIPE_TEXTURE_2D};
+use crate::generated::p_format::PIPE_FORMAT_B8G8R8X8_UNORM;
+use crate::generated::virglrenderer::*;
+
+pub use crate::command_buffer::CommandBufferBuilder;
+pub use crate::generated::virglrenderer::{
+    virgl_renderer_resource_create_args, virgl_renderer_resource_info, VIRGL_RES_BIND_SCANOUT,
+};
+pub use crate::pipe_format_fourcc::pipe_format_fourcc as format_fourcc;
+
+/// Arguments used in `Renderer::create_resource`..
+pub type ResourceCreateArgs = virgl_renderer_resource_create_args;
+/// Information returned from `Resource::get_info`.
+pub type ResourceInfo = virgl_renderer_resource_info;
+
+/// An error generated while using this crate.
+#[derive(Debug)]
+pub enum Error {
+    /// Inidcates `Renderer` was already initialized, and only one renderer per process is allowed.
+    AlreadyInitialized,
+    /// Indicates libeopoxy was unable to load the EGL function with the given name.
+    MissingEGLFunction(&'static str),
+    /// A call to eglGetDisplay indicated failure.
+    EGLGetDisplay,
+    /// A call to eglInitialize indicated failure.
+    EGLInitialize,
+    /// A call to eglChooseConfig indicated failure.
+    EGLChooseConfig,
+    /// A call to eglBindAPI indicated failure.
+    EGLBindAPI,
+    /// A call to eglCreateContext indicated failure.
+    EGLCreateContext,
+    /// A call to eglMakeCurrent indicated failure.
+    EGLMakeCurrent,
+    /// An internal virglrenderer error was returned.
+    Virglrenderer(i32),
+    /// An EGLIMageKHR could not be created, indicating a EGL driver error.
+    CreateImage,
+    /// The EGL driver failed to export an EGLImageKHR as a dmabuf.
+    ExportedResourceDmabuf,
+    /// The indicated region of guest memory is invalid.
+    InvalidIovec,
+    /// A command size was submitted that was invalid.
+    InvalidCommandSize(usize),
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            AlreadyInitialized => write!(f, "global gpu renderer was already initailized"),
+            MissingEGLFunction(name) => write!(f, "egl function `{}` was missing", name),
+            EGLGetDisplay => write!(f, "call to eglGetDisplay failed"),
+            EGLInitialize => write!(f, "call to eglInitialize failed"),
+            EGLChooseConfig => write!(f, "call to eglChooseConfig failed"),
+            EGLBindAPI => write!(f, "call to eglBindAPI failed"),
+            EGLCreateContext => write!(f, "call to eglCreateContext failed"),
+            EGLMakeCurrent => write!(f, "call to eglMakeCurrent failed"),
+            Virglrenderer(ret) => write!(f, "virglrenderer failed with error {}", ret),
+            CreateImage => write!(f, "failed to create EGLImage"),
+            ExportedResourceDmabuf => write!(f, "failed to export dmabuf from EGLImageKHR"),
+            InvalidIovec => write!(f, "an iovec is outside of guest memory's range"),
+            InvalidCommandSize(s) => write!(f, "command buffer submitted with invalid size: {}", s),
+        }
+    }
+}
+
+/// The result of an operation in this crate.
+pub type Result<T> = result::Result<T, Error>;
+
+fn ret_to_res(ret: i32) -> Result<()> {
+    match ret {
+        0 => Ok(()),
+        _ => Err(Error::Virglrenderer(ret)),
+    }
+}
+
+#[derive(Debug)]
+#[repr(C)]
+struct VirglVec {
+    base: *mut c_void,
+    len: usize,
+}
+
+/// An axis aligned box in 3 dimensional space.
+#[derive(Debug)]
+#[repr(C)]
+pub struct Box3 {
+    pub x: u32,
+    pub y: u32,
+    pub z: u32,
+    pub w: u32,
+    pub h: u32,
+    pub d: u32,
+}
+
+impl Box3 {
+    /// Constructs a 2 dimensional XY box in 3 dimensional space with unit depth and zero
+    /// displacement on the Z axis.
+    pub fn new_2d(x: u32, w: u32, y: u32, h: u32) -> Box3 {
+        Box3 {
+            x,
+            y,
+            z: 0,
+            w,
+            h,
+            d: 1,
+        }
+    }
+}
+
+struct FenceState {
+    latest_fence: u32,
+}
+impl FenceState {
+    pub fn write(&mut self, latest_fence: u32) {
+        if latest_fence > self.latest_fence {
+            self.latest_fence = latest_fence;
+        }
+    }
+}
+
+struct VirglCookie {
+    fence_state: Rc<RefCell<FenceState>>,
+}
+
+extern "C" fn write_fence(cookie: *mut c_void, fence: u32) {
+    assert!(!cookie.is_null());
+    let cookie = unsafe { &*(cookie as *mut VirglCookie) };
+
+    // Track the most recent fence.
+    let mut fence_state = cookie.fence_state.borrow_mut();
+    fence_state.write(fence);
+}
+
+const VIRGL_RENDERER_CALLBACKS: &virgl_renderer_callbacks = &virgl_renderer_callbacks {
+    version: 1,
+    write_fence: Some(write_fence),
+    create_gl_context: None,
+    destroy_gl_context: None,
+    make_current: None,
+    get_drm_fd: None,
+};
+
+unsafe extern "C" fn error_callback(
+    error: c_uint,
+    command: *const c_char,
+    _: c_int,
+    _: *mut c_void,
+    _: *mut c_void,
+    message: *const c_char,
+) {
+    eprint!("EGL ERROR {}: {:?}", error, CStr::from_ptr(command));
+    if !message.is_null() {
+        eprint!(": {:?}", CStr::from_ptr(message));
+    }
+    eprintln!();
+}
+
+#[allow(non_snake_case)]
+struct EGLFunctionsInner {
+    BindAPI: unsafe extern "C" fn(api: EGLenum) -> EGLBoolean,
+    ChooseConfig: unsafe extern "C" fn(
+        dpy: EGLDisplay,
+        attrib_list: *const EGLint,
+        configs: *mut EGLConfig,
+        config_size: EGLint,
+        num_config: *mut EGLint,
+    ) -> EGLBoolean,
+    CreateContext: unsafe extern "C" fn(
+        dpy: EGLDisplay,
+        config: EGLConfig,
+        share_context: EGLContext,
+        attrib_list: *const EGLint,
+    ) -> EGLContext,
+    CreateImageKHR: unsafe extern "C" fn(
+        dpy: EGLDisplay,
+        ctx: EGLContext,
+        target: EGLenum,
+        buffer: EGLClientBuffer,
+        attrib_list: *const EGLint,
+    ) -> EGLImageKHR,
+    DebugMessageControlKHR:
+        unsafe extern "C" fn(callback: EGLDEBUGPROCKHR, attrib_list: *const EGLAttrib) -> EGLint,
+    DestroyImageKHR: unsafe extern "C" fn(dpy: EGLDisplay, image: EGLImageKHR) -> EGLBoolean,
+    ExportDRMImageMESA: unsafe extern "C" fn(
+        dpy: EGLDisplay,
+        image: EGLImageKHR,
+        fds: *mut ::std::os::raw::c_int,
+        strides: *mut EGLint,
+        offsets: *mut EGLint,
+    ) -> EGLBoolean,
+    ExportDMABUFImageQueryMESA: unsafe extern "C" fn(
+        dpy: EGLDisplay,
+        image: EGLImageKHR,
+        fourcc: *mut ::std::os::raw::c_int,
+        num_planes: *mut ::std::os::raw::c_int,
+        modifiers: *mut EGLuint64KHR,
+    ) -> EGLBoolean,
+    GetCurrentContext: unsafe extern "C" fn() -> EGLContext,
+    GetCurrentDisplay: unsafe extern "C" fn() -> EGLDisplay,
+    GetDisplay: unsafe extern "C" fn(display_id: EGLNativeDisplayType) -> EGLDisplay,
+    Initialize:
+        unsafe extern "C" fn(dpy: EGLDisplay, major: *mut EGLint, minor: *mut EGLint) -> EGLBoolean,
+    MakeCurrent: unsafe extern "C" fn(
+        dpy: EGLDisplay,
+        draw: EGLSurface,
+        read: EGLSurface,
+        ctx: EGLContext,
+    ) -> EGLBoolean,
+    no_sync_send: PhantomData<*mut ()>,
+}
+
+#[derive(Clone)]
+struct EGLFunctions(Rc<EGLFunctionsInner>);
+
+impl EGLFunctions {
+    fn new() -> Result<EGLFunctions> {
+        use crate::generated::epoxy_egl::{
+            epoxy_eglBindAPI, epoxy_eglChooseConfig, epoxy_eglCreateContext,
+            epoxy_eglCreateImageKHR, epoxy_eglDebugMessageControlKHR, epoxy_eglDestroyImageKHR,
+            epoxy_eglExportDMABUFImageQueryMESA, epoxy_eglExportDRMImageMESA,
+            epoxy_eglGetCurrentContext, epoxy_eglGetCurrentDisplay, epoxy_eglGetDisplay,
+            epoxy_eglInitialize, epoxy_eglMakeCurrent,
+        };
+        // This is unsafe because it is reading mutable static variables exported by epoxy. These
+        // variables are initialized during the binary's init and never modified again, so it should
+        // be safe to read them now.
+        unsafe {
+            Ok(EGLFunctions(Rc::new(EGLFunctionsInner {
+                BindAPI: epoxy_eglBindAPI.ok_or(Error::MissingEGLFunction("eglBindAPI"))?,
+                ChooseConfig: epoxy_eglChooseConfig
+                    .ok_or(Error::MissingEGLFunction("eglChooseConfig"))?,
+                CreateContext: epoxy_eglCreateContext
+                    .ok_or(Error::MissingEGLFunction("eglCreateContext"))?,
+                CreateImageKHR: epoxy_eglCreateImageKHR
+                    .ok_or(Error::MissingEGLFunction("eglCreateImageKHR"))?,
+                DebugMessageControlKHR: epoxy_eglDebugMessageControlKHR
+                    .ok_or(Error::MissingEGLFunction("eglDebugMessageControlKHR"))?,
+                DestroyImageKHR: epoxy_eglDestroyImageKHR
+                    .ok_or(Error::MissingEGLFunction("eglDestroyImageKHR"))?,
+                ExportDRMImageMESA: epoxy_eglExportDRMImageMESA
+                    .ok_or(Error::MissingEGLFunction("eglExportDRMImageMESA"))?,
+                ExportDMABUFImageQueryMESA: epoxy_eglExportDMABUFImageQueryMESA
+                    .ok_or(Error::MissingEGLFunction("eglExportDMABUFImageQueryMESA"))?,
+                GetCurrentContext: epoxy_eglGetCurrentContext
+                    .ok_or(Error::MissingEGLFunction("eglGetCurrentContext"))?,
+                GetCurrentDisplay: epoxy_eglGetCurrentDisplay
+                    .ok_or(Error::MissingEGLFunction("eglGetCurrentDisplay"))?,
+                GetDisplay: epoxy_eglGetDisplay
+                    .ok_or(Error::MissingEGLFunction("eglGetDisplay"))?,
+                Initialize: epoxy_eglInitialize
+                    .ok_or(Error::MissingEGLFunction("eglInitialize"))?,
+                MakeCurrent: epoxy_eglMakeCurrent
+                    .ok_or(Error::MissingEGLFunction("eglMakeCurrent"))?,
+                no_sync_send: PhantomData,
+            })))
+        }
+    }
+}
+
+impl Deref for EGLFunctions {
+    type Target = EGLFunctionsInner;
+    fn deref(&self) -> &EGLFunctionsInner {
+        self.0.deref()
+    }
+}
+
+/// The global renderer handle used to query capability sets, and create resources and contexts.
+pub struct Renderer {
+    no_sync_send: PhantomData<*mut ()>,
+    egl_funcs: EGLFunctions,
+    display: EGLDisplay,
+    fence_state: Rc<RefCell<FenceState>>,
+}
+
+impl Renderer {
+    /// Initializes the renderer and returns a handle to it.
+    ///
+    /// This may only be called once per process. Calls after the first will return an error.
+    pub fn init() -> Result<Renderer> {
+        // virglrenderer is a global state backed library that uses thread bound OpenGL contexts.
+        // Initialize it only once and use the non-send/non-sync Renderer struct to keep things tied
+        // to whichever thread called this function first.
+        static INIT_ONCE: AtomicBool = AtomicBool::new(false);
+        if INIT_ONCE.compare_and_swap(false, true, Ordering::Acquire) {
+            return Err(Error::AlreadyInitialized);
+        }
+
+        let egl_funcs = EGLFunctions::new()?;
+
+        // Safe because only valid callbacks are given and only one thread can execute this
+        // function.
+        unsafe {
+            (egl_funcs.DebugMessageControlKHR)(Some(error_callback), null());
+        }
+
+        // Trivially safe.
+        let display = unsafe { (egl_funcs.GetDisplay)(null_mut()) };
+        if display.is_null() {
+            return Err(Error::EGLGetDisplay);
+        }
+
+        // Safe because only a valid display is given.
+        let ret = unsafe { (egl_funcs.Initialize)(display, null_mut(), null_mut()) };
+        if ret == 0 {
+            return Err(Error::EGLInitialize);
+        }
+
+        let config_attribs = [EGL_SURFACE_TYPE as i32, -1, EGL_NONE as i32];
+        let mut egl_config: *mut c_void = null_mut();
+        let mut num_configs = 0;
+        // Safe because only a valid, initialized display is used, along with validly sized
+        // pointers to stack variables.
+        let ret = unsafe {
+            (egl_funcs.ChooseConfig)(
+                display,
+                config_attribs.as_ptr(),
+                &mut egl_config,
+                1,
+                &mut num_configs, /* unused but can't be null */
+            )
+        };
+        if ret == 0 {
+            return Err(Error::EGLChooseConfig);
+        }
+
+        // Cookie is intentionally never freed because virglrenderer never gets uninitialized.
+        // Otherwise, Resource and Context would become invalid because their lifetime is not tied
+        // to the Renderer instance. Doing so greatly simplifies the ownership for users of this
+        // library.
+
+        let fence_state = Rc::new(RefCell::new(FenceState { latest_fence: 0 }));
+
+        let cookie: *mut VirglCookie = Box::into_raw(Box::new(VirglCookie {
+            fence_state: Rc::clone(&fence_state),
+        }));
+
+        // Safe because EGL was properly initialized before here..
+        let ret = unsafe { (egl_funcs.BindAPI)(EGL_OPENGL_ES_API) };
+        if ret == 0 {
+            return Err(Error::EGLBindAPI);
+        }
+
+        let context_attribs = [EGL_CONTEXT_CLIENT_VERSION as i32, 3, EGL_NONE as i32];
+        // Safe because a valid display, config, and config_attribs pointer are given.
+        let ctx = unsafe {
+            (egl_funcs.CreateContext)(display, egl_config, null_mut(), context_attribs.as_ptr())
+        };
+        if ctx.is_null() {
+            return Err(Error::EGLCreateContext);
+        }
+
+        // Safe because a valid display and context is used, and the two null surfaces are not
+        // used.
+        let ret = unsafe { (egl_funcs.MakeCurrent)(display, null_mut(), null_mut(), ctx) };
+        if ret == 0 {
+            return Err(Error::EGLMakeCurrent);
+        }
+
+        // Safe because a valid cookie and set of callbacks is used and the result is checked for
+        // error.
+        let ret = unsafe {
+            virgl_renderer_init(
+                cookie as *mut c_void,
+                (VIRGL_RENDERER_USE_EGL | VIRGL_RENDERER_USE_SURFACELESS | VIRGL_RENDERER_USE_GLES)
+                    as i32,
+                transmute(VIRGL_RENDERER_CALLBACKS),
+            )
+        };
+        ret_to_res(ret)?;
+
+        Ok(Renderer {
+            no_sync_send: PhantomData,
+            egl_funcs,
+            display,
+            fence_state,
+        })
+    }
+
+    /// Gets the version and size for the given capability set ID.
+    pub fn get_cap_set_info(&self, id: u32) -> (u32, u32) {
+        let mut version = 0;
+        let mut size = 0;
+        // Safe because virglrenderer is initialized by now and properly size stack variables are
+        // used for the pointers.
+        unsafe {
+            virgl_renderer_get_cap_set(id, &mut version, &mut size);
+        }
+        (version, size)
+    }
+
+    /// Gets the capability set for the given ID and version.
+    pub fn get_cap_set(&self, id: u32, version: u32) -> Vec<u8> {
+        let (_, max_size) = self.get_cap_set_info(id);
+        let mut buf = vec![0u8; max_size as usize];
+        // Safe because virglrenderer is initialized by now and the given buffer is sized properly
+        // for the given cap id/version.
+        unsafe {
+            virgl_renderer_fill_caps(id, version, buf.as_mut_ptr() as *mut c_void);
+        }
+        buf
+    }
+
+    /// Creates a rendering context with the given id.
+    pub fn create_context(&self, id: u32) -> Result<Context> {
+        const CONTEXT_NAME: &[u8] = b"gpu_renderer";
+        // Safe because virglrenderer is initialized by now and the context name is statically
+        // allocated. The return value is checked before returning a new context.
+        let ret = unsafe {
+            virgl_renderer_context_create(
+                id,
+                CONTEXT_NAME.len() as u32,
+                CONTEXT_NAME.as_ptr() as *const c_char,
+            )
+        };
+        ret_to_res(ret)?;
+        Ok(Context {
+            id,
+            no_sync_send: PhantomData,
+        })
+    }
+
+    /// Creates a resource with the given arguments.
+    pub fn create_resource(
+        &self,
+        mut args: virgl_renderer_resource_create_args,
+    ) -> Result<Resource> {
+        // Safe because virglrenderer is initialized by now, and the return value is checked before
+        // returning a new resource. The backing buffers are not supplied with this call.
+        let ret = unsafe { virgl_renderer_resource_create(&mut args, null_mut(), 0) };
+        ret_to_res(ret)?;
+        Ok(Resource {
+            id: args.handle,
+            backing_iovecs: Vec::new(),
+            backing_mem: None,
+            egl_funcs: self.egl_funcs.clone(),
+            no_sync_send: PhantomData,
+        })
+    }
+
+    /// Imports a resource from an EGLImage.
+    pub fn import_resource(
+        &self,
+        mut args: virgl_renderer_resource_create_args,
+        image: &Image,
+    ) -> Result<Resource> {
+        let ret = unsafe { virgl_renderer_resource_import_eglimage(&mut args, image.image) };
+        ret_to_res(ret)?;
+        Ok(Resource {
+            id: args.handle,
+            backing_iovecs: Vec::new(),
+            backing_mem: None,
+            egl_funcs: self.egl_funcs.clone(),
+            no_sync_send: PhantomData,
+        })
+    }
+
+    /// Helper that creates a simple 1 dimensional resource with basic metadata.
+    pub fn create_tex_1d(&self, id: u32, width: u32) -> Result<Resource> {
+        self.create_resource(virgl_renderer_resource_create_args {
+            handle: id,
+            target: PIPE_TEXTURE_1D,
+            format: PIPE_FORMAT_B8G8R8X8_UNORM,
+            width,
+            height: 1,
+            depth: 1,
+            array_size: 1,
+            last_level: 0,
+            nr_samples: 0,
+            bind: PIPE_BIND_SAMPLER_VIEW,
+            flags: 0,
+        })
+    }
+
+    /// Helper that creates a simple 2 dimensional resource with basic metadata.
+    pub fn create_tex_2d(&self, id: u32, width: u32, height: u32) -> Result<Resource> {
+        self.create_resource(virgl_renderer_resource_create_args {
+            handle: id,
+            target: PIPE_TEXTURE_2D,
+            format: PIPE_FORMAT_B8G8R8X8_UNORM,
+            width,
+            height,
+            depth: 1,
+            array_size: 1,
+            last_level: 0,
+            nr_samples: 0,
+            bind: PIPE_BIND_SAMPLER_VIEW,
+            flags: 0,
+        })
+    }
+
+    /// Creates an EGLImage from a DMA buffer.
+    pub fn image_from_dmabuf(
+        &self,
+        fourcc: u32,
+        width: u32,
+        height: u32,
+        fd: RawFd,
+        offset: u32,
+        stride: u32,
+    ) -> Result<Image> {
+        let mut attrs = [
+            EGL_WIDTH as EGLint,
+            width as EGLint,
+            EGL_HEIGHT as EGLint,
+            height as EGLint,
+            EGL_LINUX_DRM_FOURCC_EXT as EGLint,
+            fourcc as EGLint,
+            EGL_DMA_BUF_PLANE0_FD_EXT as EGLint,
+            fd as EGLint,
+            EGL_DMA_BUF_PLANE0_OFFSET_EXT as EGLint,
+            offset as EGLint,
+            EGL_DMA_BUF_PLANE0_PITCH_EXT as EGLint,
+            stride as EGLint,
+            EGL_NONE as EGLint,
+        ];
+
+        let image = unsafe {
+            (self.egl_funcs.CreateImageKHR)(
+                self.display,
+                0 as EGLContext,
+                EGL_LINUX_DMA_BUF_EXT,
+                null_mut() as EGLClientBuffer,
+                attrs.as_mut_ptr(),
+            )
+        };
+
+        if image.is_null() {
+            return Err(Error::CreateImage);
+        }
+
+        Ok(Image {
+            egl_funcs: self.egl_funcs.clone(),
+            egl_dpy: self.display,
+            image,
+        })
+    }
+
+    pub fn poll(&self) -> u32 {
+        unsafe { virgl_renderer_poll() };
+        self.fence_state.borrow().latest_fence
+    }
+
+    pub fn create_fence(&mut self, fence_id: u32, ctx_id: u32) -> Result<()> {
+        let ret = unsafe { virgl_renderer_create_fence(fence_id as i32, ctx_id) };
+        ret_to_res(ret)
+    }
+
+    pub fn force_ctx_0(&self) {
+        unsafe { virgl_renderer_force_ctx_0() };
+    }
+}
+
+/// A context in which resources can be attached/detached and commands can be submitted.
+pub struct Context {
+    id: u32,
+    no_sync_send: PhantomData<*mut ()>,
+}
+
+impl Context {
+    /// Gets the ID assigned to this context when it was created.
+    pub fn id(&self) -> u32 {
+        self.id
+    }
+
+    /// Submits a command stream to this rendering context.
+    pub fn submit<T: AsMut<[u8]>>(&mut self, mut buf: T) -> Result<()> {
+        let buf = buf.as_mut();
+        if buf.len() % size_of::<u32>() != 0 {
+            return Err(Error::InvalidCommandSize(buf.len()));
+        }
+        let dword_count = (buf.len() / size_of::<u32>()) as i32;
+        // Safe because the context and buffer are valid and virglrenderer will have been
+        // initialized if there are Context instances.
+        let ret = unsafe {
+            virgl_renderer_submit_cmd(buf.as_mut_ptr() as *mut c_void, self.id as i32, dword_count)
+        };
+        ret_to_res(ret)
+    }
+
+    /// Attaches the given resource to this rendering context.
+    pub fn attach(&mut self, res: &Resource) {
+        // The context id and resource id must be valid because the respective instances ensure
+        // their lifetime.
+        unsafe {
+            virgl_renderer_ctx_attach_resource(self.id as i32, res.id() as i32);
+        }
+    }
+
+    /// Detaches a previously attached resource from this rendering context.
+    pub fn detach(&mut self, res: &Resource) {
+        // The context id and resource id must be valid because the respective instances ensure
+        // their lifetime.
+        unsafe {
+            virgl_renderer_ctx_detach_resource(self.id as i32, res.id() as i32);
+        }
+    }
+}
+
+impl Drop for Context {
+    fn drop(&mut self) {
+        // The context is safe to destroy because nothing else can be referencing it.
+        unsafe {
+            virgl_renderer_context_destroy(self.id);
+        }
+    }
+}
+
+/// A wrapper of an EGLImage to manage its destruction.
+pub struct Image {
+    egl_funcs: EGLFunctions,
+    egl_dpy: EGLDisplay,
+    image: EGLImageKHR,
+}
+
+impl Drop for Image {
+    fn drop(&mut self) {
+        unsafe {
+            (self.egl_funcs.DestroyImageKHR)(self.egl_dpy, self.image);
+        }
+    }
+}
+
+/// A DMABUF file descriptor handle and metadata returned from `Resource::export`.
+#[derive(Debug)]
+pub struct ExportedResource {
+    /// The file descriptor that represents the DMABUF kernel object.
+    pub dmabuf: File,
+    /// The width in pixels of the exported resource.
+    pub width: u32,
+    /// The height in pixels of the exported resource.
+    pub height: u32,
+    /// The fourcc identifier for the format of the resource.
+    pub fourcc: u32,
+    /// Extra modifiers for the format.
+    pub modifiers: u64,
+    /// The number of bytes between successive rows in the exported resource.
+    pub stride: u32,
+    /// The number of bytes from the start of the exported resource to the first pixel.
+    pub offset: u32,
+}
+
+/// A resource handle used by the renderer.
+pub struct Resource {
+    id: u32,
+    backing_iovecs: Vec<VirglVec>,
+    backing_mem: Option<GuestMemory>,
+    egl_funcs: EGLFunctions,
+    no_sync_send: PhantomData<*mut ()>,
+}
+
+impl Resource {
+    /// Gets the ID assigned to this resource when it was created.
+    pub fn id(&self) -> u32 {
+        self.id
+    }
+
+    /// Retrieves metadata about this resource.
+    pub fn get_info(&self) -> Result<ResourceInfo> {
+        let mut res_info = Default::default();
+        let ret = unsafe { virgl_renderer_resource_get_info(self.id as i32, &mut res_info) };
+        ret_to_res(ret)?;
+        Ok(res_info)
+    }
+
+    /// Performs an export of this resource so that it may be imported by other processes.
+    pub fn export(&self) -> Result<ExportedResource> {
+        let res_info = self.get_info()?;
+        let mut fourcc = 0;
+        let mut modifiers = 0;
+        let mut fd = -1;
+        let mut stride = 0;
+        let mut offset = 0;
+        // Always safe on the same thread with an already initialized virglrenderer.
+        unsafe {
+            virgl_renderer_force_ctx_0();
+        }
+        // These are trivially safe and always return successfully because we bind the context in
+        // the previous line.
+        let egl_dpy: EGLDisplay = unsafe { (self.egl_funcs.GetCurrentDisplay)() };
+        let egl_ctx: EGLContext = unsafe { (self.egl_funcs.GetCurrentContext)() };
+
+        // Safe because a valid display, context, and texture ID are given. The attribute list is
+        // not needed. The result is checked to ensure the returned image is valid.
+        let image = unsafe {
+            (self.egl_funcs.CreateImageKHR)(
+                egl_dpy,
+                egl_ctx,
+                EGL_GL_TEXTURE_2D_KHR,
+                res_info.tex_id as EGLClientBuffer,
+                null(),
+            )
+        };
+
+        if image.is_null() {
+            return Err(Error::CreateImage);
+        }
+
+        // Safe because the display and image are valid and each function call is checked for
+        // success. The returned image parameters are stored in stack variables of the correct type.
+        let export_success = unsafe {
+            (self.egl_funcs.ExportDMABUFImageQueryMESA)(
+                egl_dpy,
+                image,
+                &mut fourcc,
+                null_mut(),
+                &mut modifiers,
+            ) != 0
+                && (self.egl_funcs.ExportDRMImageMESA)(
+                    egl_dpy,
+                    image,
+                    &mut fd,
+                    &mut stride,
+                    &mut offset,
+                ) != 0
+        };
+
+        // Safe because we checked that the image was valid and nobody else owns it. The image does
+        // not need to be around for the dmabuf to be valid.
+        unsafe {
+            (self.egl_funcs.DestroyImageKHR)(egl_dpy, image);
+        }
+
+        if !export_success || fd < 0 {
+            return Err(Error::ExportedResourceDmabuf);
+        }
+
+        // Safe because the FD was just returned by a successful EGL call so it must be valid and
+        // owned by us.
+        let dmabuf = unsafe { File::from_raw_fd(fd) };
+        Ok(ExportedResource {
+            dmabuf,
+            width: res_info.width,
+            height: res_info.height,
+            fourcc: fourcc as u32,
+            modifiers,
+            stride: stride as u32,
+            offset: offset as u32,
+        })
+    }
+
+    /// Attaches a scatter-gather mapping of guest memory to this resource which used for transfers.
+    pub fn attach_backing(
+        &mut self,
+        iovecs: &[(GuestAddress, usize)],
+        mem: &GuestMemory,
+    ) -> Result<()> {
+        if iovecs
+            .iter()
+            .any(|&(addr, len)| mem.get_slice(addr.offset(), len as u64).is_err())
+        {
+            return Err(Error::InvalidIovec);
+        }
+        self.detach_backing();
+        self.backing_mem = Some(mem.clone());
+        for &(addr, len) in iovecs {
+            // Unwrap will not panic because we already checked the slices.
+            let slice = mem.get_slice(addr.offset(), len as u64).unwrap();
+            self.backing_iovecs.push(VirglVec {
+                base: slice.as_ptr() as *mut c_void,
+                len,
+            });
+        }
+        // Safe because the backing is into guest memory that we store a reference count for.
+        let ret = unsafe {
+            virgl_renderer_resource_attach_iov(
+                self.id as i32,
+                self.backing_iovecs.as_mut_ptr() as *mut iovec,
+                self.backing_iovecs.len() as i32,
+            )
+        };
+        let res = ret_to_res(ret);
+        if res.is_err() {
+            // Not strictly necessary, but it's good to clear out our collection of pointers to
+            // memory we don't own or need.
+            self.backing_iovecs.clear();
+            self.backing_mem = None;
+        }
+        res
+    }
+
+    /// Detaches previously attached scatter-gather memory from this resource.
+    pub fn detach_backing(&mut self) {
+        // Safe as we don't need the old backing iovecs returned and the reference to the guest
+        // memory can be dropped as it will no longer be needed for this resource.
+        unsafe {
+            virgl_renderer_resource_detach_iov(self.id as i32, null_mut(), null_mut());
+        }
+        self.backing_iovecs.clear();
+        self.backing_mem = None;
+    }
+
+    /// Performs a transfer to the given resource from its backing in guest memory.
+    pub fn transfer_write(
+        &self,
+        ctx: Option<&Context>,
+        level: u32,
+        stride: u32,
+        layer_stride: u32,
+        mut transfer_box: Box3,
+        offset: u64,
+    ) -> Result<()> {
+        // Safe because only stack variables of the appropriate type are used.
+        let ret = unsafe {
+            virgl_renderer_transfer_write_iov(
+                self.id,
+                ctx.map(Context::id).unwrap_or(0),
+                level as i32,
+                stride,
+                layer_stride,
+                &mut transfer_box as *mut Box3 as *mut virgl_box,
+                offset,
+                null_mut(),
+                0,
+            )
+        };
+        ret_to_res(ret)
+    }
+
+    /// Performs a transfer from the given resource to its backing in guest memory.
+    pub fn transfer_read(
+        &self,
+        ctx: Option<&Context>,
+        level: u32,
+        stride: u32,
+        layer_stride: u32,
+        mut transfer_box: Box3,
+        offset: u64,
+    ) -> Result<()> {
+        // Safe because only stack variables of the appropriate type are used.
+        let ret = unsafe {
+            virgl_renderer_transfer_read_iov(
+                self.id,
+                ctx.map(Context::id).unwrap_or(0),
+                level,
+                stride,
+                layer_stride,
+                &mut transfer_box as *mut Box3 as *mut virgl_box,
+                offset,
+                null_mut(),
+                0,
+            )
+        };
+        ret_to_res(ret)
+    }
+
+    /// Performs a transfer from the given resource to the provided `buf`
+    pub fn transfer_read_buf(
+        &self,
+        ctx: Option<&Context>,
+        level: u32,
+        stride: u32,
+        layer_stride: u32,
+        mut transfer_box: Box3,
+        offset: u64,
+        buf: &mut [u8],
+    ) -> Result<()> {
+        let mut iov = VirglVec {
+            base: buf.as_mut_ptr() as *mut c_void,
+            len: buf.len(),
+        };
+        // Safe because only stack variables of the appropriate type are used, along with a properly
+        // sized buffer.
+        let ret = unsafe {
+            virgl_renderer_transfer_read_iov(
+                self.id,
+                ctx.map(Context::id).unwrap_or(0),
+                level,
+                stride,
+                layer_stride,
+                &mut transfer_box as *mut Box3 as *mut virgl_box,
+                offset,
+                &mut iov as *mut VirglVec as *mut iovec,
+                1,
+            )
+        };
+        ret_to_res(ret)
+    }
+
+    /// Reads from this resource to a volatile slice of memory.
+    pub fn read_to_volatile(
+        &self,
+        ctx: Option<&Context>,
+        level: u32,
+        stride: u32,
+        layer_stride: u32,
+        mut transfer_box: Box3,
+        offset: u64,
+        buf: VolatileSlice,
+    ) -> Result<()> {
+        let mut iov = VirglVec {
+            base: buf.as_ptr() as *mut c_void,
+            len: buf.size() as usize,
+        };
+        // Safe because only stack variables of the appropriate type are used, along with a properly
+        // sized buffer.
+        let ret = unsafe {
+            virgl_renderer_transfer_read_iov(
+                self.id,
+                ctx.map(Context::id).unwrap_or(0),
+                level,
+                stride,
+                layer_stride,
+                &mut transfer_box as *mut Box3 as *mut virgl_box,
+                offset,
+                &mut iov as *mut VirglVec as *mut iovec,
+                1,
+            )
+        };
+        ret_to_res(ret)
+    }
+}
+
+impl Drop for Resource {
+    fn drop(&mut self) {
+        // The resource is safe to unreference destroy because no user of these bindings can still
+        // be holding a reference.
+        unsafe {
+            virgl_renderer_resource_unref(self.id);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::generated::p_defines::PIPE_CLEAR_COLOR0;
+
+    #[test]
+    #[ignore]
+    // Make sure a simple buffer clear works by using a command stream.
+    fn simple_clear() {
+        let render = Renderer::init().expect("failed to initialize virglrenderer");
+        let mut ctx = render.create_context(1).expect("failed to create context");
+
+        // Create a 50x50 texture with id=2.
+        let resource = render
+            .create_tex_2d(2, 50, 50)
+            .expect("failed to create texture");
+        ctx.attach(&resource);
+
+        // Create a command buffer that uses the resource as a render target and clears it.
+        const CLEAR_COLOR: [f32; 4] = [0.5, 0.4, 0.3, 0.2];
+        let mut cbuf = CommandBufferBuilder::new();
+        cbuf.e_create_surface(1, &resource, PIPE_FORMAT_B8G8R8X8_UNORM, 0, 0, 0);
+        cbuf.e_set_fb_state(&[1], None);
+        cbuf.e_clear(PIPE_CLEAR_COLOR0, CLEAR_COLOR, 0.0, 0);
+        ctx.submit(&mut cbuf)
+            .expect("failed to submit command buffer to context");
+
+        // Read the result of the rendering into a buffer.
+        let mut pix_buf = [0; 50 * 50 * 4];
+        resource
+            .transfer_read_buf(
+                Some(&ctx),
+                0,
+                50,
+                0,
+                Box3::new_2d(0, 5, 0, 1),
+                0,
+                &mut pix_buf[..],
+            )
+            .expect("failed to read back resource data");
+
+        // Check that the pixels are the color we cleared to. The red and blue channels are switched
+        // because the surface was created with the BGR format, but the colors are RGB order in the
+        // command stream.
+        assert_eq!(pix_buf[0], (256.0 * CLEAR_COLOR[2]) as u8);
+        assert_eq!(pix_buf[1], (256.0 * CLEAR_COLOR[1]) as u8);
+        assert_eq!(pix_buf[2], (256.0 * CLEAR_COLOR[0]) as u8);
+        assert_eq!(pix_buf[3], (256.0 * CLEAR_COLOR[3]) as u8);
+    }
+}
diff --git a/gpu_renderer/src/pipe_format_fourcc.rs b/gpu_renderer/src/pipe_format_fourcc.rs
new file mode 100644
index 0000000..5a93167
--- /dev/null
+++ b/gpu_renderer/src/pipe_format_fourcc.rs
@@ -0,0 +1,26 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::generated::p_format;
+
+macro_rules! fourcc {
+    ($a:expr, $b:expr, $c:expr, $d:expr) => {
+        Some($a as u32 | ($b as u32) << 8 | ($c as u32) << 16 | ($d as u32) << 24)
+    };
+}
+
+/// Gets the fourcc that corresponds to the given pipe format, or `None` if the format is
+/// unrecognized.
+pub fn pipe_format_fourcc(f: p_format::pipe_format) -> Option<u32> {
+    match f {
+        p_format::PIPE_FORMAT_B8G8R8A8_UNORM => fourcc!('A', 'R', '2', '4'),
+        p_format::PIPE_FORMAT_B8G8R8X8_UNORM => fourcc!('X', 'R', '2', '4'),
+        p_format::PIPE_FORMAT_R8G8B8A8_UNORM => fourcc!('A', 'B', '2', '4'),
+        p_format::PIPE_FORMAT_R8G8B8X8_UNORM => fourcc!('X', 'B', '2', '4'),
+        p_format::PIPE_FORMAT_B5G6R5_UNORM => fourcc!('R', 'G', '1', '6'),
+        // p_format::PIPE_FORMAT_R8_UNORM => fourcc!('R', '8', ' ', ' '),
+        // p_format::PIPE_FORMAT_G8R8_UNORM => fourcc!('R', 'G', '8', '8'),
+        _ => None,
+    }
+}
diff --git a/io_jail/Cargo.toml b/io_jail/Cargo.toml
new file mode 100644
index 0000000..5e7ca5d
--- /dev/null
+++ b/io_jail/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "io_jail"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+libc = "*"
diff --git a/io_jail/src/lib.rs b/io_jail/src/lib.rs
new file mode 100644
index 0000000..43698aa
--- /dev/null
+++ b/io_jail/src/lib.rs
@@ -0,0 +1,719 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#[allow(dead_code)]
+#[allow(non_camel_case_types)]
+#[allow(non_snake_case)]
+#[allow(non_upper_case_globals)]
+mod libminijail;
+
+use libc::pid_t;
+use std::ffi::CString;
+use std::fmt::{self, Display};
+use std::fs;
+use std::io;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::path::{Path, PathBuf};
+use std::ptr::{null, null_mut};
+
+#[derive(Debug)]
+pub enum Error {
+    // minijail failed to accept bind mount.
+    BindMount {
+        errno: i32,
+        src: PathBuf,
+        dst: PathBuf,
+    },
+    // minijail failed to accept mount.
+    Mount {
+        errno: i32,
+        src: PathBuf,
+        dest: PathBuf,
+        fstype: String,
+        flags: usize,
+        data: String,
+    },
+    /// Failure to count the number of threads in /proc/self/tasks.
+    CheckingMultiThreaded(io::Error),
+    /// minjail_new failed, this is an allocation failure.
+    CreatingMinijail,
+    /// minijail_fork failed with the given error code.
+    ForkingMinijail(i32),
+    /// Attempt to `fork` while already multithreaded.
+    ForkingWhileMultiThreaded,
+    /// The seccomp policy path doesn't exist.
+    SeccompPath(PathBuf),
+    /// The string passed in didn't parse to a valid CString.
+    StrToCString(String),
+    /// The path passed in didn't parse to a valid CString.
+    PathToCString(PathBuf),
+    /// Failed to call dup2 to set stdin, stdout, or stderr to /dev/null.
+    DupDevNull(i32),
+    /// Failed to set up /dev/null for FDs 0, 1, or 2.
+    OpenDevNull(io::Error),
+    /// Setting the specified alt-syscall table failed with errno. Is the table in the kernel?
+    SetAltSyscallTable { errno: i32, name: String },
+    /// chroot failed with the provided errno.
+    SettingChrootDirectory(i32, PathBuf),
+    /// pivot_root failed with the provided errno.
+    SettingPivotRootDirectory(i32, PathBuf),
+    /// There is an entry in /proc/self/fd that isn't a valid PID.
+    ReadFdDirEntry(io::Error),
+    /// /proc/self/fd failed to open.
+    ReadFdDir(io::Error),
+    /// An entry in /proc/self/fd is not an integer
+    ProcFd(String),
+    /// Minijail refused to preserve an FD in the inherit list of `fork()`.
+    PreservingFd(i32),
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            BindMount { src, dst, errno } => write!(
+                f,
+                "failed to accept bind mount {} -> {}: {}",
+                src.display(),
+                dst.display(),
+                io::Error::from_raw_os_error(*errno),
+            ),
+            Mount {
+                errno,
+                src,
+                dest,
+                fstype,
+                flags,
+                data,
+            } => write!(
+                f,
+                "failed to accept mount {} -> {} of type {:?} with flags 0x{:x} \
+                 and data {:?}: {}",
+                src.display(),
+                dest.display(),
+                fstype,
+                flags,
+                data,
+                io::Error::from_raw_os_error(*errno),
+            ),
+            CheckingMultiThreaded(e) => write!(
+                f,
+                "Failed to count the number of threads from /proc/self/tasks {}",
+                e
+            ),
+            CreatingMinijail => write!(f, "minjail_new failed due to an allocation failure"),
+            ForkingMinijail(e) => write!(f, "minijail_fork failed with error {}", e),
+            ForkingWhileMultiThreaded => write!(f, "Attempt to call fork() while multithreaded"),
+            SeccompPath(p) => write!(f, "missing seccomp policy path: {}", p.display()),
+            StrToCString(s) => write!(f, "failed to convert string into CString: {}", s),
+            PathToCString(s) => write!(f, "failed to convert path into CString: {}", s.display()),
+            DupDevNull(errno) => write!(
+                f,
+                "failed to call dup2 to set stdin, stdout, or stderr to /dev/null: {}",
+                io::Error::from_raw_os_error(*errno),
+            ),
+            OpenDevNull(e) => write!(
+                f,
+                "fail to open /dev/null for setting FDs 0, 1, or 2: {}",
+                e,
+            ),
+            SetAltSyscallTable { name, errno } => write!(
+                f,
+                "failed to set alt-syscall table {}: {}",
+                name,
+                io::Error::from_raw_os_error(*errno),
+            ),
+            SettingChrootDirectory(errno, p) => write!(
+                f,
+                "failed to set chroot {}: {}",
+                p.display(),
+                io::Error::from_raw_os_error(*errno),
+            ),
+            SettingPivotRootDirectory(errno, p) => write!(
+                f,
+                "failed to set pivot root {}: {}",
+                p.display(),
+                io::Error::from_raw_os_error(*errno),
+            ),
+            ReadFdDirEntry(e) => write!(f, "failed to read an entry in /proc/self/fd: {}", e),
+            ReadFdDir(e) => write!(f, "failed to open /proc/self/fd: {}", e),
+            ProcFd(s) => write!(f, "an entry in /proc/self/fd is not an integer: {}", s),
+            PreservingFd(e) => write!(f, "fork failed in minijail_preserve_fd with error {}", e),
+        }
+    }
+}
+
+impl std::error::Error for Error {}
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+/// Configuration to jail a process based on wrapping libminijail.
+///
+/// Intentionally leave out everything related to `minijail_run`.  Forking is
+/// hard to reason about w.r.t. memory and resource safety.  It is better to avoid
+/// forking from rust code.  Leave forking to the library user, who can make
+/// an informed decision about when to fork to minimize risk.
+/// # Examples
+/// * Load seccomp policy - like "minijail0 -n -S myfilter.policy"
+///
+/// ```
+/// # use std::path::Path;
+/// # use io_jail::Minijail;
+/// # fn seccomp_filter_test() -> Result<(), ()> {
+///       let mut j = Minijail::new().map_err(|_| ())?;
+///       j.no_new_privs();
+///       j.parse_seccomp_filters(Path::new("my_filter.policy")).map_err(|_| ())?;
+///       j.use_seccomp_filter();
+///       unsafe { // `fork` will close all the programs FDs.
+///           j.fork(None).map_err(|_| ())?;
+///       }
+/// #     Ok(())
+/// # }
+/// ```
+///
+/// * Keep stdin, stdout, and stderr open after jailing.
+///
+/// ```
+/// # use io_jail::Minijail;
+/// # use std::os::unix::io::RawFd;
+/// # fn seccomp_filter_test() -> Result<(), ()> {
+///       let j = Minijail::new().map_err(|_| ())?;
+///       let preserve_fds: Vec<RawFd> = vec![0, 1, 2];
+///       unsafe { // `fork` will close all the programs FDs.
+///           j.fork(Some(&preserve_fds)).map_err(|_| ())?;
+///       }
+/// #     Ok(())
+/// # }
+/// ```
+/// # Errors
+/// The `fork` function might not return an error if it fails after forking. A
+/// partial jail is not recoverable and will instead result in killing the
+/// process.
+pub struct Minijail {
+    jail: *mut libminijail::minijail,
+}
+
+impl Minijail {
+    /// Creates a new jail configuration.
+    pub fn new() -> Result<Minijail> {
+        let j = unsafe {
+            // libminijail actually owns the minijail structure. It will live until we call
+            // minijail_destroy.
+            libminijail::minijail_new()
+        };
+        if j.is_null() {
+            return Err(Error::CreatingMinijail);
+        }
+        Ok(Minijail { jail: j })
+    }
+
+    // The following functions are safe because they only set values in the
+    // struct already owned by minijail.  The struct's lifetime is tied to
+    // `struct Minijail` so it is guaranteed to be valid
+
+    pub fn change_uid(&mut self, uid: libc::uid_t) {
+        unsafe {
+            libminijail::minijail_change_uid(self.jail, uid);
+        }
+    }
+    pub fn change_gid(&mut self, gid: libc::gid_t) {
+        unsafe {
+            libminijail::minijail_change_gid(self.jail, gid);
+        }
+    }
+    pub fn set_supplementary_gids(&mut self, ids: &[libc::gid_t]) {
+        unsafe {
+            libminijail::minijail_set_supplementary_gids(self.jail, ids.len(), ids.as_ptr());
+        }
+    }
+    pub fn keep_supplementary_gids(&mut self) {
+        unsafe {
+            libminijail::minijail_keep_supplementary_gids(self.jail);
+        }
+    }
+    pub fn use_seccomp(&mut self) {
+        unsafe {
+            libminijail::minijail_use_seccomp(self.jail);
+        }
+    }
+    pub fn no_new_privs(&mut self) {
+        unsafe {
+            libminijail::minijail_no_new_privs(self.jail);
+        }
+    }
+    pub fn use_seccomp_filter(&mut self) {
+        unsafe {
+            libminijail::minijail_use_seccomp_filter(self.jail);
+        }
+    }
+    pub fn set_seccomp_filter_tsync(&mut self) {
+        unsafe {
+            libminijail::minijail_set_seccomp_filter_tsync(self.jail);
+        }
+    }
+    pub fn parse_seccomp_filters(&mut self, path: &Path) -> Result<()> {
+        if !path.is_file() {
+            return Err(Error::SeccompPath(path.to_owned()));
+        }
+
+        let pathstring = path
+            .as_os_str()
+            .to_str()
+            .ok_or(Error::PathToCString(path.to_owned()))?;
+        let filename =
+            CString::new(pathstring).map_err(|_| Error::PathToCString(path.to_owned()))?;
+        unsafe {
+            libminijail::minijail_parse_seccomp_filters(self.jail, filename.as_ptr());
+        }
+        Ok(())
+    }
+    pub fn log_seccomp_filter_failures(&mut self) {
+        unsafe {
+            libminijail::minijail_log_seccomp_filter_failures(self.jail);
+        }
+    }
+    pub fn use_caps(&mut self, capmask: u64) {
+        unsafe {
+            libminijail::minijail_use_caps(self.jail, capmask);
+        }
+    }
+    pub fn capbset_drop(&mut self, capmask: u64) {
+        unsafe {
+            libminijail::minijail_capbset_drop(self.jail, capmask);
+        }
+    }
+    pub fn set_ambient_caps(&mut self) {
+        unsafe {
+            libminijail::minijail_set_ambient_caps(self.jail);
+        }
+    }
+    pub fn reset_signal_mask(&mut self) {
+        unsafe {
+            libminijail::minijail_reset_signal_mask(self.jail);
+        }
+    }
+    pub fn run_as_init(&mut self) {
+        unsafe {
+            libminijail::minijail_run_as_init(self.jail);
+        }
+    }
+    pub fn namespace_pids(&mut self) {
+        unsafe {
+            libminijail::minijail_namespace_pids(self.jail);
+        }
+    }
+    pub fn namespace_user(&mut self) {
+        unsafe {
+            libminijail::minijail_namespace_user(self.jail);
+        }
+    }
+    pub fn namespace_user_disable_setgroups(&mut self) {
+        unsafe {
+            libminijail::minijail_namespace_user_disable_setgroups(self.jail);
+        }
+    }
+    pub fn namespace_vfs(&mut self) {
+        unsafe {
+            libminijail::minijail_namespace_vfs(self.jail);
+        }
+    }
+    pub fn new_session_keyring(&mut self) {
+        unsafe {
+            libminijail::minijail_new_session_keyring(self.jail);
+        }
+    }
+    pub fn skip_remount_private(&mut self) {
+        unsafe {
+            libminijail::minijail_skip_remount_private(self.jail);
+        }
+    }
+    pub fn namespace_ipc(&mut self) {
+        unsafe {
+            libminijail::minijail_namespace_ipc(self.jail);
+        }
+    }
+    pub fn namespace_net(&mut self) {
+        unsafe {
+            libminijail::minijail_namespace_net(self.jail);
+        }
+    }
+    pub fn namespace_cgroups(&mut self) {
+        unsafe {
+            libminijail::minijail_namespace_cgroups(self.jail);
+        }
+    }
+    pub fn remount_proc_readonly(&mut self) {
+        unsafe {
+            libminijail::minijail_remount_proc_readonly(self.jail);
+        }
+    }
+    pub fn uidmap(&mut self, uid_map: &str) -> Result<()> {
+        let map_cstring =
+            CString::new(uid_map).map_err(|_| Error::StrToCString(uid_map.to_owned()))?;
+        unsafe {
+            libminijail::minijail_uidmap(self.jail, map_cstring.as_ptr());
+        }
+        Ok(())
+    }
+    pub fn gidmap(&mut self, gid_map: &str) -> Result<()> {
+        let map_cstring =
+            CString::new(gid_map).map_err(|_| Error::StrToCString(gid_map.to_owned()))?;
+        unsafe {
+            libminijail::minijail_gidmap(self.jail, map_cstring.as_ptr());
+        }
+        Ok(())
+    }
+    pub fn inherit_usergroups(&mut self) {
+        unsafe {
+            libminijail::minijail_inherit_usergroups(self.jail);
+        }
+    }
+    pub fn use_alt_syscall(&mut self, table_name: &str) -> Result<()> {
+        let table_name_string =
+            CString::new(table_name).map_err(|_| Error::StrToCString(table_name.to_owned()))?;
+        let ret =
+            unsafe { libminijail::minijail_use_alt_syscall(self.jail, table_name_string.as_ptr()) };
+        if ret < 0 {
+            return Err(Error::SetAltSyscallTable {
+                errno: ret,
+                name: table_name.to_owned(),
+            });
+        }
+        Ok(())
+    }
+    pub fn enter_chroot(&mut self, dir: &Path) -> Result<()> {
+        let pathstring = dir
+            .as_os_str()
+            .to_str()
+            .ok_or(Error::PathToCString(dir.to_owned()))?;
+        let dirname = CString::new(pathstring).map_err(|_| Error::PathToCString(dir.to_owned()))?;
+        let ret = unsafe { libminijail::minijail_enter_chroot(self.jail, dirname.as_ptr()) };
+        if ret < 0 {
+            return Err(Error::SettingChrootDirectory(ret, dir.to_owned()));
+        }
+        Ok(())
+    }
+    pub fn enter_pivot_root(&mut self, dir: &Path) -> Result<()> {
+        let pathstring = dir
+            .as_os_str()
+            .to_str()
+            .ok_or(Error::PathToCString(dir.to_owned()))?;
+        let dirname = CString::new(pathstring).map_err(|_| Error::PathToCString(dir.to_owned()))?;
+        let ret = unsafe { libminijail::minijail_enter_pivot_root(self.jail, dirname.as_ptr()) };
+        if ret < 0 {
+            return Err(Error::SettingPivotRootDirectory(ret, dir.to_owned()));
+        }
+        Ok(())
+    }
+    pub fn mount(&mut self, src: &Path, dest: &Path, fstype: &str, flags: usize) -> Result<()> {
+        self.mount_with_data(src, dest, fstype, flags, "")
+    }
+    pub fn mount_with_data(
+        &mut self,
+        src: &Path,
+        dest: &Path,
+        fstype: &str,
+        flags: usize,
+        data: &str,
+    ) -> Result<()> {
+        let src_os = src
+            .as_os_str()
+            .to_str()
+            .ok_or(Error::PathToCString(src.to_owned()))?;
+        let src_path = CString::new(src_os).map_err(|_| Error::StrToCString(src_os.to_owned()))?;
+        let dest_os = dest
+            .as_os_str()
+            .to_str()
+            .ok_or(Error::PathToCString(dest.to_owned()))?;
+        let dest_path =
+            CString::new(dest_os).map_err(|_| Error::StrToCString(dest_os.to_owned()))?;
+        let fstype_string =
+            CString::new(fstype).map_err(|_| Error::StrToCString(fstype.to_owned()))?;
+        let data_string = CString::new(data).map_err(|_| Error::StrToCString(data.to_owned()))?;
+        let ret = unsafe {
+            libminijail::minijail_mount_with_data(
+                self.jail,
+                src_path.as_ptr(),
+                dest_path.as_ptr(),
+                fstype_string.as_ptr(),
+                flags as _,
+                data_string.as_ptr(),
+            )
+        };
+        if ret < 0 {
+            return Err(Error::Mount {
+                errno: ret,
+                src: src.to_owned(),
+                dest: dest.to_owned(),
+                fstype: fstype.to_owned(),
+                flags,
+                data: data.to_owned(),
+            });
+        }
+        Ok(())
+    }
+    pub fn mount_dev(&mut self) {
+        unsafe {
+            libminijail::minijail_mount_dev(self.jail);
+        }
+    }
+    pub fn mount_tmp(&mut self) {
+        unsafe {
+            libminijail::minijail_mount_tmp(self.jail);
+        }
+    }
+    pub fn mount_tmp_size(&mut self, size: usize) {
+        unsafe {
+            libminijail::minijail_mount_tmp_size(self.jail, size);
+        }
+    }
+    pub fn mount_bind(&mut self, src: &Path, dest: &Path, writable: bool) -> Result<()> {
+        let src_os = src
+            .as_os_str()
+            .to_str()
+            .ok_or(Error::PathToCString(src.to_owned()))?;
+        let src_path = CString::new(src_os).map_err(|_| Error::StrToCString(src_os.to_owned()))?;
+        let dest_os = dest
+            .as_os_str()
+            .to_str()
+            .ok_or(Error::PathToCString(dest.to_owned()))?;
+        let dest_path =
+            CString::new(dest_os).map_err(|_| Error::StrToCString(dest_os.to_owned()))?;
+        let ret = unsafe {
+            libminijail::minijail_bind(
+                self.jail,
+                src_path.as_ptr(),
+                dest_path.as_ptr(),
+                writable as _,
+            )
+        };
+        if ret < 0 {
+            return Err(Error::BindMount {
+                errno: ret,
+                src: src.to_owned(),
+                dst: dest.to_owned(),
+            });
+        }
+        Ok(())
+    }
+
+    /// Forks and execs a child and puts it in the previously configured minijail.
+    /// FDs 0, 1, and 2 are overwritten with /dev/null FDs unless they are included in the
+    /// inheritable_fds list. This function may abort in the child on error because a partially
+    /// entered jail isn't recoverable.
+    pub fn run(&self, cmd: &Path, inheritable_fds: &[RawFd], args: &[&str]) -> Result<pid_t> {
+        let cmd_os = cmd.to_str().ok_or(Error::PathToCString(cmd.to_owned()))?;
+        let cmd_cstr = CString::new(cmd_os).map_err(|_| Error::StrToCString(cmd_os.to_owned()))?;
+
+        // Converts each incoming `args` string to a `CString`, and then puts each `CString` pointer
+        // into a null terminated array, suitable for use as an argv parameter to `execve`.
+        let mut args_cstr = Vec::with_capacity(args.len());
+        let mut args_array = Vec::with_capacity(args.len());
+        for &arg in args {
+            let arg_cstr = CString::new(arg).map_err(|_| Error::StrToCString(arg.to_owned()))?;
+            args_array.push(arg_cstr.as_ptr());
+            args_cstr.push(arg_cstr);
+        }
+        args_array.push(null());
+
+        for fd in inheritable_fds {
+            let ret = unsafe { libminijail::minijail_preserve_fd(self.jail, *fd, *fd) };
+            if ret < 0 {
+                return Err(Error::PreservingFd(ret));
+            }
+        }
+
+        let dev_null = fs::OpenOptions::new()
+            .read(true)
+            .write(true)
+            .open("/dev/null")
+            .map_err(Error::OpenDevNull)?;
+        // Set stdin, stdout, and stderr to /dev/null unless they are in the inherit list.
+        // These will only be closed when this process exits.
+        for io_fd in &[libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO] {
+            if !inheritable_fds.contains(io_fd) {
+                let ret = unsafe {
+                    libminijail::minijail_preserve_fd(self.jail, dev_null.as_raw_fd(), *io_fd)
+                };
+                if ret < 0 {
+                    return Err(Error::PreservingFd(ret));
+                }
+            }
+        }
+
+        unsafe {
+            libminijail::minijail_close_open_fds(self.jail);
+        }
+
+        let mut pid = 0;
+        let ret = unsafe {
+            libminijail::minijail_run_pid_pipes(
+                self.jail,
+                cmd_cstr.as_ptr(),
+                args_array.as_ptr(),
+                &mut pid,
+                null_mut(),
+                null_mut(),
+                null_mut(),
+            )
+        };
+        if ret < 0 {
+            return Err(Error::ForkingMinijail(ret));
+        }
+        Ok(pid)
+    }
+
+    /// Forks a child and puts it in the previously configured minijail.
+    /// `fork` is unsafe because it closes all open FD for this process.  That
+    /// could cause a lot of trouble if not handled carefully.  FDs 0, 1, and 2
+    /// are overwritten with /dev/null FDs unless they are included in the
+    /// inheritable_fds list.
+    /// This Function may abort in the child on error because a partially
+    /// entered jail isn't recoverable.
+    pub unsafe fn fork(&self, inheritable_fds: Option<&[RawFd]>) -> Result<pid_t> {
+        if !is_single_threaded().map_err(Error::CheckingMultiThreaded)? {
+            // This test will fail during `cargo test` because the test harness always spawns a test
+            // thread. We will make an exception for that case because the tests for this module
+            // should always be run in a serial fashion using `--test-threads=1`.
+            #[cfg(not(test))]
+            return Err(Error::ForkingWhileMultiThreaded);
+        }
+
+        if let Some(keep_fds) = inheritable_fds {
+            for fd in keep_fds {
+                let ret = libminijail::minijail_preserve_fd(self.jail, *fd, *fd);
+                if ret < 0 {
+                    return Err(Error::PreservingFd(ret));
+                }
+            }
+        }
+
+        let dev_null = fs::OpenOptions::new()
+            .read(true)
+            .write(true)
+            .open("/dev/null")
+            .map_err(Error::OpenDevNull)?;
+        // Set stdin, stdout, and stderr to /dev/null unless they are in the inherit list.
+        // These will only be closed when this process exits.
+        for io_fd in &[libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO] {
+            if inheritable_fds.is_none() || !inheritable_fds.unwrap().contains(io_fd) {
+                let ret =
+                    libminijail::minijail_preserve_fd(self.jail, dev_null.as_raw_fd(), *io_fd);
+                if ret < 0 {
+                    return Err(Error::PreservingFd(ret));
+                }
+            }
+        }
+
+        libminijail::minijail_close_open_fds(self.jail);
+
+        let ret = libminijail::minijail_fork(self.jail);
+        if ret < 0 {
+            return Err(Error::ForkingMinijail(ret));
+        }
+        Ok(ret as pid_t)
+    }
+}
+
+impl Drop for Minijail {
+    /// Frees the Minijail created in Minijail::new.
+    fn drop(&mut self) {
+        unsafe {
+            // Destroys the minijail's memory.  It is safe to do here because all references to
+            // this object have been dropped.
+            libminijail::minijail_destroy(self.jail);
+        }
+    }
+}
+
+// Count the number of files in the directory specified by `path`.
+fn count_dir_entries<P: AsRef<Path>>(path: P) -> io::Result<usize> {
+    Ok(fs::read_dir(path)?.count())
+}
+
+// Return true if the current thread is the only thread in the process.
+fn is_single_threaded() -> io::Result<bool> {
+    match count_dir_entries("/proc/self/task") {
+        Ok(1) => Ok(true),
+        Ok(_) => Ok(false),
+        Err(e) => Err(e),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn create_and_free() {
+        unsafe {
+            let j = libminijail::minijail_new();
+            assert_ne!(std::ptr::null_mut(), j);
+            libminijail::minijail_destroy(j);
+        }
+
+        let j = Minijail::new().unwrap();
+        drop(j);
+    }
+
+    #[test]
+    // Test that setting a seccomp filter with no-new-privs works as non-root.
+    // This is equivalent to minijail0 -n -S <seccomp_policy>
+    fn seccomp_no_new_privs() {
+        let mut j = Minijail::new().unwrap();
+        j.no_new_privs();
+        j.parse_seccomp_filters(Path::new("src/test_filter.policy"))
+            .unwrap();
+        j.use_seccomp_filter();
+        unsafe {
+            j.fork(None).unwrap();
+        }
+    }
+
+    #[test]
+    // Test that open FDs get closed and that FDs in the inherit list are left open.
+    fn close_fds() {
+        unsafe {
+            // Using libc to open/close FDs for testing.
+            const FILE_PATH: &[u8] = b"/dev/null\0";
+            let j = Minijail::new().unwrap();
+            let first = libc::open(FILE_PATH.as_ptr() as *const i8, libc::O_RDONLY);
+            assert!(first >= 0);
+            let second = libc::open(FILE_PATH.as_ptr() as *const i8, libc::O_RDONLY);
+            assert!(second >= 0);
+            let fds: Vec<RawFd> = vec![0, 1, 2, first];
+            if j.fork(Some(&fds)).unwrap() == 0 {
+                assert!(libc::close(second) < 0); // Should fail as second should be closed already.
+                assert_eq!(libc::close(first), 0); // Should succeed as first should be untouched.
+            }
+        }
+    }
+
+    #[test]
+    #[ignore] // privileged operation.
+    fn chroot() {
+        let mut j = Minijail::new().unwrap();
+        j.enter_chroot(Path::new(".")).unwrap();
+        unsafe {
+            j.fork(None).unwrap();
+        }
+    }
+
+    #[test]
+    #[ignore] // privileged operation.
+    fn namespace_vfs() {
+        let mut j = Minijail::new().unwrap();
+        j.namespace_vfs();
+        unsafe {
+            j.fork(None).unwrap();
+        }
+    }
+
+    #[test]
+    fn run() {
+        let j = Minijail::new().unwrap();
+        j.run(Path::new("/bin/true"), &[], &[]).unwrap();
+    }
+}
diff --git a/io_jail/src/libminijail.rs b/io_jail/src/libminijail.rs
new file mode 100644
index 0000000..f8c3654
--- /dev/null
+++ b/io_jail/src/libminijail.rs
@@ -0,0 +1,126 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use libc::{gid_t, pid_t, uid_t};
+use std::os::raw::{c_char, c_int, c_ulong};
+
+/// Struct minijail is an opaque type inside libminijail.
+/// See the minijail man page for a description of functions.
+#[derive(Debug, Copy, Clone)]
+pub enum minijail {}
+
+#[link(name = "minijail")]
+extern "C" {
+    pub fn minijail_new() -> *mut minijail;
+    pub fn minijail_change_uid(j: *mut minijail, uid: uid_t);
+    pub fn minijail_change_gid(j: *mut minijail, gid: gid_t);
+    pub fn minijail_set_supplementary_gids(j: *mut minijail, size: usize, list: *const gid_t);
+    pub fn minijail_keep_supplementary_gids(j: *mut minijail);
+    pub fn minijail_change_user(j: *mut minijail, user: *const c_char) -> c_int;
+    pub fn minijail_change_group(j: *mut minijail, group: *const c_char) -> c_int;
+    pub fn minijail_use_seccomp(j: *mut minijail);
+    pub fn minijail_no_new_privs(j: *mut minijail);
+    pub fn minijail_use_seccomp_filter(j: *mut minijail);
+    pub fn minijail_set_seccomp_filter_tsync(j: *mut minijail);
+    pub fn minijail_parse_seccomp_filters(j: *mut minijail, path: *const c_char);
+    pub fn minijail_parse_seccomp_filters_from_fd(j: *mut minijail, fd: c_int);
+    pub fn minijail_log_seccomp_filter_failures(j: *mut minijail);
+    pub fn minijail_use_caps(j: *mut minijail, capmask: u64);
+    pub fn minijail_capbset_drop(j: *mut minijail, capmask: u64);
+    pub fn minijail_set_ambient_caps(j: *mut minijail);
+    pub fn minijail_reset_signal_mask(j: *mut minijail);
+    pub fn minijail_namespace_vfs(j: *mut minijail);
+    pub fn minijail_namespace_enter_vfs(j: *mut minijail, ns_path: *const c_char);
+    pub fn minijail_new_session_keyring(j: *mut minijail);
+    pub fn minijail_skip_remount_private(j: *mut minijail);
+    pub fn minijail_namespace_ipc(j: *mut minijail);
+    pub fn minijail_namespace_net(j: *mut minijail);
+    pub fn minijail_namespace_enter_net(j: *mut minijail, ns_path: *const c_char);
+    pub fn minijail_namespace_cgroups(j: *mut minijail);
+    pub fn minijail_close_open_fds(j: *mut minijail);
+    pub fn minijail_namespace_pids(j: *mut minijail);
+    pub fn minijail_namespace_user(j: *mut minijail);
+    pub fn minijail_namespace_user_disable_setgroups(j: *mut minijail);
+    pub fn minijail_uidmap(j: *mut minijail, uidmap: *const c_char) -> c_int;
+    pub fn minijail_gidmap(j: *mut minijail, gidmap: *const c_char) -> c_int;
+    pub fn minijail_remount_proc_readonly(j: *mut minijail);
+    pub fn minijail_run_as_init(j: *mut minijail);
+    pub fn minijail_write_pid_file(j: *mut minijail, path: *const c_char) -> c_int;
+    pub fn minijail_inherit_usergroups(j: *mut minijail);
+    pub fn minijail_use_alt_syscall(j: *mut minijail, table: *const c_char) -> c_int;
+    pub fn minijail_add_to_cgroup(j: *mut minijail, path: *const c_char) -> c_int;
+    pub fn minijail_enter_chroot(j: *mut minijail, dir: *const c_char) -> c_int;
+    pub fn minijail_enter_pivot_root(j: *mut minijail, dir: *const c_char) -> c_int;
+    pub fn minijail_fork(j: *mut minijail) -> pid_t;
+    pub fn minijail_get_original_path(j: *mut minijail, chroot_path: *const c_char) -> *mut c_char;
+    pub fn minijail_mount_dev(j: *mut minijail);
+    pub fn minijail_mount_tmp(j: *mut minijail);
+    pub fn minijail_mount_tmp_size(j: *mut minijail, size: usize);
+    pub fn minijail_mount_with_data(
+        j: *mut minijail,
+        src: *const c_char,
+        dest: *const c_char,
+        type_: *const c_char,
+        flags: c_ulong,
+        data: *const c_char,
+    ) -> c_int;
+    pub fn minijail_mount(
+        j: *mut minijail,
+        src: *const c_char,
+        dest: *const c_char,
+        type_: *const c_char,
+        flags: c_ulong,
+    ) -> c_int;
+    pub fn minijail_bind(
+        j: *mut minijail,
+        src: *const c_char,
+        dest: *const c_char,
+        writeable: c_int,
+    ) -> c_int;
+    pub fn minijail_preserve_fd(j: *mut minijail, parent_fd: c_int, child_fd: c_int) -> c_int;
+    pub fn minijail_enter(j: *const minijail);
+    pub fn minijail_run(
+        j: *mut minijail,
+        filename: *const c_char,
+        argv: *const *const c_char,
+    ) -> c_int;
+    pub fn minijail_run_no_preload(
+        j: *mut minijail,
+        filename: *const c_char,
+        argv: *const *const c_char,
+    ) -> c_int;
+    pub fn minijail_run_pid(
+        j: *mut minijail,
+        filename: *const c_char,
+        argv: *const *const c_char,
+        pchild_pid: *mut pid_t,
+    ) -> c_int;
+    pub fn minijail_run_pipe(
+        j: *mut minijail,
+        filename: *const c_char,
+        argv: *const *const c_char,
+        pstdin_fd: *mut c_int,
+    ) -> c_int;
+    pub fn minijail_run_pid_pipes(
+        j: *mut minijail,
+        filename: *const c_char,
+        argv: *const *const c_char,
+        pchild_pid: *mut pid_t,
+        pstdin_fd: *mut c_int,
+        pstdout_fd: *mut c_int,
+        pstderr_fd: *mut c_int,
+    ) -> c_int;
+    pub fn minijail_run_pid_pipes_no_preload(
+        j: *mut minijail,
+        filename: *const c_char,
+        argv: *const *const c_char,
+        pchild_pid: *mut pid_t,
+        pstdin_fd: *mut c_int,
+        pstdout_fd: *mut c_int,
+        pstderr_fd: *mut c_int,
+    ) -> c_int;
+    pub fn minijail_kill(j: *mut minijail) -> c_int;
+    pub fn minijail_wait(j: *mut minijail) -> c_int;
+    pub fn minijail_destroy(j: *mut minijail);
+} // extern "C"
diff --git a/io_jail/src/test_filter.policy b/io_jail/src/test_filter.policy
new file mode 100644
index 0000000..9f4c943
--- /dev/null
+++ b/io_jail/src/test_filter.policy
@@ -0,0 +1,7 @@
+close: 1
+exit: 1
+futex: 1
+getpid: 1
+lseek: 1
+read: 1
+write: 1
diff --git a/kernel_cmdline/Cargo.toml b/kernel_cmdline/Cargo.toml
new file mode 100644
index 0000000..0000610
--- /dev/null
+++ b/kernel_cmdline/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "kernel_cmdline"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+libc = "*"
+
+[lib]
+path = "src/kernel_cmdline.rs"
diff --git a/kernel_cmdline/src/kernel_cmdline.rs b/kernel_cmdline/src/kernel_cmdline.rs
new file mode 100644
index 0000000..7284004
--- /dev/null
+++ b/kernel_cmdline/src/kernel_cmdline.rs
@@ -0,0 +1,230 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Helper for creating valid kernel command line strings.
+
+use std::fmt::{self, Display};
+use std::result;
+
+/// The error type for command line building operations.
+#[derive(PartialEq, Debug)]
+pub enum Error {
+    /// Operation would have resulted in a non-printable ASCII character.
+    InvalidAscii,
+    /// Key/Value Operation would have had a space in it.
+    HasSpace,
+    /// Key/Value Operation would have had an equals sign in it.
+    HasEquals,
+    /// Operation would have made the command line too large.
+    TooLarge,
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        let description = match self {
+            InvalidAscii => "string contains non-printable ASCII character",
+            HasSpace => "string contains a space",
+            HasEquals => "string contains an equals sign",
+            TooLarge => "inserting string would make command line too long",
+        };
+
+        write!(f, "{}", description)
+    }
+}
+
+/// Specialized Result type for command line operations.
+pub type Result<T> = result::Result<T, Error>;
+
+fn valid_char(c: char) -> bool {
+    match c {
+        ' '...'~' => true,
+        _ => false,
+    }
+}
+
+fn valid_str(s: &str) -> Result<()> {
+    if s.chars().all(valid_char) {
+        Ok(())
+    } else {
+        Err(Error::InvalidAscii)
+    }
+}
+
+fn valid_element(s: &str) -> Result<()> {
+    if !s.chars().all(valid_char) {
+        Err(Error::InvalidAscii)
+    } else if s.contains(' ') {
+        Err(Error::HasSpace)
+    } else if s.contains('=') {
+        Err(Error::HasEquals)
+    } else {
+        Ok(())
+    }
+}
+
+/// A builder for a kernel command line string that validates the string as its being built. A
+/// `CString` can be constructed from this directly using `CString::new`.
+pub struct Cmdline {
+    line: String,
+    capacity: usize,
+}
+
+impl Cmdline {
+    /// Constructs an empty Cmdline with the given capacity, which includes the nul terminator.
+    /// Capacity must be greater than 0.
+    pub fn new(capacity: usize) -> Cmdline {
+        assert_ne!(capacity, 0);
+        Cmdline {
+            line: String::new(),
+            capacity,
+        }
+    }
+
+    fn has_capacity(&self, more: usize) -> Result<()> {
+        let needs_space = if self.line.is_empty() { 0 } else { 1 };
+        if self.line.len() + more + needs_space < self.capacity {
+            Ok(())
+        } else {
+            Err(Error::TooLarge)
+        }
+    }
+
+    fn start_push(&mut self) {
+        if !self.line.is_empty() {
+            self.line.push(' ');
+        }
+    }
+
+    fn end_push(&mut self) {
+        // This assert is always true because of the `has_capacity` check that each insert method
+        // uses.
+        assert!(self.line.len() < self.capacity);
+    }
+
+    /// Validates and inserts a key value pair into this command line
+    pub fn insert<T: AsRef<str>>(&mut self, key: T, val: T) -> Result<()> {
+        let k = key.as_ref();
+        let v = val.as_ref();
+
+        valid_element(k)?;
+        valid_element(v)?;
+        self.has_capacity(k.len() + v.len() + 1)?;
+
+        self.start_push();
+        self.line.push_str(k);
+        self.line.push('=');
+        self.line.push_str(v);
+        self.end_push();
+
+        Ok(())
+    }
+
+    /// Validates and inserts a string to the end of the current command line
+    pub fn insert_str<T: AsRef<str>>(&mut self, slug: T) -> Result<()> {
+        let s = slug.as_ref();
+        valid_str(s)?;
+
+        self.has_capacity(s.len())?;
+
+        self.start_push();
+        self.line.push_str(s);
+        self.end_push();
+
+        Ok(())
+    }
+
+    /// Returns the cmdline in progress without nul termination
+    pub fn as_str(&self) -> &str {
+        self.line.as_str()
+    }
+}
+
+impl Into<Vec<u8>> for Cmdline {
+    fn into(self) -> Vec<u8> {
+        self.line.into_bytes()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::ffi::CString;
+
+    #[test]
+    fn insert_hello_world() {
+        let mut cl = Cmdline::new(100);
+        assert_eq!(cl.as_str(), "");
+        assert!(cl.insert("hello", "world").is_ok());
+        assert_eq!(cl.as_str(), "hello=world");
+
+        let s = CString::new(cl).expect("failed to create CString from Cmdline");
+        assert_eq!(s, CString::new("hello=world").unwrap());
+    }
+
+    #[test]
+    fn insert_multi() {
+        let mut cl = Cmdline::new(100);
+        assert!(cl.insert("hello", "world").is_ok());
+        assert!(cl.insert("foo", "bar").is_ok());
+        assert_eq!(cl.as_str(), "hello=world foo=bar");
+    }
+
+    #[test]
+    fn insert_space() {
+        let mut cl = Cmdline::new(100);
+        assert_eq!(cl.insert("a ", "b"), Err(Error::HasSpace));
+        assert_eq!(cl.insert("a", "b "), Err(Error::HasSpace));
+        assert_eq!(cl.insert("a ", "b "), Err(Error::HasSpace));
+        assert_eq!(cl.insert(" a", "b"), Err(Error::HasSpace));
+        assert_eq!(cl.as_str(), "");
+    }
+
+    #[test]
+    fn insert_equals() {
+        let mut cl = Cmdline::new(100);
+        assert_eq!(cl.insert("a=", "b"), Err(Error::HasEquals));
+        assert_eq!(cl.insert("a", "b="), Err(Error::HasEquals));
+        assert_eq!(cl.insert("a=", "b "), Err(Error::HasEquals));
+        assert_eq!(cl.insert("=a", "b"), Err(Error::HasEquals));
+        assert_eq!(cl.insert("a", "=b"), Err(Error::HasEquals));
+        assert_eq!(cl.as_str(), "");
+    }
+
+    #[test]
+    fn insert_emoji() {
+        let mut cl = Cmdline::new(100);
+        assert_eq!(cl.insert("heart", "💖"), Err(Error::InvalidAscii));
+        assert_eq!(cl.insert("💖", "love"), Err(Error::InvalidAscii));
+        assert_eq!(cl.as_str(), "");
+    }
+
+    #[test]
+    fn insert_string() {
+        let mut cl = Cmdline::new(13);
+        assert_eq!(cl.as_str(), "");
+        assert!(cl.insert_str("noapic").is_ok());
+        assert_eq!(cl.as_str(), "noapic");
+        assert!(cl.insert_str("nopci").is_ok());
+        assert_eq!(cl.as_str(), "noapic nopci");
+    }
+
+    #[test]
+    fn insert_too_large() {
+        let mut cl = Cmdline::new(4);
+        assert_eq!(cl.insert("hello", "world"), Err(Error::TooLarge));
+        assert_eq!(cl.insert("a", "world"), Err(Error::TooLarge));
+        assert_eq!(cl.insert("hello", "b"), Err(Error::TooLarge));
+        assert!(cl.insert("a", "b").is_ok());
+        assert_eq!(cl.insert("a", "b"), Err(Error::TooLarge));
+        assert_eq!(cl.insert_str("a"), Err(Error::TooLarge));
+        assert_eq!(cl.as_str(), "a=b");
+
+        let mut cl = Cmdline::new(10);
+        assert!(cl.insert("ab", "ba").is_ok()); // adds 5 length
+        assert_eq!(cl.insert("c", "da"), Err(Error::TooLarge)); // adds 5 (including space) length
+        assert!(cl.insert("c", "d").is_ok()); // adds 4 (including space) length
+    }
+}
diff --git a/kernel_loader/Cargo.toml b/kernel_loader/Cargo.toml
new file mode 100644
index 0000000..b49dbad
--- /dev/null
+++ b/kernel_loader/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "kernel_loader"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+libc = "*"
+sys_util = { path = "../sys_util" }
diff --git a/kernel_loader/src/elf.rs b/kernel_loader/src/elf.rs
new file mode 100644
index 0000000..c591e52
--- /dev/null
+++ b/kernel_loader/src/elf.rs
@@ -0,0 +1,285 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/*
+ * automatically generated by bindgen
+ * From chromeos-linux v4.19 include/uapi/linux/elf.h
+ * $ bindgen \
+ *       --no-layout-tests --with-derive-default \
+ *       --whitelist-type Elf64_Ehdr --whitelist-type Elf64_Phdr --whitelist-var .+ \
+ *       include/uapi/linux/elf.h
+ */
+
+pub const __BITS_PER_LONG: u32 = 64;
+pub const __FD_SETSIZE: u32 = 1024;
+pub const EM_NONE: u32 = 0;
+pub const EM_M32: u32 = 1;
+pub const EM_SPARC: u32 = 2;
+pub const EM_386: u32 = 3;
+pub const EM_68K: u32 = 4;
+pub const EM_88K: u32 = 5;
+pub const EM_486: u32 = 6;
+pub const EM_860: u32 = 7;
+pub const EM_MIPS: u32 = 8;
+pub const EM_MIPS_RS3_LE: u32 = 10;
+pub const EM_MIPS_RS4_BE: u32 = 10;
+pub const EM_PARISC: u32 = 15;
+pub const EM_SPARC32PLUS: u32 = 18;
+pub const EM_PPC: u32 = 20;
+pub const EM_PPC64: u32 = 21;
+pub const EM_SPU: u32 = 23;
+pub const EM_ARM: u32 = 40;
+pub const EM_SH: u32 = 42;
+pub const EM_SPARCV9: u32 = 43;
+pub const EM_H8_300: u32 = 46;
+pub const EM_IA_64: u32 = 50;
+pub const EM_X86_64: u32 = 62;
+pub const EM_S390: u32 = 22;
+pub const EM_CRIS: u32 = 76;
+pub const EM_M32R: u32 = 88;
+pub const EM_MN10300: u32 = 89;
+pub const EM_OPENRISC: u32 = 92;
+pub const EM_BLACKFIN: u32 = 106;
+pub const EM_ALTERA_NIOS2: u32 = 113;
+pub const EM_TI_C6000: u32 = 140;
+pub const EM_AARCH64: u32 = 183;
+pub const EM_TILEPRO: u32 = 188;
+pub const EM_MICROBLAZE: u32 = 189;
+pub const EM_TILEGX: u32 = 191;
+pub const EM_BPF: u32 = 247;
+pub const EM_FRV: u32 = 21569;
+pub const EM_ALPHA: u32 = 36902;
+pub const EM_CYGNUS_M32R: u32 = 36929;
+pub const EM_S390_OLD: u32 = 41872;
+pub const EM_CYGNUS_MN10300: u32 = 48879;
+pub const PT_NULL: u32 = 0;
+pub const PT_LOAD: u32 = 1;
+pub const PT_DYNAMIC: u32 = 2;
+pub const PT_INTERP: u32 = 3;
+pub const PT_NOTE: u32 = 4;
+pub const PT_SHLIB: u32 = 5;
+pub const PT_PHDR: u32 = 6;
+pub const PT_TLS: u32 = 7;
+pub const PT_LOOS: u32 = 1610612736;
+pub const PT_HIOS: u32 = 1879048191;
+pub const PT_LOPROC: u32 = 1879048192;
+pub const PT_HIPROC: u32 = 2147483647;
+pub const PT_GNU_EH_FRAME: u32 = 1685382480;
+pub const PT_GNU_STACK: u32 = 1685382481;
+pub const PN_XNUM: u32 = 65535;
+pub const ET_NONE: u32 = 0;
+pub const ET_REL: u32 = 1;
+pub const ET_EXEC: u32 = 2;
+pub const ET_DYN: u32 = 3;
+pub const ET_CORE: u32 = 4;
+pub const ET_LOPROC: u32 = 65280;
+pub const ET_HIPROC: u32 = 65535;
+pub const DT_NULL: u32 = 0;
+pub const DT_NEEDED: u32 = 1;
+pub const DT_PLTRELSZ: u32 = 2;
+pub const DT_PLTGOT: u32 = 3;
+pub const DT_HASH: u32 = 4;
+pub const DT_STRTAB: u32 = 5;
+pub const DT_SYMTAB: u32 = 6;
+pub const DT_RELA: u32 = 7;
+pub const DT_RELASZ: u32 = 8;
+pub const DT_RELAENT: u32 = 9;
+pub const DT_STRSZ: u32 = 10;
+pub const DT_SYMENT: u32 = 11;
+pub const DT_INIT: u32 = 12;
+pub const DT_FINI: u32 = 13;
+pub const DT_SONAME: u32 = 14;
+pub const DT_RPATH: u32 = 15;
+pub const DT_SYMBOLIC: u32 = 16;
+pub const DT_REL: u32 = 17;
+pub const DT_RELSZ: u32 = 18;
+pub const DT_RELENT: u32 = 19;
+pub const DT_PLTREL: u32 = 20;
+pub const DT_DEBUG: u32 = 21;
+pub const DT_TEXTREL: u32 = 22;
+pub const DT_JMPREL: u32 = 23;
+pub const DT_ENCODING: u32 = 32;
+pub const OLD_DT_LOOS: u32 = 1610612736;
+pub const DT_LOOS: u32 = 1610612749;
+pub const DT_HIOS: u32 = 1879044096;
+pub const DT_VALRNGLO: u32 = 1879047424;
+pub const DT_VALRNGHI: u32 = 1879047679;
+pub const DT_ADDRRNGLO: u32 = 1879047680;
+pub const DT_ADDRRNGHI: u32 = 1879047935;
+pub const DT_VERSYM: u32 = 1879048176;
+pub const DT_RELACOUNT: u32 = 1879048185;
+pub const DT_RELCOUNT: u32 = 1879048186;
+pub const DT_FLAGS_1: u32 = 1879048187;
+pub const DT_VERDEF: u32 = 1879048188;
+pub const DT_VERDEFNUM: u32 = 1879048189;
+pub const DT_VERNEED: u32 = 1879048190;
+pub const DT_VERNEEDNUM: u32 = 1879048191;
+pub const OLD_DT_HIOS: u32 = 1879048191;
+pub const DT_LOPROC: u32 = 1879048192;
+pub const DT_HIPROC: u32 = 2147483647;
+pub const STB_LOCAL: u32 = 0;
+pub const STB_GLOBAL: u32 = 1;
+pub const STB_WEAK: u32 = 2;
+pub const STT_NOTYPE: u32 = 0;
+pub const STT_OBJECT: u32 = 1;
+pub const STT_FUNC: u32 = 2;
+pub const STT_SECTION: u32 = 3;
+pub const STT_FILE: u32 = 4;
+pub const STT_COMMON: u32 = 5;
+pub const STT_TLS: u32 = 6;
+pub const EI_NIDENT: u32 = 16;
+pub const PF_R: u32 = 4;
+pub const PF_W: u32 = 2;
+pub const PF_X: u32 = 1;
+pub const SHT_NULL: u32 = 0;
+pub const SHT_PROGBITS: u32 = 1;
+pub const SHT_SYMTAB: u32 = 2;
+pub const SHT_STRTAB: u32 = 3;
+pub const SHT_RELA: u32 = 4;
+pub const SHT_HASH: u32 = 5;
+pub const SHT_DYNAMIC: u32 = 6;
+pub const SHT_NOTE: u32 = 7;
+pub const SHT_NOBITS: u32 = 8;
+pub const SHT_REL: u32 = 9;
+pub const SHT_SHLIB: u32 = 10;
+pub const SHT_DYNSYM: u32 = 11;
+pub const SHT_NUM: u32 = 12;
+pub const SHT_LOPROC: u32 = 1879048192;
+pub const SHT_HIPROC: u32 = 2147483647;
+pub const SHT_LOUSER: u32 = 2147483648;
+pub const SHT_HIUSER: u32 = 4294967295;
+pub const SHF_WRITE: u32 = 1;
+pub const SHF_ALLOC: u32 = 2;
+pub const SHF_EXECINSTR: u32 = 4;
+pub const SHF_RELA_LIVEPATCH: u32 = 1048576;
+pub const SHF_RO_AFTER_INIT: u32 = 2097152;
+pub const SHF_MASKPROC: u32 = 4026531840;
+pub const SHN_UNDEF: u32 = 0;
+pub const SHN_LORESERVE: u32 = 65280;
+pub const SHN_LOPROC: u32 = 65280;
+pub const SHN_HIPROC: u32 = 65311;
+pub const SHN_LIVEPATCH: u32 = 65312;
+pub const SHN_ABS: u32 = 65521;
+pub const SHN_COMMON: u32 = 65522;
+pub const SHN_HIRESERVE: u32 = 65535;
+pub const EI_MAG0: u32 = 0;
+pub const EI_MAG1: u32 = 1;
+pub const EI_MAG2: u32 = 2;
+pub const EI_MAG3: u32 = 3;
+pub const EI_CLASS: u32 = 4;
+pub const EI_DATA: u32 = 5;
+pub const EI_VERSION: u32 = 6;
+pub const EI_OSABI: u32 = 7;
+pub const EI_PAD: u32 = 8;
+pub const ELFMAG0: u32 = 127;
+pub const ELFMAG1: u8 = 69u8;
+pub const ELFMAG2: u8 = 76u8;
+pub const ELFMAG3: u8 = 70u8;
+pub const ELFMAG: &'static [u8; 5usize] = b"\x7FELF\0";
+pub const SELFMAG: u32 = 4;
+pub const ELFCLASSNONE: u32 = 0;
+pub const ELFCLASS32: u32 = 1;
+pub const ELFCLASS64: u32 = 2;
+pub const ELFCLASSNUM: u32 = 3;
+pub const ELFDATANONE: u32 = 0;
+pub const ELFDATA2LSB: u32 = 1;
+pub const ELFDATA2MSB: u32 = 2;
+pub const EV_NONE: u32 = 0;
+pub const EV_CURRENT: u32 = 1;
+pub const EV_NUM: u32 = 2;
+pub const ELFOSABI_NONE: u32 = 0;
+pub const ELFOSABI_LINUX: u32 = 3;
+pub const ELF_OSABI: u32 = 0;
+pub const NT_PRSTATUS: u32 = 1;
+pub const NT_PRFPREG: u32 = 2;
+pub const NT_PRPSINFO: u32 = 3;
+pub const NT_TASKSTRUCT: u32 = 4;
+pub const NT_AUXV: u32 = 6;
+pub const NT_SIGINFO: u32 = 1397311305;
+pub const NT_FILE: u32 = 1179208773;
+pub const NT_PRXFPREG: u32 = 1189489535;
+pub const NT_PPC_VMX: u32 = 256;
+pub const NT_PPC_SPE: u32 = 257;
+pub const NT_PPC_VSX: u32 = 258;
+pub const NT_PPC_TAR: u32 = 259;
+pub const NT_PPC_PPR: u32 = 260;
+pub const NT_PPC_DSCR: u32 = 261;
+pub const NT_PPC_EBB: u32 = 262;
+pub const NT_PPC_PMU: u32 = 263;
+pub const NT_PPC_TM_CGPR: u32 = 264;
+pub const NT_PPC_TM_CFPR: u32 = 265;
+pub const NT_PPC_TM_CVMX: u32 = 266;
+pub const NT_PPC_TM_CVSX: u32 = 267;
+pub const NT_PPC_TM_SPR: u32 = 268;
+pub const NT_PPC_TM_CTAR: u32 = 269;
+pub const NT_PPC_TM_CPPR: u32 = 270;
+pub const NT_PPC_TM_CDSCR: u32 = 271;
+pub const NT_PPC_PKEY: u32 = 272;
+pub const NT_386_TLS: u32 = 512;
+pub const NT_386_IOPERM: u32 = 513;
+pub const NT_X86_XSTATE: u32 = 514;
+pub const NT_S390_HIGH_GPRS: u32 = 768;
+pub const NT_S390_TIMER: u32 = 769;
+pub const NT_S390_TODCMP: u32 = 770;
+pub const NT_S390_TODPREG: u32 = 771;
+pub const NT_S390_CTRS: u32 = 772;
+pub const NT_S390_PREFIX: u32 = 773;
+pub const NT_S390_LAST_BREAK: u32 = 774;
+pub const NT_S390_SYSTEM_CALL: u32 = 775;
+pub const NT_S390_TDB: u32 = 776;
+pub const NT_S390_VXRS_LOW: u32 = 777;
+pub const NT_S390_VXRS_HIGH: u32 = 778;
+pub const NT_S390_GS_CB: u32 = 779;
+pub const NT_S390_GS_BC: u32 = 780;
+pub const NT_S390_RI_CB: u32 = 781;
+pub const NT_ARM_VFP: u32 = 1024;
+pub const NT_ARM_TLS: u32 = 1025;
+pub const NT_ARM_HW_BREAK: u32 = 1026;
+pub const NT_ARM_HW_WATCH: u32 = 1027;
+pub const NT_ARM_SYSTEM_CALL: u32 = 1028;
+pub const NT_ARM_SVE: u32 = 1029;
+pub const NT_ARC_V2: u32 = 1536;
+pub const NT_VMCOREDD: u32 = 1792;
+pub const NT_MIPS_DSP: u32 = 2048;
+pub const NT_MIPS_FP_MODE: u32 = 2049;
+pub type __u16 = ::std::os::raw::c_ushort;
+pub type __u32 = ::std::os::raw::c_uint;
+pub type __u64 = ::std::os::raw::c_ulonglong;
+pub type Elf64_Addr = __u64;
+pub type Elf64_Half = __u16;
+pub type Elf64_Off = __u64;
+pub type Elf64_Word = __u32;
+pub type Elf64_Xword = __u64;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct elf64_hdr {
+    pub e_ident: [::std::os::raw::c_uchar; 16usize],
+    pub e_type: Elf64_Half,
+    pub e_machine: Elf64_Half,
+    pub e_version: Elf64_Word,
+    pub e_entry: Elf64_Addr,
+    pub e_phoff: Elf64_Off,
+    pub e_shoff: Elf64_Off,
+    pub e_flags: Elf64_Word,
+    pub e_ehsize: Elf64_Half,
+    pub e_phentsize: Elf64_Half,
+    pub e_phnum: Elf64_Half,
+    pub e_shentsize: Elf64_Half,
+    pub e_shnum: Elf64_Half,
+    pub e_shstrndx: Elf64_Half,
+}
+pub type Elf64_Ehdr = elf64_hdr;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct elf64_phdr {
+    pub p_type: Elf64_Word,
+    pub p_flags: Elf64_Word,
+    pub p_offset: Elf64_Off,
+    pub p_vaddr: Elf64_Addr,
+    pub p_paddr: Elf64_Addr,
+    pub p_filesz: Elf64_Xword,
+    pub p_memsz: Elf64_Xword,
+    pub p_align: Elf64_Xword,
+}
+pub type Elf64_Phdr = elf64_phdr;
diff --git a/kernel_loader/src/lib.rs b/kernel_loader/src/lib.rs
new file mode 100644
index 0000000..7ff6efa
--- /dev/null
+++ b/kernel_loader/src/lib.rs
@@ -0,0 +1,290 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::ffi::CStr;
+use std::fmt::{self, Display};
+use std::io::{Read, Seek, SeekFrom};
+use std::mem;
+use std::os::unix::io::AsRawFd;
+
+use sys_util::{GuestAddress, GuestMemory};
+
+#[allow(dead_code)]
+#[allow(non_camel_case_types)]
+#[allow(non_snake_case)]
+#[allow(non_upper_case_globals)]
+#[allow(clippy::all)]
+mod elf;
+
+#[derive(Debug, PartialEq)]
+pub enum Error {
+    BigEndianElfOnLittle,
+    CommandLineCopy,
+    CommandLineOverflow,
+    InvalidElfMagicNumber,
+    InvalidProgramHeaderSize,
+    InvalidProgramHeaderOffset,
+    InvalidProgramHeaderAddress,
+    ReadElfHeader,
+    ReadKernelImage,
+    ReadProgramHeader,
+    SeekKernelStart,
+    SeekElfStart,
+    SeekProgramHeader,
+}
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        let description = match self {
+            BigEndianElfOnLittle => "trying to load big-endian binary on little-endian machine",
+            CommandLineCopy => "failed writing command line to guest memory",
+            CommandLineOverflow => "command line overflowed guest memory",
+            InvalidElfMagicNumber => "invalid Elf magic number",
+            InvalidProgramHeaderSize => "invalid program header size",
+            InvalidProgramHeaderOffset => "invalid program header offset",
+            InvalidProgramHeaderAddress => "invalid Program Header Address",
+            ReadElfHeader => "unable to read elf header",
+            ReadKernelImage => "unable to read kernel image",
+            ReadProgramHeader => "unable to read program header",
+            SeekKernelStart => "unable to seek to kernel start",
+            SeekElfStart => "unable to seek to elf start",
+            SeekProgramHeader => "unable to seek to program header",
+        };
+
+        write!(f, "kernel loader: {}", description)
+    }
+}
+
+/// Loads a kernel from a vmlinux elf image to a slice
+///
+/// # Arguments
+///
+/// * `guest_mem` - The guest memory region the kernel is written to.
+/// * `kernel_start` - The offset into `guest_mem` at which to load the kernel.
+/// * `kernel_image` - Input vmlinux image.
+pub fn load_kernel<F>(
+    guest_mem: &GuestMemory,
+    kernel_start: GuestAddress,
+    kernel_image: &mut F,
+) -> Result<u64>
+where
+    F: Read + Seek + AsRawFd,
+{
+    let mut ehdr: elf::Elf64_Ehdr = Default::default();
+    kernel_image
+        .seek(SeekFrom::Start(0))
+        .map_err(|_| Error::SeekElfStart)?;
+    unsafe {
+        // read_struct is safe when reading a POD struct.  It can be used and dropped without issue.
+        sys_util::read_struct(kernel_image, &mut ehdr).map_err(|_| Error::ReadElfHeader)?;
+    }
+
+    // Sanity checks
+    if ehdr.e_ident[elf::EI_MAG0 as usize] != elf::ELFMAG0 as u8
+        || ehdr.e_ident[elf::EI_MAG1 as usize] != elf::ELFMAG1
+        || ehdr.e_ident[elf::EI_MAG2 as usize] != elf::ELFMAG2
+        || ehdr.e_ident[elf::EI_MAG3 as usize] != elf::ELFMAG3
+    {
+        return Err(Error::InvalidElfMagicNumber);
+    }
+    if ehdr.e_ident[elf::EI_DATA as usize] != elf::ELFDATA2LSB as u8 {
+        return Err(Error::BigEndianElfOnLittle);
+    }
+    if ehdr.e_phentsize as usize != mem::size_of::<elf::Elf64_Phdr>() {
+        return Err(Error::InvalidProgramHeaderSize);
+    }
+    if (ehdr.e_phoff as usize) < mem::size_of::<elf::Elf64_Ehdr>() {
+        // If the program header is backwards, bail.
+        return Err(Error::InvalidProgramHeaderOffset);
+    }
+
+    kernel_image
+        .seek(SeekFrom::Start(ehdr.e_phoff))
+        .map_err(|_| Error::SeekProgramHeader)?;
+    let phdrs: Vec<elf::Elf64_Phdr> = unsafe {
+        // Reading the structs is safe for a slice of POD structs.
+        sys_util::read_struct_slice(kernel_image, ehdr.e_phnum as usize)
+            .map_err(|_| Error::ReadProgramHeader)?
+    };
+
+    let mut kernel_end = 0;
+
+    // Read in each section pointed to by the program headers.
+    for phdr in &phdrs {
+        if phdr.p_type != elf::PT_LOAD || phdr.p_filesz == 0 {
+            continue;
+        }
+
+        kernel_image
+            .seek(SeekFrom::Start(phdr.p_offset))
+            .map_err(|_| Error::SeekKernelStart)?;
+
+        let mem_offset = kernel_start
+            .checked_add(phdr.p_paddr)
+            .ok_or(Error::InvalidProgramHeaderAddress)?;
+        guest_mem
+            .read_to_memory(mem_offset, kernel_image, phdr.p_filesz as usize)
+            .map_err(|_| Error::ReadKernelImage)?;
+
+        kernel_end = mem_offset.offset() + phdr.p_memsz;
+    }
+
+    Ok(kernel_end)
+}
+
+/// Writes the command line string to the given memory slice.
+///
+/// # Arguments
+///
+/// * `guest_mem` - A u8 slice that will be partially overwritten by the command line.
+/// * `guest_addr` - The address in `guest_mem` at which to load the command line.
+/// * `cmdline` - The kernel command line.
+pub fn load_cmdline(
+    guest_mem: &GuestMemory,
+    guest_addr: GuestAddress,
+    cmdline: &CStr,
+) -> Result<()> {
+    let len = cmdline.to_bytes().len();
+    if len == 0 {
+        return Ok(());
+    }
+
+    let end = guest_addr
+        .checked_add(len as u64 + 1)
+        .ok_or(Error::CommandLineOverflow)?; // Extra for null termination.
+    if end > guest_mem.end_addr() {
+        return Err(Error::CommandLineOverflow)?;
+    }
+
+    guest_mem
+        .write_at_addr(cmdline.to_bytes_with_nul(), guest_addr)
+        .map_err(|_| Error::CommandLineCopy)?;
+
+    Ok(())
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::fs::File;
+    use std::io::Write;
+    use sys_util::{GuestAddress, GuestMemory, SharedMemory};
+
+    const MEM_SIZE: u64 = 0x8000;
+
+    fn create_guest_mem() -> GuestMemory {
+        GuestMemory::new(&vec![(GuestAddress(0x0), MEM_SIZE)]).unwrap()
+    }
+
+    #[test]
+    fn cmdline_overflow() {
+        let gm = create_guest_mem();
+        let cmdline_address = GuestAddress(MEM_SIZE - 5);
+        assert_eq!(
+            Err(Error::CommandLineOverflow),
+            load_cmdline(
+                &gm,
+                cmdline_address,
+                CStr::from_bytes_with_nul(b"12345\0").unwrap()
+            )
+        );
+    }
+
+    #[test]
+    fn cmdline_write_end() {
+        let gm = create_guest_mem();
+        let mut cmdline_address = GuestAddress(45);
+        assert_eq!(
+            Ok(()),
+            load_cmdline(
+                &gm,
+                cmdline_address,
+                CStr::from_bytes_with_nul(b"1234\0").unwrap()
+            )
+        );
+        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
+        assert_eq!(val, '1' as u8);
+        cmdline_address = cmdline_address.unchecked_add(1);
+        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
+        assert_eq!(val, '2' as u8);
+        cmdline_address = cmdline_address.unchecked_add(1);
+        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
+        assert_eq!(val, '3' as u8);
+        cmdline_address = cmdline_address.unchecked_add(1);
+        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
+        assert_eq!(val, '4' as u8);
+        cmdline_address = cmdline_address.unchecked_add(1);
+        let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap();
+        assert_eq!(val, '\0' as u8);
+    }
+
+    // Elf64 image that prints hello world on x86_64.
+    fn make_elf_bin() -> File {
+        let elf_bytes = include_bytes!("test_elf.bin");
+        let mut shm = SharedMemory::new(None).expect("failed to create shared memory");
+        shm.set_size(elf_bytes.len() as u64)
+            .expect("failed to set shared memory size");
+        shm.write_all(elf_bytes)
+            .expect("failed to write elf to shared memoy");
+        shm.into()
+    }
+
+    fn mutate_elf_bin(mut f: &File, offset: u64, val: u8) {
+        f.seek(SeekFrom::Start(offset))
+            .expect("failed to seek file");
+        f.write(&[val])
+            .expect("failed to write mutated value to file");
+    }
+
+    #[test]
+    fn load_elf() {
+        let gm = create_guest_mem();
+        let kernel_addr = GuestAddress(0x0);
+        let mut image = make_elf_bin();
+        assert_eq!(Ok(16613), load_kernel(&gm, kernel_addr, &mut image));
+    }
+
+    #[test]
+    fn bad_magic() {
+        let gm = create_guest_mem();
+        let kernel_addr = GuestAddress(0x0);
+        let mut bad_image = make_elf_bin();
+        mutate_elf_bin(&bad_image, 0x1, 0x33);
+        assert_eq!(
+            Err(Error::InvalidElfMagicNumber),
+            load_kernel(&gm, kernel_addr, &mut bad_image)
+        );
+    }
+
+    #[test]
+    fn bad_endian() {
+        // Only little endian is supported
+        let gm = create_guest_mem();
+        let kernel_addr = GuestAddress(0x0);
+        let mut bad_image = make_elf_bin();
+        mutate_elf_bin(&bad_image, 0x5, 2);
+        assert_eq!(
+            Err(Error::BigEndianElfOnLittle),
+            load_kernel(&gm, kernel_addr, &mut bad_image)
+        );
+    }
+
+    #[test]
+    fn bad_phoff() {
+        // program header has to be past the end of the elf header
+        let gm = create_guest_mem();
+        let kernel_addr = GuestAddress(0x0);
+        let mut bad_image = make_elf_bin();
+        mutate_elf_bin(&bad_image, 0x20, 0x10);
+        assert_eq!(
+            Err(Error::InvalidProgramHeaderOffset),
+            load_kernel(&gm, kernel_addr, &mut bad_image)
+        );
+    }
+}
diff --git a/kernel_loader/src/test_elf.bin b/kernel_loader/src/test_elf.bin
new file mode 100644
index 0000000..74eac6e
--- /dev/null
+++ b/kernel_loader/src/test_elf.bin
Binary files differ
diff --git a/kokoro/README.md b/kokoro/README.md
new file mode 100644
index 0000000..727b74a
--- /dev/null
+++ b/kokoro/README.md
@@ -0,0 +1,78 @@
+# Kokoro CI for crosvm
+
+For presubmit testing, each change posted for Gerrit on the master branch of crosvm will be tried by
+Kokoro. The configuration is found in [`presubmit.cfg`](presubmit.cfg) and the build script is at
+[`build.sh`](build.sh). A Docker image called `crosvm-base` is used as the testing environment which
+is built with a [`Dockerfile`](../docker/Dockerfile).
+
+[TOC]
+
+## How to use Docker to test crosvm
+
+Assuming a Docker daemon is already running, build the `crosvm-base` image:
+
+```shell
+path/to/crosvm/docker/build_crosvm_base.sh
+```
+
+Here is how to use the image to test a crosvm repository located at `$CROSVM_SRC`:
+
+```shell
+$CROSVM_SRC/docker/wrapped_smoke_test.sh
+```
+
+> **WARNING**:
+> The `--privileged` flag is used in that script so that the container will have `/dev/kvm` access.
+
+## How to update `crosvm-base`
+
+The `crosvm-base` `Dockerfile` downloads, builds, and install specific library versions needed to
+test crosvm. It also defines a run time environment and default command line for performing a test.
+If an update or new library is needed or any other adjustment is required, a new image can be
+generated as follows:
+
+```shell
+path/to/crosvm/docker/build_crosvm_base.sh
+docker save crosvm-base | xz -T 0 -z >crosvm-base.tar.xz
+```
+
+If you have x20 access, move `crosvm-base.tar.xz` to `/teams/chromeos-vm/docker/` and ensure the
+owner is `chromeos-vm-ci-read-write`. This owner is used to allow Kokoro to read the base image in
+during the test run. The updated image will be used for future Kokoro runs until it is replaced.
+
+```shell
+prodaccess
+cp crosvm-base.tar.xz /google/data/rw/teams/chromeos-vm/docker/
+```
+
+The cp command should preserve the right owner but to be sure you can confirm that it is
+`chromeos-vm-ci-read-write` in the web ui: https://x20.corp.google.com/teams/chromeos-vm/docker
+
+> **WARNING**:
+> If the image tarball uploaded to x20 is defective in any way, Kokoro will fail to verify every
+> crosvm change as if the change itself were defective. Please verify the image is good before
+> uploading to x20.
+
+## How to simulate Kokoro before uploading
+
+If you want to test a change before uploading it in a similar environment to Kokoro, use the
+[`kokoro_simulator.sh`](kokoro_simulator.sh) script. It will invoke the `build.sh` script after
+exporting environment variables and a volume that are expected to be present. The crosvm source code
+is symlinked in, and is tested exactly as in the working directory. Any changes to `build.sh` will
+also be tested, but any changes to `presubmit.cfg` will have no effect. If there are any changes to
+`Dockerfile`, they will have no effect unless the `crosvm-base` image is removed (or never existed)
+from the local Docker daemon. To test `Dockerfile` changes use the following formula to purge
+`crosvm-base`.
+
+```shell
+# So that kokoro_simulator.sh doesn't skip `docker save`.
+rm /tmp/kokoro_simulator/crosvm-base.tar.xz
+
+# Stopped containers prevent the removal of images below.
+docker container prune
+
+# So that kokoro_simulator.sh doesn't skip `docker build`.
+docker rmi crosvm-base
+```
+
+心
diff --git a/kokoro/build.sh b/kokoro/build.sh
new file mode 100755
index 0000000..96028ac
--- /dev/null
+++ b/kokoro/build.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -ex
+
+main() {
+  if [ -z "${KOKORO_ARTIFACTS_DIR}" ]; then
+    echo "This script must be run in kokoro"
+    exit 1
+  fi
+
+  local src_root="${KOKORO_ARTIFACTS_DIR}"/git/crosvm
+  local base_image_tarball="${KOKORO_GFILE_DIR}"/crosvm-base.tar.xz
+  local base_image="crosvm-base"
+
+  if [[ "$(docker images -q ${base_image} 2> /dev/null)" == "" ]]; then
+    docker load -i "${base_image_tarball}"
+  fi
+  "${src_root}"/docker/wrapped_smoke_test.sh
+
+  return 0
+}
+
+main "$@"
diff --git a/kokoro/continuous.cfg b/kokoro/continuous.cfg
new file mode 100644
index 0000000..3dc7682
--- /dev/null
+++ b/kokoro/continuous.cfg
@@ -0,0 +1,5 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+build_file: "crosvm/kokoro/build.sh"
+
+gfile_resources: "/x20/teams/chromeos-vm/docker/crosvm-base.tar.xz"
diff --git a/kokoro/kokoro_simulator.sh b/kokoro/kokoro_simulator.sh
new file mode 100755
index 0000000..08961de
--- /dev/null
+++ b/kokoro/kokoro_simulator.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -ex
+
+main() {
+  cd "$(dirname "$0")"
+
+  local kokoro_simulator_root=/tmp/kokoro_simulator
+  local src_root="${kokoro_simulator_root}"/git/crosvm
+  local base_image_tarball="${kokoro_simulator_root}"/crosvm-base.tar.xz
+  local base_image="crosvm-base"
+
+  mkdir -p "${kokoro_simulator_root}"
+  if [[ ! -e "${base_image_tarball}" ]]; then
+    if [[ "$(docker images -q ${base_image} 2> /dev/null)" == "" ]]; then
+      ../docker/build_crosvm_base.sh
+    fi
+    docker save ${base_image} | xz -T 0 -z >"${base_image_tarball}"
+  fi
+
+  if [[ ! -e "${src_root}" ]]; then
+    mkdir -p "${kokoro_simulator_root}"/git
+    ln -s "$(realpath ../)" "${src_root}"
+  fi
+
+  export KOKORO_ARTIFACTS_DIR="${kokoro_simulator_root}"
+  export KOKORO_GFILE_DIR="${kokoro_simulator_root}"
+
+  ./build.sh
+}
+
+main "$@"
diff --git a/kokoro/presubmit-cr.cfg b/kokoro/presubmit-cr.cfg
new file mode 100644
index 0000000..3dc7682
--- /dev/null
+++ b/kokoro/presubmit-cr.cfg
@@ -0,0 +1,5 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+build_file: "crosvm/kokoro/build.sh"
+
+gfile_resources: "/x20/teams/chromeos-vm/docker/crosvm-base.tar.xz"
diff --git a/kokoro/presubmit.cfg b/kokoro/presubmit.cfg
new file mode 100644
index 0000000..3dc7682
--- /dev/null
+++ b/kokoro/presubmit.cfg
@@ -0,0 +1,5 @@
+# Format: //devtools/kokoro/config/proto/build.proto
+
+build_file: "crosvm/kokoro/build.sh"
+
+gfile_resources: "/x20/teams/chromeos-vm/docker/crosvm-base.tar.xz"
diff --git a/kvm/Cargo.toml b/kvm/Cargo.toml
new file mode 100644
index 0000000..d12aa76
--- /dev/null
+++ b/kvm/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "kvm"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+kvm_sys = { path = "../kvm_sys" }
+libc = "*"
+msg_socket = { path = "../msg_socket" }
+sys_util = { path = "../sys_util" }
diff --git a/kvm/src/cap.rs b/kvm/src/cap.rs
new file mode 100644
index 0000000..b095f82
--- /dev/null
+++ b/kvm/src/cap.rs
@@ -0,0 +1,121 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use kvm_sys::*;
+
+/// A capability the kernel's KVM interface can possibly expose.
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(u32)]
+pub enum Cap {
+    Irqchip = KVM_CAP_IRQCHIP,
+    Hlt = KVM_CAP_HLT,
+    MmuShadowCacheControl = KVM_CAP_MMU_SHADOW_CACHE_CONTROL,
+    UserMemory = KVM_CAP_USER_MEMORY,
+    SetTssAddr = KVM_CAP_SET_TSS_ADDR,
+    Vapic = KVM_CAP_VAPIC,
+    ExtCpuid = KVM_CAP_EXT_CPUID,
+    Clocksource = KVM_CAP_CLOCKSOURCE,
+    NrVcpus = KVM_CAP_NR_VCPUS,
+    NrMemslots = KVM_CAP_NR_MEMSLOTS,
+    Pit = KVM_CAP_PIT,
+    NopIoDelay = KVM_CAP_NOP_IO_DELAY,
+    PvMmu = KVM_CAP_PV_MMU,
+    MpState = KVM_CAP_MP_STATE,
+    CoalescedMmio = KVM_CAP_COALESCED_MMIO,
+    SyncMmu = KVM_CAP_SYNC_MMU,
+    Iommu = KVM_CAP_IOMMU,
+    DestroyMemoryRegionWorks = KVM_CAP_DESTROY_MEMORY_REGION_WORKS,
+    UserNmi = KVM_CAP_USER_NMI,
+    SetGuestDebug = KVM_CAP_SET_GUEST_DEBUG,
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    ReinjectControl = KVM_CAP_REINJECT_CONTROL,
+    IrqRouting = KVM_CAP_IRQ_ROUTING,
+    IrqInjectStatus = KVM_CAP_IRQ_INJECT_STATUS,
+    AssignDevIrq = KVM_CAP_ASSIGN_DEV_IRQ,
+    JoinMemoryRegionsWorks = KVM_CAP_JOIN_MEMORY_REGIONS_WORKS,
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    Mce = KVM_CAP_MCE,
+    Irqfd = KVM_CAP_IRQFD,
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    Pit2 = KVM_CAP_PIT2,
+    SetBootCpuId = KVM_CAP_SET_BOOT_CPU_ID,
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    PitState2 = KVM_CAP_PIT_STATE2,
+    Ioeventfd = KVM_CAP_IOEVENTFD,
+    SetIdentityMapAddr = KVM_CAP_SET_IDENTITY_MAP_ADDR,
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    XenHvm = KVM_CAP_XEN_HVM,
+    AdjustClock = KVM_CAP_ADJUST_CLOCK,
+    InternalErrorData = KVM_CAP_INTERNAL_ERROR_DATA,
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    VcpuEvents = KVM_CAP_VCPU_EVENTS,
+    S390Psw = KVM_CAP_S390_PSW,
+    PpcSegstate = KVM_CAP_PPC_SEGSTATE,
+    Hyperv = KVM_CAP_HYPERV,
+    HypervVapic = KVM_CAP_HYPERV_VAPIC,
+    HypervSpin = KVM_CAP_HYPERV_SPIN,
+    PciSegment = KVM_CAP_PCI_SEGMENT,
+    PpcPairedSingles = KVM_CAP_PPC_PAIRED_SINGLES,
+    IntrShadow = KVM_CAP_INTR_SHADOW,
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    Debugregs = KVM_CAP_DEBUGREGS,
+    X86RobustSinglestep = KVM_CAP_X86_ROBUST_SINGLESTEP,
+    PpcOsi = KVM_CAP_PPC_OSI,
+    PpcUnsetIrq = KVM_CAP_PPC_UNSET_IRQ,
+    EnableCap = KVM_CAP_ENABLE_CAP,
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    Xsave = KVM_CAP_XSAVE,
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    Xcrs = KVM_CAP_XCRS,
+    PpcGetPvinfo = KVM_CAP_PPC_GET_PVINFO,
+    PpcIrqLevel = KVM_CAP_PPC_IRQ_LEVEL,
+    AsyncPf = KVM_CAP_ASYNC_PF,
+    TscControl = KVM_CAP_TSC_CONTROL,
+    GetTscKhz = KVM_CAP_GET_TSC_KHZ,
+    PpcBookeSregs = KVM_CAP_PPC_BOOKE_SREGS,
+    SpaprTce = KVM_CAP_SPAPR_TCE,
+    PpcSmt = KVM_CAP_PPC_SMT,
+    PpcRma = KVM_CAP_PPC_RMA,
+    MaxVcpus = KVM_CAP_MAX_VCPUS,
+    PpcHior = KVM_CAP_PPC_HIOR,
+    PpcPapr = KVM_CAP_PPC_PAPR,
+    SwTlb = KVM_CAP_SW_TLB,
+    OneReg = KVM_CAP_ONE_REG,
+    S390Gmap = KVM_CAP_S390_GMAP,
+    TscDeadlineTimer = KVM_CAP_TSC_DEADLINE_TIMER,
+    S390Ucontrol = KVM_CAP_S390_UCONTROL,
+    SyncRegs = KVM_CAP_SYNC_REGS,
+    Pci23 = KVM_CAP_PCI_2_3,
+    KvmclockCtrl = KVM_CAP_KVMCLOCK_CTRL,
+    SignalMsi = KVM_CAP_SIGNAL_MSI,
+    PpcGetSmmuInfo = KVM_CAP_PPC_GET_SMMU_INFO,
+    S390Cow = KVM_CAP_S390_COW,
+    PpcAllocHtab = KVM_CAP_PPC_ALLOC_HTAB,
+    ReadonlyMem = KVM_CAP_READONLY_MEM,
+    IrqfdResample = KVM_CAP_IRQFD_RESAMPLE,
+    PpcBookeWatchdog = KVM_CAP_PPC_BOOKE_WATCHDOG,
+    PpcHtabFd = KVM_CAP_PPC_HTAB_FD,
+    S390CssSupport = KVM_CAP_S390_CSS_SUPPORT,
+    PpcEpr = KVM_CAP_PPC_EPR,
+    ArmPsci = KVM_CAP_ARM_PSCI,
+    ArmSetDeviceAddr = KVM_CAP_ARM_SET_DEVICE_ADDR,
+    DeviceCtrl = KVM_CAP_DEVICE_CTRL,
+    IrqMpic = KVM_CAP_IRQ_MPIC,
+    PpcRtas = KVM_CAP_PPC_RTAS,
+    IrqXics = KVM_CAP_IRQ_XICS,
+    ArmEl132bit = KVM_CAP_ARM_EL1_32BIT,
+    SpaprMultitce = KVM_CAP_SPAPR_MULTITCE,
+    ExtEmulCpuid = KVM_CAP_EXT_EMUL_CPUID,
+    HypervTime = KVM_CAP_HYPERV_TIME,
+    IoapicPolarityIgnored = KVM_CAP_IOAPIC_POLARITY_IGNORED,
+    EnableCapVm = KVM_CAP_ENABLE_CAP_VM,
+    S390Irqchip = KVM_CAP_S390_IRQCHIP,
+    IoeventfdNoLength = KVM_CAP_IOEVENTFD_NO_LENGTH,
+    VmAttributes = KVM_CAP_VM_ATTRIBUTES,
+    ArmPsci02 = KVM_CAP_ARM_PSCI_0_2,
+    PpcFixupHcall = KVM_CAP_PPC_FIXUP_HCALL,
+    PpcEnableHcall = KVM_CAP_PPC_ENABLE_HCALL,
+    CheckExtensionVm = KVM_CAP_CHECK_EXTENSION_VM,
+    S390UserSigp = KVM_CAP_S390_USER_SIGP,
+}
diff --git a/kvm/src/lib.rs b/kvm/src/lib.rs
new file mode 100644
index 0000000..60ec2d1
--- /dev/null
+++ b/kvm/src/lib.rs
@@ -0,0 +1,2177 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! A safe wrapper around the kernel's KVM interface.
+
+mod cap;
+
+use std::cmp::{min, Ordering};
+use std::collections::{BinaryHeap, HashMap};
+use std::fs::File;
+use std::mem::size_of;
+use std::os::raw::*;
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::ptr::copy_nonoverlapping;
+
+use libc::sigset_t;
+use libc::{open, EINVAL, ENOENT, ENOSPC, O_CLOEXEC, O_RDWR};
+
+use kvm_sys::*;
+
+use msg_socket::MsgOnSocket;
+#[allow(unused_imports)]
+use sys_util::{
+    ioctl, ioctl_with_mut_ptr, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref, ioctl_with_val,
+    pagesize, signal, warn, Error, EventFd, GuestAddress, GuestMemory, MemoryMapping,
+    MemoryMappingArena, Result,
+};
+
+pub use crate::cap::*;
+
+fn errno_result<T>() -> Result<T> {
+    Err(Error::last())
+}
+
+// Returns a `Vec<T>` with a size in ytes at least as large as `size_in_bytes`.
+fn vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T> {
+    let rounded_size = (size_in_bytes + size_of::<T>() - 1) / size_of::<T>();
+    let mut v = Vec::with_capacity(rounded_size);
+    for _ in 0..rounded_size {
+        v.push(T::default())
+    }
+    v
+}
+
+// The kvm API has many structs that resemble the following `Foo` structure:
+//
+// ```
+// #[repr(C)]
+// struct Foo {
+//    some_data: u32
+//    entries: __IncompleteArrayField<__u32>,
+// }
+// ```
+//
+// In order to allocate such a structure, `size_of::<Foo>()` would be too small because it would not
+// include any space for `entries`. To make the allocation large enough while still being aligned
+// for `Foo`, a `Vec<Foo>` is created. Only the first element of `Vec<Foo>` would actually be used
+// as a `Foo`. The remaining memory in the `Vec<Foo>` is for `entries`, which must be contiguous
+// with `Foo`. This function is used to make the `Vec<Foo>` with enough space for `count` entries.
+fn vec_with_array_field<T: Default, F>(count: usize) -> Vec<T> {
+    let element_space = count * size_of::<F>();
+    let vec_size_bytes = size_of::<T>() + element_space;
+    vec_with_size_in_bytes(vec_size_bytes)
+}
+
+unsafe fn set_user_memory_region<F: AsRawFd>(
+    fd: &F,
+    slot: u32,
+    read_only: bool,
+    log_dirty_pages: bool,
+    guest_addr: u64,
+    memory_size: u64,
+    userspace_addr: *mut u8,
+) -> Result<()> {
+    let mut flags = if read_only { KVM_MEM_READONLY } else { 0 };
+    if log_dirty_pages {
+        flags |= KVM_MEM_LOG_DIRTY_PAGES;
+    }
+    let region = kvm_userspace_memory_region {
+        slot,
+        flags,
+        guest_phys_addr: guest_addr,
+        memory_size,
+        userspace_addr: userspace_addr as u64,
+    };
+
+    let ret = ioctl_with_ref(fd, KVM_SET_USER_MEMORY_REGION(), &region);
+    if ret == 0 {
+        Ok(())
+    } else {
+        errno_result()
+    }
+}
+
+/// Helper function to determine the size in bytes of a dirty log bitmap for the given memory region
+/// size.
+///
+/// # Arguments
+///
+/// * `size` - Number of bytes in the memory region being queried.
+pub fn dirty_log_bitmap_size(size: usize) -> usize {
+    let page_size = pagesize();
+    (((size + page_size - 1) / page_size) + 7) / 8
+}
+
+/// A wrapper around opening and using `/dev/kvm`.
+///
+/// Useful for querying extensions and basic values from the KVM backend. A `Kvm` is required to
+/// create a `Vm` object.
+pub struct Kvm {
+    kvm: File,
+}
+
+impl Kvm {
+    /// Opens `/dev/kvm/` and returns a Kvm object on success.
+    pub fn new() -> Result<Kvm> {
+        // Open calls are safe because we give a constant nul-terminated string and verify the
+        // result.
+        let ret = unsafe { open("/dev/kvm\0".as_ptr() as *const c_char, O_RDWR | O_CLOEXEC) };
+        if ret < 0 {
+            return errno_result();
+        }
+        // Safe because we verify that ret is valid and we own the fd.
+        Ok(Kvm {
+            kvm: unsafe { File::from_raw_fd(ret) },
+        })
+    }
+
+    fn check_extension_int(&self, c: Cap) -> i32 {
+        // Safe because we know that our file is a KVM fd and that the extension is one of the ones
+        // defined by kernel.
+        unsafe { ioctl_with_val(self, KVM_CHECK_EXTENSION(), c as c_ulong) }
+    }
+
+    /// Checks if a particular `Cap` is available.
+    pub fn check_extension(&self, c: Cap) -> bool {
+        self.check_extension_int(c) == 1
+    }
+
+    /// Gets the size of the mmap required to use vcpu's `kvm_run` structure.
+    pub fn get_vcpu_mmap_size(&self) -> Result<usize> {
+        // Safe because we know that our file is a KVM fd and we verify the return result.
+        let res = unsafe { ioctl(self, KVM_GET_VCPU_MMAP_SIZE() as c_ulong) };
+        if res > 0 {
+            Ok(res as usize)
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Gets the recommended maximum number of VCPUs per VM.
+    pub fn get_nr_vcpus(&self) -> u32 {
+        match self.check_extension_int(Cap::NrVcpus) {
+            0 => 4, // according to api.txt
+            x if x > 0 => x as u32,
+            _ => {
+                warn!("kernel returned invalid number of VCPUs");
+                4
+            }
+        }
+    }
+
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn get_cpuid(&self, kind: u64) -> Result<CpuId> {
+        const MAX_KVM_CPUID_ENTRIES: usize = 256;
+        let mut cpuid = CpuId::new(MAX_KVM_CPUID_ENTRIES);
+
+        let ret = unsafe {
+            // ioctl is unsafe. The kernel is trusted not to write beyond the bounds of the memory
+            // allocated for the struct. The limit is read from nent, which is set to the allocated
+            // size(MAX_KVM_CPUID_ENTRIES) above.
+            ioctl_with_mut_ptr(self, kind, cpuid.as_mut_ptr())
+        };
+        if ret < 0 {
+            return errno_result();
+        }
+
+        Ok(cpuid)
+    }
+
+    /// X86 specific call to get the system supported CPUID values
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_supported_cpuid(&self) -> Result<CpuId> {
+        self.get_cpuid(KVM_GET_SUPPORTED_CPUID())
+    }
+
+    /// X86 specific call to get the system emulated CPUID values
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_emulated_cpuid(&self) -> Result<CpuId> {
+        self.get_cpuid(KVM_GET_EMULATED_CPUID())
+    }
+
+    /// X86 specific call to get list of supported MSRS
+    ///
+    /// See the documentation for KVM_GET_MSR_INDEX_LIST.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_msr_index_list(&self) -> Result<Vec<u32>> {
+        const MAX_KVM_MSR_ENTRIES: usize = 256;
+
+        let mut msr_list = vec_with_array_field::<kvm_msr_list, u32>(MAX_KVM_MSR_ENTRIES);
+        msr_list[0].nmsrs = MAX_KVM_MSR_ENTRIES as u32;
+
+        let ret = unsafe {
+            // ioctl is unsafe. The kernel is trusted not to write beyond the bounds of the memory
+            // allocated for the struct. The limit is read from nmsrs, which is set to the allocated
+            // size (MAX_KVM_MSR_ENTRIES) above.
+            ioctl_with_mut_ref(self, KVM_GET_MSR_INDEX_LIST(), &mut msr_list[0])
+        };
+        if ret < 0 {
+            return errno_result();
+        }
+
+        let mut nmsrs = msr_list[0].nmsrs;
+
+        // Mapping the unsized array to a slice is unsafe because the length isn't known.  Using
+        // the length we originally allocated with eliminates the possibility of overflow.
+        let indices: &[u32] = unsafe {
+            if nmsrs > MAX_KVM_MSR_ENTRIES as u32 {
+                nmsrs = MAX_KVM_MSR_ENTRIES as u32;
+            }
+            msr_list[0].indices.as_slice(nmsrs as usize)
+        };
+
+        Ok(indices.to_vec())
+    }
+}
+
+impl AsRawFd for Kvm {
+    fn as_raw_fd(&self) -> RawFd {
+        self.kvm.as_raw_fd()
+    }
+}
+
+/// An address either in programmable I/O space or in memory mapped I/O space.
+#[derive(Copy, Clone, Debug, MsgOnSocket)]
+pub enum IoeventAddress {
+    Pio(u64),
+    Mmio(u64),
+}
+
+/// Used in `Vm::register_ioevent` to indicate a size and optionally value to match.
+pub enum Datamatch {
+    AnyLength,
+    U8(Option<u8>),
+    U16(Option<u16>),
+    U32(Option<u32>),
+    U64(Option<u64>),
+}
+
+/// A source of IRQs in an `IrqRoute`.
+pub enum IrqSource {
+    Irqchip { chip: u32, pin: u32 },
+    Msi { address: u64, data: u32 },
+}
+
+/// A single route for an IRQ.
+pub struct IrqRoute {
+    pub gsi: u32,
+    pub source: IrqSource,
+}
+
+/// Interrupt controller IDs
+pub enum PicId {
+    Primary = 0,
+    Secondary = 1,
+}
+
+/// Number of pins on the IOAPIC.
+pub const NUM_IOAPIC_PINS: usize = 24;
+
+// Used to invert the order when stored in a max-heap.
+#[derive(Copy, Clone, Eq, PartialEq)]
+struct MemSlot(u32);
+
+impl Ord for MemSlot {
+    fn cmp(&self, other: &MemSlot) -> Ordering {
+        // Notice the order is inverted so the lowest magnitude slot has the highest priority in a
+        // max-heap.
+        other.0.cmp(&self.0)
+    }
+}
+
+impl PartialOrd for MemSlot {
+    fn partial_cmp(&self, other: &MemSlot) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+/// A wrapper around creating and using a VM.
+pub struct Vm {
+    vm: File,
+    guest_mem: GuestMemory,
+    device_memory: HashMap<u32, MemoryMapping>,
+    mmap_arenas: HashMap<u32, MemoryMappingArena>,
+    mem_slot_gaps: BinaryHeap<MemSlot>,
+}
+
+impl Vm {
+    /// Constructs a new `Vm` using the given `Kvm` instance.
+    pub fn new(kvm: &Kvm, guest_mem: GuestMemory) -> Result<Vm> {
+        // Safe because we know kvm is a real kvm fd as this module is the only one that can make
+        // Kvm objects.
+        let ret = unsafe { ioctl(kvm, KVM_CREATE_VM()) };
+        if ret >= 0 {
+            // Safe because we verify the value of ret and we are the owners of the fd.
+            let vm_file = unsafe { File::from_raw_fd(ret) };
+            guest_mem.with_regions(|index, guest_addr, size, host_addr, _| {
+                unsafe {
+                    // Safe because the guest regions are guaranteed not to overlap.
+                    set_user_memory_region(
+                        &vm_file,
+                        index as u32,
+                        false,
+                        false,
+                        guest_addr.offset() as u64,
+                        size as u64,
+                        host_addr as *mut u8,
+                    )
+                }
+            })?;
+
+            Ok(Vm {
+                vm: vm_file,
+                guest_mem,
+                device_memory: HashMap::new(),
+                mmap_arenas: HashMap::new(),
+                mem_slot_gaps: BinaryHeap::new(),
+            })
+        } else {
+            errno_result()
+        }
+    }
+
+    // Helper method for `set_user_memory_region` that tracks available slots.
+    unsafe fn set_user_memory_region(
+        &mut self,
+        read_only: bool,
+        log_dirty_pages: bool,
+        guest_addr: u64,
+        memory_size: u64,
+        userspace_addr: *mut u8,
+    ) -> Result<u32> {
+        let slot = match self.mem_slot_gaps.pop() {
+            Some(gap) => gap.0,
+            None => {
+                (self.device_memory.len()
+                    + self.guest_mem.num_regions() as usize
+                    + self.mmap_arenas.len()) as u32
+            }
+        };
+
+        let res = set_user_memory_region(
+            &self.vm,
+            slot,
+            read_only,
+            log_dirty_pages,
+            guest_addr,
+            memory_size,
+            userspace_addr,
+        );
+        match res {
+            Ok(_) => Ok(slot),
+            Err(e) => {
+                self.mem_slot_gaps.push(MemSlot(slot));
+                Err(e)
+            }
+        }
+    }
+
+    // Helper method for `set_user_memory_region` that tracks available slots.
+    unsafe fn remove_user_memory_region(&mut self, slot: u32) -> Result<()> {
+        set_user_memory_region(&self.vm, slot, false, false, 0, 0, std::ptr::null_mut())?;
+        self.mem_slot_gaps.push(MemSlot(slot));
+        Ok(())
+    }
+
+    /// Checks if a particular `Cap` is available.
+    ///
+    /// This is distinct from the `Kvm` version of this method because the some extensions depend on
+    /// the particular `Vm` existence. This method is encouraged by the kernel because it more
+    /// accurately reflects the usable capabilities.
+    pub fn check_extension(&self, c: Cap) -> bool {
+        // Safe because we know that our file is a KVM fd and that the extension is one of the ones
+        // defined by kernel.
+        unsafe { ioctl_with_val(self, KVM_CHECK_EXTENSION(), c as c_ulong) == 1 }
+    }
+
+    /// Inserts the given `MemoryMapping` into the VM's address space at `guest_addr`.
+    ///
+    /// The slot that was assigned the device memory mapping is returned on success. The slot can be
+    /// given to `Vm::remove_device_memory` to remove the memory from the VM's address space and
+    /// take back ownership of `mem`.
+    ///
+    /// Note that memory inserted into the VM's address space must not overlap with any other memory
+    /// slot's region.
+    ///
+    /// If `read_only` is true, the guest will be able to read the memory as normal, but attempts to
+    /// write will trigger a mmio VM exit, leaving the memory untouched.
+    ///
+    /// If `log_dirty_pages` is true, the slot number can be used to retrieve the pages written to
+    /// by the guest with `get_dirty_log`.
+    pub fn add_device_memory(
+        &mut self,
+        guest_addr: GuestAddress,
+        mem: MemoryMapping,
+        read_only: bool,
+        log_dirty_pages: bool,
+    ) -> Result<u32> {
+        if guest_addr < self.guest_mem.end_addr() {
+            return Err(Error::new(ENOSPC));
+        }
+
+        // Safe because we check that the given guest address is valid and has no overlaps. We also
+        // know that the pointer and size are correct because the MemoryMapping interface ensures
+        // this. We take ownership of the memory mapping so that it won't be unmapped until the slot
+        // is removed.
+        let slot = unsafe {
+            self.set_user_memory_region(
+                read_only,
+                log_dirty_pages,
+                guest_addr.offset() as u64,
+                mem.size() as u64,
+                mem.as_ptr(),
+            )?
+        };
+        self.device_memory.insert(slot, mem);
+
+        Ok(slot)
+    }
+
+    /// Removes device memory that was previously added at the given slot.
+    ///
+    /// Ownership of the host memory mapping associated with the given slot is returned on success.
+    pub fn remove_device_memory(&mut self, slot: u32) -> Result<MemoryMapping> {
+        if self.device_memory.contains_key(&slot) {
+            // Safe because the slot is checked against the list of device memory slots.
+            unsafe {
+                self.remove_user_memory_region(slot)?;
+            }
+            // Safe to unwrap since map is checked to contain key
+            Ok(self.device_memory.remove(&slot).unwrap())
+        } else {
+            Err(Error::new(ENOENT))
+        }
+    }
+
+    /// Inserts the given `MemoryMappingArena` into the VM's address space at `guest_addr`.
+    ///
+    /// The slot that was assigned the device memory mapping is returned on success. The slot can be
+    /// given to `Vm::remove_mmap_arena` to remove the memory from the VM's address space and
+    /// take back ownership of `mmap_arena`.
+    ///
+    /// Note that memory inserted into the VM's address space must not overlap with any other memory
+    /// slot's region.
+    ///
+    /// If `read_only` is true, the guest will be able to read the memory as normal, but attempts to
+    /// write will trigger a mmio VM exit, leaving the memory untouched.
+    ///
+    /// If `log_dirty_pages` is true, the slot number can be used to retrieve the pages written to
+    /// by the guest with `get_dirty_log`.
+    pub fn add_mmap_arena(
+        &mut self,
+        guest_addr: GuestAddress,
+        mmap_arena: MemoryMappingArena,
+        read_only: bool,
+        log_dirty_pages: bool,
+    ) -> Result<u32> {
+        if guest_addr < self.guest_mem.end_addr() {
+            return Err(Error::new(ENOSPC));
+        }
+
+        // Safe because we check that the given guest address is valid and has no overlaps. We also
+        // know that the pointer and size are correct because the MemoryMapping interface ensures
+        // this. We take ownership of the memory mapping so that it won't be unmapped until the slot
+        // is removed.
+        let slot = unsafe {
+            self.set_user_memory_region(
+                read_only,
+                log_dirty_pages,
+                guest_addr.offset() as u64,
+                mmap_arena.size() as u64,
+                mmap_arena.as_ptr(),
+            )?
+        };
+        self.mmap_arenas.insert(slot, mmap_arena);
+
+        Ok(slot)
+    }
+
+    /// Removes memory map arena that was previously added at the given slot.
+    ///
+    /// Ownership of the host memory mapping associated with the given slot is returned on success.
+    pub fn remove_mmap_arena(&mut self, slot: u32) -> Result<MemoryMappingArena> {
+        if self.mmap_arenas.contains_key(&slot) {
+            // Safe because the slot is checked against the list of device memory slots.
+            unsafe {
+                self.remove_user_memory_region(slot)?;
+            }
+            // Safe to unwrap since map is checked to contain key
+            Ok(self.mmap_arenas.remove(&slot).unwrap())
+        } else {
+            Err(Error::new(ENOENT))
+        }
+    }
+
+    /// Get a mutable reference to the memory map arena added at the given slot.
+    pub fn get_mmap_arena(&mut self, slot: u32) -> Option<&mut MemoryMappingArena> {
+        self.mmap_arenas.get_mut(&slot)
+    }
+
+    /// Gets the bitmap of dirty pages since the last call to `get_dirty_log` for the memory at
+    /// `slot`.
+    ///
+    /// The size of `dirty_log` must be at least as many bits as there are pages in the memory
+    /// region `slot` represents. For example, if the size of `slot` is 16 pages, `dirty_log` must
+    /// be 2 bytes or greater.
+    pub fn get_dirty_log(&self, slot: u32, dirty_log: &mut [u8]) -> Result<()> {
+        match self.device_memory.get(&slot) {
+            Some(mmap) => {
+                // Ensures that there are as many bytes in dirty_log as there are pages in the mmap.
+                if dirty_log_bitmap_size(mmap.size()) > dirty_log.len() {
+                    return Err(Error::new(EINVAL));
+                }
+                let mut dirty_log_kvm = kvm_dirty_log {
+                    slot,
+                    ..Default::default()
+                };
+                dirty_log_kvm.__bindgen_anon_1.dirty_bitmap = dirty_log.as_ptr() as *mut c_void;
+                // Safe because the `dirty_bitmap` pointer assigned above is guaranteed to be valid
+                // (because it's from a slice) and we checked that it will be large enough to hold
+                // the entire log.
+                let ret = unsafe { ioctl_with_ref(self, KVM_GET_DIRTY_LOG(), &dirty_log_kvm) };
+                if ret == 0 {
+                    Ok(())
+                } else {
+                    errno_result()
+                }
+            }
+            _ => Err(Error::new(ENOENT)),
+        }
+    }
+
+    /// Gets a reference to the guest memory owned by this VM.
+    ///
+    /// Note that `GuestMemory` does not include any device memory that may have been added after
+    /// this VM was constructed.
+    pub fn get_memory(&self) -> &GuestMemory {
+        &self.guest_mem
+    }
+
+    /// Sets the address of the three-page region in the VM's address space.
+    ///
+    /// See the documentation on the KVM_SET_TSS_ADDR ioctl.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_tss_addr(&self, addr: GuestAddress) -> Result<()> {
+        // Safe because we know that our file is a VM fd and we verify the return result.
+        let ret = unsafe { ioctl_with_val(self, KVM_SET_TSS_ADDR(), addr.offset() as u64) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Sets the address of a one-page region in the VM's address space.
+    ///
+    /// See the documentation on the KVM_SET_IDENTITY_MAP_ADDR ioctl.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_identity_map_addr(&self, addr: GuestAddress) -> Result<()> {
+        // Safe because we know that our file is a VM fd and we verify the return result.
+        let ret =
+            unsafe { ioctl_with_ref(self, KVM_SET_IDENTITY_MAP_ADDR(), &(addr.offset() as u64)) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Retrieves the current timestamp of kvmclock as seen by the current guest.
+    ///
+    /// See the documentation on the KVM_GET_CLOCK ioctl.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_clock(&self) -> Result<kvm_clock_data> {
+        // Safe because we know that our file is a VM fd, we know the kernel will only write
+        // correct amount of memory to our pointer, and we verify the return result.
+        let mut clock_data = unsafe { std::mem::zeroed() };
+        let ret = unsafe { ioctl_with_mut_ref(self, KVM_GET_CLOCK(), &mut clock_data) };
+        if ret == 0 {
+            Ok(clock_data)
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Sets the current timestamp of kvmclock to the specified value.
+    ///
+    /// See the documentation on the KVM_SET_CLOCK ioctl.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_clock(&self, clock_data: &kvm_clock_data) -> Result<()> {
+        // Safe because we know that our file is a VM fd, we know the kernel will only read
+        // correct amount of memory from our pointer, and we verify the return result.
+        let ret = unsafe { ioctl_with_ref(self, KVM_SET_CLOCK(), clock_data) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Crates an in kernel interrupt controller.
+    ///
+    /// See the documentation on the KVM_CREATE_IRQCHIP ioctl.
+    #[cfg(any(
+        target_arch = "x86",
+        target_arch = "x86_64",
+        target_arch = "arm",
+        target_arch = "aarch64"
+    ))]
+    pub fn create_irq_chip(&self) -> Result<()> {
+        // Safe because we know that our file is a VM fd and we verify the return result.
+        let ret = unsafe { ioctl(self, KVM_CREATE_IRQCHIP()) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Retrieves the state of given interrupt controller by issuing KVM_GET_IRQCHIP ioctl.
+    ///
+    /// Note that this call can only succeed after a call to `Vm::create_irq_chip`.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_pic_state(&self, id: PicId) -> Result<kvm_pic_state> {
+        let mut irqchip_state = kvm_irqchip::default();
+        irqchip_state.chip_id = id as u32;
+        let ret = unsafe {
+            // Safe because we know our file is a VM fd, we know the kernel will only write
+            // correct amount of memory to our pointer, and we verify the return result.
+            ioctl_with_mut_ref(self, KVM_GET_IRQCHIP(), &mut irqchip_state)
+        };
+        if ret == 0 {
+            Ok(unsafe {
+                // Safe as we know that we are retrieving data related to the
+                // PIC (primary or secondary) and not IOAPIC.
+                irqchip_state.chip.pic
+            })
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Sets the state of given interrupt controller by issuing KVM_SET_IRQCHIP ioctl.
+    ///
+    /// Note that this call can only succeed after a call to `Vm::create_irq_chip`.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_pic_state(&self, id: PicId, state: &kvm_pic_state) -> Result<()> {
+        let mut irqchip_state = kvm_irqchip::default();
+        irqchip_state.chip_id = id as u32;
+        irqchip_state.chip.pic = *state;
+        // Safe because we know that our file is a VM fd, we know the kernel will only read
+        // correct amount of memory from our pointer, and we verify the return result.
+        let ret = unsafe { ioctl_with_ref(self, KVM_SET_IRQCHIP(), &irqchip_state) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Retrieves the state of IOAPIC by issuing KVM_GET_IRQCHIP ioctl.
+    ///
+    /// Note that this call can only succeed after a call to `Vm::create_irq_chip`.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_ioapic_state(&self) -> Result<kvm_ioapic_state> {
+        let mut irqchip_state = kvm_irqchip::default();
+        irqchip_state.chip_id = 2;
+        let ret = unsafe {
+            // Safe because we know our file is a VM fd, we know the kernel will only write
+            // correct amount of memory to our pointer, and we verify the return result.
+            ioctl_with_mut_ref(self, KVM_GET_IRQCHIP(), &mut irqchip_state)
+        };
+        if ret == 0 {
+            Ok(unsafe {
+                // Safe as we know that we are retrieving data related to the
+                // IOAPIC and not PIC.
+                irqchip_state.chip.ioapic
+            })
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Sets the state of IOAPIC by issuing KVM_SET_IRQCHIP ioctl.
+    ///
+    /// Note that this call can only succeed after a call to `Vm::create_irq_chip`.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_ioapic_state(&self, state: &kvm_ioapic_state) -> Result<()> {
+        let mut irqchip_state = kvm_irqchip::default();
+        irqchip_state.chip_id = 2;
+        irqchip_state.chip.ioapic = *state;
+        // Safe because we know that our file is a VM fd, we know the kernel will only read
+        // correct amount of memory from our pointer, and we verify the return result.
+        let ret = unsafe { ioctl_with_ref(self, KVM_SET_IRQCHIP(), &irqchip_state) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Sets the level on the given irq to 1 if `active` is true, and 0 otherwise.
+    #[cfg(any(
+        target_arch = "x86",
+        target_arch = "x86_64",
+        target_arch = "arm",
+        target_arch = "aarch64"
+    ))]
+    pub fn set_irq_line(&self, irq: u32, active: bool) -> Result<()> {
+        let mut irq_level = kvm_irq_level::default();
+        irq_level.__bindgen_anon_1.irq = irq;
+        irq_level.level = if active { 1 } else { 0 };
+
+        // Safe because we know that our file is a VM fd, we know the kernel will only read the
+        // correct amount of memory from our pointer, and we verify the return result.
+        let ret = unsafe { ioctl_with_ref(self, KVM_IRQ_LINE(), &irq_level) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Creates a PIT as per the KVM_CREATE_PIT2 ioctl.
+    ///
+    /// Note that this call can only succeed after a call to `Vm::create_irq_chip`.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn create_pit(&self) -> Result<()> {
+        let pit_config = kvm_pit_config::default();
+        // Safe because we know that our file is a VM fd, we know the kernel will only read the
+        // correct amount of memory from our pointer, and we verify the return result.
+        let ret = unsafe { ioctl_with_ref(self, KVM_CREATE_PIT2(), &pit_config) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Retrieves the state of PIT by issuing KVM_GET_PIT2 ioctl.
+    ///
+    /// Note that this call can only succeed after a call to `Vm::create_pit`.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_pit_state(&self) -> Result<kvm_pit_state2> {
+        // Safe because we know that our file is a VM fd, we know the kernel will only write
+        // correct amount of memory to our pointer, and we verify the return result.
+        let mut pit_state = unsafe { std::mem::zeroed() };
+        let ret = unsafe { ioctl_with_mut_ref(self, KVM_GET_PIT2(), &mut pit_state) };
+        if ret == 0 {
+            Ok(pit_state)
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Sets the state of PIT by issuing KVM_SET_PIT2 ioctl.
+    ///
+    /// Note that this call can only succeed after a call to `Vm::create_pit`.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_pit_state(&self, pit_state: &kvm_pit_state2) -> Result<()> {
+        // Safe because we know that our file is a VM fd, we know the kernel will only read
+        // correct amount of memory from our pointer, and we verify the return result.
+        let ret = unsafe { ioctl_with_ref(self, KVM_SET_PIT2(), pit_state) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Registers an event to be signaled whenever a certain address is written to.
+    ///
+    /// The `datamatch` parameter can be used to limit signaling `evt` to only the cases where the
+    /// value being written is equal to `datamatch`. Note that the size of `datamatch` is important
+    /// and must match the expected size of the guest's write.
+    ///
+    /// In all cases where `evt` is signaled, the ordinary vmexit to userspace that would be
+    /// triggered is prevented.
+    pub fn register_ioevent(
+        &self,
+        evt: &EventFd,
+        addr: IoeventAddress,
+        datamatch: Datamatch,
+    ) -> Result<()> {
+        self.ioeventfd(evt, addr, datamatch, false)
+    }
+
+    /// Unregisters an event previously registered with `register_ioevent`.
+    ///
+    /// The `evt`, `addr`, and `datamatch` set must be the same as the ones passed into
+    /// `register_ioevent`.
+    pub fn unregister_ioevent(
+        &self,
+        evt: &EventFd,
+        addr: IoeventAddress,
+        datamatch: Datamatch,
+    ) -> Result<()> {
+        self.ioeventfd(evt, addr, datamatch, true)
+    }
+
+    fn ioeventfd(
+        &self,
+        evt: &EventFd,
+        addr: IoeventAddress,
+        datamatch: Datamatch,
+        deassign: bool,
+    ) -> Result<()> {
+        let (do_datamatch, datamatch_value, datamatch_len) = match datamatch {
+            Datamatch::AnyLength => (false, 0, 0),
+            Datamatch::U8(v) => match v {
+                Some(u) => (true, u as u64, 1),
+                None => (false, 0, 1),
+            },
+            Datamatch::U16(v) => match v {
+                Some(u) => (true, u as u64, 2),
+                None => (false, 0, 2),
+            },
+            Datamatch::U32(v) => match v {
+                Some(u) => (true, u as u64, 4),
+                None => (false, 0, 4),
+            },
+            Datamatch::U64(v) => match v {
+                Some(u) => (true, u as u64, 8),
+                None => (false, 0, 8),
+            },
+        };
+        let mut flags = 0;
+        if deassign {
+            flags |= 1 << kvm_ioeventfd_flag_nr_deassign;
+        }
+        if do_datamatch {
+            flags |= 1 << kvm_ioeventfd_flag_nr_datamatch
+        }
+        if let IoeventAddress::Pio(_) = addr {
+            flags |= 1 << kvm_ioeventfd_flag_nr_pio;
+        }
+        let ioeventfd = kvm_ioeventfd {
+            datamatch: datamatch_value,
+            len: datamatch_len,
+            addr: match addr {
+                IoeventAddress::Pio(p) => p as u64,
+                IoeventAddress::Mmio(m) => m,
+            },
+            fd: evt.as_raw_fd(),
+            flags,
+            ..Default::default()
+        };
+        // Safe because we know that our file is a VM fd, we know the kernel will only read the
+        // correct amount of memory from our pointer, and we verify the return result.
+        let ret = unsafe { ioctl_with_ref(self, KVM_IOEVENTFD(), &ioeventfd) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Registers an event that will, when signalled, trigger the `gsi` irq.
+    #[cfg(any(
+        target_arch = "x86",
+        target_arch = "x86_64",
+        target_arch = "arm",
+        target_arch = "aarch64"
+    ))]
+    pub fn register_irqfd(&self, evt: &EventFd, gsi: u32) -> Result<()> {
+        let irqfd = kvm_irqfd {
+            fd: evt.as_raw_fd() as u32,
+            gsi,
+            ..Default::default()
+        };
+        // Safe because we know that our file is a VM fd, we know the kernel will only read the
+        // correct amount of memory from our pointer, and we verify the return result.
+        let ret = unsafe { ioctl_with_ref(self, KVM_IRQFD(), &irqfd) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Registers an event that will, when signalled, trigger the `gsi` irq, and `resample_evt` will
+    /// get triggered when the irqchip is resampled.
+    #[cfg(any(
+        target_arch = "x86",
+        target_arch = "x86_64",
+        target_arch = "arm",
+        target_arch = "aarch64"
+    ))]
+    pub fn register_irqfd_resample(
+        &self,
+        evt: &EventFd,
+        resample_evt: &EventFd,
+        gsi: u32,
+    ) -> Result<()> {
+        let irqfd = kvm_irqfd {
+            flags: KVM_IRQFD_FLAG_RESAMPLE,
+            fd: evt.as_raw_fd() as u32,
+            resamplefd: resample_evt.as_raw_fd() as u32,
+            gsi,
+            ..Default::default()
+        };
+        // Safe because we know that our file is a VM fd, we know the kernel will only read the
+        // correct amount of memory from our pointer, and we verify the return result.
+        let ret = unsafe { ioctl_with_ref(self, KVM_IRQFD(), &irqfd) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Unregisters an event that was previously registered with
+    /// `register_irqfd`/`register_irqfd_resample`.
+    ///
+    /// The `evt` and `gsi` pair must be the same as the ones passed into
+    /// `register_irqfd`/`register_irqfd_resample`.
+    #[cfg(any(
+        target_arch = "x86",
+        target_arch = "x86_64",
+        target_arch = "arm",
+        target_arch = "aarch64"
+    ))]
+    pub fn unregister_irqfd(&self, evt: &EventFd, gsi: u32) -> Result<()> {
+        let irqfd = kvm_irqfd {
+            fd: evt.as_raw_fd() as u32,
+            gsi,
+            flags: KVM_IRQFD_FLAG_DEASSIGN,
+            ..Default::default()
+        };
+        // Safe because we know that our file is a VM fd, we know the kernel will only read the
+        // correct amount of memory from our pointer, and we verify the return result.
+        let ret = unsafe { ioctl_with_ref(self, KVM_IRQFD(), &irqfd) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Sets the GSI routing table, replacing any table set with previous calls to
+    /// `set_gsi_routing`.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_gsi_routing(&self, routes: &[IrqRoute]) -> Result<()> {
+        let mut irq_routing =
+            vec_with_array_field::<kvm_irq_routing, kvm_irq_routing_entry>(routes.len());
+        irq_routing[0].nr = routes.len() as u32;
+
+        // Safe because we ensured there is enough space in irq_routing to hold the number of
+        // route entries.
+        let irq_routes = unsafe { irq_routing[0].entries.as_mut_slice(routes.len()) };
+        for (route, irq_route) in routes.iter().zip(irq_routes.iter_mut()) {
+            irq_route.gsi = route.gsi;
+            match route.source {
+                IrqSource::Irqchip { chip, pin } => {
+                    irq_route.type_ = KVM_IRQ_ROUTING_IRQCHIP;
+                    irq_route.u.irqchip = kvm_irq_routing_irqchip { irqchip: chip, pin }
+                }
+                IrqSource::Msi { address, data } => {
+                    irq_route.type_ = KVM_IRQ_ROUTING_MSI;
+                    irq_route.u.msi = kvm_irq_routing_msi {
+                        address_lo: address as u32,
+                        address_hi: (address >> 32) as u32,
+                        data,
+                        ..Default::default()
+                    }
+                }
+            }
+        }
+
+        let ret = unsafe { ioctl_with_ref(self, KVM_SET_GSI_ROUTING(), &irq_routing[0]) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Does KVM_CREATE_DEVICE for a generic device.
+    pub fn create_device(&self, device: &mut kvm_create_device) -> Result<()> {
+        let ret = unsafe { sys_util::ioctl_with_ref(self, KVM_CREATE_DEVICE(), device) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
+
+    /// This queries the kernel for the preferred target CPU type.
+    #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+    pub fn arm_preferred_target(&self, kvi: &mut kvm_vcpu_init) -> Result<()> {
+        // The ioctl is safe because we allocated the struct and we know the
+        // kernel will write exactly the size of the struct.
+        let ret = unsafe { ioctl_with_mut_ref(self, KVM_ARM_PREFERRED_TARGET(), kvi) };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// Enable the specified capability.
+    /// See documentation for KVM_ENABLE_CAP.
+    pub fn kvm_enable_cap(&self, cap: &kvm_enable_cap) -> Result<()> {
+        // safe becuase we allocated the struct and we know the kernel will read
+        // exactly the size of the struct
+        let ret = unsafe { ioctl_with_ref(self, KVM_ENABLE_CAP(), cap) };
+        if ret < 0 {
+            errno_result()
+        } else {
+            Ok(())
+        }
+    }
+
+    /// (x86-only): Enable support for split-irqchip.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn enable_split_irqchip(&self) -> Result<()> {
+        let mut cap: kvm_enable_cap = Default::default();
+        cap.cap = KVM_CAP_SPLIT_IRQCHIP;
+        cap.args[0] = NUM_IOAPIC_PINS as u64;
+        self.kvm_enable_cap(&cap)
+    }
+
+    /// Request that the kernel inject the specified MSI message.
+    /// Returns Ok(true) on delivery, Ok(false) if the guest blocked delivery, or an error.
+    /// See kernel documentation for KVM_SIGNAL_MSI.
+    pub fn signal_msi(&self, msi: &kvm_msi) -> Result<bool> {
+        // safe becuase we allocated the struct and we know the kernel will read
+        // exactly the size of the struct
+        let ret = unsafe { ioctl_with_ref(self, KVM_SIGNAL_MSI(), msi) };
+        if ret < 0 {
+            errno_result()
+        } else {
+            Ok(ret > 0)
+        }
+    }
+}
+
+impl AsRawFd for Vm {
+    fn as_raw_fd(&self) -> RawFd {
+        self.vm.as_raw_fd()
+    }
+}
+
+/// A reason why a VCPU exited. One of these returns every time `Vcpu::run` is called.
+#[derive(Debug)]
+pub enum VcpuExit {
+    /// An out port instruction was run on the given port with the given data.
+    IoOut {
+        port: u16,
+        size: usize,
+        data: [u8; 8],
+    },
+    /// An in port instruction was run on the given port.
+    ///
+    /// The date that the instruction receives should be set with `set_data` before `Vcpu::run` is
+    /// called again.
+    IoIn {
+        port: u16,
+        size: usize,
+    },
+    /// A read instruction was run against the given MMIO address.
+    ///
+    /// The date that the instruction receives should be set with `set_data` before `Vcpu::run` is
+    /// called again.
+    MmioRead {
+        address: u64,
+        size: usize,
+    },
+    /// A write instruction was run against the given MMIO address with the given data.
+    MmioWrite {
+        address: u64,
+        size: usize,
+        data: [u8; 8],
+    },
+    Unknown,
+    Exception,
+    Hypercall,
+    Debug,
+    Hlt,
+    IrqWindowOpen,
+    Shutdown,
+    FailEntry,
+    Intr,
+    SetTpr,
+    TprAccess,
+    S390Sieic,
+    S390Reset,
+    Dcr,
+    Nmi,
+    InternalError,
+    Osi,
+    PaprHcall,
+    S390Ucontrol,
+    Watchdog,
+    S390Tsch,
+    Epr,
+    /// The cpu triggered a system level event which is specified by the type field.
+    /// The first field is the event type and the second field is flags.
+    /// The possible event types are shutdown, reset, or crash.  So far there
+    /// are not any flags defined.
+    SystemEvent(u32 /* event_type */, u64 /* flags */),
+}
+
+/// A wrapper around creating and using a VCPU.
+pub struct Vcpu {
+    vcpu: File,
+    run_mmap: MemoryMapping,
+    guest_mem: GuestMemory,
+}
+
+impl Vcpu {
+    /// Constructs a new VCPU for `vm`.
+    ///
+    /// The `id` argument is the CPU number between [0, max vcpus).
+    pub fn new(id: c_ulong, kvm: &Kvm, vm: &Vm) -> Result<Vcpu> {
+        let run_mmap_size = kvm.get_vcpu_mmap_size()?;
+
+        // Safe because we know that vm a VM fd and we verify the return result.
+        let vcpu_fd = unsafe { ioctl_with_val(vm, KVM_CREATE_VCPU(), id) };
+        if vcpu_fd < 0 {
+            return errno_result();
+        }
+
+        // Wrap the vcpu now in case the following ? returns early. This is safe because we verified
+        // the value of the fd and we own the fd.
+        let vcpu = unsafe { File::from_raw_fd(vcpu_fd) };
+
+        let run_mmap =
+            MemoryMapping::from_fd(&vcpu, run_mmap_size).map_err(|_| Error::new(ENOSPC))?;
+
+        let guest_mem = vm.guest_mem.clone();
+
+        Ok(Vcpu {
+            vcpu,
+            run_mmap,
+            guest_mem,
+        })
+    }
+
+    /// Gets a reference to the guest memory owned by this VM of this VCPU.
+    ///
+    /// Note that `GuestMemory` does not include any device memory that may have been added after
+    /// this VM was constructed.
+    pub fn get_memory(&self) -> &GuestMemory {
+        &self.guest_mem
+    }
+
+    /// Sets the data received by an mmio or ioport read/in instruction.
+    ///
+    /// This function should be called after `Vcpu::run` returns an `VcpuExit::IoIn` or
+    /// `Vcpu::MmioRead`.
+    #[allow(clippy::cast_ptr_alignment)]
+    pub fn set_data(&self, data: &[u8]) -> Result<()> {
+        // Safe because we know we mapped enough memory to hold the kvm_run struct because the
+        // kernel told us how large it was. The pointer is page aligned so casting to a different
+        // type is well defined, hence the clippy allow attribute.
+        let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut kvm_run) };
+        match run.exit_reason {
+            KVM_EXIT_IO => {
+                let run_start = run as *mut kvm_run as *mut u8;
+                // Safe because the exit_reason (which comes from the kernel) told us which
+                // union field to use.
+                let io = unsafe { run.__bindgen_anon_1.io };
+                if io.direction as u32 != KVM_EXIT_IO_IN {
+                    return Err(Error::new(EINVAL));
+                }
+                let data_size = (io.count as usize) * (io.size as usize);
+                if data_size != data.len() {
+                    return Err(Error::new(EINVAL));
+                }
+                // The data_offset is defined by the kernel to be some number of bytes into the
+                // kvm_run structure, which we have fully mmap'd.
+                unsafe {
+                    let data_ptr = run_start.offset(io.data_offset as isize);
+                    copy_nonoverlapping(data.as_ptr(), data_ptr, data_size);
+                }
+                Ok(())
+            }
+            KVM_EXIT_MMIO => {
+                // Safe because the exit_reason (which comes from the kernel) told us which
+                // union field to use.
+                let mmio = unsafe { &mut run.__bindgen_anon_1.mmio };
+                if mmio.is_write != 0 {
+                    return Err(Error::new(EINVAL));
+                }
+                let len = mmio.len as usize;
+                if len != data.len() {
+                    return Err(Error::new(EINVAL));
+                }
+                mmio.data[..len].copy_from_slice(data);
+                Ok(())
+            }
+            _ => Err(Error::new(EINVAL)),
+        }
+    }
+
+    /// Runs the VCPU until it exits, returning the reason.
+    ///
+    /// Note that the state of the VCPU and associated VM must be setup first for this to do
+    /// anything useful.
+    #[allow(clippy::cast_ptr_alignment)]
+    // The pointer is page aligned so casting to a different type is well defined, hence the clippy
+    // allow attribute.
+    pub fn run(&self) -> Result<VcpuExit> {
+        // Safe because we know that our file is a VCPU fd and we verify the return result.
+        let ret = unsafe { ioctl(self, KVM_RUN()) };
+        if ret == 0 {
+            // Safe because we know we mapped enough memory to hold the kvm_run struct because the
+            // kernel told us how large it was.
+            let run = unsafe { &*(self.run_mmap.as_ptr() as *const kvm_run) };
+            match run.exit_reason {
+                KVM_EXIT_IO => {
+                    // Safe because the exit_reason (which comes from the kernel) told us which
+                    // union field to use.
+                    let io = unsafe { run.__bindgen_anon_1.io };
+                    let port = io.port;
+                    let size = (io.count as usize) * (io.size as usize);
+                    match io.direction as u32 {
+                        KVM_EXIT_IO_IN => Ok(VcpuExit::IoIn { port, size }),
+                        KVM_EXIT_IO_OUT => {
+                            let mut data = [0; 8];
+                            let run_start = run as *const kvm_run as *const u8;
+                            // The data_offset is defined by the kernel to be some number of bytes
+                            // into the kvm_run structure, which we have fully mmap'd.
+                            unsafe {
+                                let data_ptr = run_start.offset(io.data_offset as isize);
+                                copy_nonoverlapping(
+                                    data_ptr,
+                                    data.as_mut_ptr(),
+                                    min(size, data.len()),
+                                );
+                            }
+                            Ok(VcpuExit::IoOut { port, size, data })
+                        }
+                        _ => Err(Error::new(EINVAL)),
+                    }
+                }
+                KVM_EXIT_MMIO => {
+                    // Safe because the exit_reason (which comes from the kernel) told us which
+                    // union field to use.
+                    let mmio = unsafe { &run.__bindgen_anon_1.mmio };
+                    let address = mmio.phys_addr;
+                    let size = min(mmio.len as usize, mmio.data.len());
+                    if mmio.is_write != 0 {
+                        Ok(VcpuExit::MmioWrite {
+                            address,
+                            size,
+                            data: mmio.data,
+                        })
+                    } else {
+                        Ok(VcpuExit::MmioRead { address, size })
+                    }
+                }
+                KVM_EXIT_UNKNOWN => Ok(VcpuExit::Unknown),
+                KVM_EXIT_EXCEPTION => Ok(VcpuExit::Exception),
+                KVM_EXIT_HYPERCALL => Ok(VcpuExit::Hypercall),
+                KVM_EXIT_DEBUG => Ok(VcpuExit::Debug),
+                KVM_EXIT_HLT => Ok(VcpuExit::Hlt),
+                KVM_EXIT_IRQ_WINDOW_OPEN => Ok(VcpuExit::IrqWindowOpen),
+                KVM_EXIT_SHUTDOWN => Ok(VcpuExit::Shutdown),
+                KVM_EXIT_FAIL_ENTRY => Ok(VcpuExit::FailEntry),
+                KVM_EXIT_INTR => Ok(VcpuExit::Intr),
+                KVM_EXIT_SET_TPR => Ok(VcpuExit::SetTpr),
+                KVM_EXIT_TPR_ACCESS => Ok(VcpuExit::TprAccess),
+                KVM_EXIT_S390_SIEIC => Ok(VcpuExit::S390Sieic),
+                KVM_EXIT_S390_RESET => Ok(VcpuExit::S390Reset),
+                KVM_EXIT_DCR => Ok(VcpuExit::Dcr),
+                KVM_EXIT_NMI => Ok(VcpuExit::Nmi),
+                KVM_EXIT_INTERNAL_ERROR => Ok(VcpuExit::InternalError),
+                KVM_EXIT_OSI => Ok(VcpuExit::Osi),
+                KVM_EXIT_PAPR_HCALL => Ok(VcpuExit::PaprHcall),
+                KVM_EXIT_S390_UCONTROL => Ok(VcpuExit::S390Ucontrol),
+                KVM_EXIT_WATCHDOG => Ok(VcpuExit::Watchdog),
+                KVM_EXIT_S390_TSCH => Ok(VcpuExit::S390Tsch),
+                KVM_EXIT_EPR => Ok(VcpuExit::Epr),
+                KVM_EXIT_SYSTEM_EVENT => {
+                    // Safe because we know the exit reason told us this union
+                    // field is valid
+                    let event_type = unsafe { run.__bindgen_anon_1.system_event.type_ };
+                    let event_flags = unsafe { run.__bindgen_anon_1.system_event.flags };
+                    Ok(VcpuExit::SystemEvent(event_type, event_flags))
+                }
+                r => panic!("unknown kvm exit reason: {}", r),
+            }
+        } else {
+            errno_result()
+        }
+    }
+
+    /// Gets the VCPU registers.
+    #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
+    pub fn get_regs(&self) -> Result<kvm_regs> {
+        // Safe because we know that our file is a VCPU fd, we know the kernel will only read the
+        // correct amount of memory from our pointer, and we verify the return result.
+        let mut regs = unsafe { std::mem::zeroed() };
+        let ret = unsafe { ioctl_with_mut_ref(self, KVM_GET_REGS(), &mut regs) };
+        if ret != 0 {
+            return errno_result();
+        }
+        Ok(regs)
+    }
+
+    /// Sets the VCPU registers.
+    #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
+    pub fn set_regs(&self, regs: &kvm_regs) -> Result<()> {
+        // Safe because we know that our file is a VCPU fd, we know the kernel will only read the
+        // correct amount of memory from our pointer, and we verify the return result.
+        let ret = unsafe { ioctl_with_ref(self, KVM_SET_REGS(), regs) };
+        if ret != 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// Gets the VCPU special registers.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_sregs(&self) -> Result<kvm_sregs> {
+        // Safe because we know that our file is a VCPU fd, we know the kernel will only write the
+        // correct amount of memory to our pointer, and we verify the return result.
+        let mut regs = unsafe { std::mem::zeroed() };
+        let ret = unsafe { ioctl_with_mut_ref(self, KVM_GET_SREGS(), &mut regs) };
+        if ret != 0 {
+            return errno_result();
+        }
+        Ok(regs)
+    }
+
+    /// Sets the VCPU special registers.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_sregs(&self, sregs: &kvm_sregs) -> Result<()> {
+        // Safe because we know that our file is a VCPU fd, we know the kernel will only read the
+        // correct amount of memory from our pointer, and we verify the return result.
+        let ret = unsafe { ioctl_with_ref(self, KVM_SET_SREGS(), sregs) };
+        if ret != 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// Gets the VCPU FPU registers.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_fpu(&self) -> Result<kvm_fpu> {
+        // Safe because we know that our file is a VCPU fd, we know the kernel will only write the
+        // correct amount of memory to our pointer, and we verify the return result.
+        let mut regs = unsafe { std::mem::zeroed() };
+        let ret = unsafe { ioctl_with_mut_ref(self, KVM_GET_FPU(), &mut regs) };
+        if ret != 0 {
+            return errno_result();
+        }
+        Ok(regs)
+    }
+
+    /// X86 specific call to setup the FPU
+    ///
+    /// See the documentation for KVM_SET_FPU.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_fpu(&self, fpu: &kvm_fpu) -> Result<()> {
+        let ret = unsafe {
+            // Here we trust the kernel not to read past the end of the kvm_fpu struct.
+            ioctl_with_ref(self, KVM_SET_FPU(), fpu)
+        };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// Gets the VCPU debug registers.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_debugregs(&self) -> Result<kvm_debugregs> {
+        // Safe because we know that our file is a VCPU fd, we know the kernel will only write the
+        // correct amount of memory to our pointer, and we verify the return result.
+        let mut regs = unsafe { std::mem::zeroed() };
+        let ret = unsafe { ioctl_with_mut_ref(self, KVM_GET_DEBUGREGS(), &mut regs) };
+        if ret != 0 {
+            return errno_result();
+        }
+        Ok(regs)
+    }
+
+    /// Sets the VCPU debug registers
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_debugregs(&self, dregs: &kvm_debugregs) -> Result<()> {
+        let ret = unsafe {
+            // Here we trust the kernel not to read past the end of the kvm_fpu struct.
+            ioctl_with_ref(self, KVM_SET_DEBUGREGS(), dregs)
+        };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// Gets the VCPU extended control registers
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_xcrs(&self) -> Result<kvm_xcrs> {
+        // Safe because we know that our file is a VCPU fd, we know the kernel will only write the
+        // correct amount of memory to our pointer, and we verify the return result.
+        let mut regs = unsafe { std::mem::zeroed() };
+        let ret = unsafe { ioctl_with_mut_ref(self, KVM_GET_XCRS(), &mut regs) };
+        if ret != 0 {
+            return errno_result();
+        }
+        Ok(regs)
+    }
+
+    /// Sets the VCPU extended control registers
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_xcrs(&self, xcrs: &kvm_xcrs) -> Result<()> {
+        let ret = unsafe {
+            // Here we trust the kernel not to read past the end of the kvm_xcrs struct.
+            ioctl_with_ref(self, KVM_SET_XCRS(), xcrs)
+        };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// X86 specific call to get the MSRS
+    ///
+    /// See the documentation for KVM_SET_MSRS.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_msrs(&self, msr_entries: &mut Vec<kvm_msr_entry>) -> Result<()> {
+        let mut msrs = vec_with_array_field::<kvm_msrs, kvm_msr_entry>(msr_entries.len());
+        unsafe {
+            // Mapping the unsized array to a slice is unsafe because the length isn't known.
+            // Providing the length used to create the struct guarantees the entire slice is valid.
+            let entries: &mut [kvm_msr_entry] = msrs[0].entries.as_mut_slice(msr_entries.len());
+            entries.copy_from_slice(&msr_entries);
+        }
+        msrs[0].nmsrs = msr_entries.len() as u32;
+        let ret = unsafe {
+            // Here we trust the kernel not to read or write past the end of the kvm_msrs struct.
+            ioctl_with_ref(self, KVM_GET_MSRS(), &msrs[0])
+        };
+        if ret < 0 {
+            // KVM_SET_MSRS actually returns the number of msr entries written.
+            return errno_result();
+        }
+        unsafe {
+            let count = ret as usize;
+            assert!(count <= msr_entries.len());
+            let entries: &mut [kvm_msr_entry] = msrs[0].entries.as_mut_slice(count);
+            msr_entries.truncate(count);
+            msr_entries.copy_from_slice(&entries);
+        }
+        Ok(())
+    }
+
+    /// X86 specific call to setup the MSRS
+    ///
+    /// See the documentation for KVM_SET_MSRS.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_msrs(&self, msrs: &kvm_msrs) -> Result<()> {
+        let ret = unsafe {
+            // Here we trust the kernel not to read past the end of the kvm_msrs struct.
+            ioctl_with_ref(self, KVM_SET_MSRS(), msrs)
+        };
+        if ret < 0 {
+            // KVM_SET_MSRS actually returns the number of msr entries written.
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// X86 specific call to setup the CPUID registers
+    ///
+    /// See the documentation for KVM_SET_CPUID2.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_cpuid2(&self, cpuid: &CpuId) -> Result<()> {
+        let ret = unsafe {
+            // Here we trust the kernel not to read past the end of the kvm_msrs struct.
+            ioctl_with_ptr(self, KVM_SET_CPUID2(), cpuid.as_ptr())
+        };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// X86 specific call to get the state of the "Local Advanced Programmable Interrupt Controller".
+    ///
+    /// See the documentation for KVM_GET_LAPIC.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_lapic(&self) -> Result<kvm_lapic_state> {
+        let mut klapic: kvm_lapic_state = Default::default();
+
+        let ret = unsafe {
+            // The ioctl is unsafe unless you trust the kernel not to write past the end of the
+            // local_apic struct.
+            ioctl_with_mut_ref(self, KVM_GET_LAPIC(), &mut klapic)
+        };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(klapic)
+    }
+
+    /// X86 specific call to set the state of the "Local Advanced Programmable Interrupt Controller".
+    ///
+    /// See the documentation for KVM_SET_LAPIC.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_lapic(&self, klapic: &kvm_lapic_state) -> Result<()> {
+        let ret = unsafe {
+            // The ioctl is safe because the kernel will only read from the klapic struct.
+            ioctl_with_ref(self, KVM_SET_LAPIC(), klapic)
+        };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// Gets the vcpu's current "multiprocessing state".
+    ///
+    /// See the documentation for KVM_GET_MP_STATE. This call can only succeed after
+    /// a call to `Vm::create_irq_chip`.
+    ///
+    /// Note that KVM defines the call for both x86 and s390 but we do not expect anyone
+    /// to run crosvm on s390.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_mp_state(&self) -> Result<kvm_mp_state> {
+        // Safe because we know that our file is a VCPU fd, we know the kernel will only
+        // write correct amount of memory to our pointer, and we verify the return result.
+        let mut state: kvm_mp_state = unsafe { std::mem::zeroed() };
+        let ret = unsafe { ioctl_with_mut_ref(self, KVM_GET_MP_STATE(), &mut state) };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(state)
+    }
+
+    /// Sets the vcpu's current "multiprocessing state".
+    ///
+    /// See the documentation for KVM_SET_MP_STATE. This call can only succeed after
+    /// a call to `Vm::create_irq_chip`.
+    ///
+    /// Note that KVM defines the call for both x86 and s390 but we do not expect anyone
+    /// to run crosvm on s390.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_mp_state(&self, state: &kvm_mp_state) -> Result<()> {
+        let ret = unsafe {
+            // The ioctl is safe because the kernel will only read from the kvm_mp_state struct.
+            ioctl_with_ref(self, KVM_SET_MP_STATE(), state)
+        };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// Gets the vcpu's currently pending exceptions, interrupts, NMIs, etc
+    ///
+    /// See the documentation for KVM_GET_VCPU_EVENTS.
+    ///
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_vcpu_events(&self) -> Result<kvm_vcpu_events> {
+        // Safe because we know that our file is a VCPU fd, we know the kernel
+        // will only write correct amount of memory to our pointer, and we
+        // verify the return result.
+        let mut events: kvm_vcpu_events = unsafe { std::mem::zeroed() };
+        let ret = unsafe { ioctl_with_mut_ref(self, KVM_GET_VCPU_EVENTS(), &mut events) };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(events)
+    }
+
+    /// Sets the vcpu's currently pending exceptions, interrupts, NMIs, etc
+    ///
+    /// See the documentation for KVM_SET_VCPU_EVENTS.
+    ///
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_vcpu_events(&self, events: &kvm_vcpu_events) -> Result<()> {
+        let ret = unsafe {
+            // The ioctl is safe because the kernel will only read from the
+            // kvm_vcpu_events.
+            ioctl_with_ref(self, KVM_SET_VCPU_EVENTS(), events)
+        };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// Signals to the host kernel that this VCPU is about to be paused.
+    ///
+    /// See the documentation for KVM_KVMCLOCK_CTRL.
+    pub fn kvmclock_ctrl(&self) -> Result<()> {
+        let ret = unsafe {
+            // The ioctl is safe because it does not read or write memory in this process.
+            ioctl(self, KVM_KVMCLOCK_CTRL())
+        };
+
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// Specifies set of signals that are blocked during execution of KVM_RUN.
+    /// Signals that are not blocked will will cause KVM_RUN to return
+    /// with -EINTR.
+    ///
+    /// See the documentation for KVM_SET_SIGNAL_MASK
+    pub fn set_signal_mask(&self, signals: &[c_int]) -> Result<()> {
+        let sigset = signal::create_sigset(signals)?;
+
+        let mut kvm_sigmask = vec_with_array_field::<kvm_signal_mask, sigset_t>(1);
+        // Rust definition of sigset_t takes 128 bytes, but the kernel only
+        // expects 8-bytes structure, so we can't write
+        // kvm_sigmask.len  = size_of::<sigset_t>() as u32;
+        kvm_sigmask[0].len = 8;
+        // Ensure the length is not too big.
+        const _ASSERT: usize = size_of::<sigset_t>() - 8 as usize;
+
+        // Safe as we allocated exactly the needed space
+        unsafe {
+            copy_nonoverlapping(
+                &sigset as *const sigset_t as *const u8,
+                kvm_sigmask[0].sigset.as_mut_ptr(),
+                8,
+            );
+        }
+
+        let ret = unsafe {
+            // The ioctl is safe because the kernel will only read from the
+            // kvm_signal_mask structure.
+            ioctl_with_ref(self, KVM_SET_SIGNAL_MASK(), &kvm_sigmask[0])
+        };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// Sets the value of one register on this VCPU.  The id of the register is
+    /// encoded as specified in the kernel documentation for KVM_SET_ONE_REG.
+    #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+    pub fn set_one_reg(&self, reg_id: u64, data: u64) -> Result<()> {
+        let data_ref = &data as *const u64;
+        let onereg = kvm_one_reg {
+            id: reg_id,
+            addr: data_ref as u64,
+        };
+        // safe becuase we allocated the struct and we know the kernel will read
+        // exactly the size of the struct
+        let ret = unsafe { ioctl_with_ref(self, KVM_SET_ONE_REG(), &onereg) };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// This initializes an ARM VCPU to the specified type with the specified features
+    /// and resets the values of all of its registers to defaults.
+    #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+    pub fn arm_vcpu_init(&self, kvi: &kvm_vcpu_init) -> Result<()> {
+        // safe becuase we allocated the struct and we know the kernel will read
+        // exactly the size of the struct
+        let ret = unsafe { ioctl_with_ref(self, KVM_ARM_VCPU_INIT(), kvi) };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// Use the KVM_INTERRUPT ioctl to inject the specified interrupt vector.
+    ///
+    /// While this ioctl exits on PPC and MIPS as well as x86, the semantics are different and
+    /// ChromeOS doesn't support PPC or MIPS.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn interrupt(&self, irq: u32) -> Result<()> {
+        let interrupt = kvm_interrupt { irq };
+        // safe becuase we allocated the struct and we know the kernel will read
+        // exactly the size of the struct
+        let ret = unsafe { ioctl_with_ref(self, KVM_INTERRUPT(), &interrupt) };
+        if ret < 0 {
+            errno_result()
+        } else {
+            Ok(())
+        }
+    }
+}
+
+impl AsRawFd for Vcpu {
+    fn as_raw_fd(&self) -> RawFd {
+        self.vcpu.as_raw_fd()
+    }
+}
+
+/// Wrapper for kvm_cpuid2 which has a zero length array at the end.
+/// Hides the zero length array behind a bounds check.
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub struct CpuId {
+    kvm_cpuid: Vec<kvm_cpuid2>,
+    allocated_len: usize, // Number of kvm_cpuid_entry2 structs at the end of kvm_cpuid2.
+}
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+impl CpuId {
+    pub fn new(array_len: usize) -> CpuId {
+        let mut kvm_cpuid = vec_with_array_field::<kvm_cpuid2, kvm_cpuid_entry2>(array_len);
+        kvm_cpuid[0].nent = array_len as u32;
+
+        CpuId {
+            kvm_cpuid,
+            allocated_len: array_len,
+        }
+    }
+
+    /// Get the entries slice so they can be modified before passing to the VCPU.
+    pub fn mut_entries_slice(&mut self) -> &mut [kvm_cpuid_entry2] {
+        // Mapping the unsized array to a slice is unsafe because the length isn't known.  Using
+        // the length we originally allocated with eliminates the possibility of overflow.
+        if self.kvm_cpuid[0].nent as usize > self.allocated_len {
+            self.kvm_cpuid[0].nent = self.allocated_len as u32;
+        }
+        let nent = self.kvm_cpuid[0].nent as usize;
+        unsafe { self.kvm_cpuid[0].entries.as_mut_slice(nent) }
+    }
+
+    /// Get a  pointer so it can be passed to the kernel.  Using this pointer is unsafe.
+    pub fn as_ptr(&self) -> *const kvm_cpuid2 {
+        &self.kvm_cpuid[0]
+    }
+
+    /// Get a mutable pointer so it can be passed to the kernel.  Using this pointer is unsafe.
+    pub fn as_mut_ptr(&mut self) -> *mut kvm_cpuid2 {
+        &mut self.kvm_cpuid[0]
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn dirty_log_size() {
+        let page_size = pagesize();
+        assert_eq!(dirty_log_bitmap_size(0), 0);
+        assert_eq!(dirty_log_bitmap_size(page_size), 1);
+        assert_eq!(dirty_log_bitmap_size(page_size * 8), 1);
+        assert_eq!(dirty_log_bitmap_size(page_size * 8 + 1), 2);
+        assert_eq!(dirty_log_bitmap_size(page_size * 100), 13);
+    }
+
+    #[test]
+    fn new() {
+        Kvm::new().unwrap();
+    }
+
+    #[test]
+    fn create_vm() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x1000)]).unwrap();
+        Vm::new(&kvm, gm).unwrap();
+    }
+
+    #[test]
+    fn check_extension() {
+        let kvm = Kvm::new().unwrap();
+        assert!(kvm.check_extension(Cap::UserMemory));
+        // I assume nobody is testing this on s390
+        assert!(!kvm.check_extension(Cap::S390UserSigp));
+    }
+
+    #[test]
+    fn check_vm_extension() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x1000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        assert!(vm.check_extension(Cap::UserMemory));
+        // I assume nobody is testing this on s390
+        assert!(!vm.check_extension(Cap::S390UserSigp));
+    }
+
+    #[test]
+    fn get_supported_cpuid() {
+        let kvm = Kvm::new().unwrap();
+        let mut cpuid = kvm.get_supported_cpuid().unwrap();
+        let cpuid_entries = cpuid.mut_entries_slice();
+        assert!(cpuid_entries.len() > 0);
+    }
+
+    #[test]
+    fn get_emulated_cpuid() {
+        let kvm = Kvm::new().unwrap();
+        kvm.get_emulated_cpuid().unwrap();
+    }
+
+    #[test]
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn get_msr_index_list() {
+        let kvm = Kvm::new().unwrap();
+        let msr_list = kvm.get_msr_index_list().unwrap();
+        assert!(msr_list.len() >= 2);
+    }
+
+    #[test]
+    fn add_memory() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x1000)]).unwrap();
+        let mut vm = Vm::new(&kvm, gm).unwrap();
+        let mem_size = 0x1000;
+        let mem = MemoryMapping::new(mem_size).unwrap();
+        vm.add_device_memory(GuestAddress(0x1000), mem, false, false)
+            .unwrap();
+    }
+
+    #[test]
+    fn add_memory_ro() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x1000)]).unwrap();
+        let mut vm = Vm::new(&kvm, gm).unwrap();
+        let mem_size = 0x1000;
+        let mem = MemoryMapping::new(mem_size).unwrap();
+        vm.add_device_memory(GuestAddress(0x1000), mem, true, false)
+            .unwrap();
+    }
+
+    #[test]
+    fn remove_memory() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x1000)]).unwrap();
+        let mut vm = Vm::new(&kvm, gm).unwrap();
+        let mem_size = 0x1000;
+        let mem = MemoryMapping::new(mem_size).unwrap();
+        let mem_ptr = mem.as_ptr();
+        let slot = vm
+            .add_device_memory(GuestAddress(0x1000), mem, false, false)
+            .unwrap();
+        let mem = vm.remove_device_memory(slot).unwrap();
+        assert_eq!(mem.size(), mem_size);
+        assert_eq!(mem.as_ptr(), mem_ptr);
+    }
+
+    #[test]
+    fn remove_invalid_memory() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x1000)]).unwrap();
+        let mut vm = Vm::new(&kvm, gm).unwrap();
+        assert!(vm.remove_device_memory(0).is_err());
+    }
+
+    #[test]
+    fn overlap_memory() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let mut vm = Vm::new(&kvm, gm).unwrap();
+        let mem_size = 0x2000;
+        let mem = MemoryMapping::new(mem_size).unwrap();
+        assert!(vm
+            .add_device_memory(GuestAddress(0x2000), mem, false, false)
+            .is_err());
+    }
+
+    #[test]
+    fn get_memory() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x1000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        let obj_addr = GuestAddress(0xf0);
+        vm.get_memory().write_obj_at_addr(67u8, obj_addr).unwrap();
+        let read_val: u8 = vm.get_memory().read_obj_from_addr(obj_addr).unwrap();
+        assert_eq!(read_val, 67u8);
+    }
+
+    #[test]
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn clock_handling() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        let mut clock_data = vm.get_clock().unwrap();
+        clock_data.clock += 1000;
+        vm.set_clock(&clock_data).unwrap();
+    }
+
+    #[test]
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn pic_handling() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        vm.create_irq_chip().unwrap();
+        let pic_state = vm.get_pic_state(PicId::Secondary).unwrap();
+        vm.set_pic_state(PicId::Secondary, &pic_state).unwrap();
+    }
+
+    #[test]
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn ioapic_handling() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        vm.create_irq_chip().unwrap();
+        let ioapic_state = vm.get_ioapic_state().unwrap();
+        vm.set_ioapic_state(&ioapic_state).unwrap();
+    }
+
+    #[test]
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn pit_handling() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        vm.create_irq_chip().unwrap();
+        vm.create_pit().unwrap();
+        let pit_state = vm.get_pit_state().unwrap();
+        vm.set_pit_state(&pit_state).unwrap();
+    }
+
+    #[test]
+    fn register_ioevent() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        let evtfd = EventFd::new().unwrap();
+        vm.register_ioevent(&evtfd, IoeventAddress::Pio(0xf4), Datamatch::AnyLength)
+            .unwrap();
+        vm.register_ioevent(&evtfd, IoeventAddress::Mmio(0x1000), Datamatch::AnyLength)
+            .unwrap();
+        vm.register_ioevent(
+            &evtfd,
+            IoeventAddress::Pio(0xc1),
+            Datamatch::U8(Some(0x7fu8)),
+        )
+        .unwrap();
+        vm.register_ioevent(
+            &evtfd,
+            IoeventAddress::Pio(0xc2),
+            Datamatch::U16(Some(0x1337u16)),
+        )
+        .unwrap();
+        vm.register_ioevent(
+            &evtfd,
+            IoeventAddress::Pio(0xc4),
+            Datamatch::U32(Some(0xdeadbeefu32)),
+        )
+        .unwrap();
+        vm.register_ioevent(
+            &evtfd,
+            IoeventAddress::Pio(0xc8),
+            Datamatch::U64(Some(0xdeadbeefdeadbeefu64)),
+        )
+        .unwrap();
+    }
+
+    #[test]
+    fn unregister_ioevent() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        let evtfd = EventFd::new().unwrap();
+        vm.register_ioevent(&evtfd, IoeventAddress::Pio(0xf4), Datamatch::AnyLength)
+            .unwrap();
+        vm.register_ioevent(&evtfd, IoeventAddress::Mmio(0x1000), Datamatch::AnyLength)
+            .unwrap();
+        vm.register_ioevent(
+            &evtfd,
+            IoeventAddress::Mmio(0x1004),
+            Datamatch::U8(Some(0x7fu8)),
+        )
+        .unwrap();
+        vm.unregister_ioevent(&evtfd, IoeventAddress::Pio(0xf4), Datamatch::AnyLength)
+            .unwrap();
+        vm.unregister_ioevent(&evtfd, IoeventAddress::Mmio(0x1000), Datamatch::AnyLength)
+            .unwrap();
+        vm.unregister_ioevent(
+            &evtfd,
+            IoeventAddress::Mmio(0x1004),
+            Datamatch::U8(Some(0x7fu8)),
+        )
+        .unwrap();
+    }
+
+    #[test]
+    fn register_irqfd() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        let evtfd1 = EventFd::new().unwrap();
+        let evtfd2 = EventFd::new().unwrap();
+        let evtfd3 = EventFd::new().unwrap();
+        vm.register_irqfd(&evtfd1, 4).unwrap();
+        vm.register_irqfd(&evtfd2, 8).unwrap();
+        vm.register_irqfd(&evtfd3, 4).unwrap();
+        vm.register_irqfd(&evtfd3, 4).unwrap_err();
+    }
+
+    #[test]
+    fn unregister_irqfd() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        let evtfd1 = EventFd::new().unwrap();
+        let evtfd2 = EventFd::new().unwrap();
+        let evtfd3 = EventFd::new().unwrap();
+        vm.register_irqfd(&evtfd1, 4).unwrap();
+        vm.register_irqfd(&evtfd2, 8).unwrap();
+        vm.register_irqfd(&evtfd3, 4).unwrap();
+        vm.unregister_irqfd(&evtfd1, 4).unwrap();
+        vm.unregister_irqfd(&evtfd2, 8).unwrap();
+        vm.unregister_irqfd(&evtfd3, 4).unwrap();
+    }
+
+    #[test]
+    fn irqfd_resample() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        let evtfd1 = EventFd::new().unwrap();
+        let evtfd2 = EventFd::new().unwrap();
+        vm.register_irqfd_resample(&evtfd1, &evtfd2, 4).unwrap();
+        vm.unregister_irqfd(&evtfd1, 4).unwrap();
+        // Ensures the ioctl is actually reading the resamplefd.
+        vm.register_irqfd_resample(&evtfd1, unsafe { &EventFd::from_raw_fd(-1) }, 4)
+            .unwrap_err();
+    }
+
+    #[test]
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn set_gsi_routing() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        vm.create_irq_chip().unwrap();
+        vm.set_gsi_routing(&[]).unwrap();
+        vm.set_gsi_routing(&[IrqRoute {
+            gsi: 1,
+            source: IrqSource::Irqchip {
+                chip: KVM_IRQCHIP_IOAPIC,
+                pin: 3,
+            },
+        }])
+        .unwrap();
+        vm.set_gsi_routing(&[IrqRoute {
+            gsi: 1,
+            source: IrqSource::Msi {
+                address: 0xf000000,
+                data: 0xa0,
+            },
+        }])
+        .unwrap();
+        vm.set_gsi_routing(&[
+            IrqRoute {
+                gsi: 1,
+                source: IrqSource::Irqchip {
+                    chip: KVM_IRQCHIP_IOAPIC,
+                    pin: 3,
+                },
+            },
+            IrqRoute {
+                gsi: 2,
+                source: IrqSource::Msi {
+                    address: 0xf000000,
+                    data: 0xa0,
+                },
+            },
+        ])
+        .unwrap();
+    }
+
+    #[test]
+    fn create_vcpu() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        Vcpu::new(0, &kvm, &vm).unwrap();
+    }
+
+    #[test]
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn debugregs() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        let vcpu = Vcpu::new(0, &kvm, &vm).unwrap();
+        let mut dregs = vcpu.get_debugregs().unwrap();
+        dregs.dr7 = 13;
+        vcpu.set_debugregs(&dregs).unwrap();
+        let dregs2 = vcpu.get_debugregs().unwrap();
+        assert_eq!(dregs.dr7, dregs2.dr7);
+    }
+
+    #[test]
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn xcrs() {
+        let kvm = Kvm::new().unwrap();
+        if !kvm.check_extension(Cap::Xcrs) {
+            return;
+        }
+
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        let vcpu = Vcpu::new(0, &kvm, &vm).unwrap();
+        let mut xcrs = vcpu.get_xcrs().unwrap();
+        xcrs.xcrs[0].value = 1;
+        vcpu.set_xcrs(&xcrs).unwrap();
+        let xcrs2 = vcpu.get_xcrs().unwrap();
+        assert_eq!(xcrs.xcrs[0].value, xcrs2.xcrs[0].value);
+    }
+
+    #[test]
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn get_msrs() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        let vcpu = Vcpu::new(0, &kvm, &vm).unwrap();
+        let mut msrs = vec![
+            // This one should succeed
+            kvm_msr_entry {
+                index: 0x0000011e,
+                ..Default::default()
+            },
+            // This one will fail to fetch
+            kvm_msr_entry {
+                index: 0x000003f1,
+                ..Default::default()
+            },
+        ];
+        vcpu.get_msrs(&mut msrs).unwrap();
+        assert_eq!(msrs.len(), 1);
+    }
+
+    #[test]
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn mp_state() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        vm.create_irq_chip().unwrap();
+        let vcpu = Vcpu::new(0, &kvm, &vm).unwrap();
+        let state = vcpu.get_mp_state().unwrap();
+        vcpu.set_mp_state(&state).unwrap();
+    }
+
+    #[test]
+    fn set_signal_mask() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        let vcpu = Vcpu::new(0, &kvm, &vm).unwrap();
+        vcpu.set_signal_mask(&[sys_util::SIGRTMIN() + 0]).unwrap();
+    }
+
+    #[test]
+    fn vcpu_mmap_size() {
+        let kvm = Kvm::new().unwrap();
+        let mmap_size = kvm.get_vcpu_mmap_size().unwrap();
+        let page_size = pagesize();
+        assert!(mmap_size >= page_size);
+        assert!(mmap_size % page_size == 0);
+    }
+
+    #[test]
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn set_identity_map_addr() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        vm.set_identity_map_addr(GuestAddress(0x20000)).unwrap();
+    }
+}
diff --git a/kvm/tests/dirty_log.rs b/kvm/tests/dirty_log.rs
new file mode 100644
index 0000000..4efb208
--- /dev/null
+++ b/kvm/tests/dirty_log.rs
@@ -0,0 +1,71 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+
+use kvm::*;
+use kvm_sys::kvm_regs;
+use sys_util::{GuestAddress, GuestMemory, MemoryMapping, SharedMemory};
+
+#[test]
+fn test_run() {
+    /*
+    0000  881C mov [si],bl
+    0002  F4   hlt
+    */
+    let code = [0x88, 0x1c, 0xf4];
+    let mem_size = 0x10000;
+    let load_addr = GuestAddress(0x1000);
+    let guest_mem = GuestMemory::new(&[]).unwrap();
+    let mut mem = SharedMemory::new(None).expect("failed to create shared memory");
+    mem.set_size(mem_size)
+        .expect("failed to set shared memory size");
+    let mmap =
+        MemoryMapping::from_fd(&mem, mem_size as usize).expect("failed to create memory mapping");
+
+    mmap.write_slice(&code[..], load_addr.offset() as usize)
+        .expect("Writing code to memory failed.");
+
+    let kvm = Kvm::new().expect("new kvm failed");
+    let mut vm = Vm::new(&kvm, guest_mem).expect("new vm failed");
+    let vcpu = Vcpu::new(0, &kvm, &vm).expect("new vcpu failed");
+    let mut vcpu_sregs = vcpu.get_sregs().expect("get sregs failed");
+    vcpu_sregs.cs.base = 0;
+    vcpu_sregs.cs.selector = 0;
+    vcpu.set_sregs(&vcpu_sregs).expect("set sregs failed");
+
+    let mut vcpu_regs: kvm_regs = unsafe { std::mem::zeroed() };
+    vcpu_regs.rip = load_addr.offset() as u64;
+    vcpu_regs.rflags = 2;
+    // Write 0x12 to the beginning of the 9th page.
+    vcpu_regs.rsi = 0x8000;
+    vcpu_regs.rbx = 0x12;
+    vcpu.set_regs(&vcpu_regs).expect("set regs failed");
+    let slot = vm
+        .add_device_memory(
+            GuestAddress(0),
+            MemoryMapping::from_fd(&mem, mem_size as usize)
+                .expect("failed to create memory mapping"),
+            false,
+            true,
+        )
+        .expect("failed to register memory");
+
+    loop {
+        match vcpu.run().expect("run failed") {
+            VcpuExit::Hlt => break,
+            r => panic!("unexpected exit reason: {:?}", r),
+        }
+    }
+
+    let mut dirty_log = [0x0, 0x0];
+    vm.get_dirty_log(slot, &mut dirty_log[..])
+        .expect("failed to get dirty log");
+    // Tests the 9th page was written to.
+    assert_eq!(dirty_log[1], 0x1);
+    assert_eq!(
+        mmap.read_obj::<u64>(vcpu_regs.rsi as usize).unwrap(),
+        vcpu_regs.rbx
+    );
+}
diff --git a/kvm/tests/read_only_memory.rs b/kvm/tests/read_only_memory.rs
new file mode 100644
index 0000000..c1dd854
--- /dev/null
+++ b/kvm/tests/read_only_memory.rs
@@ -0,0 +1,102 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+
+use kvm::*;
+use kvm_sys::kvm_regs;
+use sys_util::{GuestAddress, GuestMemory, MemoryMapping, SharedMemory};
+
+#[test]
+fn test_run() {
+    /*
+    0000  268A07  mov al,[es:bx]
+    0003  0401    add al,0x1
+    0005  268807  mov [es:bx],al
+    0008  F4      hlt
+    */
+    let code = [0x26, 0x8a, 0x07, 0x04, 0x01, 0x26, 0x88, 0x07, 0xf4];
+    let mem_size = 0x2000;
+    let load_addr = GuestAddress(0x1000);
+    let guest_mem = GuestMemory::new(&[]).unwrap();
+    let mut mem = SharedMemory::new(None).expect("failed to create shared memory");
+    mem.set_size(mem_size)
+        .expect("failed to set shared memory size");
+    let mmap =
+        MemoryMapping::from_fd(&mem, mem_size as usize).expect("failed to create memory mapping");
+
+    mmap.write_slice(&code[..], load_addr.offset() as usize)
+        .expect("Writing code to memory failed.");
+
+    let kvm = Kvm::new().expect("new kvm failed");
+    let mut vm = Vm::new(&kvm, guest_mem).expect("new vm failed");
+    let vcpu = Vcpu::new(0, &kvm, &vm).expect("new vcpu failed");
+    let mut vcpu_sregs = vcpu.get_sregs().expect("get sregs failed");
+    vcpu_sregs.cs.base = 0;
+    vcpu_sregs.cs.selector = 0;
+    vcpu_sregs.es.base = 0x3000;
+    vcpu_sregs.es.selector = 0;
+    vcpu.set_sregs(&vcpu_sregs).expect("set sregs failed");
+
+    let mut vcpu_regs: kvm_regs = unsafe { std::mem::zeroed() };
+    vcpu_regs.rip = load_addr.offset() as u64;
+    vcpu_regs.rflags = 2;
+    vcpu_regs.rax = 0x66;
+    vcpu_regs.rbx = 0;
+    vcpu.set_regs(&vcpu_regs).expect("set regs failed");
+    vm.add_device_memory(
+        GuestAddress(0),
+        MemoryMapping::from_fd(&mem, mem_size as usize).expect("failed to create memory mapping"),
+        false,
+        false,
+    )
+    .expect("failed to register memory");
+
+    // Give some read only memory for the test code to read from and force a vcpu exit when it reads
+    // from it.
+    let mut mem_ro = SharedMemory::new(None).expect("failed to create shared memory");
+    mem_ro
+        .set_size(0x1000)
+        .expect("failed to set shared memory size");
+    let mmap_ro = MemoryMapping::from_fd(&mem_ro, 0x1000).expect("failed to create memory mapping");
+    mmap_ro
+        .write_obj(vcpu_regs.rax as u8, 0)
+        .expect("failed writing data to ro memory");
+    vm.add_device_memory(
+        GuestAddress(vcpu_sregs.es.base),
+        MemoryMapping::from_fd(&mem_ro, 0x1000).expect("failed to create memory mapping"),
+        true,
+        false,
+    )
+    .expect("failed to register memory");
+
+    // Ensure we get exactly 1 exit from attempting to write to read only memory.
+    let mut exits = 0;
+
+    loop {
+        match vcpu.run().expect("run failed") {
+            VcpuExit::Hlt => break,
+            VcpuExit::MmioWrite {
+                address,
+                size: 1,
+                data,
+            } => {
+                assert_eq!(address, vcpu_sregs.es.base);
+                assert_eq!(data[0] as u64, vcpu_regs.rax + 1);
+                exits += 1;
+            }
+            r => panic!("unexpected exit reason: {:?}", r),
+        }
+    }
+
+    // Check that exactly 1 attempt to write to read only memory was made, and that the memory is
+    // unchanged after that attempt.
+    assert_eq!(exits, 1);
+    assert_eq!(
+        mmap_ro
+            .read_obj::<u8>(0)
+            .expect("failed to read data from ro memory"),
+        vcpu_regs.rax as u8
+    );
+}
diff --git a/kvm/tests/real_run_adder.rs b/kvm/tests/real_run_adder.rs
new file mode 100644
index 0000000..a419ad9
--- /dev/null
+++ b/kvm/tests/real_run_adder.rs
@@ -0,0 +1,73 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+
+use kvm::*;
+use kvm_sys::kvm_regs;
+use sys_util::{GuestAddress, GuestMemory};
+
+#[test]
+fn test_run() {
+    // This example based on https://lwn.net/Articles/658511/
+    let code = [
+        0xba, 0xf8, 0x03, /* mov $0x3f8, %dx */
+        0x00, 0xd8, /* add %bl, %al */
+        0x04, '0' as u8, /* add $'0', %al */
+        0xee,      /* out %al, (%dx) */
+        0xb0, '\n' as u8, /* mov $'\n', %al */
+        0xee,       /* out %al, (%dx) */
+        0x2e, 0xc6, 0x06, 0xf1, 0x10, 0x13, /* movb $0x13, %cs:0xf1 */
+        0xf4, /* hlt */
+    ];
+
+    let mem_size = 0x1000;
+    let load_addr = GuestAddress(0x1000);
+    let mem = GuestMemory::new(&vec![(load_addr, mem_size)]).unwrap();
+
+    let kvm = Kvm::new().expect("new kvm failed");
+    let vm = Vm::new(&kvm, mem).expect("new vm failed");
+    let vcpu = Vcpu::new(0, &kvm, &vm).expect("new vcpu failed");
+
+    vm.get_memory()
+        .write_at_addr(&code, load_addr)
+        .expect("Writing code to memory failed.");
+
+    let mut vcpu_sregs = vcpu.get_sregs().expect("get sregs failed");
+    assert_ne!(vcpu_sregs.cs.base, 0);
+    assert_ne!(vcpu_sregs.cs.selector, 0);
+    vcpu_sregs.cs.base = 0;
+    vcpu_sregs.cs.selector = 0;
+    vcpu.set_sregs(&vcpu_sregs).expect("set sregs failed");
+
+    let mut vcpu_regs: kvm_regs = unsafe { std::mem::zeroed() };
+    vcpu_regs.rip = 0x1000;
+    vcpu_regs.rax = 2;
+    vcpu_regs.rbx = 7;
+    vcpu_regs.rflags = 2;
+    vcpu.set_regs(&vcpu_regs).expect("set regs failed");
+
+    let mut out = String::new();
+    loop {
+        match vcpu.run().expect("run failed") {
+            VcpuExit::IoOut {
+                port: 0x3f8,
+                size,
+                data,
+            } => {
+                assert_eq!(size, 1);
+                out.push(data[0] as char);
+            }
+            VcpuExit::Hlt => break,
+            r => panic!("unexpected exit reason: {:?}", r),
+        }
+    }
+
+    assert_eq!(out, "9\n");
+    let result: u8 = vm
+        .get_memory()
+        .read_obj_from_addr(load_addr.checked_add(0xf1).unwrap())
+        .expect("Error reading the result.");
+    assert_eq!(result, 0x13);
+}
diff --git a/kvm_sys/Cargo.toml b/kvm_sys/Cargo.toml
new file mode 100644
index 0000000..3f62ead
--- /dev/null
+++ b/kvm_sys/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "kvm_sys"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+libc = "*"
+sys_util = { path = "../sys_util" }
diff --git a/kvm_sys/src/aarch64/bindings.rs b/kvm_sys/src/aarch64/bindings.rs
new file mode 100644
index 0000000..26b10b4
--- /dev/null
+++ b/kvm_sys/src/aarch64/bindings.rs
@@ -0,0 +1,6392 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+#[repr(C)]
+#[derive(Default)]
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
+impl<T> __IncompleteArrayField<T> {
+    #[inline]
+    pub fn new() -> Self {
+        __IncompleteArrayField(::std::marker::PhantomData)
+    }
+    #[inline]
+    pub unsafe fn as_ptr(&self) -> *const T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_slice(&self, len: usize) -> &[T] {
+        ::std::slice::from_raw_parts(self.as_ptr(), len)
+    }
+    #[inline]
+    pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
+        ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
+    }
+}
+impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        fmt.write_str("__IncompleteArrayField")
+    }
+}
+impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self::new()
+    }
+}
+impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
+pub const __BITS_PER_LONG: ::std::os::raw::c_uint = 64;
+pub const __FD_SETSIZE: ::std::os::raw::c_uint = 1024;
+pub const _IOC_NRBITS: ::std::os::raw::c_uint = 8;
+pub const _IOC_TYPEBITS: ::std::os::raw::c_uint = 8;
+pub const _IOC_SIZEBITS: ::std::os::raw::c_uint = 14;
+pub const _IOC_DIRBITS: ::std::os::raw::c_uint = 2;
+pub const _IOC_NRMASK: ::std::os::raw::c_uint = 255;
+pub const _IOC_TYPEMASK: ::std::os::raw::c_uint = 255;
+pub const _IOC_SIZEMASK: ::std::os::raw::c_uint = 16383;
+pub const _IOC_DIRMASK: ::std::os::raw::c_uint = 3;
+pub const _IOC_NRSHIFT: ::std::os::raw::c_uint = 0;
+pub const _IOC_TYPESHIFT: ::std::os::raw::c_uint = 8;
+pub const _IOC_SIZESHIFT: ::std::os::raw::c_uint = 16;
+pub const _IOC_DIRSHIFT: ::std::os::raw::c_uint = 30;
+pub const _IOC_NONE: ::std::os::raw::c_uint = 0;
+pub const _IOC_WRITE: ::std::os::raw::c_uint = 1;
+pub const _IOC_READ: ::std::os::raw::c_uint = 2;
+pub const IOC_IN: ::std::os::raw::c_uint = 1073741824;
+pub const IOC_OUT: ::std::os::raw::c_uint = 2147483648;
+pub const IOC_INOUT: ::std::os::raw::c_uint = 3221225472;
+pub const IOCSIZE_MASK: ::std::os::raw::c_uint = 1073676288;
+pub const IOCSIZE_SHIFT: ::std::os::raw::c_uint = 16;
+pub const KVM_SPSR_EL1: ::std::os::raw::c_uint = 0;
+pub const KVM_SPSR_SVC: ::std::os::raw::c_uint = 0;
+pub const KVM_SPSR_ABT: ::std::os::raw::c_uint = 1;
+pub const KVM_SPSR_UND: ::std::os::raw::c_uint = 2;
+pub const KVM_SPSR_IRQ: ::std::os::raw::c_uint = 3;
+pub const KVM_SPSR_FIQ: ::std::os::raw::c_uint = 4;
+pub const KVM_NR_SPSR: ::std::os::raw::c_uint = 5;
+pub const PSCI_0_2_FN_BASE: ::std::os::raw::c_uint = 2214592512;
+pub const PSCI_0_2_64BIT: ::std::os::raw::c_uint = 1073741824;
+pub const PSCI_0_2_FN64_BASE: ::std::os::raw::c_uint = 3288334336;
+pub const PSCI_0_2_POWER_STATE_ID_MASK: ::std::os::raw::c_uint = 65535;
+pub const PSCI_0_2_POWER_STATE_ID_SHIFT: ::std::os::raw::c_uint = 0;
+pub const PSCI_0_2_POWER_STATE_TYPE_SHIFT: ::std::os::raw::c_uint = 16;
+pub const PSCI_0_2_POWER_STATE_TYPE_MASK: ::std::os::raw::c_uint = 65536;
+pub const PSCI_0_2_POWER_STATE_AFFL_SHIFT: ::std::os::raw::c_uint = 24;
+pub const PSCI_0_2_POWER_STATE_AFFL_MASK: ::std::os::raw::c_uint = 50331648;
+pub const PSCI_1_0_EXT_POWER_STATE_ID_MASK: ::std::os::raw::c_uint = 268435455;
+pub const PSCI_1_0_EXT_POWER_STATE_ID_SHIFT: ::std::os::raw::c_uint = 0;
+pub const PSCI_1_0_EXT_POWER_STATE_TYPE_SHIFT: ::std::os::raw::c_uint = 30;
+pub const PSCI_1_0_EXT_POWER_STATE_TYPE_MASK: ::std::os::raw::c_uint = 1073741824;
+pub const PSCI_0_2_AFFINITY_LEVEL_ON: ::std::os::raw::c_uint = 0;
+pub const PSCI_0_2_AFFINITY_LEVEL_OFF: ::std::os::raw::c_uint = 1;
+pub const PSCI_0_2_AFFINITY_LEVEL_ON_PENDING: ::std::os::raw::c_uint = 2;
+pub const PSCI_0_2_TOS_UP_MIGRATE: ::std::os::raw::c_uint = 0;
+pub const PSCI_0_2_TOS_UP_NO_MIGRATE: ::std::os::raw::c_uint = 1;
+pub const PSCI_0_2_TOS_MP: ::std::os::raw::c_uint = 2;
+pub const PSCI_VERSION_MAJOR_SHIFT: ::std::os::raw::c_uint = 16;
+pub const PSCI_VERSION_MINOR_MASK: ::std::os::raw::c_uint = 65535;
+pub const PSCI_VERSION_MAJOR_MASK: ::std::os::raw::c_int = -65536;
+pub const PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT: ::std::os::raw::c_uint = 1;
+pub const PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK: ::std::os::raw::c_uint = 2;
+pub const PSCI_RET_SUCCESS: ::std::os::raw::c_uint = 0;
+pub const PSCI_RET_NOT_SUPPORTED: ::std::os::raw::c_int = -1;
+pub const PSCI_RET_INVALID_PARAMS: ::std::os::raw::c_int = -2;
+pub const PSCI_RET_DENIED: ::std::os::raw::c_int = -3;
+pub const PSCI_RET_ALREADY_ON: ::std::os::raw::c_int = -4;
+pub const PSCI_RET_ON_PENDING: ::std::os::raw::c_int = -5;
+pub const PSCI_RET_INTERNAL_FAILURE: ::std::os::raw::c_int = -6;
+pub const PSCI_RET_NOT_PRESENT: ::std::os::raw::c_int = -7;
+pub const PSCI_RET_DISABLED: ::std::os::raw::c_int = -8;
+pub const PSCI_RET_INVALID_ADDRESS: ::std::os::raw::c_int = -9;
+pub const HWCAP_FP: ::std::os::raw::c_uint = 1;
+pub const HWCAP_ASIMD: ::std::os::raw::c_uint = 2;
+pub const HWCAP_EVTSTRM: ::std::os::raw::c_uint = 4;
+pub const HWCAP_AES: ::std::os::raw::c_uint = 8;
+pub const HWCAP_PMULL: ::std::os::raw::c_uint = 16;
+pub const HWCAP_SHA1: ::std::os::raw::c_uint = 32;
+pub const HWCAP_SHA2: ::std::os::raw::c_uint = 64;
+pub const HWCAP_CRC32: ::std::os::raw::c_uint = 128;
+pub const HWCAP_ATOMICS: ::std::os::raw::c_uint = 256;
+pub const PSR_MODE_EL0t: ::std::os::raw::c_uint = 0;
+pub const PSR_MODE_EL1t: ::std::os::raw::c_uint = 4;
+pub const PSR_MODE_EL1h: ::std::os::raw::c_uint = 5;
+pub const PSR_MODE_EL2t: ::std::os::raw::c_uint = 8;
+pub const PSR_MODE_EL2h: ::std::os::raw::c_uint = 9;
+pub const PSR_MODE_EL3t: ::std::os::raw::c_uint = 12;
+pub const PSR_MODE_EL3h: ::std::os::raw::c_uint = 13;
+pub const PSR_MODE_MASK: ::std::os::raw::c_uint = 15;
+pub const PSR_MODE32_BIT: ::std::os::raw::c_uint = 16;
+pub const PSR_F_BIT: ::std::os::raw::c_uint = 64;
+pub const PSR_I_BIT: ::std::os::raw::c_uint = 128;
+pub const PSR_A_BIT: ::std::os::raw::c_uint = 256;
+pub const PSR_D_BIT: ::std::os::raw::c_uint = 512;
+pub const PSR_PAN_BIT: ::std::os::raw::c_uint = 4194304;
+pub const PSR_Q_BIT: ::std::os::raw::c_uint = 134217728;
+pub const PSR_V_BIT: ::std::os::raw::c_uint = 268435456;
+pub const PSR_C_BIT: ::std::os::raw::c_uint = 536870912;
+pub const PSR_Z_BIT: ::std::os::raw::c_uint = 1073741824;
+pub const PSR_N_BIT: ::std::os::raw::c_uint = 2147483648;
+pub const PSR_f: ::std::os::raw::c_uint = 4278190080;
+pub const PSR_s: ::std::os::raw::c_uint = 16711680;
+pub const PSR_x: ::std::os::raw::c_uint = 65280;
+pub const PSR_c: ::std::os::raw::c_uint = 255;
+pub const KVM_ARM_TARGET_AEM_V8: ::std::os::raw::c_uint = 0;
+pub const KVM_ARM_TARGET_FOUNDATION_V8: ::std::os::raw::c_uint = 1;
+pub const KVM_ARM_TARGET_CORTEX_A57: ::std::os::raw::c_uint = 2;
+pub const KVM_ARM_TARGET_XGENE_POTENZA: ::std::os::raw::c_uint = 3;
+pub const KVM_ARM_TARGET_CORTEX_A53: ::std::os::raw::c_uint = 4;
+pub const KVM_ARM_TARGET_GENERIC_V8: ::std::os::raw::c_uint = 5;
+pub const KVM_ARM_NUM_TARGETS: ::std::os::raw::c_uint = 6;
+pub const KVM_ARM_DEVICE_TYPE_SHIFT: ::std::os::raw::c_uint = 0;
+pub const KVM_ARM_DEVICE_TYPE_MASK: ::std::os::raw::c_uint = 65535;
+pub const KVM_ARM_DEVICE_ID_SHIFT: ::std::os::raw::c_uint = 16;
+pub const KVM_ARM_DEVICE_ID_MASK: ::std::os::raw::c_uint = 4294901760;
+pub const KVM_ARM_DEVICE_VGIC_V2: ::std::os::raw::c_uint = 0;
+pub const KVM_VGIC_V2_ADDR_TYPE_DIST: ::std::os::raw::c_uint = 0;
+pub const KVM_VGIC_V2_ADDR_TYPE_CPU: ::std::os::raw::c_uint = 1;
+pub const KVM_VGIC_V2_DIST_SIZE: ::std::os::raw::c_uint = 4096;
+pub const KVM_VGIC_V2_CPU_SIZE: ::std::os::raw::c_uint = 8192;
+pub const KVM_VGIC_V3_ADDR_TYPE_DIST: ::std::os::raw::c_uint = 2;
+pub const KVM_VGIC_V3_ADDR_TYPE_REDIST: ::std::os::raw::c_uint = 3;
+pub const KVM_ARM_VCPU_POWER_OFF: ::std::os::raw::c_uint = 0;
+pub const KVM_ARM_VCPU_EL1_32BIT: ::std::os::raw::c_uint = 1;
+pub const KVM_ARM_VCPU_PSCI_0_2: ::std::os::raw::c_uint = 2;
+pub const KVM_ARM_MAX_DBG_REGS: ::std::os::raw::c_uint = 16;
+pub const KVM_GUESTDBG_USE_SW_BP: ::std::os::raw::c_uint = 65536;
+pub const KVM_GUESTDBG_USE_HW: ::std::os::raw::c_uint = 131072;
+pub const KVM_REG_ARM_COPROC_MASK: ::std::os::raw::c_uint = 268369920;
+pub const KVM_REG_ARM_COPROC_SHIFT: ::std::os::raw::c_uint = 16;
+pub const KVM_REG_ARM_CORE: ::std::os::raw::c_uint = 1048576;
+pub const KVM_REG_ARM_DEMUX: ::std::os::raw::c_uint = 1114112;
+pub const KVM_REG_ARM_DEMUX_ID_MASK: ::std::os::raw::c_uint = 65280;
+pub const KVM_REG_ARM_DEMUX_ID_SHIFT: ::std::os::raw::c_uint = 8;
+pub const KVM_REG_ARM_DEMUX_ID_CCSIDR: ::std::os::raw::c_uint = 0;
+pub const KVM_REG_ARM_DEMUX_VAL_MASK: ::std::os::raw::c_uint = 255;
+pub const KVM_REG_ARM_DEMUX_VAL_SHIFT: ::std::os::raw::c_uint = 0;
+pub const KVM_REG_ARM64_SYSREG: ::std::os::raw::c_uint = 1245184;
+pub const KVM_REG_ARM64_SYSREG_OP0_MASK: ::std::os::raw::c_uint = 49152;
+pub const KVM_REG_ARM64_SYSREG_OP0_SHIFT: ::std::os::raw::c_uint = 14;
+pub const KVM_REG_ARM64_SYSREG_OP1_MASK: ::std::os::raw::c_uint = 14336;
+pub const KVM_REG_ARM64_SYSREG_OP1_SHIFT: ::std::os::raw::c_uint = 11;
+pub const KVM_REG_ARM64_SYSREG_CRN_MASK: ::std::os::raw::c_uint = 1920;
+pub const KVM_REG_ARM64_SYSREG_CRN_SHIFT: ::std::os::raw::c_uint = 7;
+pub const KVM_REG_ARM64_SYSREG_CRM_MASK: ::std::os::raw::c_uint = 120;
+pub const KVM_REG_ARM64_SYSREG_CRM_SHIFT: ::std::os::raw::c_uint = 3;
+pub const KVM_REG_ARM64_SYSREG_OP2_MASK: ::std::os::raw::c_uint = 7;
+pub const KVM_REG_ARM64_SYSREG_OP2_SHIFT: ::std::os::raw::c_uint = 0;
+pub const KVM_DEV_ARM_VGIC_GRP_ADDR: ::std::os::raw::c_uint = 0;
+pub const KVM_DEV_ARM_VGIC_GRP_DIST_REGS: ::std::os::raw::c_uint = 1;
+pub const KVM_DEV_ARM_VGIC_GRP_CPU_REGS: ::std::os::raw::c_uint = 2;
+pub const KVM_DEV_ARM_VGIC_CPUID_SHIFT: ::std::os::raw::c_uint = 32;
+pub const KVM_DEV_ARM_VGIC_CPUID_MASK: ::std::os::raw::c_ulonglong = 1095216660480;
+pub const KVM_DEV_ARM_VGIC_OFFSET_SHIFT: ::std::os::raw::c_uint = 0;
+pub const KVM_DEV_ARM_VGIC_OFFSET_MASK: ::std::os::raw::c_uint = 4294967295;
+pub const KVM_DEV_ARM_VGIC_GRP_NR_IRQS: ::std::os::raw::c_uint = 3;
+pub const KVM_DEV_ARM_VGIC_GRP_CTRL: ::std::os::raw::c_uint = 4;
+pub const KVM_DEV_ARM_VGIC_CTRL_INIT: ::std::os::raw::c_uint = 0;
+pub const KVM_ARM_IRQ_TYPE_SHIFT: ::std::os::raw::c_uint = 24;
+pub const KVM_ARM_IRQ_TYPE_MASK: ::std::os::raw::c_uint = 255;
+pub const KVM_ARM_IRQ_VCPU_SHIFT: ::std::os::raw::c_uint = 16;
+pub const KVM_ARM_IRQ_VCPU_MASK: ::std::os::raw::c_uint = 255;
+pub const KVM_ARM_IRQ_NUM_SHIFT: ::std::os::raw::c_uint = 0;
+pub const KVM_ARM_IRQ_NUM_MASK: ::std::os::raw::c_uint = 65535;
+pub const KVM_ARM_IRQ_TYPE_CPU: ::std::os::raw::c_uint = 0;
+pub const KVM_ARM_IRQ_TYPE_SPI: ::std::os::raw::c_uint = 1;
+pub const KVM_ARM_IRQ_TYPE_PPI: ::std::os::raw::c_uint = 2;
+pub const KVM_ARM_IRQ_CPU_IRQ: ::std::os::raw::c_uint = 0;
+pub const KVM_ARM_IRQ_CPU_FIQ: ::std::os::raw::c_uint = 1;
+pub const KVM_ARM_IRQ_GIC_MAX: ::std::os::raw::c_uint = 127;
+pub const KVM_NR_IRQCHIPS: ::std::os::raw::c_uint = 1;
+pub const KVM_PSCI_FN_BASE: ::std::os::raw::c_uint = 2512501342;
+pub const KVM_PSCI_RET_SUCCESS: ::std::os::raw::c_uint = 0;
+pub const KVM_PSCI_RET_NI: ::std::os::raw::c_int = -1;
+pub const KVM_PSCI_RET_INVAL: ::std::os::raw::c_int = -2;
+pub const KVM_PSCI_RET_DENIED: ::std::os::raw::c_int = -3;
+pub const KVM_API_VERSION: ::std::os::raw::c_uint = 12;
+pub const KVM_TRC_SHIFT: ::std::os::raw::c_uint = 16;
+pub const KVM_TRC_ENTRYEXIT: ::std::os::raw::c_uint = 65536;
+pub const KVM_TRC_HANDLER: ::std::os::raw::c_uint = 131072;
+pub const KVM_TRC_VMENTRY: ::std::os::raw::c_uint = 65537;
+pub const KVM_TRC_VMEXIT: ::std::os::raw::c_uint = 65538;
+pub const KVM_TRC_PAGE_FAULT: ::std::os::raw::c_uint = 131073;
+pub const KVM_TRC_HEAD_SIZE: ::std::os::raw::c_uint = 12;
+pub const KVM_TRC_CYCLE_SIZE: ::std::os::raw::c_uint = 8;
+pub const KVM_TRC_EXTRA_MAX: ::std::os::raw::c_uint = 7;
+pub const KVM_TRC_INJ_VIRQ: ::std::os::raw::c_uint = 131074;
+pub const KVM_TRC_REDELIVER_EVT: ::std::os::raw::c_uint = 131075;
+pub const KVM_TRC_PEND_INTR: ::std::os::raw::c_uint = 131076;
+pub const KVM_TRC_IO_READ: ::std::os::raw::c_uint = 131077;
+pub const KVM_TRC_IO_WRITE: ::std::os::raw::c_uint = 131078;
+pub const KVM_TRC_CR_READ: ::std::os::raw::c_uint = 131079;
+pub const KVM_TRC_CR_WRITE: ::std::os::raw::c_uint = 131080;
+pub const KVM_TRC_DR_READ: ::std::os::raw::c_uint = 131081;
+pub const KVM_TRC_DR_WRITE: ::std::os::raw::c_uint = 131082;
+pub const KVM_TRC_MSR_READ: ::std::os::raw::c_uint = 131083;
+pub const KVM_TRC_MSR_WRITE: ::std::os::raw::c_uint = 131084;
+pub const KVM_TRC_CPUID: ::std::os::raw::c_uint = 131085;
+pub const KVM_TRC_INTR: ::std::os::raw::c_uint = 131086;
+pub const KVM_TRC_NMI: ::std::os::raw::c_uint = 131087;
+pub const KVM_TRC_VMMCALL: ::std::os::raw::c_uint = 131088;
+pub const KVM_TRC_HLT: ::std::os::raw::c_uint = 131089;
+pub const KVM_TRC_CLTS: ::std::os::raw::c_uint = 131090;
+pub const KVM_TRC_LMSW: ::std::os::raw::c_uint = 131091;
+pub const KVM_TRC_APIC_ACCESS: ::std::os::raw::c_uint = 131092;
+pub const KVM_TRC_TDP_FAULT: ::std::os::raw::c_uint = 131093;
+pub const KVM_TRC_GTLB_WRITE: ::std::os::raw::c_uint = 131094;
+pub const KVM_TRC_STLB_WRITE: ::std::os::raw::c_uint = 131095;
+pub const KVM_TRC_STLB_INVAL: ::std::os::raw::c_uint = 131096;
+pub const KVM_TRC_PPC_INSTR: ::std::os::raw::c_uint = 131097;
+pub const KVM_MEM_LOG_DIRTY_PAGES: ::std::os::raw::c_uint = 1;
+pub const KVM_MEM_READONLY: ::std::os::raw::c_uint = 2;
+pub const KVM_PIT_SPEAKER_DUMMY: ::std::os::raw::c_uint = 1;
+pub const KVM_S390_GET_SKEYS_NONE: ::std::os::raw::c_uint = 1;
+pub const KVM_S390_SKEYS_MAX: ::std::os::raw::c_uint = 1048576;
+pub const KVM_EXIT_UNKNOWN: ::std::os::raw::c_uint = 0;
+pub const KVM_EXIT_EXCEPTION: ::std::os::raw::c_uint = 1;
+pub const KVM_EXIT_IO: ::std::os::raw::c_uint = 2;
+pub const KVM_EXIT_HYPERCALL: ::std::os::raw::c_uint = 3;
+pub const KVM_EXIT_DEBUG: ::std::os::raw::c_uint = 4;
+pub const KVM_EXIT_HLT: ::std::os::raw::c_uint = 5;
+pub const KVM_EXIT_MMIO: ::std::os::raw::c_uint = 6;
+pub const KVM_EXIT_IRQ_WINDOW_OPEN: ::std::os::raw::c_uint = 7;
+pub const KVM_EXIT_SHUTDOWN: ::std::os::raw::c_uint = 8;
+pub const KVM_EXIT_FAIL_ENTRY: ::std::os::raw::c_uint = 9;
+pub const KVM_EXIT_INTR: ::std::os::raw::c_uint = 10;
+pub const KVM_EXIT_SET_TPR: ::std::os::raw::c_uint = 11;
+pub const KVM_EXIT_TPR_ACCESS: ::std::os::raw::c_uint = 12;
+pub const KVM_EXIT_S390_SIEIC: ::std::os::raw::c_uint = 13;
+pub const KVM_EXIT_S390_RESET: ::std::os::raw::c_uint = 14;
+pub const KVM_EXIT_DCR: ::std::os::raw::c_uint = 15;
+pub const KVM_EXIT_NMI: ::std::os::raw::c_uint = 16;
+pub const KVM_EXIT_INTERNAL_ERROR: ::std::os::raw::c_uint = 17;
+pub const KVM_EXIT_OSI: ::std::os::raw::c_uint = 18;
+pub const KVM_EXIT_PAPR_HCALL: ::std::os::raw::c_uint = 19;
+pub const KVM_EXIT_S390_UCONTROL: ::std::os::raw::c_uint = 20;
+pub const KVM_EXIT_WATCHDOG: ::std::os::raw::c_uint = 21;
+pub const KVM_EXIT_S390_TSCH: ::std::os::raw::c_uint = 22;
+pub const KVM_EXIT_EPR: ::std::os::raw::c_uint = 23;
+pub const KVM_EXIT_SYSTEM_EVENT: ::std::os::raw::c_uint = 24;
+pub const KVM_EXIT_S390_STSI: ::std::os::raw::c_uint = 25;
+pub const KVM_EXIT_IOAPIC_EOI: ::std::os::raw::c_uint = 26;
+pub const KVM_INTERNAL_ERROR_EMULATION: ::std::os::raw::c_uint = 1;
+pub const KVM_INTERNAL_ERROR_SIMUL_EX: ::std::os::raw::c_uint = 2;
+pub const KVM_INTERNAL_ERROR_DELIVERY_EV: ::std::os::raw::c_uint = 3;
+pub const KVM_EXIT_IO_IN: ::std::os::raw::c_uint = 0;
+pub const KVM_EXIT_IO_OUT: ::std::os::raw::c_uint = 1;
+pub const KVM_S390_RESET_POR: ::std::os::raw::c_uint = 1;
+pub const KVM_S390_RESET_CLEAR: ::std::os::raw::c_uint = 2;
+pub const KVM_S390_RESET_SUBSYSTEM: ::std::os::raw::c_uint = 4;
+pub const KVM_S390_RESET_CPU_INIT: ::std::os::raw::c_uint = 8;
+pub const KVM_S390_RESET_IPL: ::std::os::raw::c_uint = 16;
+pub const KVM_SYSTEM_EVENT_SHUTDOWN: ::std::os::raw::c_uint = 1;
+pub const KVM_SYSTEM_EVENT_RESET: ::std::os::raw::c_uint = 2;
+pub const KVM_SYSTEM_EVENT_CRASH: ::std::os::raw::c_uint = 3;
+pub const KVM_S390_MEMOP_LOGICAL_READ: ::std::os::raw::c_uint = 0;
+pub const KVM_S390_MEMOP_LOGICAL_WRITE: ::std::os::raw::c_uint = 1;
+pub const KVM_S390_MEMOP_F_CHECK_ONLY: ::std::os::raw::c_uint = 1;
+pub const KVM_S390_MEMOP_F_INJECT_EXCEPTION: ::std::os::raw::c_uint = 2;
+pub const KVM_MP_STATE_RUNNABLE: ::std::os::raw::c_uint = 0;
+pub const KVM_MP_STATE_UNINITIALIZED: ::std::os::raw::c_uint = 1;
+pub const KVM_MP_STATE_INIT_RECEIVED: ::std::os::raw::c_uint = 2;
+pub const KVM_MP_STATE_HALTED: ::std::os::raw::c_uint = 3;
+pub const KVM_MP_STATE_SIPI_RECEIVED: ::std::os::raw::c_uint = 4;
+pub const KVM_MP_STATE_STOPPED: ::std::os::raw::c_uint = 5;
+pub const KVM_MP_STATE_CHECK_STOP: ::std::os::raw::c_uint = 6;
+pub const KVM_MP_STATE_OPERATING: ::std::os::raw::c_uint = 7;
+pub const KVM_MP_STATE_LOAD: ::std::os::raw::c_uint = 8;
+pub const KVM_S390_SIGP_STOP: ::std::os::raw::c_uint = 4294836224;
+pub const KVM_S390_PROGRAM_INT: ::std::os::raw::c_uint = 4294836225;
+pub const KVM_S390_SIGP_SET_PREFIX: ::std::os::raw::c_uint = 4294836226;
+pub const KVM_S390_RESTART: ::std::os::raw::c_uint = 4294836227;
+pub const KVM_S390_INT_PFAULT_INIT: ::std::os::raw::c_uint = 4294836228;
+pub const KVM_S390_INT_PFAULT_DONE: ::std::os::raw::c_uint = 4294836229;
+pub const KVM_S390_MCHK: ::std::os::raw::c_uint = 4294840320;
+pub const KVM_S390_INT_CLOCK_COMP: ::std::os::raw::c_uint = 4294905860;
+pub const KVM_S390_INT_CPU_TIMER: ::std::os::raw::c_uint = 4294905861;
+pub const KVM_S390_INT_VIRTIO: ::std::os::raw::c_uint = 4294911491;
+pub const KVM_S390_INT_SERVICE: ::std::os::raw::c_uint = 4294910977;
+pub const KVM_S390_INT_EMERGENCY: ::std::os::raw::c_uint = 4294906369;
+pub const KVM_S390_INT_EXTERNAL_CALL: ::std::os::raw::c_uint = 4294906370;
+pub const KVM_S390_INT_IO_MIN: ::std::os::raw::c_uint = 0;
+pub const KVM_S390_INT_IO_MAX: ::std::os::raw::c_uint = 4294836223;
+pub const KVM_S390_INT_IO_AI_MASK: ::std::os::raw::c_uint = 67108864;
+pub const KVM_S390_STOP_FLAG_STORE_STATUS: ::std::os::raw::c_uint = 1;
+pub const KVM_GUESTDBG_ENABLE: ::std::os::raw::c_uint = 1;
+pub const KVM_GUESTDBG_SINGLESTEP: ::std::os::raw::c_uint = 2;
+pub const KVM_PPC_PAGE_SIZES_MAX_SZ: ::std::os::raw::c_uint = 8;
+pub const KVM_PPC_PAGE_SIZES_REAL: ::std::os::raw::c_uint = 1;
+pub const KVM_PPC_1T_SEGMENTS: ::std::os::raw::c_uint = 2;
+pub const KVM_PPC_PVINFO_FLAGS_EV_IDLE: ::std::os::raw::c_uint = 1;
+pub const KVMIO: ::std::os::raw::c_uint = 174;
+pub const KVM_VM_S390_UCONTROL: ::std::os::raw::c_uint = 1;
+pub const KVM_VM_PPC_HV: ::std::os::raw::c_uint = 1;
+pub const KVM_VM_PPC_PR: ::std::os::raw::c_uint = 2;
+pub const KVM_S390_SIE_PAGE_OFFSET: ::std::os::raw::c_uint = 1;
+pub const KVM_CAP_IRQCHIP: ::std::os::raw::c_uint = 0;
+pub const KVM_CAP_HLT: ::std::os::raw::c_uint = 1;
+pub const KVM_CAP_MMU_SHADOW_CACHE_CONTROL: ::std::os::raw::c_uint = 2;
+pub const KVM_CAP_USER_MEMORY: ::std::os::raw::c_uint = 3;
+pub const KVM_CAP_SET_TSS_ADDR: ::std::os::raw::c_uint = 4;
+pub const KVM_CAP_VAPIC: ::std::os::raw::c_uint = 6;
+pub const KVM_CAP_EXT_CPUID: ::std::os::raw::c_uint = 7;
+pub const KVM_CAP_CLOCKSOURCE: ::std::os::raw::c_uint = 8;
+pub const KVM_CAP_NR_VCPUS: ::std::os::raw::c_uint = 9;
+pub const KVM_CAP_NR_MEMSLOTS: ::std::os::raw::c_uint = 10;
+pub const KVM_CAP_PIT: ::std::os::raw::c_uint = 11;
+pub const KVM_CAP_NOP_IO_DELAY: ::std::os::raw::c_uint = 12;
+pub const KVM_CAP_PV_MMU: ::std::os::raw::c_uint = 13;
+pub const KVM_CAP_MP_STATE: ::std::os::raw::c_uint = 14;
+pub const KVM_CAP_COALESCED_MMIO: ::std::os::raw::c_uint = 15;
+pub const KVM_CAP_SYNC_MMU: ::std::os::raw::c_uint = 16;
+pub const KVM_CAP_IOMMU: ::std::os::raw::c_uint = 18;
+pub const KVM_CAP_DESTROY_MEMORY_REGION_WORKS: ::std::os::raw::c_uint = 21;
+pub const KVM_CAP_USER_NMI: ::std::os::raw::c_uint = 22;
+pub const KVM_CAP_SET_GUEST_DEBUG: ::std::os::raw::c_uint = 23;
+pub const KVM_CAP_IRQ_ROUTING: ::std::os::raw::c_uint = 25;
+pub const KVM_CAP_IRQ_INJECT_STATUS: ::std::os::raw::c_uint = 26;
+pub const KVM_CAP_ASSIGN_DEV_IRQ: ::std::os::raw::c_uint = 29;
+pub const KVM_CAP_JOIN_MEMORY_REGIONS_WORKS: ::std::os::raw::c_uint = 30;
+pub const KVM_CAP_IRQFD: ::std::os::raw::c_uint = 32;
+pub const KVM_CAP_SET_BOOT_CPU_ID: ::std::os::raw::c_uint = 34;
+pub const KVM_CAP_IOEVENTFD: ::std::os::raw::c_uint = 36;
+pub const KVM_CAP_SET_IDENTITY_MAP_ADDR: ::std::os::raw::c_uint = 37;
+pub const KVM_CAP_ADJUST_CLOCK: ::std::os::raw::c_uint = 39;
+pub const KVM_CAP_INTERNAL_ERROR_DATA: ::std::os::raw::c_uint = 40;
+pub const KVM_CAP_S390_PSW: ::std::os::raw::c_uint = 42;
+pub const KVM_CAP_PPC_SEGSTATE: ::std::os::raw::c_uint = 43;
+pub const KVM_CAP_HYPERV: ::std::os::raw::c_uint = 44;
+pub const KVM_CAP_HYPERV_VAPIC: ::std::os::raw::c_uint = 45;
+pub const KVM_CAP_HYPERV_SPIN: ::std::os::raw::c_uint = 46;
+pub const KVM_CAP_PCI_SEGMENT: ::std::os::raw::c_uint = 47;
+pub const KVM_CAP_PPC_PAIRED_SINGLES: ::std::os::raw::c_uint = 48;
+pub const KVM_CAP_INTR_SHADOW: ::std::os::raw::c_uint = 49;
+pub const KVM_CAP_X86_ROBUST_SINGLESTEP: ::std::os::raw::c_uint = 51;
+pub const KVM_CAP_PPC_OSI: ::std::os::raw::c_uint = 52;
+pub const KVM_CAP_PPC_UNSET_IRQ: ::std::os::raw::c_uint = 53;
+pub const KVM_CAP_ENABLE_CAP: ::std::os::raw::c_uint = 54;
+pub const KVM_CAP_PPC_GET_PVINFO: ::std::os::raw::c_uint = 57;
+pub const KVM_CAP_PPC_IRQ_LEVEL: ::std::os::raw::c_uint = 58;
+pub const KVM_CAP_ASYNC_PF: ::std::os::raw::c_uint = 59;
+pub const KVM_CAP_TSC_CONTROL: ::std::os::raw::c_uint = 60;
+pub const KVM_CAP_GET_TSC_KHZ: ::std::os::raw::c_uint = 61;
+pub const KVM_CAP_PPC_BOOKE_SREGS: ::std::os::raw::c_uint = 62;
+pub const KVM_CAP_SPAPR_TCE: ::std::os::raw::c_uint = 63;
+pub const KVM_CAP_PPC_SMT: ::std::os::raw::c_uint = 64;
+pub const KVM_CAP_PPC_RMA: ::std::os::raw::c_uint = 65;
+pub const KVM_CAP_MAX_VCPUS: ::std::os::raw::c_uint = 66;
+pub const KVM_CAP_PPC_HIOR: ::std::os::raw::c_uint = 67;
+pub const KVM_CAP_PPC_PAPR: ::std::os::raw::c_uint = 68;
+pub const KVM_CAP_SW_TLB: ::std::os::raw::c_uint = 69;
+pub const KVM_CAP_ONE_REG: ::std::os::raw::c_uint = 70;
+pub const KVM_CAP_S390_GMAP: ::std::os::raw::c_uint = 71;
+pub const KVM_CAP_TSC_DEADLINE_TIMER: ::std::os::raw::c_uint = 72;
+pub const KVM_CAP_S390_UCONTROL: ::std::os::raw::c_uint = 73;
+pub const KVM_CAP_SYNC_REGS: ::std::os::raw::c_uint = 74;
+pub const KVM_CAP_PCI_2_3: ::std::os::raw::c_uint = 75;
+pub const KVM_CAP_KVMCLOCK_CTRL: ::std::os::raw::c_uint = 76;
+pub const KVM_CAP_SIGNAL_MSI: ::std::os::raw::c_uint = 77;
+pub const KVM_CAP_PPC_GET_SMMU_INFO: ::std::os::raw::c_uint = 78;
+pub const KVM_CAP_S390_COW: ::std::os::raw::c_uint = 79;
+pub const KVM_CAP_PPC_ALLOC_HTAB: ::std::os::raw::c_uint = 80;
+pub const KVM_CAP_READONLY_MEM: ::std::os::raw::c_uint = 81;
+pub const KVM_CAP_IRQFD_RESAMPLE: ::std::os::raw::c_uint = 82;
+pub const KVM_CAP_PPC_BOOKE_WATCHDOG: ::std::os::raw::c_uint = 83;
+pub const KVM_CAP_PPC_HTAB_FD: ::std::os::raw::c_uint = 84;
+pub const KVM_CAP_S390_CSS_SUPPORT: ::std::os::raw::c_uint = 85;
+pub const KVM_CAP_PPC_EPR: ::std::os::raw::c_uint = 86;
+pub const KVM_CAP_ARM_PSCI: ::std::os::raw::c_uint = 87;
+pub const KVM_CAP_ARM_SET_DEVICE_ADDR: ::std::os::raw::c_uint = 88;
+pub const KVM_CAP_DEVICE_CTRL: ::std::os::raw::c_uint = 89;
+pub const KVM_CAP_IRQ_MPIC: ::std::os::raw::c_uint = 90;
+pub const KVM_CAP_PPC_RTAS: ::std::os::raw::c_uint = 91;
+pub const KVM_CAP_IRQ_XICS: ::std::os::raw::c_uint = 92;
+pub const KVM_CAP_ARM_EL1_32BIT: ::std::os::raw::c_uint = 93;
+pub const KVM_CAP_SPAPR_MULTITCE: ::std::os::raw::c_uint = 94;
+pub const KVM_CAP_EXT_EMUL_CPUID: ::std::os::raw::c_uint = 95;
+pub const KVM_CAP_HYPERV_TIME: ::std::os::raw::c_uint = 96;
+pub const KVM_CAP_IOAPIC_POLARITY_IGNORED: ::std::os::raw::c_uint = 97;
+pub const KVM_CAP_ENABLE_CAP_VM: ::std::os::raw::c_uint = 98;
+pub const KVM_CAP_S390_IRQCHIP: ::std::os::raw::c_uint = 99;
+pub const KVM_CAP_IOEVENTFD_NO_LENGTH: ::std::os::raw::c_uint = 100;
+pub const KVM_CAP_VM_ATTRIBUTES: ::std::os::raw::c_uint = 101;
+pub const KVM_CAP_ARM_PSCI_0_2: ::std::os::raw::c_uint = 102;
+pub const KVM_CAP_PPC_FIXUP_HCALL: ::std::os::raw::c_uint = 103;
+pub const KVM_CAP_PPC_ENABLE_HCALL: ::std::os::raw::c_uint = 104;
+pub const KVM_CAP_CHECK_EXTENSION_VM: ::std::os::raw::c_uint = 105;
+pub const KVM_CAP_S390_USER_SIGP: ::std::os::raw::c_uint = 106;
+pub const KVM_CAP_S390_VECTOR_REGISTERS: ::std::os::raw::c_uint = 107;
+pub const KVM_CAP_S390_MEM_OP: ::std::os::raw::c_uint = 108;
+pub const KVM_CAP_S390_USER_STSI: ::std::os::raw::c_uint = 109;
+pub const KVM_CAP_S390_SKEYS: ::std::os::raw::c_uint = 110;
+pub const KVM_CAP_MIPS_FPU: ::std::os::raw::c_uint = 111;
+pub const KVM_CAP_MIPS_MSA: ::std::os::raw::c_uint = 112;
+pub const KVM_CAP_S390_INJECT_IRQ: ::std::os::raw::c_uint = 113;
+pub const KVM_CAP_S390_IRQ_STATE: ::std::os::raw::c_uint = 114;
+pub const KVM_CAP_PPC_HWRNG: ::std::os::raw::c_uint = 115;
+pub const KVM_CAP_DISABLE_QUIRKS: ::std::os::raw::c_uint = 116;
+pub const KVM_CAP_X86_SMM: ::std::os::raw::c_uint = 117;
+pub const KVM_CAP_MULTI_ADDRESS_SPACE: ::std::os::raw::c_uint = 118;
+pub const KVM_CAP_GUEST_DEBUG_HW_BPS: ::std::os::raw::c_uint = 119;
+pub const KVM_CAP_GUEST_DEBUG_HW_WPS: ::std::os::raw::c_uint = 120;
+pub const KVM_CAP_SPLIT_IRQCHIP: ::std::os::raw::c_uint = 121;
+pub const KVM_CAP_IOEVENTFD_ANY_LENGTH: ::std::os::raw::c_uint = 122;
+pub const KVM_IRQ_ROUTING_IRQCHIP: ::std::os::raw::c_uint = 1;
+pub const KVM_IRQ_ROUTING_MSI: ::std::os::raw::c_uint = 2;
+pub const KVM_IRQ_ROUTING_S390_ADAPTER: ::std::os::raw::c_uint = 3;
+pub const KVM_IRQFD_FLAG_DEASSIGN: ::std::os::raw::c_uint = 1;
+pub const KVM_IRQFD_FLAG_RESAMPLE: ::std::os::raw::c_uint = 2;
+pub const KVM_MMU_FSL_BOOKE_NOHV: ::std::os::raw::c_uint = 0;
+pub const KVM_MMU_FSL_BOOKE_HV: ::std::os::raw::c_uint = 1;
+pub const KVM_REG_ARCH_MASK: ::std::os::raw::c_longlong = -72057594037927936;
+pub const KVM_REG_GENERIC: ::std::os::raw::c_uint = 0;
+pub const KVM_REG_PPC: ::std::os::raw::c_ulonglong = 1152921504606846976;
+pub const KVM_REG_X86: ::std::os::raw::c_ulonglong = 2305843009213693952;
+pub const KVM_REG_IA64: ::std::os::raw::c_ulonglong = 3458764513820540928;
+pub const KVM_REG_ARM: ::std::os::raw::c_ulonglong = 4611686018427387904;
+pub const KVM_REG_S390: ::std::os::raw::c_ulonglong = 5764607523034234880;
+pub const KVM_REG_ARM64: ::std::os::raw::c_ulonglong = 6917529027641081856;
+pub const KVM_REG_MIPS: ::std::os::raw::c_ulonglong = 8070450532247928832;
+pub const KVM_REG_SIZE_SHIFT: ::std::os::raw::c_uint = 52;
+pub const KVM_REG_SIZE_MASK: ::std::os::raw::c_ulonglong = 67553994410557440;
+pub const KVM_REG_SIZE_U8: ::std::os::raw::c_uint = 0;
+pub const KVM_REG_SIZE_U16: ::std::os::raw::c_ulonglong = 4503599627370496;
+pub const KVM_REG_SIZE_U32: ::std::os::raw::c_ulonglong = 9007199254740992;
+pub const KVM_REG_SIZE_U64: ::std::os::raw::c_ulonglong = 13510798882111488;
+pub const KVM_REG_SIZE_U128: ::std::os::raw::c_ulonglong = 18014398509481984;
+pub const KVM_REG_SIZE_U256: ::std::os::raw::c_ulonglong = 22517998136852480;
+pub const KVM_REG_SIZE_U512: ::std::os::raw::c_ulonglong = 27021597764222976;
+pub const KVM_REG_SIZE_U1024: ::std::os::raw::c_ulonglong = 31525197391593472;
+pub const KVM_CREATE_DEVICE_TEST: ::std::os::raw::c_uint = 1;
+pub const KVM_DEV_VFIO_GROUP: ::std::os::raw::c_uint = 1;
+pub const KVM_DEV_VFIO_GROUP_ADD: ::std::os::raw::c_uint = 1;
+pub const KVM_DEV_VFIO_GROUP_DEL: ::std::os::raw::c_uint = 2;
+pub const KVM_S390_STORE_STATUS_NOADDR: ::std::os::raw::c_int = -1;
+pub const KVM_S390_STORE_STATUS_PREFIXED: ::std::os::raw::c_int = -2;
+pub const KVM_DEV_ASSIGN_ENABLE_IOMMU: ::std::os::raw::c_uint = 1;
+pub const KVM_DEV_ASSIGN_PCI_2_3: ::std::os::raw::c_uint = 2;
+pub const KVM_DEV_ASSIGN_MASK_INTX: ::std::os::raw::c_uint = 4;
+pub const KVM_DEV_IRQ_HOST_INTX: ::std::os::raw::c_uint = 1;
+pub const KVM_DEV_IRQ_HOST_MSI: ::std::os::raw::c_uint = 2;
+pub const KVM_DEV_IRQ_HOST_MSIX: ::std::os::raw::c_uint = 4;
+pub const KVM_DEV_IRQ_GUEST_INTX: ::std::os::raw::c_uint = 256;
+pub const KVM_DEV_IRQ_GUEST_MSI: ::std::os::raw::c_uint = 512;
+pub const KVM_DEV_IRQ_GUEST_MSIX: ::std::os::raw::c_uint = 1024;
+pub const KVM_DEV_IRQ_HOST_MASK: ::std::os::raw::c_uint = 255;
+pub const KVM_DEV_IRQ_GUEST_MASK: ::std::os::raw::c_uint = 65280;
+pub const KVM_MAX_MSIX_PER_DEV: ::std::os::raw::c_uint = 256;
+pub type __s8 = ::std::os::raw::c_schar;
+pub type __u8 = ::std::os::raw::c_uchar;
+pub type __s16 = ::std::os::raw::c_short;
+pub type __u16 = ::std::os::raw::c_ushort;
+pub type __s32 = ::std::os::raw::c_int;
+pub type __u32 = ::std::os::raw::c_uint;
+pub type __s64 = ::std::os::raw::c_longlong;
+pub type __u64 = ::std::os::raw::c_ulonglong;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct __kernel_fd_set {
+    pub fds_bits: [::std::os::raw::c_ulong; 16usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fd_set() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fd_set>(),
+        128usize,
+        concat!("Size of: ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fd_set>(),
+        8usize,
+        concat!("Alignment of ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<__kernel_fd_set>())).fds_bits as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__kernel_fd_set),
+            "::",
+            stringify!(fds_bits)
+        )
+    );
+}
+pub type __kernel_sighandler_t =
+    ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
+pub type __kernel_key_t = ::std::os::raw::c_int;
+pub type __kernel_mqd_t = ::std::os::raw::c_int;
+pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
+pub type __kernel_long_t = ::std::os::raw::c_long;
+pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
+pub type __kernel_ino_t = __kernel_ulong_t;
+pub type __kernel_mode_t = ::std::os::raw::c_uint;
+pub type __kernel_pid_t = ::std::os::raw::c_int;
+pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
+pub type __kernel_uid_t = ::std::os::raw::c_uint;
+pub type __kernel_gid_t = ::std::os::raw::c_uint;
+pub type __kernel_suseconds_t = __kernel_long_t;
+pub type __kernel_daddr_t = ::std::os::raw::c_int;
+pub type __kernel_uid32_t = ::std::os::raw::c_uint;
+pub type __kernel_gid32_t = ::std::os::raw::c_uint;
+pub type __kernel_old_dev_t = ::std::os::raw::c_uint;
+pub type __kernel_size_t = __kernel_ulong_t;
+pub type __kernel_ssize_t = __kernel_long_t;
+pub type __kernel_ptrdiff_t = __kernel_long_t;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct __kernel_fsid_t {
+    pub val: [::std::os::raw::c_int; 2usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fsid_t() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fsid_t>(),
+        8usize,
+        concat!("Size of: ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fsid_t>(),
+        4usize,
+        concat!("Alignment of ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<__kernel_fsid_t>())).val as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__kernel_fsid_t),
+            "::",
+            stringify!(val)
+        )
+    );
+}
+pub type __kernel_off_t = __kernel_long_t;
+pub type __kernel_loff_t = ::std::os::raw::c_longlong;
+pub type __kernel_time_t = __kernel_long_t;
+pub type __kernel_clock_t = __kernel_long_t;
+pub type __kernel_timer_t = ::std::os::raw::c_int;
+pub type __kernel_clockid_t = ::std::os::raw::c_int;
+pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
+pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
+pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
+pub type __le16 = __u16;
+pub type __be16 = __u16;
+pub type __le32 = __u32;
+pub type __be32 = __u32;
+pub type __le64 = __u64;
+pub type __be64 = __u64;
+pub type __sum16 = __u16;
+pub type __wsum = __u32;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct user_pt_regs {
+    pub regs: [__u64; 31usize],
+    pub sp: __u64,
+    pub pc: __u64,
+    pub pstate: __u64,
+}
+#[test]
+fn bindgen_test_layout_user_pt_regs() {
+    assert_eq!(
+        ::std::mem::size_of::<user_pt_regs>(),
+        272usize,
+        concat!("Size of: ", stringify!(user_pt_regs))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<user_pt_regs>(),
+        8usize,
+        concat!("Alignment of ", stringify!(user_pt_regs))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<user_pt_regs>())).regs as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(user_pt_regs),
+            "::",
+            stringify!(regs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<user_pt_regs>())).sp as *const _ as usize },
+        248usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(user_pt_regs),
+            "::",
+            stringify!(sp)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<user_pt_regs>())).pc as *const _ as usize },
+        256usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(user_pt_regs),
+            "::",
+            stringify!(pc)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<user_pt_regs>())).pstate as *const _ as usize },
+        264usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(user_pt_regs),
+            "::",
+            stringify!(pstate)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct user_fpsimd_state {
+    pub vregs: [__uint128_t; 32usize],
+    pub fpsr: __u32,
+    pub fpcr: __u32,
+    pub __bindgen_padding_0: u64,
+}
+#[test]
+fn bindgen_test_layout_user_fpsimd_state() {
+    assert_eq!(
+        ::std::mem::size_of::<user_fpsimd_state>(),
+        528usize,
+        concat!("Size of: ", stringify!(user_fpsimd_state))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<user_fpsimd_state>())).vregs as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(user_fpsimd_state),
+            "::",
+            stringify!(vregs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<user_fpsimd_state>())).fpsr as *const _ as usize },
+        512usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(user_fpsimd_state),
+            "::",
+            stringify!(fpsr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<user_fpsimd_state>())).fpcr as *const _ as usize },
+        516usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(user_fpsimd_state),
+            "::",
+            stringify!(fpcr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct user_hwdebug_state {
+    pub dbg_info: __u32,
+    pub pad: __u32,
+    pub dbg_regs: [user_hwdebug_state__bindgen_ty_1; 16usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct user_hwdebug_state__bindgen_ty_1 {
+    pub addr: __u64,
+    pub ctrl: __u32,
+    pub pad: __u32,
+}
+#[test]
+fn bindgen_test_layout_user_hwdebug_state__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<user_hwdebug_state__bindgen_ty_1>(),
+        16usize,
+        concat!("Size of: ", stringify!(user_hwdebug_state__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<user_hwdebug_state__bindgen_ty_1>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(user_hwdebug_state__bindgen_ty_1)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<user_hwdebug_state__bindgen_ty_1>())).addr as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(user_hwdebug_state__bindgen_ty_1),
+            "::",
+            stringify!(addr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<user_hwdebug_state__bindgen_ty_1>())).ctrl as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(user_hwdebug_state__bindgen_ty_1),
+            "::",
+            stringify!(ctrl)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<user_hwdebug_state__bindgen_ty_1>())).pad as *const _ as usize
+        },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(user_hwdebug_state__bindgen_ty_1),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[test]
+fn bindgen_test_layout_user_hwdebug_state() {
+    assert_eq!(
+        ::std::mem::size_of::<user_hwdebug_state>(),
+        264usize,
+        concat!("Size of: ", stringify!(user_hwdebug_state))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<user_hwdebug_state>(),
+        8usize,
+        concat!("Alignment of ", stringify!(user_hwdebug_state))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<user_hwdebug_state>())).dbg_info as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(user_hwdebug_state),
+            "::",
+            stringify!(dbg_info)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<user_hwdebug_state>())).pad as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(user_hwdebug_state),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<user_hwdebug_state>())).dbg_regs as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(user_hwdebug_state),
+            "::",
+            stringify!(dbg_regs)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_regs {
+    pub regs: user_pt_regs,
+    pub sp_el1: __u64,
+    pub elr_el1: __u64,
+    pub spsr: [__u64; 5usize],
+    pub __bindgen_padding_0: u64,
+    pub fp_regs: user_fpsimd_state,
+}
+#[test]
+fn bindgen_test_layout_kvm_regs() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_regs>(),
+        864usize,
+        concat!("Size of: ", stringify!(kvm_regs))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).regs as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(regs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).sp_el1 as *const _ as usize },
+        272usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(sp_el1)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).elr_el1 as *const _ as usize },
+        280usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(elr_el1)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).spsr as *const _ as usize },
+        288usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(spsr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).fp_regs as *const _ as usize },
+        336usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(fp_regs)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_vcpu_init {
+    pub target: __u32,
+    pub features: [__u32; 7usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_vcpu_init() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_vcpu_init>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_vcpu_init))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_vcpu_init>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_vcpu_init))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_vcpu_init>())).target as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_init),
+            "::",
+            stringify!(target)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_vcpu_init>())).features as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_init),
+            "::",
+            stringify!(features)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sregs {}
+#[test]
+fn bindgen_test_layout_kvm_sregs() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_sregs>(),
+        0usize,
+        concat!("Size of: ", stringify!(kvm_sregs))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_sregs>(),
+        1usize,
+        concat!("Alignment of ", stringify!(kvm_sregs))
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_fpu {}
+#[test]
+fn bindgen_test_layout_kvm_fpu() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_fpu>(),
+        0usize,
+        concat!("Size of: ", stringify!(kvm_fpu))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_fpu>(),
+        1usize,
+        concat!("Alignment of ", stringify!(kvm_fpu))
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_guest_debug_arch {
+    pub dbg_bcr: [__u64; 16usize],
+    pub dbg_bvr: [__u64; 16usize],
+    pub dbg_wcr: [__u64; 16usize],
+    pub dbg_wvr: [__u64; 16usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_guest_debug_arch() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_guest_debug_arch>(),
+        512usize,
+        concat!("Size of: ", stringify!(kvm_guest_debug_arch))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_guest_debug_arch>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_guest_debug_arch))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_guest_debug_arch>())).dbg_bcr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_guest_debug_arch),
+            "::",
+            stringify!(dbg_bcr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_guest_debug_arch>())).dbg_bvr as *const _ as usize },
+        128usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_guest_debug_arch),
+            "::",
+            stringify!(dbg_bvr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_guest_debug_arch>())).dbg_wcr as *const _ as usize },
+        256usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_guest_debug_arch),
+            "::",
+            stringify!(dbg_wcr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_guest_debug_arch>())).dbg_wvr as *const _ as usize },
+        384usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_guest_debug_arch),
+            "::",
+            stringify!(dbg_wvr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_debug_exit_arch {
+    pub hsr: __u32,
+    pub far: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_debug_exit_arch() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_debug_exit_arch>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_debug_exit_arch))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_debug_exit_arch>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_debug_exit_arch))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_exit_arch>())).hsr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_exit_arch),
+            "::",
+            stringify!(hsr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_exit_arch>())).far as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_exit_arch),
+            "::",
+            stringify!(far)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sync_regs {}
+#[test]
+fn bindgen_test_layout_kvm_sync_regs() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_sync_regs>(),
+        0usize,
+        concat!("Size of: ", stringify!(kvm_sync_regs))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_sync_regs>(),
+        1usize,
+        concat!("Alignment of ", stringify!(kvm_sync_regs))
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_arch_memory_slot {}
+#[test]
+fn bindgen_test_layout_kvm_arch_memory_slot() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_arch_memory_slot>(),
+        0usize,
+        concat!("Size of: ", stringify!(kvm_arch_memory_slot))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_arch_memory_slot>(),
+        1usize,
+        concat!("Alignment of ", stringify!(kvm_arch_memory_slot))
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_user_trace_setup {
+    pub buf_size: __u32,
+    pub buf_nr: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_user_trace_setup() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_user_trace_setup>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_user_trace_setup))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_user_trace_setup>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_user_trace_setup))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_user_trace_setup>())).buf_size as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_user_trace_setup),
+            "::",
+            stringify!(buf_size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_user_trace_setup>())).buf_nr as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_user_trace_setup),
+            "::",
+            stringify!(buf_nr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_breakpoint {
+    pub enabled: __u32,
+    pub padding: __u32,
+    pub address: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_breakpoint() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_breakpoint>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_breakpoint))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_breakpoint>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_breakpoint))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_breakpoint>())).enabled as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_breakpoint),
+            "::",
+            stringify!(enabled)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_breakpoint>())).padding as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_breakpoint),
+            "::",
+            stringify!(padding)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_breakpoint>())).address as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_breakpoint),
+            "::",
+            stringify!(address)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_debug_guest {
+    pub enabled: __u32,
+    pub pad: __u32,
+    pub breakpoints: [kvm_breakpoint; 4usize],
+    pub singlestep: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_debug_guest() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_debug_guest>(),
+        80usize,
+        concat!("Size of: ", stringify!(kvm_debug_guest))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_debug_guest>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_debug_guest))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_guest>())).enabled as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_guest),
+            "::",
+            stringify!(enabled)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_guest>())).pad as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_guest),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_guest>())).breakpoints as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_guest),
+            "::",
+            stringify!(breakpoints)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_guest>())).singlestep as *const _ as usize },
+        72usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_guest),
+            "::",
+            stringify!(singlestep)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_memory_region {
+    pub slot: __u32,
+    pub flags: __u32,
+    pub guest_phys_addr: __u64,
+    pub memory_size: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_memory_region() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_memory_region>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_memory_region))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_memory_region>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_memory_region))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_memory_region>())).slot as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_memory_region),
+            "::",
+            stringify!(slot)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_memory_region>())).flags as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_memory_region),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_memory_region>())).guest_phys_addr as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_memory_region),
+            "::",
+            stringify!(guest_phys_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_memory_region>())).memory_size as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_memory_region),
+            "::",
+            stringify!(memory_size)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_userspace_memory_region {
+    pub slot: __u32,
+    pub flags: __u32,
+    pub guest_phys_addr: __u64,
+    pub memory_size: __u64,
+    pub userspace_addr: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_userspace_memory_region() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_userspace_memory_region>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_userspace_memory_region))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_userspace_memory_region>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_userspace_memory_region))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_userspace_memory_region>())).slot as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_userspace_memory_region),
+            "::",
+            stringify!(slot)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_userspace_memory_region>())).flags as *const _ as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_userspace_memory_region),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_userspace_memory_region>())).guest_phys_addr as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_userspace_memory_region),
+            "::",
+            stringify!(guest_phys_addr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_userspace_memory_region>())).memory_size as *const _ as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_userspace_memory_region),
+            "::",
+            stringify!(memory_size)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_userspace_memory_region>())).userspace_addr as *const _
+                as usize
+        },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_userspace_memory_region),
+            "::",
+            stringify!(userspace_addr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_irq_level {
+    pub __bindgen_anon_1: kvm_irq_level__bindgen_ty_1,
+    pub level: __u32,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_irq_level__bindgen_ty_1 {
+    pub irq: __u32,
+    pub status: __s32,
+    _bindgen_union_align: u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_level__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_level__bindgen_ty_1>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_irq_level__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_level__bindgen_ty_1>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_irq_level__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_level__bindgen_ty_1>())).irq as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_level__bindgen_ty_1),
+            "::",
+            stringify!(irq)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_level__bindgen_ty_1>())).status as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_level__bindgen_ty_1),
+            "::",
+            stringify!(status)
+        )
+    );
+}
+impl Default for kvm_irq_level__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_level() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_level>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_irq_level))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_level>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_irq_level))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_level>())).level as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_level),
+            "::",
+            stringify!(level)
+        )
+    );
+}
+impl Default for kvm_irq_level {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_irqchip {
+    pub chip_id: __u32,
+    pub pad: __u32,
+    pub chip: kvm_irqchip__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_irqchip__bindgen_ty_1 {
+    pub dummy: [::std::os::raw::c_char; 512usize],
+    _bindgen_union_align: [u8; 512usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_irqchip__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irqchip__bindgen_ty_1>(),
+        512usize,
+        concat!("Size of: ", stringify!(kvm_irqchip__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irqchip__bindgen_ty_1>(),
+        1usize,
+        concat!("Alignment of ", stringify!(kvm_irqchip__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqchip__bindgen_ty_1>())).dummy as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqchip__bindgen_ty_1),
+            "::",
+            stringify!(dummy)
+        )
+    );
+}
+impl Default for kvm_irqchip__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_irqchip() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irqchip>(),
+        520usize,
+        concat!("Size of: ", stringify!(kvm_irqchip))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irqchip>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_irqchip))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqchip>())).chip_id as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqchip),
+            "::",
+            stringify!(chip_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqchip>())).pad as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqchip),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqchip>())).chip as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqchip),
+            "::",
+            stringify!(chip)
+        )
+    );
+}
+impl Default for kvm_irqchip {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_pit_config {
+    pub flags: __u32,
+    pub pad: [__u32; 15usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_pit_config() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_pit_config>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_pit_config))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_pit_config>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_pit_config))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pit_config>())).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_config),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pit_config>())).pad as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_config),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_skeys {
+    pub start_gfn: __u64,
+    pub count: __u64,
+    pub skeydata_addr: __u64,
+    pub flags: __u32,
+    pub reserved: [__u32; 9usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_skeys() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_skeys>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_s390_skeys))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_skeys>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_skeys))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_skeys>())).start_gfn as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_skeys),
+            "::",
+            stringify!(start_gfn)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_skeys>())).count as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_skeys),
+            "::",
+            stringify!(count)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_skeys>())).skeydata_addr as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_skeys),
+            "::",
+            stringify!(skeydata_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_skeys>())).flags as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_skeys),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_skeys>())).reserved as *const _ as usize },
+        28usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_skeys),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_run {
+    pub request_interrupt_window: __u8,
+    pub padding1: [__u8; 7usize],
+    pub exit_reason: __u32,
+    pub ready_for_interrupt_injection: __u8,
+    pub if_flag: __u8,
+    pub flags: __u16,
+    pub cr8: __u64,
+    pub apic_base: __u64,
+    pub __bindgen_anon_1: kvm_run__bindgen_ty_1,
+    pub kvm_valid_regs: __u64,
+    pub kvm_dirty_regs: __u64,
+    pub s: kvm_run__bindgen_ty_2,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_1 {
+    pub hardware_exit_reason: __u64,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_run__bindgen_ty_1 {
+    pub hw: kvm_run__bindgen_ty_1__bindgen_ty_1,
+    pub fail_entry: kvm_run__bindgen_ty_1__bindgen_ty_2,
+    pub ex: kvm_run__bindgen_ty_1__bindgen_ty_3,
+    pub io: kvm_run__bindgen_ty_1__bindgen_ty_4,
+    pub debug: kvm_run__bindgen_ty_1__bindgen_ty_5,
+    pub mmio: kvm_run__bindgen_ty_1__bindgen_ty_6,
+    pub hypercall: kvm_run__bindgen_ty_1__bindgen_ty_7,
+    pub tpr_access: kvm_run__bindgen_ty_1__bindgen_ty_8,
+    pub s390_sieic: kvm_run__bindgen_ty_1__bindgen_ty_9,
+    pub s390_reset_flags: __u64,
+    pub s390_ucontrol: kvm_run__bindgen_ty_1__bindgen_ty_10,
+    pub dcr: kvm_run__bindgen_ty_1__bindgen_ty_11,
+    pub internal: kvm_run__bindgen_ty_1__bindgen_ty_12,
+    pub osi: kvm_run__bindgen_ty_1__bindgen_ty_13,
+    pub papr_hcall: kvm_run__bindgen_ty_1__bindgen_ty_14,
+    pub s390_tsch: kvm_run__bindgen_ty_1__bindgen_ty_15,
+    pub epr: kvm_run__bindgen_ty_1__bindgen_ty_16,
+    pub system_event: kvm_run__bindgen_ty_1__bindgen_ty_17,
+    pub s390_stsi: kvm_run__bindgen_ty_1__bindgen_ty_18,
+    pub eoi: kvm_run__bindgen_ty_1__bindgen_ty_19,
+    pub padding: [::std::os::raw::c_char; 256usize],
+    _bindgen_union_align: [u64; 32usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_1>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_1>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_1>())).hardware_exit_reason
+                as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1),
+            "::",
+            stringify!(hardware_exit_reason)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_2 {
+    pub hardware_entry_failure_reason: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_2() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_2>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_2>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_2>()))
+                .hardware_entry_failure_reason as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2),
+            "::",
+            stringify!(hardware_entry_failure_reason)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_3 {
+    pub exception: __u32,
+    pub error_code: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_3() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_3>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_3>(),
+        4usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_3>())).exception as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3),
+            "::",
+            stringify!(exception)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_3>())).error_code as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3),
+            "::",
+            stringify!(error_code)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_4 {
+    pub direction: __u8,
+    pub size: __u8,
+    pub port: __u16,
+    pub count: __u32,
+    pub data_offset: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_4() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_4>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_4>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_4>())).direction as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4),
+            "::",
+            stringify!(direction)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_4>())).size as *const _
+                as usize
+        },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4),
+            "::",
+            stringify!(size)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_4>())).port as *const _
+                as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4),
+            "::",
+            stringify!(port)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_4>())).count as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4),
+            "::",
+            stringify!(count)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_4>())).data_offset as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4),
+            "::",
+            stringify!(data_offset)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_5 {
+    pub arch: kvm_debug_exit_arch,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_5() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_5>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_5>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_5>())).arch as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5),
+            "::",
+            stringify!(arch)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_6 {
+    pub phys_addr: __u64,
+    pub data: [__u8; 8usize],
+    pub len: __u32,
+    pub is_write: __u8,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_6() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_6>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_6>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_6>())).phys_addr as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6),
+            "::",
+            stringify!(phys_addr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_6>())).data as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6),
+            "::",
+            stringify!(data)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_6>())).len as *const _ as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6),
+            "::",
+            stringify!(len)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_6>())).is_write as *const _
+                as usize
+        },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6),
+            "::",
+            stringify!(is_write)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_7 {
+    pub nr: __u64,
+    pub args: [__u64; 6usize],
+    pub ret: __u64,
+    pub longmode: __u32,
+    pub pad: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_7() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_7>(),
+        72usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_7>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_7>())).nr as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7),
+            "::",
+            stringify!(nr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_7>())).args as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7),
+            "::",
+            stringify!(args)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_7>())).ret as *const _ as usize
+        },
+        56usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7),
+            "::",
+            stringify!(ret)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_7>())).longmode as *const _
+                as usize
+        },
+        64usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7),
+            "::",
+            stringify!(longmode)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_7>())).pad as *const _ as usize
+        },
+        68usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_8 {
+    pub rip: __u64,
+    pub is_write: __u32,
+    pub pad: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_8() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_8>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_8>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_8>())).rip as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8),
+            "::",
+            stringify!(rip)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_8>())).is_write as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8),
+            "::",
+            stringify!(is_write)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_8>())).pad as *const _ as usize
+        },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_9 {
+    pub icptcode: __u8,
+    pub ipa: __u16,
+    pub ipb: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_9() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_9>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_9>(),
+        4usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_9>())).icptcode as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9),
+            "::",
+            stringify!(icptcode)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_9>())).ipa as *const _ as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9),
+            "::",
+            stringify!(ipa)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_9>())).ipb as *const _ as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9),
+            "::",
+            stringify!(ipb)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_10 {
+    pub trans_exc_code: __u64,
+    pub pgm_code: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_10() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_10>(),
+        16usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_10>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_10>())).trans_exc_code
+                as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10),
+            "::",
+            stringify!(trans_exc_code)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_10>())).pgm_code as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10),
+            "::",
+            stringify!(pgm_code)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_11 {
+    pub dcrn: __u32,
+    pub data: __u32,
+    pub is_write: __u8,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_11() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_11>(),
+        12usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_11>(),
+        4usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_11>())).dcrn as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11),
+            "::",
+            stringify!(dcrn)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_11>())).data as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11),
+            "::",
+            stringify!(data)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_11>())).is_write as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11),
+            "::",
+            stringify!(is_write)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_12 {
+    pub suberror: __u32,
+    pub ndata: __u32,
+    pub data: [__u64; 16usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_12() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_12>(),
+        136usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_12>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_12>())).suberror as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12),
+            "::",
+            stringify!(suberror)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_12>())).ndata as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12),
+            "::",
+            stringify!(ndata)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_12>())).data as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12),
+            "::",
+            stringify!(data)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_13 {
+    pub gprs: [__u64; 32usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_13() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_13>(),
+        256usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_13>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_13>())).gprs as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13),
+            "::",
+            stringify!(gprs)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_14 {
+    pub nr: __u64,
+    pub ret: __u64,
+    pub args: [__u64; 9usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_14() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_14>(),
+        88usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_14>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_14>())).nr as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14),
+            "::",
+            stringify!(nr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_14>())).ret as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14),
+            "::",
+            stringify!(ret)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_14>())).args as *const _
+                as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14),
+            "::",
+            stringify!(args)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_15 {
+    pub subchannel_id: __u16,
+    pub subchannel_nr: __u16,
+    pub io_int_parm: __u32,
+    pub io_int_word: __u32,
+    pub ipb: __u32,
+    pub dequeued: __u8,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_15() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_15>(),
+        20usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_15>(),
+        4usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_15>())).subchannel_id
+                as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15),
+            "::",
+            stringify!(subchannel_id)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_15>())).subchannel_nr
+                as *const _ as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15),
+            "::",
+            stringify!(subchannel_nr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_15>())).io_int_parm as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15),
+            "::",
+            stringify!(io_int_parm)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_15>())).io_int_word as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15),
+            "::",
+            stringify!(io_int_word)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_15>())).ipb as *const _
+                as usize
+        },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15),
+            "::",
+            stringify!(ipb)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_15>())).dequeued as *const _
+                as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15),
+            "::",
+            stringify!(dequeued)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_16 {
+    pub epr: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_16() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_16>(),
+        4usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_16>(),
+        4usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_16>())).epr as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16),
+            "::",
+            stringify!(epr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_17 {
+    pub type_: __u32,
+    pub flags: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_17() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_17>(),
+        16usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_17>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_17>())).type_ as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_17>())).flags as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17),
+            "::",
+            stringify!(flags)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_18 {
+    pub addr: __u64,
+    pub ar: __u8,
+    pub reserved: __u8,
+    pub fc: __u8,
+    pub sel1: __u8,
+    pub sel2: __u16,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_18() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_18>(),
+        16usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_18>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_18>())).addr as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18),
+            "::",
+            stringify!(addr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_18>())).ar as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18),
+            "::",
+            stringify!(ar)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_18>())).reserved as *const _
+                as usize
+        },
+        9usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18),
+            "::",
+            stringify!(reserved)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_18>())).fc as *const _ as usize
+        },
+        10usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18),
+            "::",
+            stringify!(fc)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_18>())).sel1 as *const _
+                as usize
+        },
+        11usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18),
+            "::",
+            stringify!(sel1)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_18>())).sel2 as *const _
+                as usize
+        },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18),
+            "::",
+            stringify!(sel2)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_19 {
+    pub vector: __u8,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_19() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_19>(),
+        1usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_19>(),
+        1usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_19>())).vector as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19),
+            "::",
+            stringify!(vector)
+        )
+    );
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1>(),
+        256usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).hw as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(hw)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).fail_entry as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(fail_entry)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).ex as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(ex)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).io as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(io)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).debug as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(debug)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).mmio as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(mmio)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).hypercall as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(hypercall)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).tpr_access as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(tpr_access)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).s390_sieic as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(s390_sieic)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).s390_reset_flags as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(s390_reset_flags)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).s390_ucontrol as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(s390_ucontrol)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).dcr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(dcr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).internal as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(internal)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).osi as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(osi)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).papr_hcall as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(papr_hcall)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).s390_tsch as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(s390_tsch)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).epr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(epr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).system_event as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(system_event)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).s390_stsi as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(s390_stsi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).eoi as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(eoi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).padding as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(padding)
+        )
+    );
+}
+impl Default for kvm_run__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_run__bindgen_ty_2 {
+    pub regs: kvm_sync_regs,
+    pub padding: [::std::os::raw::c_char; 2048usize],
+    _bindgen_union_align: [u8; 2048usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_2() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_2>(),
+        2048usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_2))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_2>(),
+        1usize,
+        concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_2))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_2>())).regs as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_2),
+            "::",
+            stringify!(regs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_2>())).padding as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_2),
+            "::",
+            stringify!(padding)
+        )
+    );
+}
+impl Default for kvm_run__bindgen_ty_2 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_run() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run>(),
+        2352usize,
+        concat!("Size of: ", stringify!(kvm_run))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_run))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run>())).request_interrupt_window as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(request_interrupt_window)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).padding1 as *const _ as usize },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(padding1)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).exit_reason as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(exit_reason)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run>())).ready_for_interrupt_injection as *const _ as usize
+        },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(ready_for_interrupt_injection)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).if_flag as *const _ as usize },
+        13usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(if_flag)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).flags as *const _ as usize },
+        14usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).cr8 as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(cr8)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).apic_base as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(apic_base)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).kvm_valid_regs as *const _ as usize },
+        288usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(kvm_valid_regs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).kvm_dirty_regs as *const _ as usize },
+        296usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(kvm_dirty_regs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).s as *const _ as usize },
+        304usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(s)
+        )
+    );
+}
+impl Default for kvm_run {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_coalesced_mmio_zone {
+    pub addr: __u64,
+    pub size: __u32,
+    pub pad: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_coalesced_mmio_zone() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_coalesced_mmio_zone>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_coalesced_mmio_zone))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_coalesced_mmio_zone>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_coalesced_mmio_zone))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio_zone>())).addr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio_zone),
+            "::",
+            stringify!(addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio_zone>())).size as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio_zone),
+            "::",
+            stringify!(size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio_zone>())).pad as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio_zone),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_coalesced_mmio {
+    pub phys_addr: __u64,
+    pub len: __u32,
+    pub pad: __u32,
+    pub data: [__u8; 8usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_coalesced_mmio() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_coalesced_mmio>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_coalesced_mmio))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_coalesced_mmio>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_coalesced_mmio))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio>())).phys_addr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio),
+            "::",
+            stringify!(phys_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio>())).len as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio),
+            "::",
+            stringify!(len)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio>())).pad as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio>())).data as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio),
+            "::",
+            stringify!(data)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct kvm_coalesced_mmio_ring {
+    pub first: __u32,
+    pub last: __u32,
+    pub coalesced_mmio: __IncompleteArrayField<kvm_coalesced_mmio>,
+    // Manually added to work around rust bindgen issue 684
+    __force_alignment: [u64; 0],
+}
+#[test]
+fn bindgen_test_layout_kvm_coalesced_mmio_ring() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_coalesced_mmio_ring>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_coalesced_mmio_ring))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_coalesced_mmio_ring>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_coalesced_mmio_ring))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio_ring>())).first as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio_ring),
+            "::",
+            stringify!(first)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio_ring>())).last as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio_ring),
+            "::",
+            stringify!(last)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_coalesced_mmio_ring>())).coalesced_mmio as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio_ring),
+            "::",
+            stringify!(coalesced_mmio)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_translation {
+    pub linear_address: __u64,
+    pub physical_address: __u64,
+    pub valid: __u8,
+    pub writeable: __u8,
+    pub usermode: __u8,
+    pub pad: [__u8; 5usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_translation() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_translation>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_translation))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_translation>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_translation))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_translation>())).linear_address as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_translation),
+            "::",
+            stringify!(linear_address)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_translation>())).physical_address as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_translation),
+            "::",
+            stringify!(physical_address)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_translation>())).valid as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_translation),
+            "::",
+            stringify!(valid)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_translation>())).writeable as *const _ as usize },
+        17usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_translation),
+            "::",
+            stringify!(writeable)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_translation>())).usermode as *const _ as usize },
+        18usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_translation),
+            "::",
+            stringify!(usermode)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_translation>())).pad as *const _ as usize },
+        19usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_translation),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_mem_op {
+    pub gaddr: __u64,
+    pub flags: __u64,
+    pub size: __u32,
+    pub op: __u32,
+    pub buf: __u64,
+    pub ar: __u8,
+    pub reserved: [__u8; 31usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_mem_op() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_mem_op>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_s390_mem_op))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_mem_op>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_mem_op))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mem_op>())).gaddr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mem_op),
+            "::",
+            stringify!(gaddr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mem_op>())).flags as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mem_op),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mem_op>())).size as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mem_op),
+            "::",
+            stringify!(size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mem_op>())).op as *const _ as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mem_op),
+            "::",
+            stringify!(op)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mem_op>())).buf as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mem_op),
+            "::",
+            stringify!(buf)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mem_op>())).ar as *const _ as usize },
+        32usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mem_op),
+            "::",
+            stringify!(ar)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mem_op>())).reserved as *const _ as usize },
+        33usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mem_op),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_interrupt {
+    pub irq: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_interrupt() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_interrupt>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_interrupt))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_interrupt>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_interrupt))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_interrupt>())).irq as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_interrupt),
+            "::",
+            stringify!(irq)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_dirty_log {
+    pub slot: __u32,
+    pub padding1: __u32,
+    pub __bindgen_anon_1: kvm_dirty_log__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_dirty_log__bindgen_ty_1 {
+    pub dirty_bitmap: *mut ::std::os::raw::c_void,
+    pub padding2: __u64,
+    _bindgen_union_align: u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_dirty_log__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_dirty_log__bindgen_ty_1>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_dirty_log__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_dirty_log__bindgen_ty_1>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_dirty_log__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_dirty_log__bindgen_ty_1>())).dirty_bitmap as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dirty_log__bindgen_ty_1),
+            "::",
+            stringify!(dirty_bitmap)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_dirty_log__bindgen_ty_1>())).padding2 as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dirty_log__bindgen_ty_1),
+            "::",
+            stringify!(padding2)
+        )
+    );
+}
+impl Default for kvm_dirty_log__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_dirty_log() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_dirty_log>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_dirty_log))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_dirty_log>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_dirty_log))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_dirty_log>())).slot as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dirty_log),
+            "::",
+            stringify!(slot)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_dirty_log>())).padding1 as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dirty_log),
+            "::",
+            stringify!(padding1)
+        )
+    );
+}
+impl Default for kvm_dirty_log {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct kvm_signal_mask {
+    pub len: __u32,
+    pub sigset: __IncompleteArrayField<__u8>,
+}
+#[test]
+fn bindgen_test_layout_kvm_signal_mask() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_signal_mask>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_signal_mask))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_signal_mask>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_signal_mask))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_signal_mask>())).len as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_signal_mask),
+            "::",
+            stringify!(len)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_signal_mask>())).sigset as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_signal_mask),
+            "::",
+            stringify!(sigset)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_tpr_access_ctl {
+    pub enabled: __u32,
+    pub flags: __u32,
+    pub reserved: [__u32; 8usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_tpr_access_ctl() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_tpr_access_ctl>(),
+        40usize,
+        concat!("Size of: ", stringify!(kvm_tpr_access_ctl))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_tpr_access_ctl>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_tpr_access_ctl))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_tpr_access_ctl>())).enabled as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_tpr_access_ctl),
+            "::",
+            stringify!(enabled)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_tpr_access_ctl>())).flags as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_tpr_access_ctl),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_tpr_access_ctl>())).reserved as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_tpr_access_ctl),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_vapic_addr {
+    pub vapic_addr: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_vapic_addr() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_vapic_addr>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_vapic_addr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_vapic_addr>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_vapic_addr))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_vapic_addr>())).vapic_addr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vapic_addr),
+            "::",
+            stringify!(vapic_addr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_mp_state {
+    pub mp_state: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_mp_state() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_mp_state>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_mp_state))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_mp_state>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_mp_state))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_mp_state>())).mp_state as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_mp_state),
+            "::",
+            stringify!(mp_state)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_psw {
+    pub mask: __u64,
+    pub addr: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_psw() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_psw>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_s390_psw))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_psw>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_psw))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_psw>())).mask as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_psw),
+            "::",
+            stringify!(mask)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_psw>())).addr as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_psw),
+            "::",
+            stringify!(addr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_interrupt {
+    pub type_: __u32,
+    pub parm: __u32,
+    pub parm64: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_interrupt() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_interrupt>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_s390_interrupt))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_interrupt>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_interrupt))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_interrupt>())).type_ as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_interrupt),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_interrupt>())).parm as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_interrupt),
+            "::",
+            stringify!(parm)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_interrupt>())).parm64 as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_interrupt),
+            "::",
+            stringify!(parm64)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_io_info {
+    pub subchannel_id: __u16,
+    pub subchannel_nr: __u16,
+    pub io_int_parm: __u32,
+    pub io_int_word: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_io_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_io_info>(),
+        12usize,
+        concat!("Size of: ", stringify!(kvm_s390_io_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_io_info>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_s390_io_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_io_info>())).subchannel_id as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_io_info),
+            "::",
+            stringify!(subchannel_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_io_info>())).subchannel_nr as *const _ as usize },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_io_info),
+            "::",
+            stringify!(subchannel_nr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_io_info>())).io_int_parm as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_io_info),
+            "::",
+            stringify!(io_int_parm)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_io_info>())).io_int_word as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_io_info),
+            "::",
+            stringify!(io_int_word)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_ext_info {
+    pub ext_params: __u32,
+    pub pad: __u32,
+    pub ext_params2: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_ext_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_ext_info>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_s390_ext_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_ext_info>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_ext_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_ext_info>())).ext_params as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_ext_info),
+            "::",
+            stringify!(ext_params)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_ext_info>())).pad as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_ext_info),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_ext_info>())).ext_params2 as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_ext_info),
+            "::",
+            stringify!(ext_params2)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_pgm_info {
+    pub trans_exc_code: __u64,
+    pub mon_code: __u64,
+    pub per_address: __u64,
+    pub data_exc_code: __u32,
+    pub code: __u16,
+    pub mon_class_nr: __u16,
+    pub per_code: __u8,
+    pub per_atmid: __u8,
+    pub exc_access_id: __u8,
+    pub per_access_id: __u8,
+    pub op_access_id: __u8,
+    pub pad: [__u8; 3usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_pgm_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_pgm_info>(),
+        40usize,
+        concat!("Size of: ", stringify!(kvm_s390_pgm_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_pgm_info>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_pgm_info))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_s390_pgm_info>())).trans_exc_code as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(trans_exc_code)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).mon_code as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(mon_code)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).per_address as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(per_address)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).data_exc_code as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(data_exc_code)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).code as *const _ as usize },
+        28usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(code)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).mon_class_nr as *const _ as usize },
+        30usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(mon_class_nr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).per_code as *const _ as usize },
+        32usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(per_code)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).per_atmid as *const _ as usize },
+        33usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(per_atmid)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).exc_access_id as *const _ as usize },
+        34usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(exc_access_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).per_access_id as *const _ as usize },
+        35usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(per_access_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).op_access_id as *const _ as usize },
+        36usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(op_access_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).pad as *const _ as usize },
+        37usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_prefix_info {
+    pub address: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_prefix_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_prefix_info>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_s390_prefix_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_prefix_info>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_s390_prefix_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_prefix_info>())).address as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_prefix_info),
+            "::",
+            stringify!(address)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_extcall_info {
+    pub code: __u16,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_extcall_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_extcall_info>(),
+        2usize,
+        concat!("Size of: ", stringify!(kvm_s390_extcall_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_extcall_info>(),
+        2usize,
+        concat!("Alignment of ", stringify!(kvm_s390_extcall_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_extcall_info>())).code as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_extcall_info),
+            "::",
+            stringify!(code)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_emerg_info {
+    pub code: __u16,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_emerg_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_emerg_info>(),
+        2usize,
+        concat!("Size of: ", stringify!(kvm_s390_emerg_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_emerg_info>(),
+        2usize,
+        concat!("Alignment of ", stringify!(kvm_s390_emerg_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_emerg_info>())).code as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_emerg_info),
+            "::",
+            stringify!(code)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_stop_info {
+    pub flags: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_stop_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_stop_info>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_s390_stop_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_stop_info>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_s390_stop_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_stop_info>())).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_stop_info),
+            "::",
+            stringify!(flags)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_mchk_info {
+    pub cr14: __u64,
+    pub mcic: __u64,
+    pub failing_storage_address: __u64,
+    pub ext_damage_code: __u32,
+    pub pad: __u32,
+    pub fixed_logout: [__u8; 16usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_mchk_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_mchk_info>(),
+        48usize,
+        concat!("Size of: ", stringify!(kvm_s390_mchk_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_mchk_info>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_mchk_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mchk_info>())).cr14 as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mchk_info),
+            "::",
+            stringify!(cr14)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mchk_info>())).mcic as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mchk_info),
+            "::",
+            stringify!(mcic)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_s390_mchk_info>())).failing_storage_address as *const _
+                as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mchk_info),
+            "::",
+            stringify!(failing_storage_address)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_s390_mchk_info>())).ext_damage_code as *const _ as usize
+        },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mchk_info),
+            "::",
+            stringify!(ext_damage_code)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mchk_info>())).pad as *const _ as usize },
+        28usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mchk_info),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mchk_info>())).fixed_logout as *const _ as usize },
+        32usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mchk_info),
+            "::",
+            stringify!(fixed_logout)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_s390_irq {
+    pub type_: __u64,
+    pub u: kvm_s390_irq__bindgen_ty_1,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_s390_irq__bindgen_ty_1 {
+    pub io: kvm_s390_io_info,
+    pub ext: kvm_s390_ext_info,
+    pub pgm: kvm_s390_pgm_info,
+    pub emerg: kvm_s390_emerg_info,
+    pub extcall: kvm_s390_extcall_info,
+    pub prefix: kvm_s390_prefix_info,
+    pub stop: kvm_s390_stop_info,
+    pub mchk: kvm_s390_mchk_info,
+    pub reserved: [::std::os::raw::c_char; 64usize],
+    _bindgen_union_align: [u64; 8usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_irq__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_irq__bindgen_ty_1>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_s390_irq__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_irq__bindgen_ty_1>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_irq__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).io as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(io)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).ext as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(ext)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).pgm as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(pgm)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).emerg as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(emerg)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).extcall as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(extcall)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).prefix as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(prefix)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).stop as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(stop)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).mchk as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(mchk)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).reserved as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+impl Default for kvm_s390_irq__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_irq() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_irq>(),
+        72usize,
+        concat!("Size of: ", stringify!(kvm_s390_irq))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_irq>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_irq))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq>())).type_ as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq>())).u as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq),
+            "::",
+            stringify!(u)
+        )
+    );
+}
+impl Default for kvm_s390_irq {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_irq_state {
+    pub buf: __u64,
+    pub flags: __u32,
+    pub len: __u32,
+    pub reserved: [__u32; 4usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_irq_state() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_irq_state>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_s390_irq_state))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_irq_state>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_irq_state))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq_state>())).buf as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq_state),
+            "::",
+            stringify!(buf)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq_state>())).flags as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq_state),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq_state>())).len as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq_state),
+            "::",
+            stringify!(len)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq_state>())).reserved as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq_state),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_guest_debug {
+    pub control: __u32,
+    pub pad: __u32,
+    pub arch: kvm_guest_debug_arch,
+}
+#[test]
+fn bindgen_test_layout_kvm_guest_debug() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_guest_debug>(),
+        520usize,
+        concat!("Size of: ", stringify!(kvm_guest_debug))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_guest_debug>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_guest_debug))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_guest_debug>())).control as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_guest_debug),
+            "::",
+            stringify!(control)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_guest_debug>())).pad as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_guest_debug),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_guest_debug>())).arch as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_guest_debug),
+            "::",
+            stringify!(arch)
+        )
+    );
+}
+pub const kvm_ioeventfd_flag_nr_datamatch: _bindgen_ty_1 = 0;
+pub const kvm_ioeventfd_flag_nr_pio: _bindgen_ty_1 = 1;
+pub const kvm_ioeventfd_flag_nr_deassign: _bindgen_ty_1 = 2;
+pub const kvm_ioeventfd_flag_nr_virtio_ccw_notify: _bindgen_ty_1 = 3;
+pub const kvm_ioeventfd_flag_nr_fast_mmio: _bindgen_ty_1 = 4;
+pub const kvm_ioeventfd_flag_nr_max: _bindgen_ty_1 = 5;
+pub type _bindgen_ty_1 = ::std::os::raw::c_uint;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_ioeventfd {
+    pub datamatch: __u64,
+    pub addr: __u64,
+    pub len: __u32,
+    pub fd: __s32,
+    pub flags: __u32,
+    pub pad: [__u8; 36usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_ioeventfd() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_ioeventfd>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_ioeventfd))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_ioeventfd>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_ioeventfd))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioeventfd>())).datamatch as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioeventfd),
+            "::",
+            stringify!(datamatch)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioeventfd>())).addr as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioeventfd),
+            "::",
+            stringify!(addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioeventfd>())).len as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioeventfd),
+            "::",
+            stringify!(len)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioeventfd>())).fd as *const _ as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioeventfd),
+            "::",
+            stringify!(fd)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioeventfd>())).flags as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioeventfd),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioeventfd>())).pad as *const _ as usize },
+        28usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioeventfd),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+impl Default for kvm_ioeventfd {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_enable_cap {
+    pub cap: __u32,
+    pub flags: __u32,
+    pub args: [__u64; 4usize],
+    pub pad: [__u8; 64usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_enable_cap() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_enable_cap>(),
+        104usize,
+        concat!("Size of: ", stringify!(kvm_enable_cap))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_enable_cap>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_enable_cap))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_enable_cap>())).cap as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_enable_cap),
+            "::",
+            stringify!(cap)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_enable_cap>())).flags as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_enable_cap),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_enable_cap>())).args as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_enable_cap),
+            "::",
+            stringify!(args)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_enable_cap>())).pad as *const _ as usize },
+        40usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_enable_cap),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+impl Default for kvm_enable_cap {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_ppc_pvinfo {
+    pub flags: __u32,
+    pub hcall: [__u32; 4usize],
+    pub pad: [__u8; 108usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_ppc_pvinfo() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_ppc_pvinfo>(),
+        128usize,
+        concat!("Size of: ", stringify!(kvm_ppc_pvinfo))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_ppc_pvinfo>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_ppc_pvinfo))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_pvinfo>())).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_pvinfo),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_pvinfo>())).hcall as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_pvinfo),
+            "::",
+            stringify!(hcall)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_pvinfo>())).pad as *const _ as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_pvinfo),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+impl Default for kvm_ppc_pvinfo {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_ppc_one_page_size {
+    pub page_shift: __u32,
+    pub pte_enc: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_ppc_one_page_size() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_ppc_one_page_size>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_ppc_one_page_size))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_ppc_one_page_size>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_ppc_one_page_size))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_ppc_one_page_size>())).page_shift as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_one_page_size),
+            "::",
+            stringify!(page_shift)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_one_page_size>())).pte_enc as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_one_page_size),
+            "::",
+            stringify!(pte_enc)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_ppc_one_seg_page_size {
+    pub page_shift: __u32,
+    pub slb_enc: __u32,
+    pub enc: [kvm_ppc_one_page_size; 8usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_ppc_one_seg_page_size() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_ppc_one_seg_page_size>(),
+        72usize,
+        concat!("Size of: ", stringify!(kvm_ppc_one_seg_page_size))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_ppc_one_seg_page_size>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_ppc_one_seg_page_size))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_ppc_one_seg_page_size>())).page_shift as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_one_seg_page_size),
+            "::",
+            stringify!(page_shift)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_ppc_one_seg_page_size>())).slb_enc as *const _ as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_one_seg_page_size),
+            "::",
+            stringify!(slb_enc)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_one_seg_page_size>())).enc as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_one_seg_page_size),
+            "::",
+            stringify!(enc)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_ppc_smmu_info {
+    pub flags: __u64,
+    pub slb_size: __u32,
+    pub pad: __u32,
+    pub sps: [kvm_ppc_one_seg_page_size; 8usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_ppc_smmu_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_ppc_smmu_info>(),
+        592usize,
+        concat!("Size of: ", stringify!(kvm_ppc_smmu_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_ppc_smmu_info>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_ppc_smmu_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_smmu_info>())).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_smmu_info),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_smmu_info>())).slb_size as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_smmu_info),
+            "::",
+            stringify!(slb_size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_smmu_info>())).pad as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_smmu_info),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_smmu_info>())).sps as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_smmu_info),
+            "::",
+            stringify!(sps)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_irq_routing_irqchip {
+    pub irqchip: __u32,
+    pub pin: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing_irqchip() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_routing_irqchip>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_irq_routing_irqchip))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_routing_irqchip>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_irq_routing_irqchip))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_irqchip>())).irqchip as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_irqchip),
+            "::",
+            stringify!(irqchip)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_irqchip>())).pin as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_irqchip),
+            "::",
+            stringify!(pin)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_irq_routing_msi {
+    pub address_lo: __u32,
+    pub address_hi: __u32,
+    pub data: __u32,
+    pub pad: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing_msi() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_routing_msi>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_irq_routing_msi))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_routing_msi>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_irq_routing_msi))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_msi>())).address_lo as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_msi),
+            "::",
+            stringify!(address_lo)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_msi>())).address_hi as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_msi),
+            "::",
+            stringify!(address_hi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_msi>())).data as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_msi),
+            "::",
+            stringify!(data)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_msi>())).pad as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_msi),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_irq_routing_s390_adapter {
+    pub ind_addr: __u64,
+    pub summary_addr: __u64,
+    pub ind_offset: __u64,
+    pub summary_offset: __u32,
+    pub adapter_id: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing_s390_adapter() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_routing_s390_adapter>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_irq_routing_s390_adapter))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_routing_s390_adapter>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_irq_routing_s390_adapter))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_s390_adapter>())).ind_addr as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_s390_adapter),
+            "::",
+            stringify!(ind_addr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_s390_adapter>())).summary_addr as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_s390_adapter),
+            "::",
+            stringify!(summary_addr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_s390_adapter>())).ind_offset as *const _ as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_s390_adapter),
+            "::",
+            stringify!(ind_offset)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_s390_adapter>())).summary_offset as *const _
+                as usize
+        },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_s390_adapter),
+            "::",
+            stringify!(summary_offset)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_s390_adapter>())).adapter_id as *const _ as usize
+        },
+        28usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_s390_adapter),
+            "::",
+            stringify!(adapter_id)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_irq_routing_entry {
+    pub gsi: __u32,
+    pub type_: __u32,
+    pub flags: __u32,
+    pub pad: __u32,
+    pub u: kvm_irq_routing_entry__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_irq_routing_entry__bindgen_ty_1 {
+    pub irqchip: kvm_irq_routing_irqchip,
+    pub msi: kvm_irq_routing_msi,
+    pub adapter: kvm_irq_routing_s390_adapter,
+    pub pad: [__u32; 8usize],
+    _bindgen_union_align: [u64; 4usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing_entry__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_routing_entry__bindgen_ty_1>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_irq_routing_entry__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_routing_entry__bindgen_ty_1>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_irq_routing_entry__bindgen_ty_1)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_entry__bindgen_ty_1>())).irqchip as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry__bindgen_ty_1),
+            "::",
+            stringify!(irqchip)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_entry__bindgen_ty_1>())).msi as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry__bindgen_ty_1),
+            "::",
+            stringify!(msi)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_entry__bindgen_ty_1>())).adapter as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry__bindgen_ty_1),
+            "::",
+            stringify!(adapter)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_entry__bindgen_ty_1>())).pad as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry__bindgen_ty_1),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+impl Default for kvm_irq_routing_entry__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing_entry() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_routing_entry>(),
+        48usize,
+        concat!("Size of: ", stringify!(kvm_irq_routing_entry))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_routing_entry>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_irq_routing_entry))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_entry>())).gsi as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry),
+            "::",
+            stringify!(gsi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_entry>())).type_ as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_entry>())).flags as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_entry>())).pad as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_entry>())).u as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry),
+            "::",
+            stringify!(u)
+        )
+    );
+}
+impl Default for kvm_irq_routing_entry {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+pub struct kvm_irq_routing {
+    pub nr: __u32,
+    pub flags: __u32,
+    pub entries: __IncompleteArrayField<kvm_irq_routing_entry>,
+    // Manually added to work around rust bindgen issue 684
+    __force_alignment: [u64; 0],
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_routing>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_irq_routing))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_routing>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_irq_routing))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing>())).nr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing),
+            "::",
+            stringify!(nr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing>())).flags as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing>())).entries as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing),
+            "::",
+            stringify!(entries)
+        )
+    );
+}
+impl Default for kvm_irq_routing {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_irqfd {
+    pub fd: __u32,
+    pub gsi: __u32,
+    pub flags: __u32,
+    pub resamplefd: __u32,
+    pub pad: [__u8; 16usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_irqfd() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irqfd>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_irqfd))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irqfd>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_irqfd))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqfd>())).fd as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqfd),
+            "::",
+            stringify!(fd)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqfd>())).gsi as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqfd),
+            "::",
+            stringify!(gsi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqfd>())).flags as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqfd),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqfd>())).resamplefd as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqfd),
+            "::",
+            stringify!(resamplefd)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqfd>())).pad as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqfd),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_clock_data {
+    pub clock: __u64,
+    pub flags: __u32,
+    pub pad: [__u32; 9usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_clock_data() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_clock_data>(),
+        48usize,
+        concat!("Size of: ", stringify!(kvm_clock_data))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_clock_data>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_clock_data))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_clock_data>())).clock as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_clock_data),
+            "::",
+            stringify!(clock)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_clock_data>())).flags as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_clock_data),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_clock_data>())).pad as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_clock_data),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_config_tlb {
+    pub params: __u64,
+    pub array: __u64,
+    pub mmu_type: __u32,
+    pub array_len: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_config_tlb() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_config_tlb>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_config_tlb))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_config_tlb>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_config_tlb))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_config_tlb>())).params as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_config_tlb),
+            "::",
+            stringify!(params)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_config_tlb>())).array as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_config_tlb),
+            "::",
+            stringify!(array)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_config_tlb>())).mmu_type as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_config_tlb),
+            "::",
+            stringify!(mmu_type)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_config_tlb>())).array_len as *const _ as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_config_tlb),
+            "::",
+            stringify!(array_len)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_dirty_tlb {
+    pub bitmap: __u64,
+    pub num_dirty: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_dirty_tlb() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_dirty_tlb>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_dirty_tlb))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_dirty_tlb>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_dirty_tlb))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_dirty_tlb>())).bitmap as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dirty_tlb),
+            "::",
+            stringify!(bitmap)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_dirty_tlb>())).num_dirty as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dirty_tlb),
+            "::",
+            stringify!(num_dirty)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct kvm_reg_list {
+    pub n: __u64,
+    pub reg: __IncompleteArrayField<__u64>,
+}
+#[test]
+fn bindgen_test_layout_kvm_reg_list() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_reg_list>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_reg_list))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_reg_list>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_reg_list))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_reg_list>())).n as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_reg_list),
+            "::",
+            stringify!(n)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_reg_list>())).reg as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_reg_list),
+            "::",
+            stringify!(reg)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_one_reg {
+    pub id: __u64,
+    pub addr: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_one_reg() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_one_reg>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_one_reg))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_one_reg>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_one_reg))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_one_reg>())).id as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_one_reg),
+            "::",
+            stringify!(id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_one_reg>())).addr as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_one_reg),
+            "::",
+            stringify!(addr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_msi {
+    pub address_lo: __u32,
+    pub address_hi: __u32,
+    pub data: __u32,
+    pub flags: __u32,
+    pub pad: [__u8; 16usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_msi() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_msi>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_msi))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_msi>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_msi))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msi>())).address_lo as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msi),
+            "::",
+            stringify!(address_lo)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msi>())).address_hi as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msi),
+            "::",
+            stringify!(address_hi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msi>())).data as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msi),
+            "::",
+            stringify!(data)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msi>())).flags as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msi),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msi>())).pad as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msi),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_arm_device_addr {
+    pub id: __u64,
+    pub addr: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_arm_device_addr() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_arm_device_addr>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_arm_device_addr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_arm_device_addr>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_arm_device_addr))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_arm_device_addr>())).id as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_arm_device_addr),
+            "::",
+            stringify!(id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_arm_device_addr>())).addr as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_arm_device_addr),
+            "::",
+            stringify!(addr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_create_device {
+    pub type_: __u32,
+    pub fd: __u32,
+    pub flags: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_create_device() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_create_device>(),
+        12usize,
+        concat!("Size of: ", stringify!(kvm_create_device))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_create_device>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_create_device))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_create_device>())).type_ as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_create_device),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_create_device>())).fd as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_create_device),
+            "::",
+            stringify!(fd)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_create_device>())).flags as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_create_device),
+            "::",
+            stringify!(flags)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_device_attr {
+    pub flags: __u32,
+    pub group: __u32,
+    pub attr: __u64,
+    pub addr: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_device_attr() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_device_attr>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_device_attr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_device_attr>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_device_attr))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_device_attr>())).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_device_attr),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_device_attr>())).group as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_device_attr),
+            "::",
+            stringify!(group)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_device_attr>())).attr as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_device_attr),
+            "::",
+            stringify!(attr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_device_attr>())).addr as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_device_attr),
+            "::",
+            stringify!(addr)
+        )
+    );
+}
+pub const kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_20: kvm_device_type = 1;
+pub const kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_42: kvm_device_type = 2;
+pub const kvm_device_type_KVM_DEV_TYPE_XICS: kvm_device_type = 3;
+pub const kvm_device_type_KVM_DEV_TYPE_VFIO: kvm_device_type = 4;
+pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2: kvm_device_type = 5;
+pub const kvm_device_type_KVM_DEV_TYPE_FLIC: kvm_device_type = 6;
+pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3: kvm_device_type = 7;
+pub const kvm_device_type_KVM_DEV_TYPE_MAX: kvm_device_type = 8;
+pub type kvm_device_type = ::std::os::raw::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_ucas_mapping {
+    pub user_addr: __u64,
+    pub vcpu_addr: __u64,
+    pub length: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_ucas_mapping() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_ucas_mapping>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_s390_ucas_mapping))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_ucas_mapping>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_ucas_mapping))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_ucas_mapping>())).user_addr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_ucas_mapping),
+            "::",
+            stringify!(user_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_ucas_mapping>())).vcpu_addr as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_ucas_mapping),
+            "::",
+            stringify!(vcpu_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_ucas_mapping>())).length as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_ucas_mapping),
+            "::",
+            stringify!(length)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_assigned_pci_dev {
+    pub assigned_dev_id: __u32,
+    pub busnr: __u32,
+    pub devfn: __u32,
+    pub flags: __u32,
+    pub segnr: __u32,
+    pub __bindgen_anon_1: kvm_assigned_pci_dev__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_assigned_pci_dev__bindgen_ty_1 {
+    pub reserved: [__u32; 11usize],
+    _bindgen_union_align: [u32; 11usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_assigned_pci_dev__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_assigned_pci_dev__bindgen_ty_1>(),
+        44usize,
+        concat!("Size of: ", stringify!(kvm_assigned_pci_dev__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_assigned_pci_dev__bindgen_ty_1>(),
+        4usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_assigned_pci_dev__bindgen_ty_1)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_assigned_pci_dev__bindgen_ty_1>())).reserved as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_pci_dev__bindgen_ty_1),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+impl Default for kvm_assigned_pci_dev__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_assigned_pci_dev() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_assigned_pci_dev>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_assigned_pci_dev))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_assigned_pci_dev>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_assigned_pci_dev))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_assigned_pci_dev>())).assigned_dev_id as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_pci_dev),
+            "::",
+            stringify!(assigned_dev_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_pci_dev>())).busnr as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_pci_dev),
+            "::",
+            stringify!(busnr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_pci_dev>())).devfn as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_pci_dev),
+            "::",
+            stringify!(devfn)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_pci_dev>())).flags as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_pci_dev),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_pci_dev>())).segnr as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_pci_dev),
+            "::",
+            stringify!(segnr)
+        )
+    );
+}
+impl Default for kvm_assigned_pci_dev {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_assigned_irq {
+    pub assigned_dev_id: __u32,
+    pub host_irq: __u32,
+    pub guest_irq: __u32,
+    pub flags: __u32,
+    pub __bindgen_anon_1: kvm_assigned_irq__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_assigned_irq__bindgen_ty_1 {
+    pub reserved: [__u32; 12usize],
+    _bindgen_union_align: [u32; 12usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_assigned_irq__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_assigned_irq__bindgen_ty_1>(),
+        48usize,
+        concat!("Size of: ", stringify!(kvm_assigned_irq__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_assigned_irq__bindgen_ty_1>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_assigned_irq__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_assigned_irq__bindgen_ty_1>())).reserved as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_irq__bindgen_ty_1),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+impl Default for kvm_assigned_irq__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_assigned_irq() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_assigned_irq>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_assigned_irq))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_assigned_irq>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_assigned_irq))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_assigned_irq>())).assigned_dev_id as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_irq),
+            "::",
+            stringify!(assigned_dev_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_irq>())).host_irq as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_irq),
+            "::",
+            stringify!(host_irq)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_irq>())).guest_irq as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_irq),
+            "::",
+            stringify!(guest_irq)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_irq>())).flags as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_irq),
+            "::",
+            stringify!(flags)
+        )
+    );
+}
+impl Default for kvm_assigned_irq {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_assigned_msix_nr {
+    pub assigned_dev_id: __u32,
+    pub entry_nr: __u16,
+    pub padding: __u16,
+}
+#[test]
+fn bindgen_test_layout_kvm_assigned_msix_nr() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_assigned_msix_nr>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_assigned_msix_nr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_assigned_msix_nr>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_assigned_msix_nr))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_assigned_msix_nr>())).assigned_dev_id as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_msix_nr),
+            "::",
+            stringify!(assigned_dev_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_msix_nr>())).entry_nr as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_msix_nr),
+            "::",
+            stringify!(entry_nr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_msix_nr>())).padding as *const _ as usize },
+        6usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_msix_nr),
+            "::",
+            stringify!(padding)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_assigned_msix_entry {
+    pub assigned_dev_id: __u32,
+    pub gsi: __u32,
+    pub entry: __u16,
+    pub padding: [__u16; 3usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_assigned_msix_entry() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_assigned_msix_entry>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_assigned_msix_entry))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_assigned_msix_entry>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_assigned_msix_entry))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_assigned_msix_entry>())).assigned_dev_id as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_msix_entry),
+            "::",
+            stringify!(assigned_dev_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_msix_entry>())).gsi as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_msix_entry),
+            "::",
+            stringify!(gsi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_msix_entry>())).entry as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_msix_entry),
+            "::",
+            stringify!(entry)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_msix_entry>())).padding as *const _ as usize },
+        10usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_msix_entry),
+            "::",
+            stringify!(padding)
+        )
+    );
+}
+pub type __uint128_t = [u64; 2];
diff --git a/kvm_sys/src/lib.rs b/kvm_sys/src/lib.rs
new file mode 100644
index 0000000..b9748a3
--- /dev/null
+++ b/kvm_sys/src/lib.rs
@@ -0,0 +1,161 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+use sys_util::{ioctl_io_nr, ioctl_ior_nr, ioctl_iow_nr, ioctl_iowr_nr};
+
+// Somehow this one gets missed by bindgen
+pub const KVM_EXIT_IO_OUT: ::std::os::raw::c_uint = 1;
+
+// Each of the below modules defines ioctls specific to their platform.
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub mod x86 {
+    // generated with bindgen /usr/include/linux/kvm.h --no-unstable-rust --constified-enum '*' --with-derive-default
+    #[allow(clippy::all)]
+    pub mod bindings;
+    pub use crate::bindings::*;
+    use sys_util::{ioctl_ior_nr, ioctl_iow_nr, ioctl_iowr_nr};
+
+    ioctl_iow_nr!(KVM_SET_GSI_ROUTING, KVMIO, 0x6a, kvm_irq_routing);
+    ioctl_iowr_nr!(KVM_GET_MSR_INDEX_LIST, KVMIO, 0x02, kvm_msr_list);
+    ioctl_iowr_nr!(KVM_GET_SUPPORTED_CPUID, KVMIO, 0x05, kvm_cpuid2);
+    ioctl_iowr_nr!(KVM_GET_EMULATED_CPUID, KVMIO, 0x09, kvm_cpuid2);
+    ioctl_iow_nr!(KVM_SET_MEMORY_ALIAS, KVMIO, 0x43, kvm_memory_alias);
+    ioctl_iow_nr!(KVM_XEN_HVM_CONFIG, KVMIO, 0x7a, kvm_xen_hvm_config);
+    ioctl_ior_nr!(KVM_GET_PIT2, KVMIO, 0x9f, kvm_pit_state2);
+    ioctl_iow_nr!(KVM_SET_PIT2, KVMIO, 0xa0, kvm_pit_state2);
+    ioctl_iowr_nr!(KVM_GET_MSRS, KVMIO, 0x88, kvm_msrs);
+    ioctl_iow_nr!(KVM_SET_MSRS, KVMIO, 0x89, kvm_msrs);
+    ioctl_iow_nr!(KVM_SET_CPUID, KVMIO, 0x8a, kvm_cpuid);
+    ioctl_ior_nr!(KVM_GET_LAPIC, KVMIO, 0x8e, kvm_lapic_state);
+    ioctl_iow_nr!(KVM_SET_LAPIC, KVMIO, 0x8f, kvm_lapic_state);
+    ioctl_iow_nr!(KVM_SET_CPUID2, KVMIO, 0x90, kvm_cpuid2);
+    ioctl_iowr_nr!(KVM_GET_CPUID2, KVMIO, 0x91, kvm_cpuid2);
+    ioctl_iow_nr!(KVM_X86_SETUP_MCE, KVMIO, 0x9c, __u64);
+    ioctl_ior_nr!(KVM_X86_GET_MCE_CAP_SUPPORTED, KVMIO, 0x9d, __u64);
+    ioctl_iow_nr!(KVM_X86_SET_MCE, KVMIO, 0x9e, kvm_x86_mce);
+    ioctl_ior_nr!(KVM_GET_VCPU_EVENTS, KVMIO, 0x9f, kvm_vcpu_events);
+    ioctl_iow_nr!(KVM_SET_VCPU_EVENTS, KVMIO, 0xa0, kvm_vcpu_events);
+    ioctl_ior_nr!(KVM_GET_DEBUGREGS, KVMIO, 0xa1, kvm_debugregs);
+    ioctl_iow_nr!(KVM_SET_DEBUGREGS, KVMIO, 0xa2, kvm_debugregs);
+    ioctl_ior_nr!(KVM_GET_XSAVE, KVMIO, 0xa4, kvm_xsave);
+    ioctl_iow_nr!(KVM_SET_XSAVE, KVMIO, 0xa5, kvm_xsave);
+    ioctl_ior_nr!(KVM_GET_XCRS, KVMIO, 0xa6, kvm_xcrs);
+    ioctl_iow_nr!(KVM_SET_XCRS, KVMIO, 0xa7, kvm_xcrs);
+}
+
+#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+pub mod aarch64 {
+    // generated with bindgen <arm sysroot>/usr/include/linux/kvm.h --no-unstable-rust --constified-enum '*' --with-derive-default -- -I<arm sysroot>/usr/include
+    pub mod bindings;
+    pub use bindings::*;
+    use sys_util::{ioctl_ior_nr, ioctl_iow_nr};
+
+    ioctl_iow_nr!(KVM_ARM_SET_DEVICE_ADDR, KVMIO, 0xab, kvm_arm_device_addr);
+    ioctl_iow_nr!(KVM_ARM_VCPU_INIT, KVMIO, 0xae, kvm_vcpu_init);
+    ioctl_ior_nr!(KVM_ARM_PREFERRED_TARGET, KVMIO, 0xaf, kvm_vcpu_init);
+}
+
+// These ioctls are commonly defined on all/multiple platforms.
+ioctl_io_nr!(KVM_GET_API_VERSION, KVMIO, 0x00);
+ioctl_io_nr!(KVM_CREATE_VM, KVMIO, 0x01);
+ioctl_io_nr!(KVM_CHECK_EXTENSION, KVMIO, 0x03);
+ioctl_io_nr!(KVM_GET_VCPU_MMAP_SIZE, KVMIO, 0x04);
+ioctl_iow_nr!(KVM_SET_MEMORY_REGION, KVMIO, 0x40, kvm_memory_region);
+ioctl_io_nr!(KVM_CREATE_VCPU, KVMIO, 0x41);
+ioctl_iow_nr!(KVM_GET_DIRTY_LOG, KVMIO, 0x42, kvm_dirty_log);
+ioctl_io_nr!(KVM_SET_NR_MMU_PAGES, KVMIO, 0x44);
+ioctl_io_nr!(KVM_GET_NR_MMU_PAGES, KVMIO, 0x45);
+ioctl_iow_nr!(
+    KVM_SET_USER_MEMORY_REGION,
+    KVMIO,
+    0x46,
+    kvm_userspace_memory_region
+);
+ioctl_io_nr!(KVM_SET_TSS_ADDR, KVMIO, 0x47);
+ioctl_iow_nr!(KVM_SET_IDENTITY_MAP_ADDR, KVMIO, 0x48, __u64);
+ioctl_io_nr!(KVM_CREATE_IRQCHIP, KVMIO, 0x60);
+ioctl_iow_nr!(KVM_IRQ_LINE, KVMIO, 0x61, kvm_irq_level);
+ioctl_iowr_nr!(KVM_GET_IRQCHIP, KVMIO, 0x62, kvm_irqchip);
+ioctl_ior_nr!(KVM_SET_IRQCHIP, KVMIO, 0x63, kvm_irqchip);
+ioctl_io_nr!(KVM_CREATE_PIT, KVMIO, 0x64);
+ioctl_iowr_nr!(KVM_IRQ_LINE_STATUS, KVMIO, 0x67, kvm_irq_level);
+ioctl_iow_nr!(
+    KVM_REGISTER_COALESCED_MMIO,
+    KVMIO,
+    0x67,
+    kvm_coalesced_mmio_zone
+);
+ioctl_iow_nr!(
+    KVM_UNREGISTER_COALESCED_MMIO,
+    KVMIO,
+    0x68,
+    kvm_coalesced_mmio_zone
+);
+ioctl_ior_nr!(KVM_ASSIGN_PCI_DEVICE, KVMIO, 0x69, kvm_assigned_pci_dev);
+ioctl_iow_nr!(KVM_ASSIGN_DEV_IRQ, KVMIO, 0x70, kvm_assigned_irq);
+ioctl_io_nr!(KVM_REINJECT_CONTROL, KVMIO, 0x71);
+ioctl_iow_nr!(KVM_DEASSIGN_PCI_DEVICE, KVMIO, 0x72, kvm_assigned_pci_dev);
+ioctl_iow_nr!(KVM_ASSIGN_SET_MSIX_NR, KVMIO, 0x73, kvm_assigned_msix_nr);
+ioctl_iow_nr!(
+    KVM_ASSIGN_SET_MSIX_ENTRY,
+    KVMIO,
+    0x74,
+    kvm_assigned_msix_entry
+);
+ioctl_iow_nr!(KVM_DEASSIGN_DEV_IRQ, KVMIO, 0x75, kvm_assigned_irq);
+ioctl_iow_nr!(KVM_IRQFD, KVMIO, 0x76, kvm_irqfd);
+ioctl_iow_nr!(KVM_CREATE_PIT2, KVMIO, 0x77, kvm_pit_config);
+ioctl_io_nr!(KVM_SET_BOOT_CPU_ID, KVMIO, 0x78);
+ioctl_iow_nr!(KVM_IOEVENTFD, KVMIO, 0x79, kvm_ioeventfd);
+ioctl_iow_nr!(KVM_SET_CLOCK, KVMIO, 0x7b, kvm_clock_data);
+ioctl_ior_nr!(KVM_GET_CLOCK, KVMIO, 0x7c, kvm_clock_data);
+ioctl_io_nr!(KVM_SET_TSC_KHZ, KVMIO, 0xa2);
+ioctl_io_nr!(KVM_GET_TSC_KHZ, KVMIO, 0xa3);
+ioctl_iow_nr!(KVM_ASSIGN_SET_INTX_MASK, KVMIO, 0xa4, kvm_assigned_pci_dev);
+ioctl_iow_nr!(KVM_SIGNAL_MSI, KVMIO, 0xa5, kvm_msi);
+ioctl_iowr_nr!(KVM_CREATE_DEVICE, KVMIO, 0xe0, kvm_create_device);
+ioctl_iow_nr!(KVM_SET_DEVICE_ATTR, KVMIO, 0xe1, kvm_device_attr);
+ioctl_iow_nr!(KVM_GET_DEVICE_ATTR, KVMIO, 0xe2, kvm_device_attr);
+ioctl_iow_nr!(KVM_HAS_DEVICE_ATTR, KVMIO, 0xe3, kvm_device_attr);
+ioctl_io_nr!(KVM_RUN, KVMIO, 0x80);
+// The following two ioctls are commonly defined but specifically excluded
+// from arm platforms.
+#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
+ioctl_ior_nr!(KVM_GET_REGS, KVMIO, 0x81, kvm_regs);
+#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
+ioctl_iow_nr!(KVM_SET_REGS, KVMIO, 0x82, kvm_regs);
+ioctl_ior_nr!(KVM_GET_SREGS, KVMIO, 0x83, kvm_sregs);
+ioctl_iow_nr!(KVM_SET_SREGS, KVMIO, 0x84, kvm_sregs);
+ioctl_iowr_nr!(KVM_TRANSLATE, KVMIO, 0x85, kvm_translation);
+ioctl_iow_nr!(KVM_INTERRUPT, KVMIO, 0x86, kvm_interrupt);
+ioctl_iow_nr!(KVM_SET_SIGNAL_MASK, KVMIO, 0x8b, kvm_signal_mask);
+ioctl_ior_nr!(KVM_GET_FPU, KVMIO, 0x8c, kvm_fpu);
+ioctl_iow_nr!(KVM_SET_FPU, KVMIO, 0x8d, kvm_fpu);
+ioctl_iowr_nr!(KVM_TPR_ACCESS_REPORTING, KVMIO, 0x92, kvm_tpr_access_ctl);
+ioctl_iow_nr!(KVM_SET_VAPIC_ADDR, KVMIO, 0x93, kvm_vapic_addr);
+ioctl_ior_nr!(KVM_GET_MP_STATE, KVMIO, 0x98, kvm_mp_state);
+ioctl_iow_nr!(KVM_SET_MP_STATE, KVMIO, 0x99, kvm_mp_state);
+ioctl_io_nr!(KVM_NMI, KVMIO, 0x9a);
+ioctl_iow_nr!(KVM_SET_GUEST_DEBUG, KVMIO, 0x9b, kvm_guest_debug);
+ioctl_iow_nr!(KVM_ENABLE_CAP, KVMIO, 0xa3, kvm_enable_cap);
+ioctl_iow_nr!(KVM_DIRTY_TLB, KVMIO, 0xaa, kvm_dirty_tlb);
+ioctl_iow_nr!(KVM_GET_ONE_REG, KVMIO, 0xab, kvm_one_reg);
+ioctl_iow_nr!(KVM_SET_ONE_REG, KVMIO, 0xac, kvm_one_reg);
+ioctl_io_nr!(KVM_KVMCLOCK_CTRL, KVMIO, 0xad);
+ioctl_iowr_nr!(KVM_GET_REG_LIST, KVMIO, 0xb0, kvm_reg_list);
+ioctl_io_nr!(KVM_SMI, KVMIO, 0xb7);
+
+// Along with the common ioctls, we reexport the ioctls of the current
+// platform.
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub use crate::x86::*;
+
+#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+pub use aarch64::*;
diff --git a/kvm_sys/src/x86/bindings.rs b/kvm_sys/src/x86/bindings.rs
new file mode 100644
index 0000000..06b8680
--- /dev/null
+++ b/kvm_sys/src/x86/bindings.rs
@@ -0,0 +1,8967 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+#[repr(C)]
+#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct __BindgenBitfieldUnit<Storage, Align>
+where
+    Storage: AsRef<[u8]> + AsMut<[u8]>,
+{
+    storage: Storage,
+    align: [Align; 0],
+}
+
+impl<Storage, Align> __BindgenBitfieldUnit<Storage, Align>
+where
+    Storage: AsRef<[u8]> + AsMut<[u8]>,
+{
+    #[inline]
+    pub fn new(storage: Storage) -> Self {
+        Self { storage, align: [] }
+    }
+
+    #[inline]
+    pub fn get_bit(&self, index: usize) -> bool {
+        debug_assert!(index / 8 < self.storage.as_ref().len());
+
+        let byte_index = index / 8;
+        let byte = self.storage.as_ref()[byte_index];
+
+        let bit_index = index % 8;
+        let mask = 1 << bit_index;
+
+        byte & mask == mask
+    }
+
+    #[inline]
+    pub fn set_bit(&mut self, index: usize, val: bool) {
+        debug_assert!(index / 8 < self.storage.as_ref().len());
+
+        let byte_index = index / 8;
+        let byte = &mut self.storage.as_mut()[byte_index];
+
+        let bit_index = index % 8;
+        let mask = 1 << bit_index;
+
+        if val {
+            *byte |= mask;
+        } else {
+            *byte &= !mask;
+        }
+    }
+
+    #[inline]
+    pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
+        debug_assert!(bit_width <= 64);
+        debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
+        debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
+
+        let mut val = 0;
+
+        for i in 0..(bit_width as usize) {
+            if self.get_bit(i + bit_offset) {
+                val |= 1 << i;
+            }
+        }
+
+        val
+    }
+
+    #[inline]
+    pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
+        debug_assert!(bit_width <= 64);
+        debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
+        debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
+
+        for i in 0..(bit_width as usize) {
+            let mask = 1 << i;
+            let val_bit_is_set = val & mask == mask;
+            self.set_bit(i + bit_offset, val_bit_is_set);
+        }
+    }
+}
+#[repr(C)]
+#[derive(Default)]
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
+impl<T> __IncompleteArrayField<T> {
+    #[inline]
+    pub fn new() -> Self {
+        __IncompleteArrayField(::std::marker::PhantomData)
+    }
+    #[inline]
+    pub unsafe fn as_ptr(&self) -> *const T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_slice(&self, len: usize) -> &[T] {
+        ::std::slice::from_raw_parts(self.as_ptr(), len)
+    }
+    #[inline]
+    pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
+        ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
+    }
+}
+impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        fmt.write_str("__IncompleteArrayField")
+    }
+}
+impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self::new()
+    }
+}
+impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
+pub const __BITS_PER_LONG: ::std::os::raw::c_uint = 64;
+pub const __FD_SETSIZE: ::std::os::raw::c_uint = 1024;
+pub const _IOC_NRBITS: ::std::os::raw::c_uint = 8;
+pub const _IOC_TYPEBITS: ::std::os::raw::c_uint = 8;
+pub const _IOC_SIZEBITS: ::std::os::raw::c_uint = 14;
+pub const _IOC_DIRBITS: ::std::os::raw::c_uint = 2;
+pub const _IOC_NRMASK: ::std::os::raw::c_uint = 255;
+pub const _IOC_TYPEMASK: ::std::os::raw::c_uint = 255;
+pub const _IOC_SIZEMASK: ::std::os::raw::c_uint = 16383;
+pub const _IOC_DIRMASK: ::std::os::raw::c_uint = 3;
+pub const _IOC_NRSHIFT: ::std::os::raw::c_uint = 0;
+pub const _IOC_TYPESHIFT: ::std::os::raw::c_uint = 8;
+pub const _IOC_SIZESHIFT: ::std::os::raw::c_uint = 16;
+pub const _IOC_DIRSHIFT: ::std::os::raw::c_uint = 30;
+pub const _IOC_NONE: ::std::os::raw::c_uint = 0;
+pub const _IOC_WRITE: ::std::os::raw::c_uint = 1;
+pub const _IOC_READ: ::std::os::raw::c_uint = 2;
+pub const IOC_IN: ::std::os::raw::c_uint = 1073741824;
+pub const IOC_OUT: ::std::os::raw::c_uint = 2147483648;
+pub const IOC_INOUT: ::std::os::raw::c_uint = 3221225472;
+pub const IOCSIZE_MASK: ::std::os::raw::c_uint = 1073676288;
+pub const IOCSIZE_SHIFT: ::std::os::raw::c_uint = 16;
+pub const DE_VECTOR: ::std::os::raw::c_uint = 0;
+pub const DB_VECTOR: ::std::os::raw::c_uint = 1;
+pub const BP_VECTOR: ::std::os::raw::c_uint = 3;
+pub const OF_VECTOR: ::std::os::raw::c_uint = 4;
+pub const BR_VECTOR: ::std::os::raw::c_uint = 5;
+pub const UD_VECTOR: ::std::os::raw::c_uint = 6;
+pub const NM_VECTOR: ::std::os::raw::c_uint = 7;
+pub const DF_VECTOR: ::std::os::raw::c_uint = 8;
+pub const TS_VECTOR: ::std::os::raw::c_uint = 10;
+pub const NP_VECTOR: ::std::os::raw::c_uint = 11;
+pub const SS_VECTOR: ::std::os::raw::c_uint = 12;
+pub const GP_VECTOR: ::std::os::raw::c_uint = 13;
+pub const PF_VECTOR: ::std::os::raw::c_uint = 14;
+pub const MF_VECTOR: ::std::os::raw::c_uint = 16;
+pub const AC_VECTOR: ::std::os::raw::c_uint = 17;
+pub const MC_VECTOR: ::std::os::raw::c_uint = 18;
+pub const XM_VECTOR: ::std::os::raw::c_uint = 19;
+pub const VE_VECTOR: ::std::os::raw::c_uint = 20;
+pub const KVM_NR_INTERRUPTS: ::std::os::raw::c_uint = 256;
+pub const KVM_IOAPIC_NUM_PINS: ::std::os::raw::c_uint = 24;
+pub const KVM_IRQCHIP_PIC_MASTER: ::std::os::raw::c_uint = 0;
+pub const KVM_IRQCHIP_PIC_SLAVE: ::std::os::raw::c_uint = 1;
+pub const KVM_IRQCHIP_IOAPIC: ::std::os::raw::c_uint = 2;
+pub const KVM_NR_IRQCHIPS: ::std::os::raw::c_uint = 3;
+pub const KVM_RUN_X86_SMM: ::std::os::raw::c_uint = 1;
+pub const KVM_APIC_REG_SIZE: ::std::os::raw::c_uint = 1024;
+pub const KVM_CPUID_FLAG_SIGNIFCANT_INDEX: ::std::os::raw::c_uint = 1;
+pub const KVM_CPUID_FLAG_STATEFUL_FUNC: ::std::os::raw::c_uint = 2;
+pub const KVM_CPUID_FLAG_STATE_READ_NEXT: ::std::os::raw::c_uint = 4;
+pub const KVM_GUESTDBG_USE_SW_BP: ::std::os::raw::c_uint = 65536;
+pub const KVM_GUESTDBG_USE_HW_BP: ::std::os::raw::c_uint = 131072;
+pub const KVM_GUESTDBG_INJECT_DB: ::std::os::raw::c_uint = 262144;
+pub const KVM_GUESTDBG_INJECT_BP: ::std::os::raw::c_uint = 524288;
+pub const KVM_PIT_FLAGS_HPET_LEGACY: ::std::os::raw::c_uint = 1;
+pub const KVM_VCPUEVENT_VALID_NMI_PENDING: ::std::os::raw::c_uint = 1;
+pub const KVM_VCPUEVENT_VALID_SIPI_VECTOR: ::std::os::raw::c_uint = 2;
+pub const KVM_VCPUEVENT_VALID_SHADOW: ::std::os::raw::c_uint = 4;
+pub const KVM_VCPUEVENT_VALID_SMM: ::std::os::raw::c_uint = 8;
+pub const KVM_X86_SHADOW_INT_MOV_SS: ::std::os::raw::c_uint = 1;
+pub const KVM_X86_SHADOW_INT_STI: ::std::os::raw::c_uint = 2;
+pub const KVM_MAX_XCRS: ::std::os::raw::c_uint = 16;
+pub const KVM_X86_QUIRK_LINT0_REENABLED: ::std::os::raw::c_uint = 1;
+pub const KVM_X86_QUIRK_CD_NW_CLEARED: ::std::os::raw::c_uint = 2;
+pub const KVM_API_VERSION: ::std::os::raw::c_uint = 12;
+pub const KVM_TRC_SHIFT: ::std::os::raw::c_uint = 16;
+pub const KVM_TRC_ENTRYEXIT: ::std::os::raw::c_uint = 65536;
+pub const KVM_TRC_HANDLER: ::std::os::raw::c_uint = 131072;
+pub const KVM_TRC_VMENTRY: ::std::os::raw::c_uint = 65537;
+pub const KVM_TRC_VMEXIT: ::std::os::raw::c_uint = 65538;
+pub const KVM_TRC_PAGE_FAULT: ::std::os::raw::c_uint = 131073;
+pub const KVM_TRC_HEAD_SIZE: ::std::os::raw::c_uint = 12;
+pub const KVM_TRC_CYCLE_SIZE: ::std::os::raw::c_uint = 8;
+pub const KVM_TRC_EXTRA_MAX: ::std::os::raw::c_uint = 7;
+pub const KVM_TRC_INJ_VIRQ: ::std::os::raw::c_uint = 131074;
+pub const KVM_TRC_REDELIVER_EVT: ::std::os::raw::c_uint = 131075;
+pub const KVM_TRC_PEND_INTR: ::std::os::raw::c_uint = 131076;
+pub const KVM_TRC_IO_READ: ::std::os::raw::c_uint = 131077;
+pub const KVM_TRC_IO_WRITE: ::std::os::raw::c_uint = 131078;
+pub const KVM_TRC_CR_READ: ::std::os::raw::c_uint = 131079;
+pub const KVM_TRC_CR_WRITE: ::std::os::raw::c_uint = 131080;
+pub const KVM_TRC_DR_READ: ::std::os::raw::c_uint = 131081;
+pub const KVM_TRC_DR_WRITE: ::std::os::raw::c_uint = 131082;
+pub const KVM_TRC_MSR_READ: ::std::os::raw::c_uint = 131083;
+pub const KVM_TRC_MSR_WRITE: ::std::os::raw::c_uint = 131084;
+pub const KVM_TRC_CPUID: ::std::os::raw::c_uint = 131085;
+pub const KVM_TRC_INTR: ::std::os::raw::c_uint = 131086;
+pub const KVM_TRC_NMI: ::std::os::raw::c_uint = 131087;
+pub const KVM_TRC_VMMCALL: ::std::os::raw::c_uint = 131088;
+pub const KVM_TRC_HLT: ::std::os::raw::c_uint = 131089;
+pub const KVM_TRC_CLTS: ::std::os::raw::c_uint = 131090;
+pub const KVM_TRC_LMSW: ::std::os::raw::c_uint = 131091;
+pub const KVM_TRC_APIC_ACCESS: ::std::os::raw::c_uint = 131092;
+pub const KVM_TRC_TDP_FAULT: ::std::os::raw::c_uint = 131093;
+pub const KVM_TRC_GTLB_WRITE: ::std::os::raw::c_uint = 131094;
+pub const KVM_TRC_STLB_WRITE: ::std::os::raw::c_uint = 131095;
+pub const KVM_TRC_STLB_INVAL: ::std::os::raw::c_uint = 131096;
+pub const KVM_TRC_PPC_INSTR: ::std::os::raw::c_uint = 131097;
+pub const KVM_MEM_LOG_DIRTY_PAGES: ::std::os::raw::c_uint = 1;
+pub const KVM_MEM_READONLY: ::std::os::raw::c_uint = 2;
+pub const KVM_PIT_SPEAKER_DUMMY: ::std::os::raw::c_uint = 1;
+pub const KVM_S390_GET_SKEYS_NONE: ::std::os::raw::c_uint = 1;
+pub const KVM_S390_SKEYS_MAX: ::std::os::raw::c_uint = 1048576;
+pub const KVM_EXIT_UNKNOWN: ::std::os::raw::c_uint = 0;
+pub const KVM_EXIT_EXCEPTION: ::std::os::raw::c_uint = 1;
+pub const KVM_EXIT_IO: ::std::os::raw::c_uint = 2;
+pub const KVM_EXIT_HYPERCALL: ::std::os::raw::c_uint = 3;
+pub const KVM_EXIT_DEBUG: ::std::os::raw::c_uint = 4;
+pub const KVM_EXIT_HLT: ::std::os::raw::c_uint = 5;
+pub const KVM_EXIT_MMIO: ::std::os::raw::c_uint = 6;
+pub const KVM_EXIT_IRQ_WINDOW_OPEN: ::std::os::raw::c_uint = 7;
+pub const KVM_EXIT_SHUTDOWN: ::std::os::raw::c_uint = 8;
+pub const KVM_EXIT_FAIL_ENTRY: ::std::os::raw::c_uint = 9;
+pub const KVM_EXIT_INTR: ::std::os::raw::c_uint = 10;
+pub const KVM_EXIT_SET_TPR: ::std::os::raw::c_uint = 11;
+pub const KVM_EXIT_TPR_ACCESS: ::std::os::raw::c_uint = 12;
+pub const KVM_EXIT_S390_SIEIC: ::std::os::raw::c_uint = 13;
+pub const KVM_EXIT_S390_RESET: ::std::os::raw::c_uint = 14;
+pub const KVM_EXIT_DCR: ::std::os::raw::c_uint = 15;
+pub const KVM_EXIT_NMI: ::std::os::raw::c_uint = 16;
+pub const KVM_EXIT_INTERNAL_ERROR: ::std::os::raw::c_uint = 17;
+pub const KVM_EXIT_OSI: ::std::os::raw::c_uint = 18;
+pub const KVM_EXIT_PAPR_HCALL: ::std::os::raw::c_uint = 19;
+pub const KVM_EXIT_S390_UCONTROL: ::std::os::raw::c_uint = 20;
+pub const KVM_EXIT_WATCHDOG: ::std::os::raw::c_uint = 21;
+pub const KVM_EXIT_S390_TSCH: ::std::os::raw::c_uint = 22;
+pub const KVM_EXIT_EPR: ::std::os::raw::c_uint = 23;
+pub const KVM_EXIT_SYSTEM_EVENT: ::std::os::raw::c_uint = 24;
+pub const KVM_EXIT_S390_STSI: ::std::os::raw::c_uint = 25;
+pub const KVM_EXIT_IOAPIC_EOI: ::std::os::raw::c_uint = 26;
+pub const KVM_INTERNAL_ERROR_EMULATION: ::std::os::raw::c_uint = 1;
+pub const KVM_INTERNAL_ERROR_SIMUL_EX: ::std::os::raw::c_uint = 2;
+pub const KVM_INTERNAL_ERROR_DELIVERY_EV: ::std::os::raw::c_uint = 3;
+pub const KVM_EXIT_IO_IN: ::std::os::raw::c_uint = 0;
+pub const KVM_EXIT_IO_OUT: ::std::os::raw::c_uint = 1;
+pub const KVM_S390_RESET_POR: ::std::os::raw::c_uint = 1;
+pub const KVM_S390_RESET_CLEAR: ::std::os::raw::c_uint = 2;
+pub const KVM_S390_RESET_SUBSYSTEM: ::std::os::raw::c_uint = 4;
+pub const KVM_S390_RESET_CPU_INIT: ::std::os::raw::c_uint = 8;
+pub const KVM_S390_RESET_IPL: ::std::os::raw::c_uint = 16;
+pub const KVM_SYSTEM_EVENT_SHUTDOWN: ::std::os::raw::c_uint = 1;
+pub const KVM_SYSTEM_EVENT_RESET: ::std::os::raw::c_uint = 2;
+pub const KVM_SYSTEM_EVENT_CRASH: ::std::os::raw::c_uint = 3;
+pub const KVM_S390_MEMOP_LOGICAL_READ: ::std::os::raw::c_uint = 0;
+pub const KVM_S390_MEMOP_LOGICAL_WRITE: ::std::os::raw::c_uint = 1;
+pub const KVM_S390_MEMOP_F_CHECK_ONLY: ::std::os::raw::c_uint = 1;
+pub const KVM_S390_MEMOP_F_INJECT_EXCEPTION: ::std::os::raw::c_uint = 2;
+pub const KVM_MP_STATE_RUNNABLE: ::std::os::raw::c_uint = 0;
+pub const KVM_MP_STATE_UNINITIALIZED: ::std::os::raw::c_uint = 1;
+pub const KVM_MP_STATE_INIT_RECEIVED: ::std::os::raw::c_uint = 2;
+pub const KVM_MP_STATE_HALTED: ::std::os::raw::c_uint = 3;
+pub const KVM_MP_STATE_SIPI_RECEIVED: ::std::os::raw::c_uint = 4;
+pub const KVM_MP_STATE_STOPPED: ::std::os::raw::c_uint = 5;
+pub const KVM_MP_STATE_CHECK_STOP: ::std::os::raw::c_uint = 6;
+pub const KVM_MP_STATE_OPERATING: ::std::os::raw::c_uint = 7;
+pub const KVM_MP_STATE_LOAD: ::std::os::raw::c_uint = 8;
+pub const KVM_S390_SIGP_STOP: ::std::os::raw::c_uint = 4294836224;
+pub const KVM_S390_PROGRAM_INT: ::std::os::raw::c_uint = 4294836225;
+pub const KVM_S390_SIGP_SET_PREFIX: ::std::os::raw::c_uint = 4294836226;
+pub const KVM_S390_RESTART: ::std::os::raw::c_uint = 4294836227;
+pub const KVM_S390_INT_PFAULT_INIT: ::std::os::raw::c_uint = 4294836228;
+pub const KVM_S390_INT_PFAULT_DONE: ::std::os::raw::c_uint = 4294836229;
+pub const KVM_S390_MCHK: ::std::os::raw::c_uint = 4294840320;
+pub const KVM_S390_INT_CLOCK_COMP: ::std::os::raw::c_uint = 4294905860;
+pub const KVM_S390_INT_CPU_TIMER: ::std::os::raw::c_uint = 4294905861;
+pub const KVM_S390_INT_VIRTIO: ::std::os::raw::c_uint = 4294911491;
+pub const KVM_S390_INT_SERVICE: ::std::os::raw::c_uint = 4294910977;
+pub const KVM_S390_INT_EMERGENCY: ::std::os::raw::c_uint = 4294906369;
+pub const KVM_S390_INT_EXTERNAL_CALL: ::std::os::raw::c_uint = 4294906370;
+pub const KVM_S390_INT_IO_MIN: ::std::os::raw::c_uint = 0;
+pub const KVM_S390_INT_IO_MAX: ::std::os::raw::c_uint = 4294836223;
+pub const KVM_S390_INT_IO_AI_MASK: ::std::os::raw::c_uint = 67108864;
+pub const KVM_S390_STOP_FLAG_STORE_STATUS: ::std::os::raw::c_uint = 1;
+pub const KVM_GUESTDBG_ENABLE: ::std::os::raw::c_uint = 1;
+pub const KVM_GUESTDBG_SINGLESTEP: ::std::os::raw::c_uint = 2;
+pub const KVM_PPC_PAGE_SIZES_MAX_SZ: ::std::os::raw::c_uint = 8;
+pub const KVM_PPC_PAGE_SIZES_REAL: ::std::os::raw::c_uint = 1;
+pub const KVM_PPC_1T_SEGMENTS: ::std::os::raw::c_uint = 2;
+pub const KVM_PPC_PVINFO_FLAGS_EV_IDLE: ::std::os::raw::c_uint = 1;
+pub const KVMIO: ::std::os::raw::c_uint = 174;
+pub const KVM_VM_S390_UCONTROL: ::std::os::raw::c_uint = 1;
+pub const KVM_VM_PPC_HV: ::std::os::raw::c_uint = 1;
+pub const KVM_VM_PPC_PR: ::std::os::raw::c_uint = 2;
+pub const KVM_S390_SIE_PAGE_OFFSET: ::std::os::raw::c_uint = 1;
+pub const KVM_CAP_IRQCHIP: ::std::os::raw::c_uint = 0;
+pub const KVM_CAP_HLT: ::std::os::raw::c_uint = 1;
+pub const KVM_CAP_MMU_SHADOW_CACHE_CONTROL: ::std::os::raw::c_uint = 2;
+pub const KVM_CAP_USER_MEMORY: ::std::os::raw::c_uint = 3;
+pub const KVM_CAP_SET_TSS_ADDR: ::std::os::raw::c_uint = 4;
+pub const KVM_CAP_VAPIC: ::std::os::raw::c_uint = 6;
+pub const KVM_CAP_EXT_CPUID: ::std::os::raw::c_uint = 7;
+pub const KVM_CAP_CLOCKSOURCE: ::std::os::raw::c_uint = 8;
+pub const KVM_CAP_NR_VCPUS: ::std::os::raw::c_uint = 9;
+pub const KVM_CAP_NR_MEMSLOTS: ::std::os::raw::c_uint = 10;
+pub const KVM_CAP_PIT: ::std::os::raw::c_uint = 11;
+pub const KVM_CAP_NOP_IO_DELAY: ::std::os::raw::c_uint = 12;
+pub const KVM_CAP_PV_MMU: ::std::os::raw::c_uint = 13;
+pub const KVM_CAP_MP_STATE: ::std::os::raw::c_uint = 14;
+pub const KVM_CAP_COALESCED_MMIO: ::std::os::raw::c_uint = 15;
+pub const KVM_CAP_SYNC_MMU: ::std::os::raw::c_uint = 16;
+pub const KVM_CAP_IOMMU: ::std::os::raw::c_uint = 18;
+pub const KVM_CAP_DESTROY_MEMORY_REGION_WORKS: ::std::os::raw::c_uint = 21;
+pub const KVM_CAP_USER_NMI: ::std::os::raw::c_uint = 22;
+pub const KVM_CAP_SET_GUEST_DEBUG: ::std::os::raw::c_uint = 23;
+pub const KVM_CAP_REINJECT_CONTROL: ::std::os::raw::c_uint = 24;
+pub const KVM_CAP_IRQ_ROUTING: ::std::os::raw::c_uint = 25;
+pub const KVM_CAP_IRQ_INJECT_STATUS: ::std::os::raw::c_uint = 26;
+pub const KVM_CAP_ASSIGN_DEV_IRQ: ::std::os::raw::c_uint = 29;
+pub const KVM_CAP_JOIN_MEMORY_REGIONS_WORKS: ::std::os::raw::c_uint = 30;
+pub const KVM_CAP_MCE: ::std::os::raw::c_uint = 31;
+pub const KVM_CAP_IRQFD: ::std::os::raw::c_uint = 32;
+pub const KVM_CAP_PIT2: ::std::os::raw::c_uint = 33;
+pub const KVM_CAP_SET_BOOT_CPU_ID: ::std::os::raw::c_uint = 34;
+pub const KVM_CAP_PIT_STATE2: ::std::os::raw::c_uint = 35;
+pub const KVM_CAP_IOEVENTFD: ::std::os::raw::c_uint = 36;
+pub const KVM_CAP_SET_IDENTITY_MAP_ADDR: ::std::os::raw::c_uint = 37;
+pub const KVM_CAP_XEN_HVM: ::std::os::raw::c_uint = 38;
+pub const KVM_CAP_ADJUST_CLOCK: ::std::os::raw::c_uint = 39;
+pub const KVM_CAP_INTERNAL_ERROR_DATA: ::std::os::raw::c_uint = 40;
+pub const KVM_CAP_VCPU_EVENTS: ::std::os::raw::c_uint = 41;
+pub const KVM_CAP_S390_PSW: ::std::os::raw::c_uint = 42;
+pub const KVM_CAP_PPC_SEGSTATE: ::std::os::raw::c_uint = 43;
+pub const KVM_CAP_HYPERV: ::std::os::raw::c_uint = 44;
+pub const KVM_CAP_HYPERV_VAPIC: ::std::os::raw::c_uint = 45;
+pub const KVM_CAP_HYPERV_SPIN: ::std::os::raw::c_uint = 46;
+pub const KVM_CAP_PCI_SEGMENT: ::std::os::raw::c_uint = 47;
+pub const KVM_CAP_PPC_PAIRED_SINGLES: ::std::os::raw::c_uint = 48;
+pub const KVM_CAP_INTR_SHADOW: ::std::os::raw::c_uint = 49;
+pub const KVM_CAP_DEBUGREGS: ::std::os::raw::c_uint = 50;
+pub const KVM_CAP_X86_ROBUST_SINGLESTEP: ::std::os::raw::c_uint = 51;
+pub const KVM_CAP_PPC_OSI: ::std::os::raw::c_uint = 52;
+pub const KVM_CAP_PPC_UNSET_IRQ: ::std::os::raw::c_uint = 53;
+pub const KVM_CAP_ENABLE_CAP: ::std::os::raw::c_uint = 54;
+pub const KVM_CAP_XSAVE: ::std::os::raw::c_uint = 55;
+pub const KVM_CAP_XCRS: ::std::os::raw::c_uint = 56;
+pub const KVM_CAP_PPC_GET_PVINFO: ::std::os::raw::c_uint = 57;
+pub const KVM_CAP_PPC_IRQ_LEVEL: ::std::os::raw::c_uint = 58;
+pub const KVM_CAP_ASYNC_PF: ::std::os::raw::c_uint = 59;
+pub const KVM_CAP_TSC_CONTROL: ::std::os::raw::c_uint = 60;
+pub const KVM_CAP_GET_TSC_KHZ: ::std::os::raw::c_uint = 61;
+pub const KVM_CAP_PPC_BOOKE_SREGS: ::std::os::raw::c_uint = 62;
+pub const KVM_CAP_SPAPR_TCE: ::std::os::raw::c_uint = 63;
+pub const KVM_CAP_PPC_SMT: ::std::os::raw::c_uint = 64;
+pub const KVM_CAP_PPC_RMA: ::std::os::raw::c_uint = 65;
+pub const KVM_CAP_MAX_VCPUS: ::std::os::raw::c_uint = 66;
+pub const KVM_CAP_PPC_HIOR: ::std::os::raw::c_uint = 67;
+pub const KVM_CAP_PPC_PAPR: ::std::os::raw::c_uint = 68;
+pub const KVM_CAP_SW_TLB: ::std::os::raw::c_uint = 69;
+pub const KVM_CAP_ONE_REG: ::std::os::raw::c_uint = 70;
+pub const KVM_CAP_S390_GMAP: ::std::os::raw::c_uint = 71;
+pub const KVM_CAP_TSC_DEADLINE_TIMER: ::std::os::raw::c_uint = 72;
+pub const KVM_CAP_S390_UCONTROL: ::std::os::raw::c_uint = 73;
+pub const KVM_CAP_SYNC_REGS: ::std::os::raw::c_uint = 74;
+pub const KVM_CAP_PCI_2_3: ::std::os::raw::c_uint = 75;
+pub const KVM_CAP_KVMCLOCK_CTRL: ::std::os::raw::c_uint = 76;
+pub const KVM_CAP_SIGNAL_MSI: ::std::os::raw::c_uint = 77;
+pub const KVM_CAP_PPC_GET_SMMU_INFO: ::std::os::raw::c_uint = 78;
+pub const KVM_CAP_S390_COW: ::std::os::raw::c_uint = 79;
+pub const KVM_CAP_PPC_ALLOC_HTAB: ::std::os::raw::c_uint = 80;
+pub const KVM_CAP_READONLY_MEM: ::std::os::raw::c_uint = 81;
+pub const KVM_CAP_IRQFD_RESAMPLE: ::std::os::raw::c_uint = 82;
+pub const KVM_CAP_PPC_BOOKE_WATCHDOG: ::std::os::raw::c_uint = 83;
+pub const KVM_CAP_PPC_HTAB_FD: ::std::os::raw::c_uint = 84;
+pub const KVM_CAP_S390_CSS_SUPPORT: ::std::os::raw::c_uint = 85;
+pub const KVM_CAP_PPC_EPR: ::std::os::raw::c_uint = 86;
+pub const KVM_CAP_ARM_PSCI: ::std::os::raw::c_uint = 87;
+pub const KVM_CAP_ARM_SET_DEVICE_ADDR: ::std::os::raw::c_uint = 88;
+pub const KVM_CAP_DEVICE_CTRL: ::std::os::raw::c_uint = 89;
+pub const KVM_CAP_IRQ_MPIC: ::std::os::raw::c_uint = 90;
+pub const KVM_CAP_PPC_RTAS: ::std::os::raw::c_uint = 91;
+pub const KVM_CAP_IRQ_XICS: ::std::os::raw::c_uint = 92;
+pub const KVM_CAP_ARM_EL1_32BIT: ::std::os::raw::c_uint = 93;
+pub const KVM_CAP_SPAPR_MULTITCE: ::std::os::raw::c_uint = 94;
+pub const KVM_CAP_EXT_EMUL_CPUID: ::std::os::raw::c_uint = 95;
+pub const KVM_CAP_HYPERV_TIME: ::std::os::raw::c_uint = 96;
+pub const KVM_CAP_IOAPIC_POLARITY_IGNORED: ::std::os::raw::c_uint = 97;
+pub const KVM_CAP_ENABLE_CAP_VM: ::std::os::raw::c_uint = 98;
+pub const KVM_CAP_S390_IRQCHIP: ::std::os::raw::c_uint = 99;
+pub const KVM_CAP_IOEVENTFD_NO_LENGTH: ::std::os::raw::c_uint = 100;
+pub const KVM_CAP_VM_ATTRIBUTES: ::std::os::raw::c_uint = 101;
+pub const KVM_CAP_ARM_PSCI_0_2: ::std::os::raw::c_uint = 102;
+pub const KVM_CAP_PPC_FIXUP_HCALL: ::std::os::raw::c_uint = 103;
+pub const KVM_CAP_PPC_ENABLE_HCALL: ::std::os::raw::c_uint = 104;
+pub const KVM_CAP_CHECK_EXTENSION_VM: ::std::os::raw::c_uint = 105;
+pub const KVM_CAP_S390_USER_SIGP: ::std::os::raw::c_uint = 106;
+pub const KVM_CAP_S390_VECTOR_REGISTERS: ::std::os::raw::c_uint = 107;
+pub const KVM_CAP_S390_MEM_OP: ::std::os::raw::c_uint = 108;
+pub const KVM_CAP_S390_USER_STSI: ::std::os::raw::c_uint = 109;
+pub const KVM_CAP_S390_SKEYS: ::std::os::raw::c_uint = 110;
+pub const KVM_CAP_MIPS_FPU: ::std::os::raw::c_uint = 111;
+pub const KVM_CAP_MIPS_MSA: ::std::os::raw::c_uint = 112;
+pub const KVM_CAP_S390_INJECT_IRQ: ::std::os::raw::c_uint = 113;
+pub const KVM_CAP_S390_IRQ_STATE: ::std::os::raw::c_uint = 114;
+pub const KVM_CAP_PPC_HWRNG: ::std::os::raw::c_uint = 115;
+pub const KVM_CAP_DISABLE_QUIRKS: ::std::os::raw::c_uint = 116;
+pub const KVM_CAP_X86_SMM: ::std::os::raw::c_uint = 117;
+pub const KVM_CAP_MULTI_ADDRESS_SPACE: ::std::os::raw::c_uint = 118;
+pub const KVM_CAP_GUEST_DEBUG_HW_BPS: ::std::os::raw::c_uint = 119;
+pub const KVM_CAP_GUEST_DEBUG_HW_WPS: ::std::os::raw::c_uint = 120;
+pub const KVM_CAP_SPLIT_IRQCHIP: ::std::os::raw::c_uint = 121;
+pub const KVM_CAP_IOEVENTFD_ANY_LENGTH: ::std::os::raw::c_uint = 122;
+pub const KVM_IRQ_ROUTING_IRQCHIP: ::std::os::raw::c_uint = 1;
+pub const KVM_IRQ_ROUTING_MSI: ::std::os::raw::c_uint = 2;
+pub const KVM_IRQ_ROUTING_S390_ADAPTER: ::std::os::raw::c_uint = 3;
+pub const KVM_IRQFD_FLAG_DEASSIGN: ::std::os::raw::c_uint = 1;
+pub const KVM_IRQFD_FLAG_RESAMPLE: ::std::os::raw::c_uint = 2;
+pub const KVM_MMU_FSL_BOOKE_NOHV: ::std::os::raw::c_uint = 0;
+pub const KVM_MMU_FSL_BOOKE_HV: ::std::os::raw::c_uint = 1;
+pub const KVM_REG_ARCH_MASK: ::std::os::raw::c_longlong = -72057594037927936;
+pub const KVM_REG_GENERIC: ::std::os::raw::c_uint = 0;
+pub const KVM_REG_PPC: ::std::os::raw::c_ulonglong = 1152921504606846976;
+pub const KVM_REG_X86: ::std::os::raw::c_ulonglong = 2305843009213693952;
+pub const KVM_REG_IA64: ::std::os::raw::c_ulonglong = 3458764513820540928;
+pub const KVM_REG_ARM: ::std::os::raw::c_ulonglong = 4611686018427387904;
+pub const KVM_REG_S390: ::std::os::raw::c_ulonglong = 5764607523034234880;
+pub const KVM_REG_ARM64: ::std::os::raw::c_ulonglong = 6917529027641081856;
+pub const KVM_REG_MIPS: ::std::os::raw::c_ulonglong = 8070450532247928832;
+pub const KVM_REG_SIZE_SHIFT: ::std::os::raw::c_uint = 52;
+pub const KVM_REG_SIZE_MASK: ::std::os::raw::c_ulonglong = 67553994410557440;
+pub const KVM_REG_SIZE_U8: ::std::os::raw::c_uint = 0;
+pub const KVM_REG_SIZE_U16: ::std::os::raw::c_ulonglong = 4503599627370496;
+pub const KVM_REG_SIZE_U32: ::std::os::raw::c_ulonglong = 9007199254740992;
+pub const KVM_REG_SIZE_U64: ::std::os::raw::c_ulonglong = 13510798882111488;
+pub const KVM_REG_SIZE_U128: ::std::os::raw::c_ulonglong = 18014398509481984;
+pub const KVM_REG_SIZE_U256: ::std::os::raw::c_ulonglong = 22517998136852480;
+pub const KVM_REG_SIZE_U512: ::std::os::raw::c_ulonglong = 27021597764222976;
+pub const KVM_REG_SIZE_U1024: ::std::os::raw::c_ulonglong = 31525197391593472;
+pub const KVM_CREATE_DEVICE_TEST: ::std::os::raw::c_uint = 1;
+pub const KVM_DEV_VFIO_GROUP: ::std::os::raw::c_uint = 1;
+pub const KVM_DEV_VFIO_GROUP_ADD: ::std::os::raw::c_uint = 1;
+pub const KVM_DEV_VFIO_GROUP_DEL: ::std::os::raw::c_uint = 2;
+pub const KVM_S390_STORE_STATUS_NOADDR: ::std::os::raw::c_int = -1;
+pub const KVM_S390_STORE_STATUS_PREFIXED: ::std::os::raw::c_int = -2;
+pub const KVM_DEV_ASSIGN_ENABLE_IOMMU: ::std::os::raw::c_uint = 1;
+pub const KVM_DEV_ASSIGN_PCI_2_3: ::std::os::raw::c_uint = 2;
+pub const KVM_DEV_ASSIGN_MASK_INTX: ::std::os::raw::c_uint = 4;
+pub const KVM_DEV_IRQ_HOST_INTX: ::std::os::raw::c_uint = 1;
+pub const KVM_DEV_IRQ_HOST_MSI: ::std::os::raw::c_uint = 2;
+pub const KVM_DEV_IRQ_HOST_MSIX: ::std::os::raw::c_uint = 4;
+pub const KVM_DEV_IRQ_GUEST_INTX: ::std::os::raw::c_uint = 256;
+pub const KVM_DEV_IRQ_GUEST_MSI: ::std::os::raw::c_uint = 512;
+pub const KVM_DEV_IRQ_GUEST_MSIX: ::std::os::raw::c_uint = 1024;
+pub const KVM_DEV_IRQ_HOST_MASK: ::std::os::raw::c_uint = 255;
+pub const KVM_DEV_IRQ_GUEST_MASK: ::std::os::raw::c_uint = 65280;
+pub const KVM_MAX_MSIX_PER_DEV: ::std::os::raw::c_uint = 256;
+pub type __s8 = ::std::os::raw::c_schar;
+pub type __u8 = ::std::os::raw::c_uchar;
+pub type __s16 = ::std::os::raw::c_short;
+pub type __u16 = ::std::os::raw::c_ushort;
+pub type __s32 = ::std::os::raw::c_int;
+pub type __u32 = ::std::os::raw::c_uint;
+pub type __s64 = ::std::os::raw::c_longlong;
+pub type __u64 = ::std::os::raw::c_ulonglong;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct __kernel_fd_set {
+    pub fds_bits: [::std::os::raw::c_ulong; 16usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fd_set() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fd_set>(),
+        128usize,
+        concat!("Size of: ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fd_set>(),
+        8usize,
+        concat!("Alignment of ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<__kernel_fd_set>())).fds_bits as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__kernel_fd_set),
+            "::",
+            stringify!(fds_bits)
+        )
+    );
+}
+pub type __kernel_sighandler_t =
+    ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
+pub type __kernel_key_t = ::std::os::raw::c_int;
+pub type __kernel_mqd_t = ::std::os::raw::c_int;
+pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
+pub type __kernel_long_t = ::std::os::raw::c_long;
+pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
+pub type __kernel_ino_t = __kernel_ulong_t;
+pub type __kernel_mode_t = ::std::os::raw::c_uint;
+pub type __kernel_pid_t = ::std::os::raw::c_int;
+pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
+pub type __kernel_uid_t = ::std::os::raw::c_uint;
+pub type __kernel_gid_t = ::std::os::raw::c_uint;
+pub type __kernel_suseconds_t = __kernel_long_t;
+pub type __kernel_daddr_t = ::std::os::raw::c_int;
+pub type __kernel_uid32_t = ::std::os::raw::c_uint;
+pub type __kernel_gid32_t = ::std::os::raw::c_uint;
+pub type __kernel_size_t = __kernel_ulong_t;
+pub type __kernel_ssize_t = __kernel_long_t;
+pub type __kernel_ptrdiff_t = __kernel_long_t;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct __kernel_fsid_t {
+    pub val: [::std::os::raw::c_int; 2usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fsid_t() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fsid_t>(),
+        8usize,
+        concat!("Size of: ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fsid_t>(),
+        4usize,
+        concat!("Alignment of ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<__kernel_fsid_t>())).val as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__kernel_fsid_t),
+            "::",
+            stringify!(val)
+        )
+    );
+}
+pub type __kernel_off_t = __kernel_long_t;
+pub type __kernel_loff_t = ::std::os::raw::c_longlong;
+pub type __kernel_time_t = __kernel_long_t;
+pub type __kernel_clock_t = __kernel_long_t;
+pub type __kernel_timer_t = ::std::os::raw::c_int;
+pub type __kernel_clockid_t = ::std::os::raw::c_int;
+pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
+pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
+pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
+pub type __le16 = __u16;
+pub type __be16 = __u16;
+pub type __le32 = __u32;
+pub type __be32 = __u32;
+pub type __le64 = __u64;
+pub type __be64 = __u64;
+pub type __sum16 = __u16;
+pub type __wsum = __u32;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_memory_alias {
+    pub slot: __u32,
+    pub flags: __u32,
+    pub guest_phys_addr: __u64,
+    pub memory_size: __u64,
+    pub target_phys_addr: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_memory_alias() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_memory_alias>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_memory_alias))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_memory_alias>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_memory_alias))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_memory_alias>())).slot as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_memory_alias),
+            "::",
+            stringify!(slot)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_memory_alias>())).flags as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_memory_alias),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_memory_alias>())).guest_phys_addr as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_memory_alias),
+            "::",
+            stringify!(guest_phys_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_memory_alias>())).memory_size as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_memory_alias),
+            "::",
+            stringify!(memory_size)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_memory_alias>())).target_phys_addr as *const _ as usize
+        },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_memory_alias),
+            "::",
+            stringify!(target_phys_addr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_pic_state {
+    pub last_irr: __u8,
+    pub irr: __u8,
+    pub imr: __u8,
+    pub isr: __u8,
+    pub priority_add: __u8,
+    pub irq_base: __u8,
+    pub read_reg_select: __u8,
+    pub poll: __u8,
+    pub special_mask: __u8,
+    pub init_state: __u8,
+    pub auto_eoi: __u8,
+    pub rotate_on_auto_eoi: __u8,
+    pub special_fully_nested_mode: __u8,
+    pub init4: __u8,
+    pub elcr: __u8,
+    pub elcr_mask: __u8,
+}
+#[test]
+fn bindgen_test_layout_kvm_pic_state() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_pic_state>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_pic_state))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_pic_state>(),
+        1usize,
+        concat!("Alignment of ", stringify!(kvm_pic_state))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pic_state>())).last_irr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(last_irr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pic_state>())).irr as *const _ as usize },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(irr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pic_state>())).imr as *const _ as usize },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(imr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pic_state>())).isr as *const _ as usize },
+        3usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(isr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pic_state>())).priority_add as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(priority_add)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pic_state>())).irq_base as *const _ as usize },
+        5usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(irq_base)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pic_state>())).read_reg_select as *const _ as usize },
+        6usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(read_reg_select)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pic_state>())).poll as *const _ as usize },
+        7usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(poll)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pic_state>())).special_mask as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(special_mask)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pic_state>())).init_state as *const _ as usize },
+        9usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(init_state)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pic_state>())).auto_eoi as *const _ as usize },
+        10usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(auto_eoi)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_pic_state>())).rotate_on_auto_eoi as *const _ as usize
+        },
+        11usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(rotate_on_auto_eoi)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_pic_state>())).special_fully_nested_mode as *const _ as usize
+        },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(special_fully_nested_mode)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pic_state>())).init4 as *const _ as usize },
+        13usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(init4)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pic_state>())).elcr as *const _ as usize },
+        14usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(elcr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pic_state>())).elcr_mask as *const _ as usize },
+        15usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pic_state),
+            "::",
+            stringify!(elcr_mask)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_ioapic_state {
+    pub base_address: __u64,
+    pub ioregsel: __u32,
+    pub id: __u32,
+    pub irr: __u32,
+    pub pad: __u32,
+    pub redirtbl: [kvm_ioapic_state__bindgen_ty_1; 24usize],
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_ioapic_state__bindgen_ty_1 {
+    pub bits: __u64,
+    pub fields: kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1,
+    _bindgen_union_align: u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1 {
+    pub vector: __u8,
+    pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize], u8>,
+    pub reserved: [__u8; 4usize],
+    pub dest_id: __u8,
+}
+#[test]
+fn bindgen_test_layout_kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1>(),
+        8usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1>(),
+        1usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1>())).vector
+                as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1),
+            "::",
+            stringify!(vector)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1>())).reserved
+                as *const _ as usize
+        },
+        3usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1),
+            "::",
+            stringify!(reserved)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1>())).dest_id
+                as *const _ as usize
+        },
+        7usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1),
+            "::",
+            stringify!(dest_id)
+        )
+    );
+}
+impl kvm_ioapic_state__bindgen_ty_1__bindgen_ty_1 {
+    #[inline]
+    pub fn delivery_mode(&self) -> __u8 {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 3u8) as u8) }
+    }
+    #[inline]
+    pub fn set_delivery_mode(&mut self, val: __u8) {
+        unsafe {
+            let val: u8 = ::std::mem::transmute(val);
+            self._bitfield_1.set(0usize, 3u8, val as u64)
+        }
+    }
+    #[inline]
+    pub fn dest_mode(&self) -> __u8 {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(3usize, 1u8) as u8) }
+    }
+    #[inline]
+    pub fn set_dest_mode(&mut self, val: __u8) {
+        unsafe {
+            let val: u8 = ::std::mem::transmute(val);
+            self._bitfield_1.set(3usize, 1u8, val as u64)
+        }
+    }
+    #[inline]
+    pub fn delivery_status(&self) -> __u8 {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(4usize, 1u8) as u8) }
+    }
+    #[inline]
+    pub fn set_delivery_status(&mut self, val: __u8) {
+        unsafe {
+            let val: u8 = ::std::mem::transmute(val);
+            self._bitfield_1.set(4usize, 1u8, val as u64)
+        }
+    }
+    #[inline]
+    pub fn polarity(&self) -> __u8 {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(5usize, 1u8) as u8) }
+    }
+    #[inline]
+    pub fn set_polarity(&mut self, val: __u8) {
+        unsafe {
+            let val: u8 = ::std::mem::transmute(val);
+            self._bitfield_1.set(5usize, 1u8, val as u64)
+        }
+    }
+    #[inline]
+    pub fn remote_irr(&self) -> __u8 {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(6usize, 1u8) as u8) }
+    }
+    #[inline]
+    pub fn set_remote_irr(&mut self, val: __u8) {
+        unsafe {
+            let val: u8 = ::std::mem::transmute(val);
+            self._bitfield_1.set(6usize, 1u8, val as u64)
+        }
+    }
+    #[inline]
+    pub fn trig_mode(&self) -> __u8 {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(7usize, 1u8) as u8) }
+    }
+    #[inline]
+    pub fn set_trig_mode(&mut self, val: __u8) {
+        unsafe {
+            let val: u8 = ::std::mem::transmute(val);
+            self._bitfield_1.set(7usize, 1u8, val as u64)
+        }
+    }
+    #[inline]
+    pub fn mask(&self) -> __u8 {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(8usize, 1u8) as u8) }
+    }
+    #[inline]
+    pub fn set_mask(&mut self, val: __u8) {
+        unsafe {
+            let val: u8 = ::std::mem::transmute(val);
+            self._bitfield_1.set(8usize, 1u8, val as u64)
+        }
+    }
+    #[inline]
+    pub fn reserve(&self) -> __u8 {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(9usize, 7u8) as u8) }
+    }
+    #[inline]
+    pub fn set_reserve(&mut self, val: __u8) {
+        unsafe {
+            let val: u8 = ::std::mem::transmute(val);
+            self._bitfield_1.set(9usize, 7u8, val as u64)
+        }
+    }
+    #[inline]
+    pub fn new_bitfield_1(
+        delivery_mode: __u8,
+        dest_mode: __u8,
+        delivery_status: __u8,
+        polarity: __u8,
+        remote_irr: __u8,
+        trig_mode: __u8,
+        mask: __u8,
+        reserve: __u8,
+    ) -> __BindgenBitfieldUnit<[u8; 2usize], u8> {
+        let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 2usize], u8> =
+            Default::default();
+        __bindgen_bitfield_unit.set(0usize, 3u8, {
+            let delivery_mode: u8 = unsafe { ::std::mem::transmute(delivery_mode) };
+            delivery_mode as u64
+        });
+        __bindgen_bitfield_unit.set(3usize, 1u8, {
+            let dest_mode: u8 = unsafe { ::std::mem::transmute(dest_mode) };
+            dest_mode as u64
+        });
+        __bindgen_bitfield_unit.set(4usize, 1u8, {
+            let delivery_status: u8 = unsafe { ::std::mem::transmute(delivery_status) };
+            delivery_status as u64
+        });
+        __bindgen_bitfield_unit.set(5usize, 1u8, {
+            let polarity: u8 = unsafe { ::std::mem::transmute(polarity) };
+            polarity as u64
+        });
+        __bindgen_bitfield_unit.set(6usize, 1u8, {
+            let remote_irr: u8 = unsafe { ::std::mem::transmute(remote_irr) };
+            remote_irr as u64
+        });
+        __bindgen_bitfield_unit.set(7usize, 1u8, {
+            let trig_mode: u8 = unsafe { ::std::mem::transmute(trig_mode) };
+            trig_mode as u64
+        });
+        __bindgen_bitfield_unit.set(8usize, 1u8, {
+            let mask: u8 = unsafe { ::std::mem::transmute(mask) };
+            mask as u64
+        });
+        __bindgen_bitfield_unit.set(9usize, 7u8, {
+            let reserve: u8 = unsafe { ::std::mem::transmute(reserve) };
+            reserve as u64
+        });
+        __bindgen_bitfield_unit
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_ioapic_state__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_ioapic_state__bindgen_ty_1>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_ioapic_state__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_ioapic_state__bindgen_ty_1>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_ioapic_state__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_ioapic_state__bindgen_ty_1>())).bits as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioapic_state__bindgen_ty_1),
+            "::",
+            stringify!(bits)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_ioapic_state__bindgen_ty_1>())).fields as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioapic_state__bindgen_ty_1),
+            "::",
+            stringify!(fields)
+        )
+    );
+}
+impl Default for kvm_ioapic_state__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_ioapic_state() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_ioapic_state>(),
+        216usize,
+        concat!("Size of: ", stringify!(kvm_ioapic_state))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_ioapic_state>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_ioapic_state))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioapic_state>())).base_address as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioapic_state),
+            "::",
+            stringify!(base_address)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioapic_state>())).ioregsel as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioapic_state),
+            "::",
+            stringify!(ioregsel)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioapic_state>())).id as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioapic_state),
+            "::",
+            stringify!(id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioapic_state>())).irr as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioapic_state),
+            "::",
+            stringify!(irr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioapic_state>())).pad as *const _ as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioapic_state),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioapic_state>())).redirtbl as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioapic_state),
+            "::",
+            stringify!(redirtbl)
+        )
+    );
+}
+impl Default for kvm_ioapic_state {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_regs {
+    pub rax: __u64,
+    pub rbx: __u64,
+    pub rcx: __u64,
+    pub rdx: __u64,
+    pub rsi: __u64,
+    pub rdi: __u64,
+    pub rsp: __u64,
+    pub rbp: __u64,
+    pub r8: __u64,
+    pub r9: __u64,
+    pub r10: __u64,
+    pub r11: __u64,
+    pub r12: __u64,
+    pub r13: __u64,
+    pub r14: __u64,
+    pub r15: __u64,
+    pub rip: __u64,
+    pub rflags: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_regs() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_regs>(),
+        144usize,
+        concat!("Size of: ", stringify!(kvm_regs))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_regs>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_regs))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).rax as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(rax)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).rbx as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(rbx)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).rcx as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(rcx)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).rdx as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(rdx)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).rsi as *const _ as usize },
+        32usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(rsi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).rdi as *const _ as usize },
+        40usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(rdi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).rsp as *const _ as usize },
+        48usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(rsp)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).rbp as *const _ as usize },
+        56usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(rbp)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).r8 as *const _ as usize },
+        64usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(r8)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).r9 as *const _ as usize },
+        72usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(r9)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).r10 as *const _ as usize },
+        80usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(r10)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).r11 as *const _ as usize },
+        88usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(r11)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).r12 as *const _ as usize },
+        96usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(r12)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).r13 as *const _ as usize },
+        104usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(r13)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).r14 as *const _ as usize },
+        112usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(r14)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).r15 as *const _ as usize },
+        120usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(r15)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).rip as *const _ as usize },
+        128usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(rip)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_regs>())).rflags as *const _ as usize },
+        136usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_regs),
+            "::",
+            stringify!(rflags)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_lapic_state {
+    pub regs: [::std::os::raw::c_char; 1024usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_lapic_state() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_lapic_state>(),
+        1024usize,
+        concat!("Size of: ", stringify!(kvm_lapic_state))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_lapic_state>(),
+        1usize,
+        concat!("Alignment of ", stringify!(kvm_lapic_state))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_lapic_state>())).regs as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_lapic_state),
+            "::",
+            stringify!(regs)
+        )
+    );
+}
+impl Default for kvm_lapic_state {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_segment {
+    pub base: __u64,
+    pub limit: __u32,
+    pub selector: __u16,
+    pub type_: __u8,
+    pub present: __u8,
+    pub dpl: __u8,
+    pub db: __u8,
+    pub s: __u8,
+    pub l: __u8,
+    pub g: __u8,
+    pub avl: __u8,
+    pub unusable: __u8,
+    pub padding: __u8,
+}
+#[test]
+fn bindgen_test_layout_kvm_segment() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_segment>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_segment))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_segment>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_segment))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_segment>())).base as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_segment),
+            "::",
+            stringify!(base)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_segment>())).limit as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_segment),
+            "::",
+            stringify!(limit)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_segment>())).selector as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_segment),
+            "::",
+            stringify!(selector)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_segment>())).type_ as *const _ as usize },
+        14usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_segment),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_segment>())).present as *const _ as usize },
+        15usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_segment),
+            "::",
+            stringify!(present)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_segment>())).dpl as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_segment),
+            "::",
+            stringify!(dpl)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_segment>())).db as *const _ as usize },
+        17usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_segment),
+            "::",
+            stringify!(db)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_segment>())).s as *const _ as usize },
+        18usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_segment),
+            "::",
+            stringify!(s)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_segment>())).l as *const _ as usize },
+        19usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_segment),
+            "::",
+            stringify!(l)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_segment>())).g as *const _ as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_segment),
+            "::",
+            stringify!(g)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_segment>())).avl as *const _ as usize },
+        21usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_segment),
+            "::",
+            stringify!(avl)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_segment>())).unusable as *const _ as usize },
+        22usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_segment),
+            "::",
+            stringify!(unusable)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_segment>())).padding as *const _ as usize },
+        23usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_segment),
+            "::",
+            stringify!(padding)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_dtable {
+    pub base: __u64,
+    pub limit: __u16,
+    pub padding: [__u16; 3usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_dtable() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_dtable>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_dtable))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_dtable>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_dtable))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_dtable>())).base as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dtable),
+            "::",
+            stringify!(base)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_dtable>())).limit as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dtable),
+            "::",
+            stringify!(limit)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_dtable>())).padding as *const _ as usize },
+        10usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dtable),
+            "::",
+            stringify!(padding)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sregs {
+    pub cs: kvm_segment,
+    pub ds: kvm_segment,
+    pub es: kvm_segment,
+    pub fs: kvm_segment,
+    pub gs: kvm_segment,
+    pub ss: kvm_segment,
+    pub tr: kvm_segment,
+    pub ldt: kvm_segment,
+    pub gdt: kvm_dtable,
+    pub idt: kvm_dtable,
+    pub cr0: __u64,
+    pub cr2: __u64,
+    pub cr3: __u64,
+    pub cr4: __u64,
+    pub cr8: __u64,
+    pub efer: __u64,
+    pub apic_base: __u64,
+    pub interrupt_bitmap: [__u64; 4usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_sregs() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_sregs>(),
+        312usize,
+        concat!("Size of: ", stringify!(kvm_sregs))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_sregs>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_sregs))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).cs as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(cs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).ds as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(ds)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).es as *const _ as usize },
+        48usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(es)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).fs as *const _ as usize },
+        72usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(fs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).gs as *const _ as usize },
+        96usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(gs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).ss as *const _ as usize },
+        120usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(ss)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).tr as *const _ as usize },
+        144usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(tr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).ldt as *const _ as usize },
+        168usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(ldt)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).gdt as *const _ as usize },
+        192usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(gdt)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).idt as *const _ as usize },
+        208usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(idt)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).cr0 as *const _ as usize },
+        224usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(cr0)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).cr2 as *const _ as usize },
+        232usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(cr2)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).cr3 as *const _ as usize },
+        240usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(cr3)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).cr4 as *const _ as usize },
+        248usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(cr4)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).cr8 as *const _ as usize },
+        256usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(cr8)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).efer as *const _ as usize },
+        264usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(efer)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).apic_base as *const _ as usize },
+        272usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(apic_base)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_sregs>())).interrupt_bitmap as *const _ as usize },
+        280usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_sregs),
+            "::",
+            stringify!(interrupt_bitmap)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_fpu {
+    pub fpr: [[__u8; 16usize]; 8usize],
+    pub fcw: __u16,
+    pub fsw: __u16,
+    pub ftwx: __u8,
+    pub pad1: __u8,
+    pub last_opcode: __u16,
+    pub last_ip: __u64,
+    pub last_dp: __u64,
+    pub xmm: [[__u8; 16usize]; 16usize],
+    pub mxcsr: __u32,
+    pub pad2: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_fpu() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_fpu>(),
+        416usize,
+        concat!("Size of: ", stringify!(kvm_fpu))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_fpu>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_fpu))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_fpu>())).fpr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_fpu),
+            "::",
+            stringify!(fpr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_fpu>())).fcw as *const _ as usize },
+        128usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_fpu),
+            "::",
+            stringify!(fcw)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_fpu>())).fsw as *const _ as usize },
+        130usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_fpu),
+            "::",
+            stringify!(fsw)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_fpu>())).ftwx as *const _ as usize },
+        132usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_fpu),
+            "::",
+            stringify!(ftwx)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_fpu>())).pad1 as *const _ as usize },
+        133usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_fpu),
+            "::",
+            stringify!(pad1)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_fpu>())).last_opcode as *const _ as usize },
+        134usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_fpu),
+            "::",
+            stringify!(last_opcode)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_fpu>())).last_ip as *const _ as usize },
+        136usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_fpu),
+            "::",
+            stringify!(last_ip)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_fpu>())).last_dp as *const _ as usize },
+        144usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_fpu),
+            "::",
+            stringify!(last_dp)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_fpu>())).xmm as *const _ as usize },
+        152usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_fpu),
+            "::",
+            stringify!(xmm)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_fpu>())).mxcsr as *const _ as usize },
+        408usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_fpu),
+            "::",
+            stringify!(mxcsr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_fpu>())).pad2 as *const _ as usize },
+        412usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_fpu),
+            "::",
+            stringify!(pad2)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_msr_entry {
+    pub index: __u32,
+    pub reserved: __u32,
+    pub data: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_msr_entry() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_msr_entry>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_msr_entry))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_msr_entry>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_msr_entry))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msr_entry>())).index as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msr_entry),
+            "::",
+            stringify!(index)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msr_entry>())).reserved as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msr_entry),
+            "::",
+            stringify!(reserved)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msr_entry>())).data as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msr_entry),
+            "::",
+            stringify!(data)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct kvm_msrs {
+    pub nmsrs: __u32,
+    pub pad: __u32,
+    pub entries: __IncompleteArrayField<kvm_msr_entry>,
+    // Manually added to work around rust bindgen issue 684
+    __force_alignment: [u64; 0],
+}
+#[test]
+fn bindgen_test_layout_kvm_msrs() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_msrs>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_msrs))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_msrs>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_msrs))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msrs>())).nmsrs as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msrs),
+            "::",
+            stringify!(nmsrs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msrs>())).pad as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msrs),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msrs>())).entries as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msrs),
+            "::",
+            stringify!(entries)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct kvm_msr_list {
+    pub nmsrs: __u32,
+    pub indices: __IncompleteArrayField<__u32>,
+}
+#[test]
+fn bindgen_test_layout_kvm_msr_list() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_msr_list>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_msr_list))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_msr_list>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_msr_list))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msr_list>())).nmsrs as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msr_list),
+            "::",
+            stringify!(nmsrs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msr_list>())).indices as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msr_list),
+            "::",
+            stringify!(indices)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_cpuid_entry {
+    pub function: __u32,
+    pub eax: __u32,
+    pub ebx: __u32,
+    pub ecx: __u32,
+    pub edx: __u32,
+    pub padding: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_cpuid_entry() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_cpuid_entry>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_cpuid_entry))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_cpuid_entry>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_cpuid_entry))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid_entry>())).function as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid_entry),
+            "::",
+            stringify!(function)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid_entry>())).eax as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid_entry),
+            "::",
+            stringify!(eax)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid_entry>())).ebx as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid_entry),
+            "::",
+            stringify!(ebx)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid_entry>())).ecx as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid_entry),
+            "::",
+            stringify!(ecx)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid_entry>())).edx as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid_entry),
+            "::",
+            stringify!(edx)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid_entry>())).padding as *const _ as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid_entry),
+            "::",
+            stringify!(padding)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct kvm_cpuid {
+    pub nent: __u32,
+    pub padding: __u32,
+    pub entries: __IncompleteArrayField<kvm_cpuid_entry>,
+}
+#[test]
+fn bindgen_test_layout_kvm_cpuid() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_cpuid>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_cpuid))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_cpuid>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_cpuid))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid>())).nent as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid),
+            "::",
+            stringify!(nent)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid>())).padding as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid),
+            "::",
+            stringify!(padding)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid>())).entries as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid),
+            "::",
+            stringify!(entries)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_cpuid_entry2 {
+    pub function: __u32,
+    pub index: __u32,
+    pub flags: __u32,
+    pub eax: __u32,
+    pub ebx: __u32,
+    pub ecx: __u32,
+    pub edx: __u32,
+    pub padding: [__u32; 3usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_cpuid_entry2() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_cpuid_entry2>(),
+        40usize,
+        concat!("Size of: ", stringify!(kvm_cpuid_entry2))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_cpuid_entry2>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_cpuid_entry2))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid_entry2>())).function as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid_entry2),
+            "::",
+            stringify!(function)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid_entry2>())).index as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid_entry2),
+            "::",
+            stringify!(index)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid_entry2>())).flags as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid_entry2),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid_entry2>())).eax as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid_entry2),
+            "::",
+            stringify!(eax)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid_entry2>())).ebx as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid_entry2),
+            "::",
+            stringify!(ebx)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid_entry2>())).ecx as *const _ as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid_entry2),
+            "::",
+            stringify!(ecx)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid_entry2>())).edx as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid_entry2),
+            "::",
+            stringify!(edx)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid_entry2>())).padding as *const _ as usize },
+        28usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid_entry2),
+            "::",
+            stringify!(padding)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct kvm_cpuid2 {
+    pub nent: __u32,
+    pub padding: __u32,
+    pub entries: __IncompleteArrayField<kvm_cpuid_entry2>,
+}
+#[test]
+fn bindgen_test_layout_kvm_cpuid2() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_cpuid2>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_cpuid2))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_cpuid2>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_cpuid2))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid2>())).nent as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid2),
+            "::",
+            stringify!(nent)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid2>())).padding as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid2),
+            "::",
+            stringify!(padding)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_cpuid2>())).entries as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_cpuid2),
+            "::",
+            stringify!(entries)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_pit_channel_state {
+    pub count: __u32,
+    pub latched_count: __u16,
+    pub count_latched: __u8,
+    pub status_latched: __u8,
+    pub status: __u8,
+    pub read_state: __u8,
+    pub write_state: __u8,
+    pub write_latch: __u8,
+    pub rw_mode: __u8,
+    pub mode: __u8,
+    pub bcd: __u8,
+    pub gate: __u8,
+    pub count_load_time: __s64,
+}
+#[test]
+fn bindgen_test_layout_kvm_pit_channel_state() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_pit_channel_state>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_pit_channel_state))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_pit_channel_state>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_pit_channel_state))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pit_channel_state>())).count as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_channel_state),
+            "::",
+            stringify!(count)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_pit_channel_state>())).latched_count as *const _ as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_channel_state),
+            "::",
+            stringify!(latched_count)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_pit_channel_state>())).count_latched as *const _ as usize
+        },
+        6usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_channel_state),
+            "::",
+            stringify!(count_latched)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_pit_channel_state>())).status_latched as *const _ as usize
+        },
+        7usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_channel_state),
+            "::",
+            stringify!(status_latched)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pit_channel_state>())).status as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_channel_state),
+            "::",
+            stringify!(status)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_pit_channel_state>())).read_state as *const _ as usize
+        },
+        9usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_channel_state),
+            "::",
+            stringify!(read_state)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_pit_channel_state>())).write_state as *const _ as usize
+        },
+        10usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_channel_state),
+            "::",
+            stringify!(write_state)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_pit_channel_state>())).write_latch as *const _ as usize
+        },
+        11usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_channel_state),
+            "::",
+            stringify!(write_latch)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pit_channel_state>())).rw_mode as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_channel_state),
+            "::",
+            stringify!(rw_mode)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pit_channel_state>())).mode as *const _ as usize },
+        13usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_channel_state),
+            "::",
+            stringify!(mode)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pit_channel_state>())).bcd as *const _ as usize },
+        14usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_channel_state),
+            "::",
+            stringify!(bcd)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pit_channel_state>())).gate as *const _ as usize },
+        15usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_channel_state),
+            "::",
+            stringify!(gate)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_pit_channel_state>())).count_load_time as *const _ as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_channel_state),
+            "::",
+            stringify!(count_load_time)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_debug_exit_arch {
+    pub exception: __u32,
+    pub pad: __u32,
+    pub pc: __u64,
+    pub dr6: __u64,
+    pub dr7: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_debug_exit_arch() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_debug_exit_arch>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_debug_exit_arch))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_debug_exit_arch>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_debug_exit_arch))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_exit_arch>())).exception as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_exit_arch),
+            "::",
+            stringify!(exception)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_exit_arch>())).pad as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_exit_arch),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_exit_arch>())).pc as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_exit_arch),
+            "::",
+            stringify!(pc)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_exit_arch>())).dr6 as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_exit_arch),
+            "::",
+            stringify!(dr6)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_exit_arch>())).dr7 as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_exit_arch),
+            "::",
+            stringify!(dr7)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_guest_debug_arch {
+    pub debugreg: [__u64; 8usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_guest_debug_arch() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_guest_debug_arch>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_guest_debug_arch))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_guest_debug_arch>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_guest_debug_arch))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_guest_debug_arch>())).debugreg as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_guest_debug_arch),
+            "::",
+            stringify!(debugreg)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_pit_state {
+    pub channels: [kvm_pit_channel_state; 3usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_pit_state() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_pit_state>(),
+        72usize,
+        concat!("Size of: ", stringify!(kvm_pit_state))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_pit_state>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_pit_state))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pit_state>())).channels as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_state),
+            "::",
+            stringify!(channels)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_pit_state2 {
+    pub channels: [kvm_pit_channel_state; 3usize],
+    pub flags: __u32,
+    pub reserved: [__u32; 9usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_pit_state2() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_pit_state2>(),
+        112usize,
+        concat!("Size of: ", stringify!(kvm_pit_state2))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_pit_state2>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_pit_state2))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pit_state2>())).channels as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_state2),
+            "::",
+            stringify!(channels)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pit_state2>())).flags as *const _ as usize },
+        72usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_state2),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pit_state2>())).reserved as *const _ as usize },
+        76usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_state2),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_reinject_control {
+    pub pit_reinject: __u8,
+    pub reserved: [__u8; 31usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_reinject_control() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_reinject_control>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_reinject_control))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_reinject_control>(),
+        1usize,
+        concat!("Alignment of ", stringify!(kvm_reinject_control))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_reinject_control>())).pit_reinject as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_reinject_control),
+            "::",
+            stringify!(pit_reinject)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_reinject_control>())).reserved as *const _ as usize },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_reinject_control),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_vcpu_events {
+    pub exception: kvm_vcpu_events__bindgen_ty_1,
+    pub interrupt: kvm_vcpu_events__bindgen_ty_2,
+    pub nmi: kvm_vcpu_events__bindgen_ty_3,
+    pub sipi_vector: __u32,
+    pub flags: __u32,
+    pub smi: kvm_vcpu_events__bindgen_ty_4,
+    pub reserved: [__u32; 9usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_vcpu_events__bindgen_ty_1 {
+    pub injected: __u8,
+    pub nr: __u8,
+    pub has_error_code: __u8,
+    pub pad: __u8,
+    pub error_code: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_vcpu_events__bindgen_ty_1>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_vcpu_events__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_vcpu_events__bindgen_ty_1>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_vcpu_events__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_1>())).injected as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_1),
+            "::",
+            stringify!(injected)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_1>())).nr as *const _ as usize
+        },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_1),
+            "::",
+            stringify!(nr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_1>())).has_error_code as *const _
+                as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_1),
+            "::",
+            stringify!(has_error_code)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_1>())).pad as *const _ as usize
+        },
+        3usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_1),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_1>())).error_code as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_1),
+            "::",
+            stringify!(error_code)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_vcpu_events__bindgen_ty_2 {
+    pub injected: __u8,
+    pub nr: __u8,
+    pub soft: __u8,
+    pub shadow: __u8,
+}
+#[test]
+fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_2() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_vcpu_events__bindgen_ty_2>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_vcpu_events__bindgen_ty_2))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_vcpu_events__bindgen_ty_2>(),
+        1usize,
+        concat!("Alignment of ", stringify!(kvm_vcpu_events__bindgen_ty_2))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_2>())).injected as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_2),
+            "::",
+            stringify!(injected)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_2>())).nr as *const _ as usize
+        },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_2),
+            "::",
+            stringify!(nr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_2>())).soft as *const _ as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_2),
+            "::",
+            stringify!(soft)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_2>())).shadow as *const _ as usize
+        },
+        3usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_2),
+            "::",
+            stringify!(shadow)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_vcpu_events__bindgen_ty_3 {
+    pub injected: __u8,
+    pub pending: __u8,
+    pub masked: __u8,
+    pub pad: __u8,
+}
+#[test]
+fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_3() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_vcpu_events__bindgen_ty_3>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_vcpu_events__bindgen_ty_3))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_vcpu_events__bindgen_ty_3>(),
+        1usize,
+        concat!("Alignment of ", stringify!(kvm_vcpu_events__bindgen_ty_3))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_3>())).injected as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_3),
+            "::",
+            stringify!(injected)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_3>())).pending as *const _ as usize
+        },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_3),
+            "::",
+            stringify!(pending)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_3>())).masked as *const _ as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_3),
+            "::",
+            stringify!(masked)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_3>())).pad as *const _ as usize
+        },
+        3usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_3),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_vcpu_events__bindgen_ty_4 {
+    pub smm: __u8,
+    pub pending: __u8,
+    pub smm_inside_nmi: __u8,
+    pub latched_init: __u8,
+}
+#[test]
+fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_4() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_vcpu_events__bindgen_ty_4>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_vcpu_events__bindgen_ty_4))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_vcpu_events__bindgen_ty_4>(),
+        1usize,
+        concat!("Alignment of ", stringify!(kvm_vcpu_events__bindgen_ty_4))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_4>())).smm as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_4),
+            "::",
+            stringify!(smm)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_4>())).pending as *const _ as usize
+        },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_4),
+            "::",
+            stringify!(pending)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_4>())).smm_inside_nmi as *const _
+                as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_4),
+            "::",
+            stringify!(smm_inside_nmi)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_4>())).latched_init as *const _
+                as usize
+        },
+        3usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events__bindgen_ty_4),
+            "::",
+            stringify!(latched_init)
+        )
+    );
+}
+#[test]
+fn bindgen_test_layout_kvm_vcpu_events() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_vcpu_events>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_vcpu_events))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_vcpu_events>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_vcpu_events))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_vcpu_events>())).exception as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events),
+            "::",
+            stringify!(exception)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_vcpu_events>())).interrupt as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events),
+            "::",
+            stringify!(interrupt)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_vcpu_events>())).nmi as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events),
+            "::",
+            stringify!(nmi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_vcpu_events>())).sipi_vector as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events),
+            "::",
+            stringify!(sipi_vector)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_vcpu_events>())).flags as *const _ as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_vcpu_events>())).smi as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events),
+            "::",
+            stringify!(smi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_vcpu_events>())).reserved as *const _ as usize },
+        28usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vcpu_events),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_debugregs {
+    pub db: [__u64; 4usize],
+    pub dr6: __u64,
+    pub dr7: __u64,
+    pub flags: __u64,
+    pub reserved: [__u64; 9usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_debugregs() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_debugregs>(),
+        128usize,
+        concat!("Size of: ", stringify!(kvm_debugregs))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_debugregs>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_debugregs))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debugregs>())).db as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debugregs),
+            "::",
+            stringify!(db)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debugregs>())).dr6 as *const _ as usize },
+        32usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debugregs),
+            "::",
+            stringify!(dr6)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debugregs>())).dr7 as *const _ as usize },
+        40usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debugregs),
+            "::",
+            stringify!(dr7)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debugregs>())).flags as *const _ as usize },
+        48usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debugregs),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debugregs>())).reserved as *const _ as usize },
+        56usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debugregs),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_xsave {
+    pub region: [__u32; 1024usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_xsave() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_xsave>(),
+        4096usize,
+        concat!("Size of: ", stringify!(kvm_xsave))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_xsave>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_xsave))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xsave>())).region as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xsave),
+            "::",
+            stringify!(region)
+        )
+    );
+}
+impl Default for kvm_xsave {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_xcr {
+    pub xcr: __u32,
+    pub reserved: __u32,
+    pub value: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_xcr() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_xcr>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_xcr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_xcr>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_xcr))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xcr>())).xcr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xcr),
+            "::",
+            stringify!(xcr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xcr>())).reserved as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xcr),
+            "::",
+            stringify!(reserved)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xcr>())).value as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xcr),
+            "::",
+            stringify!(value)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_xcrs {
+    pub nr_xcrs: __u32,
+    pub flags: __u32,
+    pub xcrs: [kvm_xcr; 16usize],
+    pub padding: [__u64; 16usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_xcrs() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_xcrs>(),
+        392usize,
+        concat!("Size of: ", stringify!(kvm_xcrs))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_xcrs>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_xcrs))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xcrs>())).nr_xcrs as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xcrs),
+            "::",
+            stringify!(nr_xcrs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xcrs>())).flags as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xcrs),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xcrs>())).xcrs as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xcrs),
+            "::",
+            stringify!(xcrs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xcrs>())).padding as *const _ as usize },
+        264usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xcrs),
+            "::",
+            stringify!(padding)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sync_regs {}
+#[test]
+fn bindgen_test_layout_kvm_sync_regs() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_sync_regs>(),
+        0usize,
+        concat!("Size of: ", stringify!(kvm_sync_regs))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_sync_regs>(),
+        1usize,
+        concat!("Alignment of ", stringify!(kvm_sync_regs))
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_user_trace_setup {
+    pub buf_size: __u32,
+    pub buf_nr: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_user_trace_setup() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_user_trace_setup>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_user_trace_setup))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_user_trace_setup>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_user_trace_setup))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_user_trace_setup>())).buf_size as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_user_trace_setup),
+            "::",
+            stringify!(buf_size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_user_trace_setup>())).buf_nr as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_user_trace_setup),
+            "::",
+            stringify!(buf_nr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_breakpoint {
+    pub enabled: __u32,
+    pub padding: __u32,
+    pub address: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_breakpoint() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_breakpoint>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_breakpoint))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_breakpoint>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_breakpoint))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_breakpoint>())).enabled as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_breakpoint),
+            "::",
+            stringify!(enabled)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_breakpoint>())).padding as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_breakpoint),
+            "::",
+            stringify!(padding)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_breakpoint>())).address as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_breakpoint),
+            "::",
+            stringify!(address)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_debug_guest {
+    pub enabled: __u32,
+    pub pad: __u32,
+    pub breakpoints: [kvm_breakpoint; 4usize],
+    pub singlestep: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_debug_guest() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_debug_guest>(),
+        80usize,
+        concat!("Size of: ", stringify!(kvm_debug_guest))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_debug_guest>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_debug_guest))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_guest>())).enabled as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_guest),
+            "::",
+            stringify!(enabled)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_guest>())).pad as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_guest),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_guest>())).breakpoints as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_guest),
+            "::",
+            stringify!(breakpoints)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_debug_guest>())).singlestep as *const _ as usize },
+        72usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_debug_guest),
+            "::",
+            stringify!(singlestep)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_memory_region {
+    pub slot: __u32,
+    pub flags: __u32,
+    pub guest_phys_addr: __u64,
+    pub memory_size: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_memory_region() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_memory_region>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_memory_region))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_memory_region>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_memory_region))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_memory_region>())).slot as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_memory_region),
+            "::",
+            stringify!(slot)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_memory_region>())).flags as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_memory_region),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_memory_region>())).guest_phys_addr as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_memory_region),
+            "::",
+            stringify!(guest_phys_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_memory_region>())).memory_size as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_memory_region),
+            "::",
+            stringify!(memory_size)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_userspace_memory_region {
+    pub slot: __u32,
+    pub flags: __u32,
+    pub guest_phys_addr: __u64,
+    pub memory_size: __u64,
+    pub userspace_addr: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_userspace_memory_region() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_userspace_memory_region>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_userspace_memory_region))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_userspace_memory_region>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_userspace_memory_region))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_userspace_memory_region>())).slot as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_userspace_memory_region),
+            "::",
+            stringify!(slot)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_userspace_memory_region>())).flags as *const _ as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_userspace_memory_region),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_userspace_memory_region>())).guest_phys_addr as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_userspace_memory_region),
+            "::",
+            stringify!(guest_phys_addr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_userspace_memory_region>())).memory_size as *const _ as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_userspace_memory_region),
+            "::",
+            stringify!(memory_size)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_userspace_memory_region>())).userspace_addr as *const _
+                as usize
+        },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_userspace_memory_region),
+            "::",
+            stringify!(userspace_addr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_irq_level {
+    pub __bindgen_anon_1: kvm_irq_level__bindgen_ty_1,
+    pub level: __u32,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_irq_level__bindgen_ty_1 {
+    pub irq: __u32,
+    pub status: __s32,
+    _bindgen_union_align: u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_level__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_level__bindgen_ty_1>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_irq_level__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_level__bindgen_ty_1>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_irq_level__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_level__bindgen_ty_1>())).irq as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_level__bindgen_ty_1),
+            "::",
+            stringify!(irq)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_level__bindgen_ty_1>())).status as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_level__bindgen_ty_1),
+            "::",
+            stringify!(status)
+        )
+    );
+}
+impl Default for kvm_irq_level__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_level() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_level>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_irq_level))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_level>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_irq_level))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_level>())).level as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_level),
+            "::",
+            stringify!(level)
+        )
+    );
+}
+impl Default for kvm_irq_level {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_irqchip {
+    pub chip_id: __u32,
+    pub pad: __u32,
+    pub chip: kvm_irqchip__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_irqchip__bindgen_ty_1 {
+    pub dummy: [::std::os::raw::c_char; 512usize],
+    pub pic: kvm_pic_state,
+    pub ioapic: kvm_ioapic_state,
+    _bindgen_union_align: [u64; 64usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_irqchip__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irqchip__bindgen_ty_1>(),
+        512usize,
+        concat!("Size of: ", stringify!(kvm_irqchip__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irqchip__bindgen_ty_1>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_irqchip__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqchip__bindgen_ty_1>())).dummy as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqchip__bindgen_ty_1),
+            "::",
+            stringify!(dummy)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqchip__bindgen_ty_1>())).pic as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqchip__bindgen_ty_1),
+            "::",
+            stringify!(pic)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irqchip__bindgen_ty_1>())).ioapic as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqchip__bindgen_ty_1),
+            "::",
+            stringify!(ioapic)
+        )
+    );
+}
+impl Default for kvm_irqchip__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_irqchip() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irqchip>(),
+        520usize,
+        concat!("Size of: ", stringify!(kvm_irqchip))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irqchip>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_irqchip))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqchip>())).chip_id as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqchip),
+            "::",
+            stringify!(chip_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqchip>())).pad as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqchip),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqchip>())).chip as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqchip),
+            "::",
+            stringify!(chip)
+        )
+    );
+}
+impl Default for kvm_irqchip {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_pit_config {
+    pub flags: __u32,
+    pub pad: [__u32; 15usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_pit_config() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_pit_config>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_pit_config))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_pit_config>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_pit_config))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pit_config>())).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_config),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_pit_config>())).pad as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_pit_config),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_skeys {
+    pub start_gfn: __u64,
+    pub count: __u64,
+    pub skeydata_addr: __u64,
+    pub flags: __u32,
+    pub reserved: [__u32; 9usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_skeys() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_skeys>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_s390_skeys))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_skeys>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_skeys))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_skeys>())).start_gfn as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_skeys),
+            "::",
+            stringify!(start_gfn)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_skeys>())).count as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_skeys),
+            "::",
+            stringify!(count)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_skeys>())).skeydata_addr as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_skeys),
+            "::",
+            stringify!(skeydata_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_skeys>())).flags as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_skeys),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_skeys>())).reserved as *const _ as usize },
+        28usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_skeys),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_run {
+    pub request_interrupt_window: __u8,
+    pub padding1: [__u8; 7usize],
+    pub exit_reason: __u32,
+    pub ready_for_interrupt_injection: __u8,
+    pub if_flag: __u8,
+    pub flags: __u16,
+    pub cr8: __u64,
+    pub apic_base: __u64,
+    pub __bindgen_anon_1: kvm_run__bindgen_ty_1,
+    pub kvm_valid_regs: __u64,
+    pub kvm_dirty_regs: __u64,
+    pub s: kvm_run__bindgen_ty_2,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_1 {
+    pub hardware_exit_reason: __u64,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_run__bindgen_ty_1 {
+    pub hw: kvm_run__bindgen_ty_1__bindgen_ty_1,
+    pub fail_entry: kvm_run__bindgen_ty_1__bindgen_ty_2,
+    pub ex: kvm_run__bindgen_ty_1__bindgen_ty_3,
+    pub io: kvm_run__bindgen_ty_1__bindgen_ty_4,
+    pub debug: kvm_run__bindgen_ty_1__bindgen_ty_5,
+    pub mmio: kvm_run__bindgen_ty_1__bindgen_ty_6,
+    pub hypercall: kvm_run__bindgen_ty_1__bindgen_ty_7,
+    pub tpr_access: kvm_run__bindgen_ty_1__bindgen_ty_8,
+    pub s390_sieic: kvm_run__bindgen_ty_1__bindgen_ty_9,
+    pub s390_reset_flags: __u64,
+    pub s390_ucontrol: kvm_run__bindgen_ty_1__bindgen_ty_10,
+    pub dcr: kvm_run__bindgen_ty_1__bindgen_ty_11,
+    pub internal: kvm_run__bindgen_ty_1__bindgen_ty_12,
+    pub osi: kvm_run__bindgen_ty_1__bindgen_ty_13,
+    pub papr_hcall: kvm_run__bindgen_ty_1__bindgen_ty_14,
+    pub s390_tsch: kvm_run__bindgen_ty_1__bindgen_ty_15,
+    pub epr: kvm_run__bindgen_ty_1__bindgen_ty_16,
+    pub system_event: kvm_run__bindgen_ty_1__bindgen_ty_17,
+    pub s390_stsi: kvm_run__bindgen_ty_1__bindgen_ty_18,
+    pub eoi: kvm_run__bindgen_ty_1__bindgen_ty_19,
+    pub padding: [::std::os::raw::c_char; 256usize],
+    _bindgen_union_align: [u64; 32usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_1>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_1>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_1>())).hardware_exit_reason
+                as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_1),
+            "::",
+            stringify!(hardware_exit_reason)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_2 {
+    pub hardware_entry_failure_reason: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_2() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_2>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_2>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_2>()))
+                .hardware_entry_failure_reason as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_2),
+            "::",
+            stringify!(hardware_entry_failure_reason)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_3 {
+    pub exception: __u32,
+    pub error_code: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_3() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_3>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_3>(),
+        4usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_3>())).exception as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3),
+            "::",
+            stringify!(exception)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_3>())).error_code as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_3),
+            "::",
+            stringify!(error_code)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_4 {
+    pub direction: __u8,
+    pub size: __u8,
+    pub port: __u16,
+    pub count: __u32,
+    pub data_offset: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_4() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_4>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_4>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_4>())).direction as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4),
+            "::",
+            stringify!(direction)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_4>())).size as *const _
+                as usize
+        },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4),
+            "::",
+            stringify!(size)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_4>())).port as *const _
+                as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4),
+            "::",
+            stringify!(port)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_4>())).count as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4),
+            "::",
+            stringify!(count)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_4>())).data_offset as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_4),
+            "::",
+            stringify!(data_offset)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_5 {
+    pub arch: kvm_debug_exit_arch,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_5() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_5>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_5>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_5>())).arch as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_5),
+            "::",
+            stringify!(arch)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_6 {
+    pub phys_addr: __u64,
+    pub data: [__u8; 8usize],
+    pub len: __u32,
+    pub is_write: __u8,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_6() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_6>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_6>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_6>())).phys_addr as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6),
+            "::",
+            stringify!(phys_addr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_6>())).data as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6),
+            "::",
+            stringify!(data)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_6>())).len as *const _ as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6),
+            "::",
+            stringify!(len)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_6>())).is_write as *const _
+                as usize
+        },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_6),
+            "::",
+            stringify!(is_write)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_7 {
+    pub nr: __u64,
+    pub args: [__u64; 6usize],
+    pub ret: __u64,
+    pub longmode: __u32,
+    pub pad: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_7() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_7>(),
+        72usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_7>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_7>())).nr as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7),
+            "::",
+            stringify!(nr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_7>())).args as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7),
+            "::",
+            stringify!(args)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_7>())).ret as *const _ as usize
+        },
+        56usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7),
+            "::",
+            stringify!(ret)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_7>())).longmode as *const _
+                as usize
+        },
+        64usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7),
+            "::",
+            stringify!(longmode)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_7>())).pad as *const _ as usize
+        },
+        68usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_7),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_8 {
+    pub rip: __u64,
+    pub is_write: __u32,
+    pub pad: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_8() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_8>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_8>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_8>())).rip as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8),
+            "::",
+            stringify!(rip)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_8>())).is_write as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8),
+            "::",
+            stringify!(is_write)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_8>())).pad as *const _ as usize
+        },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_8),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_9 {
+    pub icptcode: __u8,
+    pub ipa: __u16,
+    pub ipb: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_9() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_9>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_9>(),
+        4usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_9>())).icptcode as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9),
+            "::",
+            stringify!(icptcode)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_9>())).ipa as *const _ as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9),
+            "::",
+            stringify!(ipa)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_9>())).ipb as *const _ as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_9),
+            "::",
+            stringify!(ipb)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_10 {
+    pub trans_exc_code: __u64,
+    pub pgm_code: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_10() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_10>(),
+        16usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_10>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_10>())).trans_exc_code
+                as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10),
+            "::",
+            stringify!(trans_exc_code)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_10>())).pgm_code as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_10),
+            "::",
+            stringify!(pgm_code)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_11 {
+    pub dcrn: __u32,
+    pub data: __u32,
+    pub is_write: __u8,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_11() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_11>(),
+        12usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_11>(),
+        4usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_11>())).dcrn as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11),
+            "::",
+            stringify!(dcrn)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_11>())).data as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11),
+            "::",
+            stringify!(data)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_11>())).is_write as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_11),
+            "::",
+            stringify!(is_write)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_12 {
+    pub suberror: __u32,
+    pub ndata: __u32,
+    pub data: [__u64; 16usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_12() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_12>(),
+        136usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_12>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_12>())).suberror as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12),
+            "::",
+            stringify!(suberror)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_12>())).ndata as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12),
+            "::",
+            stringify!(ndata)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_12>())).data as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_12),
+            "::",
+            stringify!(data)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_13 {
+    pub gprs: [__u64; 32usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_13() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_13>(),
+        256usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_13>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_13>())).gprs as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_13),
+            "::",
+            stringify!(gprs)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_14 {
+    pub nr: __u64,
+    pub ret: __u64,
+    pub args: [__u64; 9usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_14() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_14>(),
+        88usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_14>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_14>())).nr as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14),
+            "::",
+            stringify!(nr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_14>())).ret as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14),
+            "::",
+            stringify!(ret)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_14>())).args as *const _
+                as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_14),
+            "::",
+            stringify!(args)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_15 {
+    pub subchannel_id: __u16,
+    pub subchannel_nr: __u16,
+    pub io_int_parm: __u32,
+    pub io_int_word: __u32,
+    pub ipb: __u32,
+    pub dequeued: __u8,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_15() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_15>(),
+        20usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_15>(),
+        4usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_15>())).subchannel_id
+                as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15),
+            "::",
+            stringify!(subchannel_id)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_15>())).subchannel_nr
+                as *const _ as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15),
+            "::",
+            stringify!(subchannel_nr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_15>())).io_int_parm as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15),
+            "::",
+            stringify!(io_int_parm)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_15>())).io_int_word as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15),
+            "::",
+            stringify!(io_int_word)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_15>())).ipb as *const _
+                as usize
+        },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15),
+            "::",
+            stringify!(ipb)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_15>())).dequeued as *const _
+                as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_15),
+            "::",
+            stringify!(dequeued)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_16 {
+    pub epr: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_16() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_16>(),
+        4usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_16>(),
+        4usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_16>())).epr as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_16),
+            "::",
+            stringify!(epr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_17 {
+    pub type_: __u32,
+    pub flags: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_17() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_17>(),
+        16usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_17>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_17>())).type_ as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_17>())).flags as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_17),
+            "::",
+            stringify!(flags)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_18 {
+    pub addr: __u64,
+    pub ar: __u8,
+    pub reserved: __u8,
+    pub fc: __u8,
+    pub sel1: __u8,
+    pub sel2: __u16,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_18() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_18>(),
+        16usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_18>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_18>())).addr as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18),
+            "::",
+            stringify!(addr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_18>())).ar as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18),
+            "::",
+            stringify!(ar)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_18>())).reserved as *const _
+                as usize
+        },
+        9usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18),
+            "::",
+            stringify!(reserved)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_18>())).fc as *const _ as usize
+        },
+        10usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18),
+            "::",
+            stringify!(fc)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_18>())).sel1 as *const _
+                as usize
+        },
+        11usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18),
+            "::",
+            stringify!(sel1)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_18>())).sel2 as *const _
+                as usize
+        },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_18),
+            "::",
+            stringify!(sel2)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_19 {
+    pub vector: __u8,
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_19() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1__bindgen_ty_19>(),
+        1usize,
+        concat!(
+            "Size of: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1__bindgen_ty_19>(),
+        1usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1__bindgen_ty_19>())).vector as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1__bindgen_ty_19),
+            "::",
+            stringify!(vector)
+        )
+    );
+}
+
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_1>(),
+        256usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_1>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).hw as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(hw)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).fail_entry as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(fail_entry)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).ex as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(ex)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).io as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(io)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).debug as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(debug)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).mmio as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(mmio)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).hypercall as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(hypercall)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).tpr_access as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(tpr_access)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).s390_sieic as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(s390_sieic)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).s390_reset_flags as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(s390_reset_flags)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).s390_ucontrol as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(s390_ucontrol)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).dcr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(dcr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).internal as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(internal)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).osi as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(osi)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).papr_hcall as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(papr_hcall)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).s390_tsch as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(s390_tsch)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).epr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(epr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).system_event as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(system_event)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).s390_stsi as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(s390_stsi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).eoi as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(eoi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).padding as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_1),
+            "::",
+            stringify!(padding)
+        )
+    );
+}
+impl Default for kvm_run__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_run__bindgen_ty_2 {
+    pub regs: kvm_sync_regs,
+    pub padding: [::std::os::raw::c_char; 2048usize],
+    _bindgen_union_align: [u8; 2048usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_run__bindgen_ty_2() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run__bindgen_ty_2>(),
+        2048usize,
+        concat!("Size of: ", stringify!(kvm_run__bindgen_ty_2))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run__bindgen_ty_2>(),
+        1usize,
+        concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_2))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_2>())).regs as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_2),
+            "::",
+            stringify!(regs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_2>())).padding as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run__bindgen_ty_2),
+            "::",
+            stringify!(padding)
+        )
+    );
+}
+impl Default for kvm_run__bindgen_ty_2 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_run() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_run>(),
+        2352usize,
+        concat!("Size of: ", stringify!(kvm_run))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_run>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_run))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run>())).request_interrupt_window as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(request_interrupt_window)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).padding1 as *const _ as usize },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(padding1)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).exit_reason as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(exit_reason)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_run>())).ready_for_interrupt_injection as *const _ as usize
+        },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(ready_for_interrupt_injection)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).if_flag as *const _ as usize },
+        13usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(if_flag)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).flags as *const _ as usize },
+        14usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).cr8 as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(cr8)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).apic_base as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(apic_base)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).kvm_valid_regs as *const _ as usize },
+        288usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(kvm_valid_regs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).kvm_dirty_regs as *const _ as usize },
+        296usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(kvm_dirty_regs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_run>())).s as *const _ as usize },
+        304usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_run),
+            "::",
+            stringify!(s)
+        )
+    );
+}
+impl Default for kvm_run {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_coalesced_mmio_zone {
+    pub addr: __u64,
+    pub size: __u32,
+    pub pad: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_coalesced_mmio_zone() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_coalesced_mmio_zone>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_coalesced_mmio_zone))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_coalesced_mmio_zone>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_coalesced_mmio_zone))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio_zone>())).addr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio_zone),
+            "::",
+            stringify!(addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio_zone>())).size as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio_zone),
+            "::",
+            stringify!(size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio_zone>())).pad as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio_zone),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_coalesced_mmio {
+    pub phys_addr: __u64,
+    pub len: __u32,
+    pub pad: __u32,
+    pub data: [__u8; 8usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_coalesced_mmio() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_coalesced_mmio>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_coalesced_mmio))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_coalesced_mmio>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_coalesced_mmio))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio>())).phys_addr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio),
+            "::",
+            stringify!(phys_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio>())).len as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio),
+            "::",
+            stringify!(len)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio>())).pad as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio>())).data as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio),
+            "::",
+            stringify!(data)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct kvm_coalesced_mmio_ring {
+    pub first: __u32,
+    pub last: __u32,
+    pub coalesced_mmio: __IncompleteArrayField<kvm_coalesced_mmio>,
+    // Manually added to work around rust bindgen issue 684
+    __force_alignment: [u64; 0],
+}
+#[test]
+fn bindgen_test_layout_kvm_coalesced_mmio_ring() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_coalesced_mmio_ring>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_coalesced_mmio_ring))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_coalesced_mmio_ring>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_coalesced_mmio_ring))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio_ring>())).first as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio_ring),
+            "::",
+            stringify!(first)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio_ring>())).last as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio_ring),
+            "::",
+            stringify!(last)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_coalesced_mmio_ring>())).coalesced_mmio as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_coalesced_mmio_ring),
+            "::",
+            stringify!(coalesced_mmio)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_translation {
+    pub linear_address: __u64,
+    pub physical_address: __u64,
+    pub valid: __u8,
+    pub writeable: __u8,
+    pub usermode: __u8,
+    pub pad: [__u8; 5usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_translation() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_translation>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_translation))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_translation>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_translation))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_translation>())).linear_address as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_translation),
+            "::",
+            stringify!(linear_address)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_translation>())).physical_address as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_translation),
+            "::",
+            stringify!(physical_address)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_translation>())).valid as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_translation),
+            "::",
+            stringify!(valid)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_translation>())).writeable as *const _ as usize },
+        17usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_translation),
+            "::",
+            stringify!(writeable)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_translation>())).usermode as *const _ as usize },
+        18usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_translation),
+            "::",
+            stringify!(usermode)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_translation>())).pad as *const _ as usize },
+        19usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_translation),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_mem_op {
+    pub gaddr: __u64,
+    pub flags: __u64,
+    pub size: __u32,
+    pub op: __u32,
+    pub buf: __u64,
+    pub ar: __u8,
+    pub reserved: [__u8; 31usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_mem_op() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_mem_op>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_s390_mem_op))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_mem_op>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_mem_op))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mem_op>())).gaddr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mem_op),
+            "::",
+            stringify!(gaddr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mem_op>())).flags as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mem_op),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mem_op>())).size as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mem_op),
+            "::",
+            stringify!(size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mem_op>())).op as *const _ as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mem_op),
+            "::",
+            stringify!(op)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mem_op>())).buf as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mem_op),
+            "::",
+            stringify!(buf)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mem_op>())).ar as *const _ as usize },
+        32usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mem_op),
+            "::",
+            stringify!(ar)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mem_op>())).reserved as *const _ as usize },
+        33usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mem_op),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_interrupt {
+    pub irq: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_interrupt() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_interrupt>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_interrupt))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_interrupt>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_interrupt))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_interrupt>())).irq as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_interrupt),
+            "::",
+            stringify!(irq)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_dirty_log {
+    pub slot: __u32,
+    pub padding1: __u32,
+    pub __bindgen_anon_1: kvm_dirty_log__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_dirty_log__bindgen_ty_1 {
+    pub dirty_bitmap: *mut ::std::os::raw::c_void,
+    pub padding2: __u64,
+    _bindgen_union_align: u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_dirty_log__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_dirty_log__bindgen_ty_1>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_dirty_log__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_dirty_log__bindgen_ty_1>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_dirty_log__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_dirty_log__bindgen_ty_1>())).dirty_bitmap as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dirty_log__bindgen_ty_1),
+            "::",
+            stringify!(dirty_bitmap)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_dirty_log__bindgen_ty_1>())).padding2 as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dirty_log__bindgen_ty_1),
+            "::",
+            stringify!(padding2)
+        )
+    );
+}
+impl Default for kvm_dirty_log__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_dirty_log() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_dirty_log>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_dirty_log))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_dirty_log>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_dirty_log))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_dirty_log>())).slot as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dirty_log),
+            "::",
+            stringify!(slot)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_dirty_log>())).padding1 as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dirty_log),
+            "::",
+            stringify!(padding1)
+        )
+    );
+}
+impl Default for kvm_dirty_log {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct kvm_signal_mask {
+    pub len: __u32,
+    pub sigset: __IncompleteArrayField<__u8>,
+}
+#[test]
+fn bindgen_test_layout_kvm_signal_mask() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_signal_mask>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_signal_mask))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_signal_mask>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_signal_mask))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_signal_mask>())).len as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_signal_mask),
+            "::",
+            stringify!(len)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_signal_mask>())).sigset as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_signal_mask),
+            "::",
+            stringify!(sigset)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_tpr_access_ctl {
+    pub enabled: __u32,
+    pub flags: __u32,
+    pub reserved: [__u32; 8usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_tpr_access_ctl() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_tpr_access_ctl>(),
+        40usize,
+        concat!("Size of: ", stringify!(kvm_tpr_access_ctl))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_tpr_access_ctl>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_tpr_access_ctl))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_tpr_access_ctl>())).enabled as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_tpr_access_ctl),
+            "::",
+            stringify!(enabled)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_tpr_access_ctl>())).flags as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_tpr_access_ctl),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_tpr_access_ctl>())).reserved as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_tpr_access_ctl),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_vapic_addr {
+    pub vapic_addr: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_vapic_addr() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_vapic_addr>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_vapic_addr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_vapic_addr>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_vapic_addr))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_vapic_addr>())).vapic_addr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_vapic_addr),
+            "::",
+            stringify!(vapic_addr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_mp_state {
+    pub mp_state: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_mp_state() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_mp_state>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_mp_state))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_mp_state>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_mp_state))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_mp_state>())).mp_state as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_mp_state),
+            "::",
+            stringify!(mp_state)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_psw {
+    pub mask: __u64,
+    pub addr: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_psw() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_psw>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_s390_psw))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_psw>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_psw))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_psw>())).mask as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_psw),
+            "::",
+            stringify!(mask)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_psw>())).addr as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_psw),
+            "::",
+            stringify!(addr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_interrupt {
+    pub type_: __u32,
+    pub parm: __u32,
+    pub parm64: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_interrupt() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_interrupt>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_s390_interrupt))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_interrupt>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_interrupt))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_interrupt>())).type_ as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_interrupt),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_interrupt>())).parm as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_interrupt),
+            "::",
+            stringify!(parm)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_interrupt>())).parm64 as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_interrupt),
+            "::",
+            stringify!(parm64)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_io_info {
+    pub subchannel_id: __u16,
+    pub subchannel_nr: __u16,
+    pub io_int_parm: __u32,
+    pub io_int_word: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_io_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_io_info>(),
+        12usize,
+        concat!("Size of: ", stringify!(kvm_s390_io_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_io_info>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_s390_io_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_io_info>())).subchannel_id as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_io_info),
+            "::",
+            stringify!(subchannel_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_io_info>())).subchannel_nr as *const _ as usize },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_io_info),
+            "::",
+            stringify!(subchannel_nr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_io_info>())).io_int_parm as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_io_info),
+            "::",
+            stringify!(io_int_parm)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_io_info>())).io_int_word as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_io_info),
+            "::",
+            stringify!(io_int_word)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_ext_info {
+    pub ext_params: __u32,
+    pub pad: __u32,
+    pub ext_params2: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_ext_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_ext_info>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_s390_ext_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_ext_info>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_ext_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_ext_info>())).ext_params as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_ext_info),
+            "::",
+            stringify!(ext_params)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_ext_info>())).pad as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_ext_info),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_ext_info>())).ext_params2 as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_ext_info),
+            "::",
+            stringify!(ext_params2)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_pgm_info {
+    pub trans_exc_code: __u64,
+    pub mon_code: __u64,
+    pub per_address: __u64,
+    pub data_exc_code: __u32,
+    pub code: __u16,
+    pub mon_class_nr: __u16,
+    pub per_code: __u8,
+    pub per_atmid: __u8,
+    pub exc_access_id: __u8,
+    pub per_access_id: __u8,
+    pub op_access_id: __u8,
+    pub pad: [__u8; 3usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_pgm_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_pgm_info>(),
+        40usize,
+        concat!("Size of: ", stringify!(kvm_s390_pgm_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_pgm_info>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_pgm_info))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_s390_pgm_info>())).trans_exc_code as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(trans_exc_code)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).mon_code as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(mon_code)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).per_address as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(per_address)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).data_exc_code as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(data_exc_code)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).code as *const _ as usize },
+        28usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(code)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).mon_class_nr as *const _ as usize },
+        30usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(mon_class_nr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).per_code as *const _ as usize },
+        32usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(per_code)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).per_atmid as *const _ as usize },
+        33usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(per_atmid)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).exc_access_id as *const _ as usize },
+        34usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(exc_access_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).per_access_id as *const _ as usize },
+        35usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(per_access_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).op_access_id as *const _ as usize },
+        36usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(op_access_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).pad as *const _ as usize },
+        37usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_pgm_info),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_prefix_info {
+    pub address: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_prefix_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_prefix_info>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_s390_prefix_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_prefix_info>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_s390_prefix_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_prefix_info>())).address as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_prefix_info),
+            "::",
+            stringify!(address)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_extcall_info {
+    pub code: __u16,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_extcall_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_extcall_info>(),
+        2usize,
+        concat!("Size of: ", stringify!(kvm_s390_extcall_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_extcall_info>(),
+        2usize,
+        concat!("Alignment of ", stringify!(kvm_s390_extcall_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_extcall_info>())).code as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_extcall_info),
+            "::",
+            stringify!(code)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_emerg_info {
+    pub code: __u16,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_emerg_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_emerg_info>(),
+        2usize,
+        concat!("Size of: ", stringify!(kvm_s390_emerg_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_emerg_info>(),
+        2usize,
+        concat!("Alignment of ", stringify!(kvm_s390_emerg_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_emerg_info>())).code as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_emerg_info),
+            "::",
+            stringify!(code)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_stop_info {
+    pub flags: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_stop_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_stop_info>(),
+        4usize,
+        concat!("Size of: ", stringify!(kvm_s390_stop_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_stop_info>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_s390_stop_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_stop_info>())).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_stop_info),
+            "::",
+            stringify!(flags)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_mchk_info {
+    pub cr14: __u64,
+    pub mcic: __u64,
+    pub failing_storage_address: __u64,
+    pub ext_damage_code: __u32,
+    pub pad: __u32,
+    pub fixed_logout: [__u8; 16usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_mchk_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_mchk_info>(),
+        48usize,
+        concat!("Size of: ", stringify!(kvm_s390_mchk_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_mchk_info>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_mchk_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mchk_info>())).cr14 as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mchk_info),
+            "::",
+            stringify!(cr14)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mchk_info>())).mcic as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mchk_info),
+            "::",
+            stringify!(mcic)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_s390_mchk_info>())).failing_storage_address as *const _
+                as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mchk_info),
+            "::",
+            stringify!(failing_storage_address)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_s390_mchk_info>())).ext_damage_code as *const _ as usize
+        },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mchk_info),
+            "::",
+            stringify!(ext_damage_code)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mchk_info>())).pad as *const _ as usize },
+        28usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mchk_info),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_mchk_info>())).fixed_logout as *const _ as usize },
+        32usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_mchk_info),
+            "::",
+            stringify!(fixed_logout)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_s390_irq {
+    pub type_: __u64,
+    pub u: kvm_s390_irq__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_s390_irq__bindgen_ty_1 {
+    pub io: kvm_s390_io_info,
+    pub ext: kvm_s390_ext_info,
+    pub pgm: kvm_s390_pgm_info,
+    pub emerg: kvm_s390_emerg_info,
+    pub extcall: kvm_s390_extcall_info,
+    pub prefix: kvm_s390_prefix_info,
+    pub stop: kvm_s390_stop_info,
+    pub mchk: kvm_s390_mchk_info,
+    pub reserved: [::std::os::raw::c_char; 64usize],
+    _bindgen_union_align: [u64; 8usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_irq__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_irq__bindgen_ty_1>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_s390_irq__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_irq__bindgen_ty_1>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_irq__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).io as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(io)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).ext as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(ext)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).pgm as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(pgm)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).emerg as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(emerg)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).extcall as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(extcall)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).prefix as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(prefix)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).stop as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(stop)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).mchk as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(mchk)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_s390_irq__bindgen_ty_1>())).reserved as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq__bindgen_ty_1),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+impl Default for kvm_s390_irq__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_irq() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_irq>(),
+        72usize,
+        concat!("Size of: ", stringify!(kvm_s390_irq))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_irq>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_irq))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq>())).type_ as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq>())).u as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq),
+            "::",
+            stringify!(u)
+        )
+    );
+}
+impl Default for kvm_s390_irq {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_irq_state {
+    pub buf: __u64,
+    pub flags: __u32,
+    pub len: __u32,
+    pub reserved: [__u32; 4usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_irq_state() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_irq_state>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_s390_irq_state))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_irq_state>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_irq_state))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq_state>())).buf as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq_state),
+            "::",
+            stringify!(buf)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq_state>())).flags as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq_state),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq_state>())).len as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq_state),
+            "::",
+            stringify!(len)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_irq_state>())).reserved as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_irq_state),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_guest_debug {
+    pub control: __u32,
+    pub pad: __u32,
+    pub arch: kvm_guest_debug_arch,
+}
+#[test]
+fn bindgen_test_layout_kvm_guest_debug() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_guest_debug>(),
+        72usize,
+        concat!("Size of: ", stringify!(kvm_guest_debug))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_guest_debug>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_guest_debug))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_guest_debug>())).control as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_guest_debug),
+            "::",
+            stringify!(control)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_guest_debug>())).pad as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_guest_debug),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_guest_debug>())).arch as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_guest_debug),
+            "::",
+            stringify!(arch)
+        )
+    );
+}
+pub const kvm_ioeventfd_flag_nr_datamatch: _bindgen_ty_1 = 0;
+pub const kvm_ioeventfd_flag_nr_pio: _bindgen_ty_1 = 1;
+pub const kvm_ioeventfd_flag_nr_deassign: _bindgen_ty_1 = 2;
+pub const kvm_ioeventfd_flag_nr_virtio_ccw_notify: _bindgen_ty_1 = 3;
+pub const kvm_ioeventfd_flag_nr_fast_mmio: _bindgen_ty_1 = 4;
+pub const kvm_ioeventfd_flag_nr_max: _bindgen_ty_1 = 5;
+pub type _bindgen_ty_1 = ::std::os::raw::c_uint;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_ioeventfd {
+    pub datamatch: __u64,
+    pub addr: __u64,
+    pub len: __u32,
+    pub fd: __s32,
+    pub flags: __u32,
+    pub pad: [__u8; 36usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_ioeventfd() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_ioeventfd>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_ioeventfd))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_ioeventfd>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_ioeventfd))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioeventfd>())).datamatch as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioeventfd),
+            "::",
+            stringify!(datamatch)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioeventfd>())).addr as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioeventfd),
+            "::",
+            stringify!(addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioeventfd>())).len as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioeventfd),
+            "::",
+            stringify!(len)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioeventfd>())).fd as *const _ as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioeventfd),
+            "::",
+            stringify!(fd)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioeventfd>())).flags as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioeventfd),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ioeventfd>())).pad as *const _ as usize },
+        28usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ioeventfd),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+impl Default for kvm_ioeventfd {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_enable_cap {
+    pub cap: __u32,
+    pub flags: __u32,
+    pub args: [__u64; 4usize],
+    pub pad: [__u8; 64usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_enable_cap() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_enable_cap>(),
+        104usize,
+        concat!("Size of: ", stringify!(kvm_enable_cap))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_enable_cap>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_enable_cap))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_enable_cap>())).cap as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_enable_cap),
+            "::",
+            stringify!(cap)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_enable_cap>())).flags as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_enable_cap),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_enable_cap>())).args as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_enable_cap),
+            "::",
+            stringify!(args)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_enable_cap>())).pad as *const _ as usize },
+        40usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_enable_cap),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+impl Default for kvm_enable_cap {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_ppc_pvinfo {
+    pub flags: __u32,
+    pub hcall: [__u32; 4usize],
+    pub pad: [__u8; 108usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_ppc_pvinfo() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_ppc_pvinfo>(),
+        128usize,
+        concat!("Size of: ", stringify!(kvm_ppc_pvinfo))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_ppc_pvinfo>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_ppc_pvinfo))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_pvinfo>())).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_pvinfo),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_pvinfo>())).hcall as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_pvinfo),
+            "::",
+            stringify!(hcall)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_pvinfo>())).pad as *const _ as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_pvinfo),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+impl Default for kvm_ppc_pvinfo {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_ppc_one_page_size {
+    pub page_shift: __u32,
+    pub pte_enc: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_ppc_one_page_size() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_ppc_one_page_size>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_ppc_one_page_size))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_ppc_one_page_size>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_ppc_one_page_size))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_ppc_one_page_size>())).page_shift as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_one_page_size),
+            "::",
+            stringify!(page_shift)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_one_page_size>())).pte_enc as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_one_page_size),
+            "::",
+            stringify!(pte_enc)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_ppc_one_seg_page_size {
+    pub page_shift: __u32,
+    pub slb_enc: __u32,
+    pub enc: [kvm_ppc_one_page_size; 8usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_ppc_one_seg_page_size() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_ppc_one_seg_page_size>(),
+        72usize,
+        concat!("Size of: ", stringify!(kvm_ppc_one_seg_page_size))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_ppc_one_seg_page_size>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_ppc_one_seg_page_size))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_ppc_one_seg_page_size>())).page_shift as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_one_seg_page_size),
+            "::",
+            stringify!(page_shift)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_ppc_one_seg_page_size>())).slb_enc as *const _ as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_one_seg_page_size),
+            "::",
+            stringify!(slb_enc)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_one_seg_page_size>())).enc as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_one_seg_page_size),
+            "::",
+            stringify!(enc)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_ppc_smmu_info {
+    pub flags: __u64,
+    pub slb_size: __u32,
+    pub pad: __u32,
+    pub sps: [kvm_ppc_one_seg_page_size; 8usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_ppc_smmu_info() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_ppc_smmu_info>(),
+        592usize,
+        concat!("Size of: ", stringify!(kvm_ppc_smmu_info))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_ppc_smmu_info>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_ppc_smmu_info))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_smmu_info>())).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_smmu_info),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_smmu_info>())).slb_size as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_smmu_info),
+            "::",
+            stringify!(slb_size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_smmu_info>())).pad as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_smmu_info),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_ppc_smmu_info>())).sps as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_ppc_smmu_info),
+            "::",
+            stringify!(sps)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_irq_routing_irqchip {
+    pub irqchip: __u32,
+    pub pin: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing_irqchip() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_routing_irqchip>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_irq_routing_irqchip))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_routing_irqchip>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_irq_routing_irqchip))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_irqchip>())).irqchip as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_irqchip),
+            "::",
+            stringify!(irqchip)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_irqchip>())).pin as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_irqchip),
+            "::",
+            stringify!(pin)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_irq_routing_msi {
+    pub address_lo: __u32,
+    pub address_hi: __u32,
+    pub data: __u32,
+    pub pad: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing_msi() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_routing_msi>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_irq_routing_msi))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_routing_msi>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_irq_routing_msi))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_msi>())).address_lo as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_msi),
+            "::",
+            stringify!(address_lo)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_msi>())).address_hi as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_msi),
+            "::",
+            stringify!(address_hi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_msi>())).data as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_msi),
+            "::",
+            stringify!(data)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_msi>())).pad as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_msi),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_irq_routing_s390_adapter {
+    pub ind_addr: __u64,
+    pub summary_addr: __u64,
+    pub ind_offset: __u64,
+    pub summary_offset: __u32,
+    pub adapter_id: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing_s390_adapter() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_routing_s390_adapter>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_irq_routing_s390_adapter))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_routing_s390_adapter>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_irq_routing_s390_adapter))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_s390_adapter>())).ind_addr as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_s390_adapter),
+            "::",
+            stringify!(ind_addr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_s390_adapter>())).summary_addr as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_s390_adapter),
+            "::",
+            stringify!(summary_addr)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_s390_adapter>())).ind_offset as *const _ as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_s390_adapter),
+            "::",
+            stringify!(ind_offset)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_s390_adapter>())).summary_offset as *const _
+                as usize
+        },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_s390_adapter),
+            "::",
+            stringify!(summary_offset)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_s390_adapter>())).adapter_id as *const _ as usize
+        },
+        28usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_s390_adapter),
+            "::",
+            stringify!(adapter_id)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_irq_routing_entry {
+    pub gsi: __u32,
+    pub type_: __u32,
+    pub flags: __u32,
+    pub pad: __u32,
+    pub u: kvm_irq_routing_entry__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_irq_routing_entry__bindgen_ty_1 {
+    pub irqchip: kvm_irq_routing_irqchip,
+    pub msi: kvm_irq_routing_msi,
+    pub adapter: kvm_irq_routing_s390_adapter,
+    pub pad: [__u32; 8usize],
+    _bindgen_union_align: [u64; 4usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing_entry__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_routing_entry__bindgen_ty_1>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_irq_routing_entry__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_routing_entry__bindgen_ty_1>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_irq_routing_entry__bindgen_ty_1)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_entry__bindgen_ty_1>())).irqchip as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry__bindgen_ty_1),
+            "::",
+            stringify!(irqchip)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_entry__bindgen_ty_1>())).msi as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry__bindgen_ty_1),
+            "::",
+            stringify!(msi)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_entry__bindgen_ty_1>())).adapter as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry__bindgen_ty_1),
+            "::",
+            stringify!(adapter)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_irq_routing_entry__bindgen_ty_1>())).pad as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry__bindgen_ty_1),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+impl Default for kvm_irq_routing_entry__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing_entry() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_routing_entry>(),
+        48usize,
+        concat!("Size of: ", stringify!(kvm_irq_routing_entry))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_routing_entry>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_irq_routing_entry))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_entry>())).gsi as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry),
+            "::",
+            stringify!(gsi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_entry>())).type_ as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_entry>())).flags as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_entry>())).pad as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry),
+            "::",
+            stringify!(pad)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing_entry>())).u as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing_entry),
+            "::",
+            stringify!(u)
+        )
+    );
+}
+impl Default for kvm_irq_routing_entry {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+pub struct kvm_irq_routing {
+    pub nr: __u32,
+    pub flags: __u32,
+    pub entries: __IncompleteArrayField<kvm_irq_routing_entry>,
+    // Manually added to work around rust bindgen issue 684
+    __force_alignment: [u64; 0],
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irq_routing>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_irq_routing))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irq_routing>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_irq_routing))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing>())).nr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing),
+            "::",
+            stringify!(nr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing>())).flags as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irq_routing>())).entries as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irq_routing),
+            "::",
+            stringify!(entries)
+        )
+    );
+}
+impl Default for kvm_irq_routing {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_x86_mce {
+    pub status: __u64,
+    pub addr: __u64,
+    pub misc: __u64,
+    pub mcg_status: __u64,
+    pub bank: __u8,
+    pub pad1: [__u8; 7usize],
+    pub pad2: [__u64; 3usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_x86_mce() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_x86_mce>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_x86_mce))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_x86_mce>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_x86_mce))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_x86_mce>())).status as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_x86_mce),
+            "::",
+            stringify!(status)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_x86_mce>())).addr as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_x86_mce),
+            "::",
+            stringify!(addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_x86_mce>())).misc as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_x86_mce),
+            "::",
+            stringify!(misc)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_x86_mce>())).mcg_status as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_x86_mce),
+            "::",
+            stringify!(mcg_status)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_x86_mce>())).bank as *const _ as usize },
+        32usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_x86_mce),
+            "::",
+            stringify!(bank)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_x86_mce>())).pad1 as *const _ as usize },
+        33usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_x86_mce),
+            "::",
+            stringify!(pad1)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_x86_mce>())).pad2 as *const _ as usize },
+        40usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_x86_mce),
+            "::",
+            stringify!(pad2)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_xen_hvm_config {
+    pub flags: __u32,
+    pub msr: __u32,
+    pub blob_addr_32: __u64,
+    pub blob_addr_64: __u64,
+    pub blob_size_32: __u8,
+    pub blob_size_64: __u8,
+    pub pad2: [__u8; 30usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_xen_hvm_config() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_xen_hvm_config>(),
+        56usize,
+        concat!("Size of: ", stringify!(kvm_xen_hvm_config))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_xen_hvm_config>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_xen_hvm_config))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xen_hvm_config>())).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xen_hvm_config),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xen_hvm_config>())).msr as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xen_hvm_config),
+            "::",
+            stringify!(msr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xen_hvm_config>())).blob_addr_32 as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xen_hvm_config),
+            "::",
+            stringify!(blob_addr_32)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xen_hvm_config>())).blob_addr_64 as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xen_hvm_config),
+            "::",
+            stringify!(blob_addr_64)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xen_hvm_config>())).blob_size_32 as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xen_hvm_config),
+            "::",
+            stringify!(blob_size_32)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xen_hvm_config>())).blob_size_64 as *const _ as usize },
+        25usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xen_hvm_config),
+            "::",
+            stringify!(blob_size_64)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_xen_hvm_config>())).pad2 as *const _ as usize },
+        26usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_xen_hvm_config),
+            "::",
+            stringify!(pad2)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_irqfd {
+    pub fd: __u32,
+    pub gsi: __u32,
+    pub flags: __u32,
+    pub resamplefd: __u32,
+    pub pad: [__u8; 16usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_irqfd() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_irqfd>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_irqfd))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_irqfd>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_irqfd))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqfd>())).fd as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqfd),
+            "::",
+            stringify!(fd)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqfd>())).gsi as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqfd),
+            "::",
+            stringify!(gsi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqfd>())).flags as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqfd),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqfd>())).resamplefd as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqfd),
+            "::",
+            stringify!(resamplefd)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_irqfd>())).pad as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_irqfd),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_clock_data {
+    pub clock: __u64,
+    pub flags: __u32,
+    pub pad: [__u32; 9usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_clock_data() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_clock_data>(),
+        48usize,
+        concat!("Size of: ", stringify!(kvm_clock_data))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_clock_data>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_clock_data))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_clock_data>())).clock as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_clock_data),
+            "::",
+            stringify!(clock)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_clock_data>())).flags as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_clock_data),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_clock_data>())).pad as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_clock_data),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_config_tlb {
+    pub params: __u64,
+    pub array: __u64,
+    pub mmu_type: __u32,
+    pub array_len: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_config_tlb() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_config_tlb>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_config_tlb))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_config_tlb>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_config_tlb))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_config_tlb>())).params as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_config_tlb),
+            "::",
+            stringify!(params)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_config_tlb>())).array as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_config_tlb),
+            "::",
+            stringify!(array)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_config_tlb>())).mmu_type as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_config_tlb),
+            "::",
+            stringify!(mmu_type)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_config_tlb>())).array_len as *const _ as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_config_tlb),
+            "::",
+            stringify!(array_len)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_dirty_tlb {
+    pub bitmap: __u64,
+    pub num_dirty: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_dirty_tlb() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_dirty_tlb>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_dirty_tlb))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_dirty_tlb>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_dirty_tlb))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_dirty_tlb>())).bitmap as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dirty_tlb),
+            "::",
+            stringify!(bitmap)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_dirty_tlb>())).num_dirty as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_dirty_tlb),
+            "::",
+            stringify!(num_dirty)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct kvm_reg_list {
+    pub n: __u64,
+    pub reg: __IncompleteArrayField<__u64>,
+}
+#[test]
+fn bindgen_test_layout_kvm_reg_list() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_reg_list>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_reg_list))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_reg_list>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_reg_list))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_reg_list>())).n as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_reg_list),
+            "::",
+            stringify!(n)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_reg_list>())).reg as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_reg_list),
+            "::",
+            stringify!(reg)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_one_reg {
+    pub id: __u64,
+    pub addr: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_one_reg() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_one_reg>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_one_reg))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_one_reg>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_one_reg))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_one_reg>())).id as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_one_reg),
+            "::",
+            stringify!(id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_one_reg>())).addr as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_one_reg),
+            "::",
+            stringify!(addr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_msi {
+    pub address_lo: __u32,
+    pub address_hi: __u32,
+    pub data: __u32,
+    pub flags: __u32,
+    pub pad: [__u8; 16usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_msi() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_msi>(),
+        32usize,
+        concat!("Size of: ", stringify!(kvm_msi))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_msi>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_msi))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msi>())).address_lo as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msi),
+            "::",
+            stringify!(address_lo)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msi>())).address_hi as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msi),
+            "::",
+            stringify!(address_hi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msi>())).data as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msi),
+            "::",
+            stringify!(data)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msi>())).flags as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msi),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_msi>())).pad as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_msi),
+            "::",
+            stringify!(pad)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_arm_device_addr {
+    pub id: __u64,
+    pub addr: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_arm_device_addr() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_arm_device_addr>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_arm_device_addr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_arm_device_addr>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_arm_device_addr))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_arm_device_addr>())).id as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_arm_device_addr),
+            "::",
+            stringify!(id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_arm_device_addr>())).addr as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_arm_device_addr),
+            "::",
+            stringify!(addr)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_create_device {
+    pub type_: __u32,
+    pub fd: __u32,
+    pub flags: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_create_device() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_create_device>(),
+        12usize,
+        concat!("Size of: ", stringify!(kvm_create_device))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_create_device>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_create_device))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_create_device>())).type_ as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_create_device),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_create_device>())).fd as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_create_device),
+            "::",
+            stringify!(fd)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_create_device>())).flags as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_create_device),
+            "::",
+            stringify!(flags)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_device_attr {
+    pub flags: __u32,
+    pub group: __u32,
+    pub attr: __u64,
+    pub addr: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_device_attr() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_device_attr>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_device_attr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_device_attr>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_device_attr))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_device_attr>())).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_device_attr),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_device_attr>())).group as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_device_attr),
+            "::",
+            stringify!(group)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_device_attr>())).attr as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_device_attr),
+            "::",
+            stringify!(attr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_device_attr>())).addr as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_device_attr),
+            "::",
+            stringify!(addr)
+        )
+    );
+}
+pub const kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_20: kvm_device_type = 1;
+pub const kvm_device_type_KVM_DEV_TYPE_FSL_MPIC_42: kvm_device_type = 2;
+pub const kvm_device_type_KVM_DEV_TYPE_XICS: kvm_device_type = 3;
+pub const kvm_device_type_KVM_DEV_TYPE_VFIO: kvm_device_type = 4;
+pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2: kvm_device_type = 5;
+pub const kvm_device_type_KVM_DEV_TYPE_FLIC: kvm_device_type = 6;
+pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3: kvm_device_type = 7;
+pub const kvm_device_type_KVM_DEV_TYPE_MAX: kvm_device_type = 8;
+pub type kvm_device_type = ::std::os::raw::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_s390_ucas_mapping {
+    pub user_addr: __u64,
+    pub vcpu_addr: __u64,
+    pub length: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_ucas_mapping() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_s390_ucas_mapping>(),
+        24usize,
+        concat!("Size of: ", stringify!(kvm_s390_ucas_mapping))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_s390_ucas_mapping>(),
+        8usize,
+        concat!("Alignment of ", stringify!(kvm_s390_ucas_mapping))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_ucas_mapping>())).user_addr as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_ucas_mapping),
+            "::",
+            stringify!(user_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_ucas_mapping>())).vcpu_addr as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_ucas_mapping),
+            "::",
+            stringify!(vcpu_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_s390_ucas_mapping>())).length as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_s390_ucas_mapping),
+            "::",
+            stringify!(length)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_assigned_pci_dev {
+    pub assigned_dev_id: __u32,
+    pub busnr: __u32,
+    pub devfn: __u32,
+    pub flags: __u32,
+    pub segnr: __u32,
+    pub __bindgen_anon_1: kvm_assigned_pci_dev__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_assigned_pci_dev__bindgen_ty_1 {
+    pub reserved: [__u32; 11usize],
+    _bindgen_union_align: [u32; 11usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_assigned_pci_dev__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_assigned_pci_dev__bindgen_ty_1>(),
+        44usize,
+        concat!("Size of: ", stringify!(kvm_assigned_pci_dev__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_assigned_pci_dev__bindgen_ty_1>(),
+        4usize,
+        concat!(
+            "Alignment of ",
+            stringify!(kvm_assigned_pci_dev__bindgen_ty_1)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_assigned_pci_dev__bindgen_ty_1>())).reserved as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_pci_dev__bindgen_ty_1),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+impl Default for kvm_assigned_pci_dev__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_assigned_pci_dev() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_assigned_pci_dev>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_assigned_pci_dev))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_assigned_pci_dev>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_assigned_pci_dev))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_assigned_pci_dev>())).assigned_dev_id as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_pci_dev),
+            "::",
+            stringify!(assigned_dev_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_pci_dev>())).busnr as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_pci_dev),
+            "::",
+            stringify!(busnr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_pci_dev>())).devfn as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_pci_dev),
+            "::",
+            stringify!(devfn)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_pci_dev>())).flags as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_pci_dev),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_pci_dev>())).segnr as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_pci_dev),
+            "::",
+            stringify!(segnr)
+        )
+    );
+}
+impl Default for kvm_assigned_pci_dev {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_assigned_irq {
+    pub assigned_dev_id: __u32,
+    pub host_irq: __u32,
+    pub guest_irq: __u32,
+    pub flags: __u32,
+    pub __bindgen_anon_1: kvm_assigned_irq__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_assigned_irq__bindgen_ty_1 {
+    pub reserved: [__u32; 12usize],
+    _bindgen_union_align: [u32; 12usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_assigned_irq__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_assigned_irq__bindgen_ty_1>(),
+        48usize,
+        concat!("Size of: ", stringify!(kvm_assigned_irq__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_assigned_irq__bindgen_ty_1>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_assigned_irq__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_assigned_irq__bindgen_ty_1>())).reserved as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_irq__bindgen_ty_1),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+impl Default for kvm_assigned_irq__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[test]
+fn bindgen_test_layout_kvm_assigned_irq() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_assigned_irq>(),
+        64usize,
+        concat!("Size of: ", stringify!(kvm_assigned_irq))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_assigned_irq>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_assigned_irq))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_assigned_irq>())).assigned_dev_id as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_irq),
+            "::",
+            stringify!(assigned_dev_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_irq>())).host_irq as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_irq),
+            "::",
+            stringify!(host_irq)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_irq>())).guest_irq as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_irq),
+            "::",
+            stringify!(guest_irq)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_irq>())).flags as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_irq),
+            "::",
+            stringify!(flags)
+        )
+    );
+}
+impl Default for kvm_assigned_irq {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_assigned_msix_nr {
+    pub assigned_dev_id: __u32,
+    pub entry_nr: __u16,
+    pub padding: __u16,
+}
+#[test]
+fn bindgen_test_layout_kvm_assigned_msix_nr() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_assigned_msix_nr>(),
+        8usize,
+        concat!("Size of: ", stringify!(kvm_assigned_msix_nr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_assigned_msix_nr>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_assigned_msix_nr))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_assigned_msix_nr>())).assigned_dev_id as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_msix_nr),
+            "::",
+            stringify!(assigned_dev_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_msix_nr>())).entry_nr as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_msix_nr),
+            "::",
+            stringify!(entry_nr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_msix_nr>())).padding as *const _ as usize },
+        6usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_msix_nr),
+            "::",
+            stringify!(padding)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_assigned_msix_entry {
+    pub assigned_dev_id: __u32,
+    pub gsi: __u32,
+    pub entry: __u16,
+    pub padding: [__u16; 3usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_assigned_msix_entry() {
+    assert_eq!(
+        ::std::mem::size_of::<kvm_assigned_msix_entry>(),
+        16usize,
+        concat!("Size of: ", stringify!(kvm_assigned_msix_entry))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<kvm_assigned_msix_entry>(),
+        4usize,
+        concat!("Alignment of ", stringify!(kvm_assigned_msix_entry))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<kvm_assigned_msix_entry>())).assigned_dev_id as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_msix_entry),
+            "::",
+            stringify!(assigned_dev_id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_msix_entry>())).gsi as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_msix_entry),
+            "::",
+            stringify!(gsi)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_msix_entry>())).entry as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_msix_entry),
+            "::",
+            stringify!(entry)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<kvm_assigned_msix_entry>())).padding as *const _ as usize },
+        10usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(kvm_assigned_msix_entry),
+            "::",
+            stringify!(padding)
+        )
+    );
+}
diff --git a/kvm_sys/tests/sanity.rs b/kvm_sys/tests/sanity.rs
new file mode 100644
index 0000000..7669b44
--- /dev/null
+++ b/kvm_sys/tests/sanity.rs
@@ -0,0 +1,36 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use libc::{c_char, ioctl, open, O_RDWR};
+
+use kvm_sys::*;
+
+const KVM_PATH: &'static str = "/dev/kvm\0";
+
+#[test]
+fn get_version() {
+    let sys_fd = unsafe { open(KVM_PATH.as_ptr() as *const c_char, O_RDWR) };
+    assert!(sys_fd >= 0);
+
+    let ret = unsafe { ioctl(sys_fd, KVM_GET_API_VERSION(), 0) };
+    assert_eq!(ret as u32, KVM_API_VERSION);
+}
+
+#[test]
+fn create_vm_fd() {
+    let sys_fd = unsafe { open(KVM_PATH.as_ptr() as *const c_char, O_RDWR) };
+    assert!(sys_fd >= 0);
+
+    let vm_fd = unsafe { ioctl(sys_fd, KVM_CREATE_VM(), 0) };
+    assert!(vm_fd >= 0);
+}
+
+#[test]
+fn check_vm_extension() {
+    let sys_fd = unsafe { open(KVM_PATH.as_ptr() as *const c_char, O_RDWR) };
+    assert!(sys_fd >= 0);
+
+    let has_user_memory = unsafe { ioctl(sys_fd, KVM_CHECK_EXTENSION(), KVM_CAP_USER_MEMORY) };
+    assert_eq!(has_user_memory, 1);
+}
diff --git a/msg_socket/Cargo.toml b/msg_socket/Cargo.toml
new file mode 100644
index 0000000..dcfccfc
--- /dev/null
+++ b/msg_socket/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "msg_socket"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+data_model = { path = "../data_model" }
+msg_on_socket_derive = { path = "msg_on_socket_derive" }
+sys_util = { path = "../sys_util"  }
diff --git a/msg_socket/msg_on_socket_derive/Cargo.toml b/msg_socket/msg_on_socket_derive/Cargo.toml
new file mode 100644
index 0000000..78e88de
--- /dev/null
+++ b/msg_socket/msg_on_socket_derive/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "msg_on_socket_derive"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+proc-macro2 = "=0.4"
+quote = "=0.6"
+syn = "=0.15"
+
+[lib]
+proc-macro = true
+path = "msg_on_socket_derive.rs"
diff --git a/msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs b/msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs
new file mode 100644
index 0000000..3779357
--- /dev/null
+++ b/msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs
@@ -0,0 +1,747 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![recursion_limit = "256"]
+extern crate proc_macro;
+
+use std::vec::Vec;
+
+use proc_macro2::{Span, TokenStream};
+use quote::quote;
+use syn::{parse_macro_input, Data, DataEnum, DataStruct, DeriveInput, Fields, Ident};
+
+/// The function that derives the recursive implementation for struct or enum.
+#[proc_macro_derive(MsgOnSocket)]
+pub fn msg_on_socket_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let input = parse_macro_input!(input as DeriveInput);
+    let impl_for_input = socket_msg_impl(input);
+    impl_for_input.into()
+}
+
+fn socket_msg_impl(input: DeriveInput) -> TokenStream {
+    if !input.generics.params.is_empty() {
+        return quote! {
+            compile_error!("derive(SocketMsg) does not support generic parameters");
+        };
+    }
+    match input.data {
+        Data::Struct(ds) => {
+            if is_named_struct(&ds) {
+                impl_for_named_struct(input.ident, ds)
+            } else {
+                impl_for_tuple_struct(input.ident, ds)
+            }
+        }
+        Data::Enum(de) => impl_for_enum(input.ident, de),
+        _ => quote! {
+            compile_error!("derive(SocketMsg) only support struct and enum");
+        },
+    }
+}
+
+fn is_named_struct(ds: &DataStruct) -> bool {
+    match &ds.fields {
+        Fields::Named(_f) => true,
+        _ => false,
+    }
+}
+
+/************************** Named Struct Impls ********************************************/
+fn impl_for_named_struct(name: Ident, ds: DataStruct) -> TokenStream {
+    let fields = get_struct_fields(ds);
+    let fields_types = get_types_from_fields_vec(&fields);
+    let buffer_sizes_impls = define_buffer_size_for_struct(&fields_types);
+
+    let read_buffer = define_read_buffer_for_struct(&name, &fields);
+    let write_buffer = define_write_buffer_for_struct(&name, &fields);
+    quote! {
+        impl msg_socket::MsgOnSocket for #name {
+            #buffer_sizes_impls
+            #read_buffer
+            #write_buffer
+        }
+    }
+}
+
+fn get_types_from_fields_vec(v: &[(Ident, syn::Type)]) -> Vec<syn::Type> {
+    let mut fields_types = Vec::new();
+    for (_i, t) in v {
+        fields_types.push(t.clone());
+    }
+    fields_types
+}
+
+// Flatten struct fields.
+// "myfield : Type" -> \(ident\("myfield"\), Token\(Type\)\)
+fn get_struct_fields(ds: DataStruct) -> Vec<(Ident, syn::Type)> {
+    let fields = match ds.fields {
+        Fields::Named(fields_named) => fields_named.named,
+        _ => {
+            panic!("Struct must have named fields");
+        }
+    };
+    let mut vec = Vec::new();
+    for field in fields {
+        let ident = match field.ident {
+            Some(ident) => ident,
+            None => panic!("Unknown Error."),
+        };
+        let ty = field.ty;
+        vec.push((ident, ty));
+    }
+    vec
+}
+
+fn define_buffer_size_for_struct(field_types: &[syn::Type]) -> TokenStream {
+    let (msg_size, max_fd_count) = get_fields_buffer_size_sum(field_types);
+    quote! {
+        fn msg_size() -> usize {
+            #msg_size
+        }
+        fn max_fd_count() -> usize {
+            #max_fd_count
+        }
+    }
+}
+
+fn define_read_buffer_for_struct(_name: &Ident, fields: &[(Ident, syn::Type)]) -> TokenStream {
+    let mut read_fields = Vec::new();
+    let mut init_fields = Vec::new();
+    for f in fields {
+        let read_field = read_from_buffer_and_move_offset(&f.0, &f.1);
+        read_fields.push(read_field);
+        let name = f.0.clone();
+        init_fields.push(quote!(#name));
+    }
+    quote! {
+        unsafe fn read_from_buffer(
+            buffer: &[u8],
+            fds: &[std::os::unix::io::RawFd],
+        ) -> msg_socket::MsgResult<(Self, usize)> {
+            let mut __offset = 0usize;
+            let mut __fd_offset = 0usize;
+            #(#read_fields)*
+            Ok((
+                Self {
+                    #(#init_fields),*
+                },
+                __fd_offset
+            ))
+        }
+    }
+}
+
+fn define_write_buffer_for_struct(_name: &Ident, fields: &[(Ident, syn::Type)]) -> TokenStream {
+    let mut write_fields = Vec::new();
+    for f in fields {
+        let write_field = write_to_buffer_and_move_offset(&f.0, &f.1);
+        write_fields.push(write_field);
+    }
+    quote! {
+        fn write_to_buffer(
+            &self,
+            buffer: &mut [u8],
+            fds: &mut [std::os::unix::io::RawFd],
+        ) -> msg_socket::MsgResult<usize> {
+            let mut __offset = 0usize;
+            let mut __fd_offset = 0usize;
+            #(#write_fields)*
+            Ok(__fd_offset)
+        }
+    }
+}
+
+/************************** Enum Impls ********************************************/
+fn impl_for_enum(name: Ident, de: DataEnum) -> TokenStream {
+    let variants = get_enum_variant_types(&de);
+    let buffer_sizes_impls = define_buffer_size_for_enum(&variants);
+
+    let read_buffer = define_read_buffer_for_enum(&name, &de);
+    let write_buffer = define_write_buffer_for_enum(&name, &de);
+    quote! {
+        impl msg_socket::MsgOnSocket for #name {
+            #buffer_sizes_impls
+            #read_buffer
+            #write_buffer
+        }
+    }
+}
+
+fn define_buffer_size_for_enum(variants: &[(Ident, Vec<syn::Type>)]) -> TokenStream {
+    let mut variant_buffer_sizes = Vec::new();
+    let mut variant_fd_sizes = Vec::new();
+    for v in variants {
+        let (msg_size_impl, fd_count_impl) = get_fields_buffer_size_sum(&v.1);
+        variant_buffer_sizes.push(msg_size_impl);
+        variant_fd_sizes.push(fd_count_impl);
+    }
+    quote! {
+        fn msg_size() -> usize {
+            // First byte is used for variant.
+            [#(#variant_buffer_sizes,)*].iter().max().unwrap().clone() as usize + 1
+        }
+        fn max_fd_count() -> usize {
+            [#(#variant_fd_sizes,)*].iter().max().unwrap().clone() as usize
+        }
+    }
+}
+
+// Flatten enum variants. Return value = \[variant_name, \[types_of_this_variant\]\]
+fn get_enum_variant_types(de: &DataEnum) -> Vec<(Ident, Vec<syn::Type>)> {
+    let mut variants = Vec::new();
+    let de = de.clone();
+    for v in de.variants {
+        let name = v.ident;
+        match v.fields {
+            Fields::Unnamed(fields) => {
+                let mut vec = Vec::new();
+                for field in fields.unnamed {
+                    let ty = field.ty;
+                    vec.push(ty);
+                }
+                variants.push((name, vec));
+            }
+            Fields::Unit => {
+                variants.push((name, Vec::new()));
+                continue;
+            }
+            Fields::Named(fields) => {
+                let mut vec = Vec::new();
+                for field in fields.named {
+                    let ty = field.ty;
+                    vec.push(ty);
+                }
+                variants.push((name, vec));
+            }
+        };
+    }
+    variants
+}
+
+fn define_read_buffer_for_enum(name: &Ident, de: &DataEnum) -> TokenStream {
+    let mut match_variants = Vec::new();
+    let de = de.clone();
+    let mut i = 0u8;
+    for v in de.variants {
+        let variant_name = v.ident;
+        match v.fields {
+            Fields::Named(fields) => {
+                let mut tmp_names = Vec::new();
+                let mut read_tmps = Vec::new();
+                for f in fields.named {
+                    tmp_names.push(f.ident.clone());
+                    let read_tmp = read_from_buffer_and_move_offset(&f.ident.unwrap(), &f.ty);
+                    read_tmps.push(read_tmp);
+                }
+                let v = quote! {
+                    #i => {
+                        let mut __offset = 1usize;
+                        let mut __fd_offset = 0usize;
+                        #(#read_tmps)*
+                        Ok((#name::#variant_name { #(#tmp_names),* }, __fd_offset))
+                    }
+                };
+                match_variants.push(v);
+            }
+            Fields::Unnamed(fields) => {
+                let mut tmp_names = Vec::new();
+                let mut read_tmps = Vec::new();
+                let mut j = 0usize;
+                for f in fields.unnamed {
+                    let tmp_name = format!("enum_variant_tmp{}", j);
+                    let tmp_name = Ident::new(&tmp_name, Span::call_site());
+                    tmp_names.push(tmp_name.clone());
+                    let read_tmp = read_from_buffer_and_move_offset(&tmp_name, &f.ty);
+                    read_tmps.push(read_tmp);
+                    j += 1;
+                }
+
+                let v = quote! {
+                    #i => {
+                        let mut __offset = 1usize;
+                        let mut __fd_offset = 0usize;
+                        #(#read_tmps)*
+                        Ok((#name::#variant_name( #(#tmp_names),*), __fd_offset))
+                    }
+                };
+                match_variants.push(v);
+            }
+            Fields::Unit => {
+                let v = quote! {
+                    #i => Ok((#name::#variant_name, 0)),
+                };
+                match_variants.push(v);
+            }
+        }
+        i += 1;
+    }
+    quote! {
+        unsafe fn read_from_buffer(
+            buffer: &[u8],
+            fds: &[std::os::unix::io::RawFd],
+        ) -> msg_socket::MsgResult<(Self, usize)> {
+            let v = buffer[0];
+            match v {
+                #(#match_variants)*
+                _ => Err(msg_socket::MsgError::InvalidType),
+            }
+        }
+    }
+}
+
+fn define_write_buffer_for_enum(name: &Ident, de: &DataEnum) -> TokenStream {
+    let mut match_variants = Vec::new();
+    let mut i = 0u8;
+    let de = de.clone();
+    for v in de.variants {
+        let variant_name = v.ident;
+        match v.fields {
+            Fields::Named(fields) => {
+                let mut tmp_names = Vec::new();
+                let mut write_tmps = Vec::new();
+                for f in fields.named {
+                    tmp_names.push(f.ident.clone().unwrap());
+                    let write_tmp = enum_write_to_buffer_and_move_offset(&f.ident.unwrap(), &f.ty);
+                    write_tmps.push(write_tmp);
+                }
+
+                let v = quote! {
+                    #name::#variant_name { #(#tmp_names),* } => {
+                        buffer[0] = #i;
+                        let mut __offset = 1usize;
+                        let mut __fd_offset = 0usize;
+                        #(#write_tmps)*
+                        Ok(__fd_offset)
+                    }
+                };
+                match_variants.push(v);
+            }
+            Fields::Unnamed(fields) => {
+                let mut tmp_names = Vec::new();
+                let mut write_tmps = Vec::new();
+                let mut j = 0usize;
+                for f in fields.unnamed {
+                    let tmp_name = format!("enum_variant_tmp{}", j);
+                    let tmp_name = Ident::new(&tmp_name, Span::call_site());
+                    tmp_names.push(tmp_name.clone());
+                    let write_tmp = enum_write_to_buffer_and_move_offset(&tmp_name, &f.ty);
+                    write_tmps.push(write_tmp);
+                    j += 1;
+                }
+
+                let v = quote! {
+                    #name::#variant_name(#(#tmp_names),*) => {
+                        buffer[0] = #i;
+                        let mut __offset = 1usize;
+                        let mut __fd_offset = 0usize;
+                        #(#write_tmps)*
+                        Ok(__fd_offset)
+                    }
+                };
+                match_variants.push(v);
+            }
+            Fields::Unit => {
+                let v = quote! {
+                    #name::#variant_name => {
+                        buffer[0] = #i;
+                        Ok(0)
+                    }
+                };
+                match_variants.push(v);
+            }
+        }
+        i += 1;
+    }
+
+    quote! {
+        fn write_to_buffer(
+            &self,
+            buffer: &mut [u8],
+            fds: &mut [std::os::unix::io::RawFd],
+        ) -> msg_socket::MsgResult<usize> {
+            match self {
+                #(#match_variants)*
+            }
+        }
+    }
+}
+
+fn enum_write_to_buffer_and_move_offset(name: &Ident, ty: &syn::Type) -> TokenStream {
+    quote! {
+        let o = #name.write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
+        __offset += <#ty>::msg_size();
+        __fd_offset += o;
+    }
+}
+
+/************************** Tuple Impls ********************************************/
+fn impl_for_tuple_struct(name: Ident, ds: DataStruct) -> TokenStream {
+    let types = get_tuple_types(ds);
+
+    let buffer_sizes_impls = define_buffer_size_for_struct(&types);
+
+    let read_buffer = define_read_buffer_for_tuples(&name, &types);
+    let write_buffer = define_write_buffer_for_tuples(&name, &types);
+    quote! {
+        impl msg_socket::MsgOnSocket for #name {
+            #buffer_sizes_impls
+            #read_buffer
+            #write_buffer
+        }
+    }
+}
+
+fn get_tuple_types(ds: DataStruct) -> Vec<syn::Type> {
+    let mut types = Vec::new();
+    let fields = match ds.fields {
+        Fields::Unnamed(fields_unnamed) => fields_unnamed.unnamed,
+        _ => {
+            panic!("Tuple struct must have unnamed fields.");
+        }
+    };
+    for field in fields {
+        let ty = field.ty;
+        types.push(ty);
+    }
+    types
+}
+
+fn define_read_buffer_for_tuples(name: &Ident, fields: &[syn::Type]) -> TokenStream {
+    let mut read_fields = Vec::new();
+    let mut init_fields = Vec::new();
+    for i in 0..fields.len() {
+        let tmp_name = format!("tuple_tmp{}", i);
+        let tmp_name = Ident::new(&tmp_name, Span::call_site());
+        let read_field = read_from_buffer_and_move_offset(&tmp_name, &fields[i]);
+        read_fields.push(read_field);
+        init_fields.push(quote!(#tmp_name));
+    }
+
+    quote! {
+        unsafe fn read_from_buffer(
+            buffer: &[u8],
+            fds: &[std::os::unix::io::RawFd],
+        ) -> msg_socket::MsgResult<(Self, usize)> {
+            let mut __offset = 0usize;
+            let mut __fd_offset = 0usize;
+            #(#read_fields)*
+            Ok((
+                #name (
+                    #(#init_fields),*
+                ),
+                __fd_offset
+            ))
+        }
+    }
+}
+
+fn define_write_buffer_for_tuples(name: &Ident, fields: &[syn::Type]) -> TokenStream {
+    let mut write_fields = Vec::new();
+    let mut tmp_names = Vec::new();
+    for i in 0..fields.len() {
+        let tmp_name = format!("tuple_tmp{}", i);
+        let tmp_name = Ident::new(&tmp_name, Span::call_site());
+        let write_field = enum_write_to_buffer_and_move_offset(&tmp_name, &fields[i]);
+        write_fields.push(write_field);
+        tmp_names.push(tmp_name);
+    }
+    quote! {
+        fn write_to_buffer(
+            &self,
+            buffer: &mut [u8],
+            fds: &mut [std::os::unix::io::RawFd],
+        ) -> msg_socket::MsgResult<usize> {
+            let mut __offset = 0usize;
+            let mut __fd_offset = 0usize;
+            let #name( #(#tmp_names),* ) = self;
+            #(#write_fields)*
+            Ok(__fd_offset)
+        }
+    }
+}
+/************************** Helpers ********************************************/
+fn get_fields_buffer_size_sum(field_types: &[syn::Type]) -> (TokenStream, TokenStream) {
+    if field_types.len() > 0 {
+        (
+            quote! {
+                #( <#field_types>::msg_size() as usize )+*
+            },
+            quote! {
+                #( <#field_types>::max_fd_count() as usize )+*
+            },
+        )
+    } else {
+        (quote!(0), quote!(0))
+    }
+}
+
+fn read_from_buffer_and_move_offset(name: &Ident, ty: &syn::Type) -> TokenStream {
+    quote! {
+        let t = <#ty>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
+        __offset += <#ty>::msg_size();
+        __fd_offset += t.1;
+        let #name = t.0;
+    }
+}
+
+fn write_to_buffer_and_move_offset(name: &Ident, ty: &syn::Type) -> TokenStream {
+    quote! {
+        let o = self.#name.write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
+        __offset += <#ty>::msg_size();
+        __fd_offset += o;
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::socket_msg_impl;
+    use quote::quote;
+    use syn::{parse_quote, DeriveInput};
+
+    #[test]
+    fn end_to_end_struct_test() {
+        let input: DeriveInput = parse_quote! {
+            struct MyMsg {
+                a: u8,
+                b: RawFd,
+                c: u32,
+            }
+        };
+
+        let expected = quote! {
+            impl msg_socket::MsgOnSocket for MyMsg {
+                fn msg_size() -> usize {
+                    <u8>::msg_size() as usize
+                        + <RawFd>::msg_size() as usize
+                        + <u32>::msg_size() as usize
+                }
+                fn max_fd_count() -> usize {
+                    <u8>::max_fd_count() as usize
+                        + <RawFd>::max_fd_count() as usize
+                        + <u32>::max_fd_count() as usize
+                }
+                unsafe fn read_from_buffer(
+                    buffer: &[u8],
+                    fds: &[std::os::unix::io::RawFd],
+                ) -> msg_socket::MsgResult<(Self, usize)> {
+                    let mut __offset = 0usize;
+                    let mut __fd_offset = 0usize;
+                    let t = <u8>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
+                    __offset += <u8>::msg_size();
+                    __fd_offset += t.1;
+                    let a = t.0;
+                    let t = <RawFd>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
+                    __offset += <RawFd>::msg_size();
+                    __fd_offset += t.1;
+                    let b = t.0;
+                    let t = <u32>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
+                    __offset += <u32>::msg_size();
+                    __fd_offset += t.1;
+                    let c = t.0;
+                    Ok((Self { a, b, c }, __fd_offset))
+                }
+                fn write_to_buffer(
+                    &self,
+                    buffer: &mut [u8],
+                    fds: &mut [std::os::unix::io::RawFd],
+                ) -> msg_socket::MsgResult<usize> {
+                    let mut __offset = 0usize;
+                    let mut __fd_offset = 0usize;
+                    let o = self.a
+                        .write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
+                    __offset += <u8>::msg_size();
+                    __fd_offset += o;
+                    let o = self.b
+                        .write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
+                    __offset += <RawFd>::msg_size();
+                    __fd_offset += o;
+                    let o = self.c
+                        .write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
+                    __offset += <u32>::msg_size();
+                    __fd_offset += o;
+                    Ok(__fd_offset)
+                }
+            }
+        };
+
+        assert_eq!(socket_msg_impl(input).to_string(), expected.to_string());
+    }
+
+    #[test]
+    fn end_to_end_tuple_struct_test() {
+        let input: DeriveInput = parse_quote! {
+            struct MyMsg(u8, u32, File);
+        };
+
+        let expected = quote! {
+            impl msg_socket::MsgOnSocket for MyMsg {
+                fn msg_size() -> usize {
+                    <u8>::msg_size() as usize
+                        + <u32>::msg_size() as usize
+                        + <File>::msg_size() as usize
+                }
+                fn max_fd_count() -> usize {
+                    <u8>::max_fd_count() as usize
+                        + <u32>::max_fd_count() as usize
+                        + <File>::max_fd_count() as usize
+                }
+                unsafe fn read_from_buffer(
+                    buffer: &[u8],
+                    fds: &[std::os::unix::io::RawFd],
+                ) -> msg_socket::MsgResult<(Self, usize)> {
+                    let mut __offset = 0usize;
+                    let mut __fd_offset = 0usize;
+                    let t = <u8>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
+                    __offset += <u8>::msg_size();
+                    __fd_offset += t.1;
+                    let tuple_tmp0 = t.0;
+                    let t = <u32>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
+                    __offset += <u32>::msg_size();
+                    __fd_offset += t.1;
+                    let tuple_tmp1 = t.0;
+                    let t = <File>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
+                    __offset += <File>::msg_size();
+                    __fd_offset += t.1;
+                    let tuple_tmp2 = t.0;
+                    Ok((MyMsg(tuple_tmp0, tuple_tmp1, tuple_tmp2), __fd_offset))
+                }
+                fn write_to_buffer(
+                    &self,
+                    buffer: &mut [u8],
+                    fds: &mut [std::os::unix::io::RawFd],
+                ) -> msg_socket::MsgResult<usize> {
+                    let mut __offset = 0usize;
+                    let mut __fd_offset = 0usize;
+                    let MyMsg(tuple_tmp0, tuple_tmp1, tuple_tmp2) = self;
+                    let o = tuple_tmp0
+                        .write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
+                    __offset += <u8>::msg_size();
+                    __fd_offset += o;
+                    let o = tuple_tmp1
+                        .write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
+                    __offset += <u32>::msg_size();
+                    __fd_offset += o;
+                    let o = tuple_tmp2
+                        .write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
+                    __offset += <File>::msg_size();
+                    __fd_offset += o;
+                    Ok(__fd_offset)
+                }
+            }
+        };
+
+        assert_eq!(socket_msg_impl(input).to_string(), expected.to_string());
+    }
+
+    #[test]
+    fn end_to_end_enum_test() {
+        let input: DeriveInput = parse_quote! {
+            enum MyMsg {
+                A(u8),
+                B,
+                C {
+                    f0: u8,
+                    f1: RawFd,
+                },
+            }
+        };
+
+        let expected = quote! {
+            impl msg_socket::MsgOnSocket for MyMsg {
+                fn msg_size() -> usize {
+                    [
+                        <u8>::msg_size() as usize,
+                        0,
+                        <u8>::msg_size() as usize + <RawFd>::msg_size() as usize,
+                    ].iter()
+                        .max().unwrap().clone() as usize+ 1
+                }
+                fn max_fd_count() -> usize {
+                    [
+                        <u8>::max_fd_count() as usize,
+                        0,
+                        <u8>::max_fd_count() as usize + <RawFd>::max_fd_count() as usize,
+                    ].iter()
+                        .max().unwrap().clone() as usize
+                }
+                unsafe fn read_from_buffer(
+                    buffer: &[u8],
+                    fds: &[std::os::unix::io::RawFd],
+                ) -> msg_socket::MsgResult<(Self, usize)> {
+                    let v = buffer[0];
+                    match v {
+                        0u8 => {
+                            let mut __offset = 1usize;
+                            let mut __fd_offset = 0usize;
+                            let t =
+                                <u8>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
+                            __offset += <u8>::msg_size();
+                            __fd_offset += t.1;
+                            let enum_variant_tmp0 = t.0;
+                            Ok((MyMsg::A(enum_variant_tmp0), __fd_offset))
+                        }
+                        1u8 => Ok((MyMsg::B, 0)),
+                        2u8 => {
+                            let mut __offset = 1usize;
+                            let mut __fd_offset = 0usize;
+                            let t =
+                                <u8>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
+                            __offset += <u8>::msg_size();
+                            __fd_offset += t.1;
+                            let f0 = t.0;
+                            let t = <RawFd>::read_from_buffer(
+                                &buffer[__offset..],
+                                &fds[__fd_offset..]
+                            )?;
+                            __offset += <RawFd>::msg_size();
+                            __fd_offset += t.1;
+                            let f1 = t.0;
+                            Ok((MyMsg::C { f0, f1 }, __fd_offset))
+                        }
+                        _ => Err(msg_socket::MsgError::InvalidType),
+                    }
+                }
+                fn write_to_buffer(
+                    &self,
+                    buffer: &mut [u8],
+                    fds: &mut [std::os::unix::io::RawFd],
+                ) -> msg_socket::MsgResult<usize> {
+                    match self {
+                        MyMsg::A(enum_variant_tmp0) => {
+                            buffer[0] = 0u8;
+                            let mut __offset = 1usize;
+                            let mut __fd_offset = 0usize;
+                            let o = enum_variant_tmp0
+                                .write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
+                            __offset += <u8>::msg_size();
+                            __fd_offset += o;
+                            Ok(__fd_offset)
+                        }
+                        MyMsg::B => {
+                            buffer[0] = 1u8;
+                            Ok(0)
+                        }
+                        MyMsg::C { f0, f1 } => {
+                            buffer[0] = 2u8;
+                            let mut __offset = 1usize;
+                            let mut __fd_offset = 0usize;
+                            let o = f0
+                                .write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
+                            __offset += <u8>::msg_size();
+                            __fd_offset += o;
+                            let o = f1
+                                .write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
+                            __offset += <RawFd>::msg_size();
+                            __fd_offset += o;
+                            Ok(__fd_offset)
+                        }
+                    }
+                }
+            }
+
+        };
+
+        assert_eq!(socket_msg_impl(input).to_string(), expected.to_string());
+    }
+}
diff --git a/msg_socket/src/lib.rs b/msg_socket/src/lib.rs
new file mode 100644
index 0000000..bead3da
--- /dev/null
+++ b/msg_socket/src/lib.rs
@@ -0,0 +1,191 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+mod msg_on_socket;
+
+use std::io::Result;
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::os::unix::io::{AsRawFd, RawFd};
+
+use sys_util::{handle_eintr, net::UnixSeqpacket, Error as SysError, ScmSocket};
+
+pub use crate::msg_on_socket::*;
+pub use msg_on_socket_derive::*;
+
+/// Create a pair of socket. Request is send in one direction while response is in the other
+/// direction.
+pub fn pair<Request: MsgOnSocket, Response: MsgOnSocket>(
+) -> Result<(MsgSocket<Request, Response>, MsgSocket<Response, Request>)> {
+    let (sock1, sock2) = UnixSeqpacket::pair()?;
+    let requester = MsgSocket {
+        sock: sock1,
+        _i: PhantomData,
+        _o: PhantomData,
+    };
+    let responder = MsgSocket {
+        sock: sock2,
+        _i: PhantomData,
+        _o: PhantomData,
+    };
+    Ok((requester, responder))
+}
+
+/// Bidirection sock that support both send and recv.
+pub struct MsgSocket<I: MsgOnSocket, O: MsgOnSocket> {
+    sock: UnixSeqpacket,
+    _i: PhantomData<I>,
+    _o: PhantomData<O>,
+}
+
+impl<I: MsgOnSocket, O: MsgOnSocket> MsgSocket<I, O> {
+    // Create a new MsgSocket.
+    pub fn new(s: UnixSeqpacket) -> MsgSocket<I, O> {
+        MsgSocket {
+            sock: s,
+            _i: PhantomData,
+            _o: PhantomData,
+        }
+    }
+}
+
+impl<I: MsgOnSocket, O: MsgOnSocket> Deref for MsgSocket<I, O> {
+    type Target = UnixSeqpacket;
+    fn deref(&self) -> &Self::Target {
+        &self.sock
+    }
+}
+
+/// One direction socket that only supports sending.
+pub struct Sender<M: MsgOnSocket> {
+    sock: UnixSeqpacket,
+    _m: PhantomData<M>,
+}
+
+impl<M: MsgOnSocket> Sender<M> {
+    /// Create a new sender sock.
+    pub fn new(s: UnixSeqpacket) -> Sender<M> {
+        Sender {
+            sock: s,
+            _m: PhantomData,
+        }
+    }
+}
+
+/// One direction socket that only supports receiving.
+pub struct Receiver<M: MsgOnSocket> {
+    sock: UnixSeqpacket,
+    _m: PhantomData<M>,
+}
+
+impl<M: MsgOnSocket> Receiver<M> {
+    /// Create a new receiver sock.
+    pub fn new(s: UnixSeqpacket) -> Receiver<M> {
+        Receiver {
+            sock: s,
+            _m: PhantomData,
+        }
+    }
+}
+
+impl<I: MsgOnSocket, O: MsgOnSocket> AsRef<UnixSeqpacket> for MsgSocket<I, O> {
+    fn as_ref(&self) -> &UnixSeqpacket {
+        &self.sock
+    }
+}
+
+impl<I: MsgOnSocket, O: MsgOnSocket> AsRawFd for MsgSocket<I, O> {
+    fn as_raw_fd(&self) -> RawFd {
+        self.sock.as_raw_fd()
+    }
+}
+
+impl<M: MsgOnSocket> AsRef<UnixSeqpacket> for Sender<M> {
+    fn as_ref(&self) -> &UnixSeqpacket {
+        &self.sock
+    }
+}
+
+impl<M: MsgOnSocket> AsRawFd for Sender<M> {
+    fn as_raw_fd(&self) -> RawFd {
+        self.sock.as_raw_fd()
+    }
+}
+
+impl<M: MsgOnSocket> AsRef<UnixSeqpacket> for Receiver<M> {
+    fn as_ref(&self) -> &UnixSeqpacket {
+        &self.sock
+    }
+}
+
+impl<M: MsgOnSocket> AsRawFd for Receiver<M> {
+    fn as_raw_fd(&self) -> RawFd {
+        self.sock.as_raw_fd()
+    }
+}
+
+/// Types that could send a message.
+pub trait MsgSender<M: MsgOnSocket>: AsRef<UnixSeqpacket> {
+    fn send(&self, msg: &M) -> MsgResult<()> {
+        let msg_size = M::msg_size();
+        let fd_size = M::max_fd_count();
+        let mut msg_buffer: Vec<u8> = vec![0; msg_size];
+        let mut fd_buffer: Vec<RawFd> = vec![0; fd_size];
+
+        let fd_size = msg.write_to_buffer(&mut msg_buffer, &mut fd_buffer)?;
+        let sock: &UnixSeqpacket = self.as_ref();
+        if fd_size == 0 {
+            handle_eintr!(sock.send(&msg_buffer))
+                .map_err(|e| MsgError::Send(SysError::new(e.raw_os_error().unwrap_or(0))))?;
+        } else {
+            sock.send_with_fds(&msg_buffer[..], &fd_buffer[0..fd_size])
+                .map_err(MsgError::Send)?;
+        }
+        Ok(())
+    }
+}
+
+/// Types that could receive a message.
+pub trait MsgReceiver<M: MsgOnSocket>: AsRef<UnixSeqpacket> {
+    fn recv(&self) -> MsgResult<M> {
+        let msg_size = M::msg_size();
+        let fd_size = M::max_fd_count();
+        let mut msg_buffer: Vec<u8> = vec![0; msg_size];
+        let mut fd_buffer: Vec<RawFd> = vec![0; fd_size];
+
+        let sock: &UnixSeqpacket = self.as_ref();
+
+        let (recv_msg_size, recv_fd_size) = {
+            if fd_size == 0 {
+                let size = sock
+                    .recv(&mut msg_buffer)
+                    .map_err(|e| MsgError::Recv(SysError::new(e.raw_os_error().unwrap_or(0))))?;
+                (size, 0)
+            } else {
+                sock.recv_with_fds(&mut msg_buffer, &mut fd_buffer)
+                    .map_err(MsgError::Recv)?
+            }
+        };
+        if msg_size != recv_msg_size {
+            return Err(MsgError::BadRecvSize {
+                expected: msg_size,
+                actual: recv_msg_size,
+            });
+        }
+        // Safe because fd buffer is read from socket.
+        let (v, read_fd_size) = unsafe {
+            M::read_from_buffer(&msg_buffer[0..recv_msg_size], &fd_buffer[0..recv_fd_size])?
+        };
+        if recv_fd_size != read_fd_size {
+            return Err(MsgError::NotExpectFd);
+        }
+        Ok(v)
+    }
+}
+
+impl<I: MsgOnSocket, O: MsgOnSocket> MsgSender<I> for MsgSocket<I, O> {}
+impl<I: MsgOnSocket, O: MsgOnSocket> MsgReceiver<O> for MsgSocket<I, O> {}
+
+impl<M: MsgOnSocket> MsgSender<M> for Sender<M> {}
+impl<M: MsgOnSocket> MsgReceiver<M> for Receiver<M> {}
diff --git a/msg_socket/src/msg_on_socket.rs b/msg_socket/src/msg_on_socket.rs
new file mode 100644
index 0000000..2924dc6
--- /dev/null
+++ b/msg_socket/src/msg_on_socket.rs
@@ -0,0 +1,385 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::net::{TcpListener, TcpStream, UdpSocket};
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
+use std::result;
+
+use data_model::*;
+use sys_util::{Error as SysError, EventFd};
+
+#[derive(Debug, PartialEq)]
+/// An error during transaction or serialization/deserialization.
+pub enum MsgError {
+    /// Error while sending a request or response.
+    Send(SysError),
+    /// Error while receiving a request or response.
+    Recv(SysError),
+    /// The type of a received request or response is unknown.
+    InvalidType,
+    /// There was not the expected amount of data when receiving a message. The inner
+    /// value is how much data is expected and how much data was actually received.
+    BadRecvSize { expected: usize, actual: usize },
+    /// There was no associated file descriptor received for a request that expected it.
+    ExpectFd,
+    /// There was some associated file descriptor received but not used when deserialize.
+    NotExpectFd,
+    /// Trying to serialize/deserialize, but fd buffer size is too small. This typically happens
+    /// when max_fd_count() returns a value that is too small.
+    WrongFdBufferSize,
+    /// Trying to serialize/deserialize, but msg buffer size is too small. This typically happens
+    /// when msg_size() returns a value that is too small.
+    WrongMsgBufferSize,
+}
+
+pub type MsgResult<T> = result::Result<T, MsgError>;
+
+impl Display for MsgError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::MsgError::*;
+
+        match self {
+            Send(e) => write!(f, "failed to send request or response: {}", e),
+            Recv(e) => write!(f, "failed to receive request or response: {}", e),
+            InvalidType => write!(f, "invalid type"),
+            BadRecvSize { expected, actual } => write!(
+                f,
+                "wrong amount of data received; expected {} bytes; got {} bytes",
+                expected, actual
+            ),
+            ExpectFd => write!(f, "missing associated file descriptor for request"),
+            NotExpectFd => write!(f, "unexpected file descriptor is unused"),
+            WrongFdBufferSize => write!(f, "fd buffer size too small"),
+            WrongMsgBufferSize => write!(f, "msg buffer size too small"),
+        }
+    }
+}
+
+/// A msg that could be serialized to and deserialize from array in little endian.
+///
+/// For structs, we always have fixed size of bytes and fixed count of fds.
+/// For enums, the size needed might be different for each variant.
+///
+/// e.g.
+/// ```
+/// use std::os::unix::io::RawFd;
+/// enum Message {
+///     VariantA(u8),
+///     VariantB(u32, RawFd),
+///     VariantC,
+/// }
+/// ```
+///
+/// For variant A, we need 1 byte to store its inner value.
+/// For variant B, we need 4 bytes and 1 RawFd to store its inner value.
+/// For variant C, we need 0 bytes to store its inner value.
+/// When we serialize Message to (buffer, fd_buffer), we always use fixed number of bytes in
+/// the buffer. Unused buffer bytes will be padded with zero.
+/// However, for fd_buffer, we could not do the same thing. Otherwise, we are essentially sending
+/// fd 0 through the socket.
+/// Thus, read/write functions always the return correct count of fds in this variant. There will be
+/// no padding in fd_buffer.
+pub trait MsgOnSocket: Sized {
+    /// Size of message in bytes.
+    fn msg_size() -> usize;
+    /// Max possible fd count in this type.
+    fn max_fd_count() -> usize {
+        0
+    }
+    /// Returns (self, fd read count).
+    /// This function is safe only when:
+    ///     0. fds contains valid fds, received from socket, serialized by Self::write_to_buffer.
+    ///     1. For enum, fds contains correct fd layout of the particular variant.
+    ///     2. write_to_buffer is implemented correctly(put valid fds into the buffer, has no padding,
+    ///        return correct count).
+    unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)>;
+    /// Serialize self to buffers.
+    fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize>;
+}
+
+impl MsgOnSocket for SysError {
+    fn msg_size() -> usize {
+        u32::msg_size()
+    }
+    unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+        let (v, size) = u32::read_from_buffer(buffer, fds)?;
+        Ok((SysError::new(v as i32), size))
+    }
+    fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
+        let v = self.errno() as u32;
+        v.write_to_buffer(buffer, fds)
+    }
+}
+
+impl MsgOnSocket for RawFd {
+    fn msg_size() -> usize {
+        0
+    }
+    fn max_fd_count() -> usize {
+        1
+    }
+    unsafe fn read_from_buffer(_buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+        if fds.is_empty() {
+            return Err(MsgError::ExpectFd);
+        }
+        Ok((fds[0], 1))
+    }
+    fn write_to_buffer(&self, _buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
+        if fds.is_empty() {
+            return Err(MsgError::WrongFdBufferSize);
+        }
+        fds[0] = *self;
+        Ok(1)
+    }
+}
+
+impl<T: MsgOnSocket> MsgOnSocket for Option<T> {
+    fn msg_size() -> usize {
+        T::msg_size() + 1
+    }
+
+    fn max_fd_count() -> usize {
+        T::max_fd_count()
+    }
+
+    unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+        match buffer[0] {
+            0 => Ok((None, 0)),
+            1 => {
+                let (inner, len) = T::read_from_buffer(&buffer[1..], fds)?;
+                Ok((Some(inner), len))
+            }
+            _ => Err(MsgError::InvalidType),
+        }
+    }
+
+    fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
+        match self {
+            None => {
+                buffer[0] = 0;
+                Ok(0)
+            }
+            Some(inner) => {
+                buffer[0] = 1;
+                inner.write_to_buffer(&mut buffer[1..], fds)
+            }
+        }
+    }
+}
+
+impl MsgOnSocket for () {
+    fn msg_size() -> usize {
+        0
+    }
+
+    fn max_fd_count() -> usize {
+        0
+    }
+
+    unsafe fn read_from_buffer(_buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+        Ok(((), 0))
+    }
+
+    fn write_to_buffer(&self, _buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
+        Ok(0)
+    }
+}
+
+macro_rules! rawfd_impl {
+    ($type:ident) => {
+        impl MsgOnSocket for $type {
+            fn msg_size() -> usize {
+                0
+            }
+            fn max_fd_count() -> usize {
+                1
+            }
+            unsafe fn read_from_buffer(_buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+                if fds.len() < 1 {
+                    return Err(MsgError::ExpectFd);
+                }
+                Ok(($type::from_raw_fd(fds[0].clone()), 1))
+            }
+            fn write_to_buffer(&self, _buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
+                if fds.len() < 1 {
+                    return Err(MsgError::WrongFdBufferSize);
+                }
+                fds[0] = self.as_raw_fd();
+                Ok(1)
+            }
+        }
+    };
+}
+
+rawfd_impl!(EventFd);
+rawfd_impl!(File);
+rawfd_impl!(UnixStream);
+rawfd_impl!(TcpStream);
+rawfd_impl!(TcpListener);
+rawfd_impl!(UdpSocket);
+rawfd_impl!(UnixListener);
+rawfd_impl!(UnixDatagram);
+
+// Converts a slice into an array of fixed size inferred from by the return value. Panics if the
+// slice is too small, but will tolerate slices that are too large.
+fn slice_to_array<T, O>(s: &[T]) -> O
+where
+    T: Copy,
+    O: Default + AsMut<[T]>,
+{
+    let mut o = O::default();
+    let o_slice = o.as_mut();
+    let len = o_slice.len();
+    o_slice.copy_from_slice(&s[..len]);
+    o
+}
+
+// usize could be different sizes on different targets. We always use u64.
+impl MsgOnSocket for usize {
+    fn msg_size() -> usize {
+        std::mem::size_of::<u64>()
+    }
+    unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+        if buffer.len() < std::mem::size_of::<u64>() {
+            return Err(MsgError::WrongMsgBufferSize);
+        }
+        let t = u64::from_le_bytes(slice_to_array(buffer));
+        Ok((t as usize, 0))
+    }
+
+    fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
+        if buffer.len() < std::mem::size_of::<u64>() {
+            return Err(MsgError::WrongMsgBufferSize);
+        }
+        let t: Le64 = (*self as u64).into();
+        buffer[0..Self::msg_size()].copy_from_slice(t.as_slice());
+        Ok(0)
+    }
+}
+
+// Encode bool as a u8 of value 0 or 1
+impl MsgOnSocket for bool {
+    fn msg_size() -> usize {
+        std::mem::size_of::<u8>()
+    }
+    unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+        if buffer.len() < std::mem::size_of::<u8>() {
+            return Err(MsgError::WrongMsgBufferSize);
+        }
+        let t: u8 = buffer[0];
+        match t {
+            0 => Ok((false, 0)),
+            1 => Ok((true, 0)),
+            _ => Err(MsgError::InvalidType),
+        }
+    }
+    fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
+        if buffer.len() < std::mem::size_of::<u8>() {
+            return Err(MsgError::WrongMsgBufferSize);
+        }
+        buffer[0] = *self as u8;
+        Ok(0)
+    }
+}
+
+macro_rules! le_impl {
+    ($type:ident, $native_type:ident) => {
+        impl MsgOnSocket for $type {
+            fn msg_size() -> usize {
+                std::mem::size_of::<$native_type>()
+            }
+            unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+                if buffer.len() < std::mem::size_of::<$native_type>() {
+                    return Err(MsgError::WrongMsgBufferSize);
+                }
+                let t = $native_type::from_le_bytes(slice_to_array(buffer));
+                Ok((t.into(), 0))
+            }
+
+            fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
+                if buffer.len() < std::mem::size_of::<$native_type>() {
+                    return Err(MsgError::WrongMsgBufferSize);
+                }
+                let t: $native_type = self.clone().into();
+                buffer[0..Self::msg_size()].copy_from_slice(&t.to_le_bytes());
+                Ok(0)
+            }
+        }
+    };
+}
+
+le_impl!(u8, u8);
+le_impl!(u16, u16);
+le_impl!(u32, u32);
+le_impl!(u64, u64);
+
+le_impl!(Le16, u16);
+le_impl!(Le32, u32);
+le_impl!(Le64, u64);
+
+macro_rules! array_impls {
+    ($N:expr, $t: ident $($ts:ident)*)
+    => {
+        impl<T: MsgOnSocket + Clone> MsgOnSocket for [T; $N] {
+            fn msg_size() -> usize {
+                T::msg_size() * $N
+            }
+            fn max_fd_count() -> usize {
+                T::max_fd_count() * $N
+            }
+            unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+                if buffer.len() < Self::msg_size() {
+                    return Err(MsgError::WrongMsgBufferSize);
+                }
+                let mut offset = 0usize;
+                let mut fd_offset = 0usize;
+                let ($t, fd_size) =
+                    T::read_from_buffer(&buffer[offset..], &fds[fd_offset..])?;
+                offset += T::msg_size();
+                fd_offset += fd_size;
+                $(
+                    let ($ts, fd_size) =
+                        T::read_from_buffer(&buffer[offset..], &fds[fd_offset..])?;
+                    offset += T::msg_size();
+                    fd_offset += fd_size;
+                    )*
+                assert_eq!(offset, Self::msg_size());
+                Ok(([$t, $($ts),*], fd_offset))
+            }
+
+            fn write_to_buffer(
+                &self,
+                buffer: &mut [u8],
+                fds: &mut [RawFd],
+                ) -> MsgResult<usize> {
+                if buffer.len() < Self::msg_size() {
+                    return Err(MsgError::WrongMsgBufferSize);
+                }
+                let mut offset = 0usize;
+                let mut fd_offset = 0usize;
+                for idx in 0..$N {
+                    let fd_size = self[idx].clone().write_to_buffer(&mut buffer[offset..],
+                                                            &mut fds[fd_offset..])?;
+                    offset += T::msg_size();
+                    fd_offset += fd_size;
+                }
+
+                Ok(fd_offset)
+            }
+        }
+        array_impls!(($N - 1), $($ts)*);
+    };
+    {$N:expr, } => {};
+}
+
+array_impls! {
+    32, tmp1 tmp2 tmp3 tmp4 tmp5 tmp6 tmp7 tmp8 tmp9 tmp10 tmp11 tmp12 tmp13 tmp14 tmp15 tmp16
+        tmp17 tmp18 tmp19 tmp20 tmp21 tmp22 tmp23 tmp24 tmp25 tmp26 tmp27 tmp28 tmp29 tmp30 tmp31
+        tmp32
+}
+
+// TODO(jkwang) Define MsgOnSocket for tuple?
diff --git a/msg_socket/tests/enum.rs b/msg_socket/tests/enum.rs
new file mode 100644
index 0000000..0e590f0
--- /dev/null
+++ b/msg_socket/tests/enum.rs
@@ -0,0 +1,67 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use sys_util::EventFd;
+
+use msg_socket::*;
+
+#[derive(MsgOnSocket)]
+struct DummyRequest {}
+
+#[derive(MsgOnSocket)]
+enum Response {
+    A(u8),
+    B,
+    C(u32, EventFd),
+    D([u8; 4]),
+    E { f0: u8, f1: u32 },
+}
+
+#[test]
+fn sock_send_recv_enum() {
+    let (req, res) = pair::<DummyRequest, Response>().unwrap();
+    let e0 = EventFd::new().unwrap();
+    let e1 = e0.try_clone().unwrap();
+    res.send(&Response::C(0xf0f0, e0)).unwrap();
+    let r = req.recv().unwrap();
+    match r {
+        Response::C(v, efd) => {
+            assert_eq!(v, 0xf0f0);
+            efd.write(0x0f0f).unwrap();
+        }
+        _ => panic!("wrong type"),
+    };
+    assert_eq!(e1.read().unwrap(), 0x0f0f);
+
+    res.send(&Response::B).unwrap();
+    match req.recv().unwrap() {
+        Response::B => {}
+        _ => panic!("Wrong enum type"),
+    };
+
+    res.send(&Response::A(0x3)).unwrap();
+    match req.recv().unwrap() {
+        Response::A(v) => assert_eq!(v, 0x3),
+        _ => panic!("Wrong enum type"),
+    };
+
+    res.send(&Response::D([0, 1, 2, 3])).unwrap();
+    match req.recv().unwrap() {
+        Response::D(v) => assert_eq!(v, [0, 1, 2, 3]),
+        _ => panic!("Wrong enum type"),
+    };
+
+    res.send(&Response::E {
+        f0: 0x12,
+        f1: 0x0f0f,
+    })
+    .unwrap();
+    match req.recv().unwrap() {
+        Response::E { f0, f1 } => {
+            assert_eq!(f0, 0x12);
+            assert_eq!(f1, 0x0f0f);
+        }
+        _ => panic!("Wrong enum type"),
+    };
+}
diff --git a/msg_socket/tests/struct.rs b/msg_socket/tests/struct.rs
new file mode 100644
index 0000000..5efc369
--- /dev/null
+++ b/msg_socket/tests/struct.rs
@@ -0,0 +1,38 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use sys_util::EventFd;
+
+use msg_socket::*;
+
+#[derive(MsgOnSocket)]
+struct Request {
+    field0: u8,
+    field1: EventFd,
+    field2: u32,
+    field3: bool,
+}
+
+#[derive(MsgOnSocket)]
+struct DummyResponse {}
+
+#[test]
+fn sock_send_recv_struct() {
+    let (req, res) = pair::<Request, DummyResponse>().unwrap();
+    let e0 = EventFd::new().unwrap();
+    let e1 = e0.try_clone().unwrap();
+    req.send(&Request {
+        field0: 2,
+        field1: e0,
+        field2: 0xf0f0,
+        field3: true,
+    })
+    .unwrap();
+    let r = res.recv().unwrap();
+    assert_eq!(r.field0, 2);
+    assert_eq!(r.field2, 0xf0f0);
+    assert_eq!(r.field3, true);
+    r.field1.write(0x0f0f).unwrap();
+    assert_eq!(e1.read().unwrap(), 0x0f0f);
+}
diff --git a/msg_socket/tests/tuple.rs b/msg_socket/tests/tuple.rs
new file mode 100644
index 0000000..862e0cb
--- /dev/null
+++ b/msg_socket/tests/tuple.rs
@@ -0,0 +1,22 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use msg_socket::*;
+use sys_util::EventFd;
+
+#[derive(MsgOnSocket)]
+struct Message(u8, u16, EventFd);
+
+#[test]
+fn sock_send_recv_tuple() {
+    let (req, res) = pair::<Message, Message>().unwrap();
+    let e0 = EventFd::new().unwrap();
+    let e1 = e0.try_clone().unwrap();
+    req.send(&Message(1, 0x12, e0)).unwrap();
+    let r = res.recv().unwrap();
+    assert_eq!(r.0, 1);
+    assert_eq!(r.1, 0x12);
+    r.2.write(0x0f0f).unwrap();
+    assert_eq!(e1.read().unwrap(), 0x0f0f);
+}
diff --git a/msg_socket/tests/unit.rs b/msg_socket/tests/unit.rs
new file mode 100644
index 0000000..9855752
--- /dev/null
+++ b/msg_socket/tests/unit.rs
@@ -0,0 +1,12 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use msg_socket::*;
+
+#[test]
+fn sock_send_recv_unit() {
+    let (req, res) = pair::<(), ()>().unwrap();
+    req.send(&()).unwrap();
+    let _ = res.recv().unwrap();
+}
diff --git a/net_sys/Cargo.toml b/net_sys/Cargo.toml
new file mode 100644
index 0000000..ec04269
--- /dev/null
+++ b/net_sys/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "net_sys"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+sys_util = { path = "../sys_util" }
diff --git a/net_sys/src/if_tun.rs b/net_sys/src/if_tun.rs
new file mode 100644
index 0000000..0874b77
--- /dev/null
+++ b/net_sys/src/if_tun.rs
@@ -0,0 +1,599 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+#[repr(C)]
+#[derive(Default)]
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
+impl<T> __IncompleteArrayField<T> {
+    #[inline]
+    pub fn new() -> Self {
+        __IncompleteArrayField(::std::marker::PhantomData)
+    }
+    #[inline]
+    pub unsafe fn as_ptr(&self) -> *const T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_slice(&self, len: usize) -> &[T] {
+        ::std::slice::from_raw_parts(self.as_ptr(), len)
+    }
+    #[inline]
+    pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
+        ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
+    }
+}
+impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        fmt.write_str("__IncompleteArrayField")
+    }
+}
+impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self::new()
+    }
+}
+impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
+pub const __BITS_PER_LONG: ::std::os::raw::c_uint = 64;
+pub const __FD_SETSIZE: ::std::os::raw::c_uint = 1024;
+pub const ETH_ALEN: ::std::os::raw::c_uint = 6;
+pub const ETH_HLEN: ::std::os::raw::c_uint = 14;
+pub const ETH_ZLEN: ::std::os::raw::c_uint = 60;
+pub const ETH_DATA_LEN: ::std::os::raw::c_uint = 1500;
+pub const ETH_FRAME_LEN: ::std::os::raw::c_uint = 1514;
+pub const ETH_FCS_LEN: ::std::os::raw::c_uint = 4;
+pub const ETH_P_LOOP: ::std::os::raw::c_uint = 96;
+pub const ETH_P_PUP: ::std::os::raw::c_uint = 512;
+pub const ETH_P_PUPAT: ::std::os::raw::c_uint = 513;
+pub const ETH_P_TSN: ::std::os::raw::c_uint = 8944;
+pub const ETH_P_IP: ::std::os::raw::c_uint = 2048;
+pub const ETH_P_X25: ::std::os::raw::c_uint = 2053;
+pub const ETH_P_ARP: ::std::os::raw::c_uint = 2054;
+pub const ETH_P_BPQ: ::std::os::raw::c_uint = 2303;
+pub const ETH_P_IEEEPUP: ::std::os::raw::c_uint = 2560;
+pub const ETH_P_IEEEPUPAT: ::std::os::raw::c_uint = 2561;
+pub const ETH_P_BATMAN: ::std::os::raw::c_uint = 17157;
+pub const ETH_P_DEC: ::std::os::raw::c_uint = 24576;
+pub const ETH_P_DNA_DL: ::std::os::raw::c_uint = 24577;
+pub const ETH_P_DNA_RC: ::std::os::raw::c_uint = 24578;
+pub const ETH_P_DNA_RT: ::std::os::raw::c_uint = 24579;
+pub const ETH_P_LAT: ::std::os::raw::c_uint = 24580;
+pub const ETH_P_DIAG: ::std::os::raw::c_uint = 24581;
+pub const ETH_P_CUST: ::std::os::raw::c_uint = 24582;
+pub const ETH_P_SCA: ::std::os::raw::c_uint = 24583;
+pub const ETH_P_TEB: ::std::os::raw::c_uint = 25944;
+pub const ETH_P_RARP: ::std::os::raw::c_uint = 32821;
+pub const ETH_P_ATALK: ::std::os::raw::c_uint = 32923;
+pub const ETH_P_AARP: ::std::os::raw::c_uint = 33011;
+pub const ETH_P_8021Q: ::std::os::raw::c_uint = 33024;
+pub const ETH_P_IPX: ::std::os::raw::c_uint = 33079;
+pub const ETH_P_IPV6: ::std::os::raw::c_uint = 34525;
+pub const ETH_P_PAUSE: ::std::os::raw::c_uint = 34824;
+pub const ETH_P_SLOW: ::std::os::raw::c_uint = 34825;
+pub const ETH_P_WCCP: ::std::os::raw::c_uint = 34878;
+pub const ETH_P_MPLS_UC: ::std::os::raw::c_uint = 34887;
+pub const ETH_P_MPLS_MC: ::std::os::raw::c_uint = 34888;
+pub const ETH_P_ATMMPOA: ::std::os::raw::c_uint = 34892;
+pub const ETH_P_PPP_DISC: ::std::os::raw::c_uint = 34915;
+pub const ETH_P_PPP_SES: ::std::os::raw::c_uint = 34916;
+pub const ETH_P_LINK_CTL: ::std::os::raw::c_uint = 34924;
+pub const ETH_P_ATMFATE: ::std::os::raw::c_uint = 34948;
+pub const ETH_P_PAE: ::std::os::raw::c_uint = 34958;
+pub const ETH_P_AOE: ::std::os::raw::c_uint = 34978;
+pub const ETH_P_8021AD: ::std::os::raw::c_uint = 34984;
+pub const ETH_P_802_EX1: ::std::os::raw::c_uint = 34997;
+pub const ETH_P_TIPC: ::std::os::raw::c_uint = 35018;
+pub const ETH_P_8021AH: ::std::os::raw::c_uint = 35047;
+pub const ETH_P_MVRP: ::std::os::raw::c_uint = 35061;
+pub const ETH_P_1588: ::std::os::raw::c_uint = 35063;
+pub const ETH_P_PRP: ::std::os::raw::c_uint = 35067;
+pub const ETH_P_FCOE: ::std::os::raw::c_uint = 35078;
+pub const ETH_P_TDLS: ::std::os::raw::c_uint = 35085;
+pub const ETH_P_FIP: ::std::os::raw::c_uint = 35092;
+pub const ETH_P_80221: ::std::os::raw::c_uint = 35095;
+pub const ETH_P_LOOPBACK: ::std::os::raw::c_uint = 36864;
+pub const ETH_P_QINQ1: ::std::os::raw::c_uint = 37120;
+pub const ETH_P_QINQ2: ::std::os::raw::c_uint = 37376;
+pub const ETH_P_QINQ3: ::std::os::raw::c_uint = 37632;
+pub const ETH_P_EDSA: ::std::os::raw::c_uint = 56026;
+pub const ETH_P_AF_IUCV: ::std::os::raw::c_uint = 64507;
+pub const ETH_P_802_3_MIN: ::std::os::raw::c_uint = 1536;
+pub const ETH_P_802_3: ::std::os::raw::c_uint = 1;
+pub const ETH_P_AX25: ::std::os::raw::c_uint = 2;
+pub const ETH_P_ALL: ::std::os::raw::c_uint = 3;
+pub const ETH_P_802_2: ::std::os::raw::c_uint = 4;
+pub const ETH_P_SNAP: ::std::os::raw::c_uint = 5;
+pub const ETH_P_DDCMP: ::std::os::raw::c_uint = 6;
+pub const ETH_P_WAN_PPP: ::std::os::raw::c_uint = 7;
+pub const ETH_P_PPP_MP: ::std::os::raw::c_uint = 8;
+pub const ETH_P_LOCALTALK: ::std::os::raw::c_uint = 9;
+pub const ETH_P_CAN: ::std::os::raw::c_uint = 12;
+pub const ETH_P_CANFD: ::std::os::raw::c_uint = 13;
+pub const ETH_P_PPPTALK: ::std::os::raw::c_uint = 16;
+pub const ETH_P_TR_802_2: ::std::os::raw::c_uint = 17;
+pub const ETH_P_MOBITEX: ::std::os::raw::c_uint = 21;
+pub const ETH_P_CONTROL: ::std::os::raw::c_uint = 22;
+pub const ETH_P_IRDA: ::std::os::raw::c_uint = 23;
+pub const ETH_P_ECONET: ::std::os::raw::c_uint = 24;
+pub const ETH_P_HDLC: ::std::os::raw::c_uint = 25;
+pub const ETH_P_ARCNET: ::std::os::raw::c_uint = 26;
+pub const ETH_P_DSA: ::std::os::raw::c_uint = 27;
+pub const ETH_P_TRAILER: ::std::os::raw::c_uint = 28;
+pub const ETH_P_PHONET: ::std::os::raw::c_uint = 245;
+pub const ETH_P_IEEE802154: ::std::os::raw::c_uint = 246;
+pub const ETH_P_CAIF: ::std::os::raw::c_uint = 247;
+pub const ETH_P_XDSA: ::std::os::raw::c_uint = 248;
+pub const BPF_LD: ::std::os::raw::c_uint = 0;
+pub const BPF_LDX: ::std::os::raw::c_uint = 1;
+pub const BPF_ST: ::std::os::raw::c_uint = 2;
+pub const BPF_STX: ::std::os::raw::c_uint = 3;
+pub const BPF_ALU: ::std::os::raw::c_uint = 4;
+pub const BPF_JMP: ::std::os::raw::c_uint = 5;
+pub const BPF_RET: ::std::os::raw::c_uint = 6;
+pub const BPF_MISC: ::std::os::raw::c_uint = 7;
+pub const BPF_W: ::std::os::raw::c_uint = 0;
+pub const BPF_H: ::std::os::raw::c_uint = 8;
+pub const BPF_B: ::std::os::raw::c_uint = 16;
+pub const BPF_IMM: ::std::os::raw::c_uint = 0;
+pub const BPF_ABS: ::std::os::raw::c_uint = 32;
+pub const BPF_IND: ::std::os::raw::c_uint = 64;
+pub const BPF_MEM: ::std::os::raw::c_uint = 96;
+pub const BPF_LEN: ::std::os::raw::c_uint = 128;
+pub const BPF_MSH: ::std::os::raw::c_uint = 160;
+pub const BPF_ADD: ::std::os::raw::c_uint = 0;
+pub const BPF_SUB: ::std::os::raw::c_uint = 16;
+pub const BPF_MUL: ::std::os::raw::c_uint = 32;
+pub const BPF_DIV: ::std::os::raw::c_uint = 48;
+pub const BPF_OR: ::std::os::raw::c_uint = 64;
+pub const BPF_AND: ::std::os::raw::c_uint = 80;
+pub const BPF_LSH: ::std::os::raw::c_uint = 96;
+pub const BPF_RSH: ::std::os::raw::c_uint = 112;
+pub const BPF_NEG: ::std::os::raw::c_uint = 128;
+pub const BPF_MOD: ::std::os::raw::c_uint = 144;
+pub const BPF_XOR: ::std::os::raw::c_uint = 160;
+pub const BPF_JA: ::std::os::raw::c_uint = 0;
+pub const BPF_JEQ: ::std::os::raw::c_uint = 16;
+pub const BPF_JGT: ::std::os::raw::c_uint = 32;
+pub const BPF_JGE: ::std::os::raw::c_uint = 48;
+pub const BPF_JSET: ::std::os::raw::c_uint = 64;
+pub const BPF_K: ::std::os::raw::c_uint = 0;
+pub const BPF_X: ::std::os::raw::c_uint = 8;
+pub const BPF_MAXINSNS: ::std::os::raw::c_uint = 4096;
+pub const BPF_MAJOR_VERSION: ::std::os::raw::c_uint = 1;
+pub const BPF_MINOR_VERSION: ::std::os::raw::c_uint = 1;
+pub const BPF_A: ::std::os::raw::c_uint = 16;
+pub const BPF_TAX: ::std::os::raw::c_uint = 0;
+pub const BPF_TXA: ::std::os::raw::c_uint = 128;
+pub const BPF_MEMWORDS: ::std::os::raw::c_uint = 16;
+pub const SKF_AD_OFF: ::std::os::raw::c_int = -4096;
+pub const SKF_AD_PROTOCOL: ::std::os::raw::c_uint = 0;
+pub const SKF_AD_PKTTYPE: ::std::os::raw::c_uint = 4;
+pub const SKF_AD_IFINDEX: ::std::os::raw::c_uint = 8;
+pub const SKF_AD_NLATTR: ::std::os::raw::c_uint = 12;
+pub const SKF_AD_NLATTR_NEST: ::std::os::raw::c_uint = 16;
+pub const SKF_AD_MARK: ::std::os::raw::c_uint = 20;
+pub const SKF_AD_QUEUE: ::std::os::raw::c_uint = 24;
+pub const SKF_AD_HATYPE: ::std::os::raw::c_uint = 28;
+pub const SKF_AD_RXHASH: ::std::os::raw::c_uint = 32;
+pub const SKF_AD_CPU: ::std::os::raw::c_uint = 36;
+pub const SKF_AD_ALU_XOR_X: ::std::os::raw::c_uint = 40;
+pub const SKF_AD_VLAN_TAG: ::std::os::raw::c_uint = 44;
+pub const SKF_AD_VLAN_TAG_PRESENT: ::std::os::raw::c_uint = 48;
+pub const SKF_AD_PAY_OFFSET: ::std::os::raw::c_uint = 52;
+pub const SKF_AD_RANDOM: ::std::os::raw::c_uint = 56;
+pub const SKF_AD_VLAN_TPID: ::std::os::raw::c_uint = 60;
+pub const SKF_AD_MAX: ::std::os::raw::c_uint = 64;
+pub const SKF_NET_OFF: ::std::os::raw::c_int = -1048576;
+pub const SKF_LL_OFF: ::std::os::raw::c_int = -2097152;
+pub const BPF_NET_OFF: ::std::os::raw::c_int = -1048576;
+pub const BPF_LL_OFF: ::std::os::raw::c_int = -2097152;
+pub const TUN_READQ_SIZE: ::std::os::raw::c_uint = 500;
+pub const TUN_TYPE_MASK: ::std::os::raw::c_uint = 15;
+pub const IFF_TUN: ::std::os::raw::c_uint = 1;
+pub const IFF_TAP: ::std::os::raw::c_uint = 2;
+pub const IFF_NO_PI: ::std::os::raw::c_uint = 4096;
+pub const IFF_ONE_QUEUE: ::std::os::raw::c_uint = 8192;
+pub const IFF_VNET_HDR: ::std::os::raw::c_uint = 16384;
+pub const IFF_TUN_EXCL: ::std::os::raw::c_uint = 32768;
+pub const IFF_MULTI_QUEUE: ::std::os::raw::c_uint = 256;
+pub const IFF_ATTACH_QUEUE: ::std::os::raw::c_uint = 512;
+pub const IFF_DETACH_QUEUE: ::std::os::raw::c_uint = 1024;
+pub const IFF_PERSIST: ::std::os::raw::c_uint = 2048;
+pub const IFF_NOFILTER: ::std::os::raw::c_uint = 4096;
+pub const TUN_TX_TIMESTAMP: ::std::os::raw::c_uint = 1;
+pub const TUN_F_CSUM: ::std::os::raw::c_uint = 1;
+pub const TUN_F_TSO4: ::std::os::raw::c_uint = 2;
+pub const TUN_F_TSO6: ::std::os::raw::c_uint = 4;
+pub const TUN_F_TSO_ECN: ::std::os::raw::c_uint = 8;
+pub const TUN_F_UFO: ::std::os::raw::c_uint = 16;
+pub const TUN_PKT_STRIP: ::std::os::raw::c_uint = 1;
+pub const TUN_FLT_ALLMULTI: ::std::os::raw::c_uint = 1;
+pub type __s8 = ::std::os::raw::c_schar;
+pub type __u8 = ::std::os::raw::c_uchar;
+pub type __s16 = ::std::os::raw::c_short;
+pub type __u16 = ::std::os::raw::c_ushort;
+pub type __s32 = ::std::os::raw::c_int;
+pub type __u32 = ::std::os::raw::c_uint;
+pub type __s64 = ::std::os::raw::c_longlong;
+pub type __u64 = ::std::os::raw::c_ulonglong;
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct __kernel_fd_set {
+    pub fds_bits: [::std::os::raw::c_ulong; 16usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fd_set() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fd_set>(),
+        128usize,
+        concat!("Size of: ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fd_set>(),
+        8usize,
+        concat!("Alignment of ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const __kernel_fd_set)).fds_bits as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(__kernel_fd_set),
+            "::",
+            stringify!(fds_bits)
+        )
+    );
+}
+impl Clone for __kernel_fd_set {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+pub type __kernel_sighandler_t =
+    ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
+pub type __kernel_key_t = ::std::os::raw::c_int;
+pub type __kernel_mqd_t = ::std::os::raw::c_int;
+pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
+pub type __kernel_long_t = ::std::os::raw::c_long;
+pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
+pub type __kernel_ino_t = __kernel_ulong_t;
+pub type __kernel_mode_t = ::std::os::raw::c_uint;
+pub type __kernel_pid_t = ::std::os::raw::c_int;
+pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
+pub type __kernel_uid_t = ::std::os::raw::c_uint;
+pub type __kernel_gid_t = ::std::os::raw::c_uint;
+pub type __kernel_suseconds_t = __kernel_long_t;
+pub type __kernel_daddr_t = ::std::os::raw::c_int;
+pub type __kernel_uid32_t = ::std::os::raw::c_uint;
+pub type __kernel_gid32_t = ::std::os::raw::c_uint;
+pub type __kernel_size_t = __kernel_ulong_t;
+pub type __kernel_ssize_t = __kernel_long_t;
+pub type __kernel_ptrdiff_t = __kernel_long_t;
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct __kernel_fsid_t {
+    pub val: [::std::os::raw::c_int; 2usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fsid_t() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fsid_t>(),
+        8usize,
+        concat!("Size of: ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fsid_t>(),
+        4usize,
+        concat!("Alignment of ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const __kernel_fsid_t)).val as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(__kernel_fsid_t),
+            "::",
+            stringify!(val)
+        )
+    );
+}
+impl Clone for __kernel_fsid_t {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+pub type __kernel_off_t = __kernel_long_t;
+pub type __kernel_loff_t = ::std::os::raw::c_longlong;
+pub type __kernel_time_t = __kernel_long_t;
+pub type __kernel_clock_t = __kernel_long_t;
+pub type __kernel_timer_t = ::std::os::raw::c_int;
+pub type __kernel_clockid_t = ::std::os::raw::c_int;
+pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
+pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
+pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
+pub type __le16 = __u16;
+pub type __be16 = __u16;
+pub type __le32 = __u32;
+pub type __be32 = __u32;
+pub type __le64 = __u64;
+pub type __be64 = __u64;
+pub type __sum16 = __u16;
+pub type __wsum = __u32;
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy)]
+pub struct ethhdr {
+    pub h_dest: [::std::os::raw::c_uchar; 6usize],
+    pub h_source: [::std::os::raw::c_uchar; 6usize],
+    pub h_proto: __be16,
+}
+#[test]
+fn bindgen_test_layout_ethhdr() {
+    assert_eq!(
+        ::std::mem::size_of::<ethhdr>(),
+        14usize,
+        concat!("Size of: ", stringify!(ethhdr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<ethhdr>(),
+        1usize,
+        concat!("Alignment of ", stringify!(ethhdr))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ethhdr)).h_dest as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ethhdr),
+            "::",
+            stringify!(h_dest)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ethhdr)).h_source as *const _ as usize },
+        6usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ethhdr),
+            "::",
+            stringify!(h_source)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ethhdr)).h_proto as *const _ as usize },
+        12usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ethhdr),
+            "::",
+            stringify!(h_proto)
+        )
+    );
+}
+impl Clone for ethhdr {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct sock_filter {
+    pub code: __u16,
+    pub jt: __u8,
+    pub jf: __u8,
+    pub k: __u32,
+}
+#[test]
+fn bindgen_test_layout_sock_filter() {
+    assert_eq!(
+        ::std::mem::size_of::<sock_filter>(),
+        8usize,
+        concat!("Size of: ", stringify!(sock_filter))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<sock_filter>(),
+        4usize,
+        concat!("Alignment of ", stringify!(sock_filter))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const sock_filter)).code as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(sock_filter),
+            "::",
+            stringify!(code)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const sock_filter)).jt as *const _ as usize },
+        2usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(sock_filter),
+            "::",
+            stringify!(jt)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const sock_filter)).jf as *const _ as usize },
+        3usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(sock_filter),
+            "::",
+            stringify!(jf)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const sock_filter)).k as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(sock_filter),
+            "::",
+            stringify!(k)
+        )
+    );
+}
+impl Clone for sock_filter {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct sock_fprog {
+    pub len: ::std::os::raw::c_ushort,
+    pub filter: *mut sock_filter,
+}
+#[test]
+fn bindgen_test_layout_sock_fprog() {
+    assert_eq!(
+        ::std::mem::size_of::<sock_fprog>(),
+        16usize,
+        concat!("Size of: ", stringify!(sock_fprog))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<sock_fprog>(),
+        8usize,
+        concat!("Alignment of ", stringify!(sock_fprog))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const sock_fprog)).len as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(sock_fprog),
+            "::",
+            stringify!(len)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const sock_fprog)).filter as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(sock_fprog),
+            "::",
+            stringify!(filter)
+        )
+    );
+}
+impl Clone for sock_fprog {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+impl Default for sock_fprog {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct tun_pi {
+    pub flags: __u16,
+    pub proto: __be16,
+}
+#[test]
+fn bindgen_test_layout_tun_pi() {
+    assert_eq!(
+        ::std::mem::size_of::<tun_pi>(),
+        4usize,
+        concat!("Size of: ", stringify!(tun_pi))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<tun_pi>(),
+        2usize,
+        concat!("Alignment of ", stringify!(tun_pi))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const tun_pi)).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(tun_pi),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const tun_pi)).proto as *const _ as usize },
+        2usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(tun_pi),
+            "::",
+            stringify!(proto)
+        )
+    );
+}
+impl Clone for tun_pi {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct tun_filter {
+    pub flags: __u16,
+    pub count: __u16,
+    pub addr: __IncompleteArrayField<[__u8; 6usize]>,
+}
+#[test]
+fn bindgen_test_layout_tun_filter() {
+    assert_eq!(
+        ::std::mem::size_of::<tun_filter>(),
+        4usize,
+        concat!("Size of: ", stringify!(tun_filter))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<tun_filter>(),
+        2usize,
+        concat!("Alignment of ", stringify!(tun_filter))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const tun_filter)).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(tun_filter),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const tun_filter)).count as *const _ as usize },
+        2usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(tun_filter),
+            "::",
+            stringify!(count)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const tun_filter)).addr as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(tun_filter),
+            "::",
+            stringify!(addr)
+        )
+    );
+}
+impl Clone for tun_filter {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
diff --git a/net_sys/src/iff.rs b/net_sys/src/iff.rs
new file mode 100644
index 0000000..928a2cc
--- /dev/null
+++ b/net_sys/src/iff.rs
@@ -0,0 +1,1254 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+#[repr(C)]
+#[derive(Default)]
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
+impl<T> __IncompleteArrayField<T> {
+    #[inline]
+    pub fn new() -> Self {
+        __IncompleteArrayField(::std::marker::PhantomData, [])
+    }
+    #[inline]
+    pub unsafe fn as_ptr(&self) -> *const T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_slice(&self, len: usize) -> &[T] {
+        ::std::slice::from_raw_parts(self.as_ptr(), len)
+    }
+    #[inline]
+    pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
+        ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
+    }
+}
+impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        fmt.write_str("__IncompleteArrayField")
+    }
+}
+impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self::new()
+    }
+}
+pub const __UAPI_DEF_IF_IFCONF: u32 = 1;
+pub const __UAPI_DEF_IF_IFMAP: u32 = 1;
+pub const __UAPI_DEF_IF_IFNAMSIZ: u32 = 1;
+pub const __UAPI_DEF_IF_IFREQ: u32 = 1;
+pub const __UAPI_DEF_IF_NET_DEVICE_FLAGS: u32 = 1;
+pub const __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO: u32 = 1;
+pub const __UAPI_DEF_IN_ADDR: u32 = 1;
+pub const __UAPI_DEF_IN_IPPROTO: u32 = 1;
+pub const __UAPI_DEF_IN_PKTINFO: u32 = 1;
+pub const __UAPI_DEF_IP_MREQ: u32 = 1;
+pub const __UAPI_DEF_SOCKADDR_IN: u32 = 1;
+pub const __UAPI_DEF_IN_CLASS: u32 = 1;
+pub const __UAPI_DEF_IN6_ADDR: u32 = 1;
+pub const __UAPI_DEF_IN6_ADDR_ALT: u32 = 1;
+pub const __UAPI_DEF_SOCKADDR_IN6: u32 = 1;
+pub const __UAPI_DEF_IPV6_MREQ: u32 = 1;
+pub const __UAPI_DEF_IPPROTO_V6: u32 = 1;
+pub const __UAPI_DEF_IPV6_OPTIONS: u32 = 1;
+pub const __UAPI_DEF_IN6_PKTINFO: u32 = 1;
+pub const __UAPI_DEF_IP6_MTUINFO: u32 = 1;
+pub const __UAPI_DEF_SOCKADDR_IPX: u32 = 1;
+pub const __UAPI_DEF_IPX_ROUTE_DEFINITION: u32 = 1;
+pub const __UAPI_DEF_IPX_INTERFACE_DEFINITION: u32 = 1;
+pub const __UAPI_DEF_IPX_CONFIG_DATA: u32 = 1;
+pub const __UAPI_DEF_IPX_ROUTE_DEF: u32 = 1;
+pub const __UAPI_DEF_XATTR: u32 = 1;
+pub const __BITS_PER_LONG: u32 = 64;
+pub const __FD_SETSIZE: u32 = 1024;
+pub const _K_SS_MAXSIZE: u32 = 128;
+pub const _SYS_SOCKET_H: u32 = 1;
+pub const _FEATURES_H: u32 = 1;
+pub const _DEFAULT_SOURCE: u32 = 1;
+pub const __USE_ISOC11: u32 = 1;
+pub const __USE_ISOC99: u32 = 1;
+pub const __USE_ISOC95: u32 = 1;
+pub const __USE_POSIX_IMPLICITLY: u32 = 1;
+pub const _POSIX_SOURCE: u32 = 1;
+pub const _POSIX_C_SOURCE: u32 = 200809;
+pub const __USE_POSIX: u32 = 1;
+pub const __USE_POSIX2: u32 = 1;
+pub const __USE_POSIX199309: u32 = 1;
+pub const __USE_POSIX199506: u32 = 1;
+pub const __USE_XOPEN2K: u32 = 1;
+pub const __USE_XOPEN2K8: u32 = 1;
+pub const _ATFILE_SOURCE: u32 = 1;
+pub const __USE_MISC: u32 = 1;
+pub const __USE_ATFILE: u32 = 1;
+pub const __USE_FORTIFY_LEVEL: u32 = 0;
+pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0;
+pub const _STDC_PREDEF_H: u32 = 1;
+pub const __STDC_IEC_559__: u32 = 1;
+pub const __STDC_IEC_559_COMPLEX__: u32 = 1;
+pub const __STDC_ISO_10646__: u32 = 201706;
+pub const __STDC_NO_THREADS__: u32 = 1;
+pub const __GNU_LIBRARY__: u32 = 6;
+pub const __GLIBC__: u32 = 2;
+pub const __GLIBC_MINOR__: u32 = 27;
+pub const _SYS_CDEFS_H: u32 = 1;
+pub const __glibc_c99_flexarr_available: u32 = 1;
+pub const __WORDSIZE: u32 = 64;
+pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1;
+pub const __SYSCALL_WORDSIZE: u32 = 64;
+pub const __HAVE_GENERIC_SELECTION: u32 = 1;
+pub const __iovec_defined: u32 = 1;
+pub const _SYS_TYPES_H: u32 = 1;
+pub const _BITS_TYPES_H: u32 = 1;
+pub const _BITS_TYPESIZES_H: u32 = 1;
+pub const __OFF_T_MATCHES_OFF64_T: u32 = 1;
+pub const __INO_T_MATCHES_INO64_T: u32 = 1;
+pub const __RLIM_T_MATCHES_RLIM64_T: u32 = 1;
+pub const __clock_t_defined: u32 = 1;
+pub const __clockid_t_defined: u32 = 1;
+pub const __time_t_defined: u32 = 1;
+pub const __timer_t_defined: u32 = 1;
+pub const _BITS_STDINT_INTN_H: u32 = 1;
+pub const __BIT_TYPES_DEFINED__: u32 = 1;
+pub const _ENDIAN_H: u32 = 1;
+pub const __LITTLE_ENDIAN: u32 = 1234;
+pub const __BIG_ENDIAN: u32 = 4321;
+pub const __PDP_ENDIAN: u32 = 3412;
+pub const __BYTE_ORDER: u32 = 1234;
+pub const __FLOAT_WORD_ORDER: u32 = 1234;
+pub const LITTLE_ENDIAN: u32 = 1234;
+pub const BIG_ENDIAN: u32 = 4321;
+pub const PDP_ENDIAN: u32 = 3412;
+pub const BYTE_ORDER: u32 = 1234;
+pub const _BITS_BYTESWAP_H: u32 = 1;
+pub const _BITS_UINTN_IDENTITY_H: u32 = 1;
+pub const _SYS_SELECT_H: u32 = 1;
+pub const __FD_ZERO_STOS: &'static [u8; 6usize] = b"stosq\0";
+pub const __sigset_t_defined: u32 = 1;
+pub const __timeval_defined: u32 = 1;
+pub const _STRUCT_TIMESPEC: u32 = 1;
+pub const FD_SETSIZE: u32 = 1024;
+pub const _BITS_PTHREADTYPES_COMMON_H: u32 = 1;
+pub const _THREAD_SHARED_TYPES_H: u32 = 1;
+pub const _BITS_PTHREADTYPES_ARCH_H: u32 = 1;
+pub const __SIZEOF_PTHREAD_MUTEX_T: u32 = 40;
+pub const __SIZEOF_PTHREAD_ATTR_T: u32 = 56;
+pub const __SIZEOF_PTHREAD_RWLOCK_T: u32 = 56;
+pub const __SIZEOF_PTHREAD_BARRIER_T: u32 = 32;
+pub const __SIZEOF_PTHREAD_MUTEXATTR_T: u32 = 4;
+pub const __SIZEOF_PTHREAD_COND_T: u32 = 48;
+pub const __SIZEOF_PTHREAD_CONDATTR_T: u32 = 4;
+pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: u32 = 8;
+pub const __SIZEOF_PTHREAD_BARRIERATTR_T: u32 = 4;
+pub const __PTHREAD_MUTEX_LOCK_ELISION: u32 = 1;
+pub const __PTHREAD_MUTEX_NUSERS_AFTER_KIND: u32 = 0;
+pub const __PTHREAD_MUTEX_USE_UNION: u32 = 0;
+pub const __PTHREAD_RWLOCK_INT_FLAGS_SHARED: u32 = 1;
+pub const __PTHREAD_MUTEX_HAVE_PREV: u32 = 1;
+pub const __have_pthread_attr_t: u32 = 1;
+pub const PF_UNSPEC: u32 = 0;
+pub const PF_LOCAL: u32 = 1;
+pub const PF_UNIX: u32 = 1;
+pub const PF_FILE: u32 = 1;
+pub const PF_INET: u32 = 2;
+pub const PF_AX25: u32 = 3;
+pub const PF_IPX: u32 = 4;
+pub const PF_APPLETALK: u32 = 5;
+pub const PF_NETROM: u32 = 6;
+pub const PF_BRIDGE: u32 = 7;
+pub const PF_ATMPVC: u32 = 8;
+pub const PF_X25: u32 = 9;
+pub const PF_INET6: u32 = 10;
+pub const PF_ROSE: u32 = 11;
+pub const PF_DECnet: u32 = 12;
+pub const PF_NETBEUI: u32 = 13;
+pub const PF_SECURITY: u32 = 14;
+pub const PF_KEY: u32 = 15;
+pub const PF_NETLINK: u32 = 16;
+pub const PF_ROUTE: u32 = 16;
+pub const PF_PACKET: u32 = 17;
+pub const PF_ASH: u32 = 18;
+pub const PF_ECONET: u32 = 19;
+pub const PF_ATMSVC: u32 = 20;
+pub const PF_RDS: u32 = 21;
+pub const PF_SNA: u32 = 22;
+pub const PF_IRDA: u32 = 23;
+pub const PF_PPPOX: u32 = 24;
+pub const PF_WANPIPE: u32 = 25;
+pub const PF_LLC: u32 = 26;
+pub const PF_IB: u32 = 27;
+pub const PF_MPLS: u32 = 28;
+pub const PF_CAN: u32 = 29;
+pub const PF_TIPC: u32 = 30;
+pub const PF_BLUETOOTH: u32 = 31;
+pub const PF_IUCV: u32 = 32;
+pub const PF_RXRPC: u32 = 33;
+pub const PF_ISDN: u32 = 34;
+pub const PF_PHONET: u32 = 35;
+pub const PF_IEEE802154: u32 = 36;
+pub const PF_CAIF: u32 = 37;
+pub const PF_ALG: u32 = 38;
+pub const PF_NFC: u32 = 39;
+pub const PF_VSOCK: u32 = 40;
+pub const PF_KCM: u32 = 41;
+pub const PF_QIPCRTR: u32 = 42;
+pub const PF_SMC: u32 = 43;
+pub const PF_MAX: u32 = 44;
+pub const AF_UNSPEC: u32 = 0;
+pub const AF_LOCAL: u32 = 1;
+pub const AF_UNIX: u32 = 1;
+pub const AF_FILE: u32 = 1;
+pub const AF_INET: u32 = 2;
+pub const AF_AX25: u32 = 3;
+pub const AF_IPX: u32 = 4;
+pub const AF_APPLETALK: u32 = 5;
+pub const AF_NETROM: u32 = 6;
+pub const AF_BRIDGE: u32 = 7;
+pub const AF_ATMPVC: u32 = 8;
+pub const AF_X25: u32 = 9;
+pub const AF_INET6: u32 = 10;
+pub const AF_ROSE: u32 = 11;
+pub const AF_DECnet: u32 = 12;
+pub const AF_NETBEUI: u32 = 13;
+pub const AF_SECURITY: u32 = 14;
+pub const AF_KEY: u32 = 15;
+pub const AF_NETLINK: u32 = 16;
+pub const AF_ROUTE: u32 = 16;
+pub const AF_PACKET: u32 = 17;
+pub const AF_ASH: u32 = 18;
+pub const AF_ECONET: u32 = 19;
+pub const AF_ATMSVC: u32 = 20;
+pub const AF_RDS: u32 = 21;
+pub const AF_SNA: u32 = 22;
+pub const AF_IRDA: u32 = 23;
+pub const AF_PPPOX: u32 = 24;
+pub const AF_WANPIPE: u32 = 25;
+pub const AF_LLC: u32 = 26;
+pub const AF_IB: u32 = 27;
+pub const AF_MPLS: u32 = 28;
+pub const AF_CAN: u32 = 29;
+pub const AF_TIPC: u32 = 30;
+pub const AF_BLUETOOTH: u32 = 31;
+pub const AF_IUCV: u32 = 32;
+pub const AF_RXRPC: u32 = 33;
+pub const AF_ISDN: u32 = 34;
+pub const AF_PHONET: u32 = 35;
+pub const AF_IEEE802154: u32 = 36;
+pub const AF_CAIF: u32 = 37;
+pub const AF_ALG: u32 = 38;
+pub const AF_NFC: u32 = 39;
+pub const AF_VSOCK: u32 = 40;
+pub const AF_KCM: u32 = 41;
+pub const AF_QIPCRTR: u32 = 42;
+pub const AF_SMC: u32 = 43;
+pub const AF_MAX: u32 = 44;
+pub const SOL_RAW: u32 = 255;
+pub const SOL_DECNET: u32 = 261;
+pub const SOL_X25: u32 = 262;
+pub const SOL_PACKET: u32 = 263;
+pub const SOL_ATM: u32 = 264;
+pub const SOL_AAL: u32 = 265;
+pub const SOL_IRDA: u32 = 266;
+pub const SOL_NETBEUI: u32 = 267;
+pub const SOL_LLC: u32 = 268;
+pub const SOL_DCCP: u32 = 269;
+pub const SOL_NETLINK: u32 = 270;
+pub const SOL_TIPC: u32 = 271;
+pub const SOL_RXRPC: u32 = 272;
+pub const SOL_PPPOL2TP: u32 = 273;
+pub const SOL_BLUETOOTH: u32 = 274;
+pub const SOL_PNPIPE: u32 = 275;
+pub const SOL_RDS: u32 = 276;
+pub const SOL_IUCV: u32 = 277;
+pub const SOL_CAIF: u32 = 278;
+pub const SOL_ALG: u32 = 279;
+pub const SOL_NFC: u32 = 280;
+pub const SOL_KCM: u32 = 281;
+pub const SOL_TLS: u32 = 282;
+pub const SOMAXCONN: u32 = 128;
+pub const _BITS_SOCKADDR_H: u32 = 1;
+pub const _SS_SIZE: u32 = 128;
+pub const FIOSETOWN: u32 = 35073;
+pub const SIOCSPGRP: u32 = 35074;
+pub const FIOGETOWN: u32 = 35075;
+pub const SIOCGPGRP: u32 = 35076;
+pub const SIOCATMARK: u32 = 35077;
+pub const SIOCGSTAMP: u32 = 35078;
+pub const SIOCGSTAMPNS: u32 = 35079;
+pub const SOL_SOCKET: u32 = 1;
+pub const SO_DEBUG: u32 = 1;
+pub const SO_REUSEADDR: u32 = 2;
+pub const SO_TYPE: u32 = 3;
+pub const SO_ERROR: u32 = 4;
+pub const SO_DONTROUTE: u32 = 5;
+pub const SO_BROADCAST: u32 = 6;
+pub const SO_SNDBUF: u32 = 7;
+pub const SO_RCVBUF: u32 = 8;
+pub const SO_SNDBUFFORCE: u32 = 32;
+pub const SO_RCVBUFFORCE: u32 = 33;
+pub const SO_KEEPALIVE: u32 = 9;
+pub const SO_OOBINLINE: u32 = 10;
+pub const SO_NO_CHECK: u32 = 11;
+pub const SO_PRIORITY: u32 = 12;
+pub const SO_LINGER: u32 = 13;
+pub const SO_BSDCOMPAT: u32 = 14;
+pub const SO_REUSEPORT: u32 = 15;
+pub const SO_PASSCRED: u32 = 16;
+pub const SO_PEERCRED: u32 = 17;
+pub const SO_RCVLOWAT: u32 = 18;
+pub const SO_SNDLOWAT: u32 = 19;
+pub const SO_RCVTIMEO: u32 = 20;
+pub const SO_SNDTIMEO: u32 = 21;
+pub const SO_SECURITY_AUTHENTICATION: u32 = 22;
+pub const SO_SECURITY_ENCRYPTION_TRANSPORT: u32 = 23;
+pub const SO_SECURITY_ENCRYPTION_NETWORK: u32 = 24;
+pub const SO_BINDTODEVICE: u32 = 25;
+pub const SO_ATTACH_FILTER: u32 = 26;
+pub const SO_DETACH_FILTER: u32 = 27;
+pub const SO_GET_FILTER: u32 = 26;
+pub const SO_PEERNAME: u32 = 28;
+pub const SO_TIMESTAMP: u32 = 29;
+pub const SCM_TIMESTAMP: u32 = 29;
+pub const SO_ACCEPTCONN: u32 = 30;
+pub const SO_PEERSEC: u32 = 31;
+pub const SO_PASSSEC: u32 = 34;
+pub const SO_TIMESTAMPNS: u32 = 35;
+pub const SCM_TIMESTAMPNS: u32 = 35;
+pub const SO_MARK: u32 = 36;
+pub const SO_TIMESTAMPING: u32 = 37;
+pub const SCM_TIMESTAMPING: u32 = 37;
+pub const SO_PROTOCOL: u32 = 38;
+pub const SO_DOMAIN: u32 = 39;
+pub const SO_RXQ_OVFL: u32 = 40;
+pub const SO_WIFI_STATUS: u32 = 41;
+pub const SCM_WIFI_STATUS: u32 = 41;
+pub const SO_PEEK_OFF: u32 = 42;
+pub const SO_NOFCS: u32 = 43;
+pub const SO_LOCK_FILTER: u32 = 44;
+pub const SO_SELECT_ERR_QUEUE: u32 = 45;
+pub const SO_BUSY_POLL: u32 = 46;
+pub const SO_MAX_PACING_RATE: u32 = 47;
+pub const SO_BPF_EXTENSIONS: u32 = 48;
+pub const SO_INCOMING_CPU: u32 = 49;
+pub const SO_ATTACH_BPF: u32 = 50;
+pub const SO_DETACH_BPF: u32 = 27;
+pub const SO_ATTACH_REUSEPORT_CBPF: u32 = 51;
+pub const SO_ATTACH_REUSEPORT_EBPF: u32 = 52;
+pub const SO_CNX_ADVICE: u32 = 53;
+pub const SCM_TIMESTAMPING_OPT_STATS: u32 = 54;
+pub const SO_MEMINFO: u32 = 55;
+pub const SO_INCOMING_NAPI_ID: u32 = 56;
+pub const SO_COOKIE: u32 = 57;
+pub const SCM_TIMESTAMPING_PKTINFO: u32 = 58;
+pub const SO_PEERGROUPS: u32 = 59;
+pub const SO_ZEROCOPY: u32 = 60;
+pub const __osockaddr_defined: u32 = 1;
+pub const IFNAMSIZ: u32 = 16;
+pub const IFALIASZ: u32 = 256;
+pub const GENERIC_HDLC_VERSION: u32 = 4;
+pub const CLOCK_DEFAULT: u32 = 0;
+pub const CLOCK_EXT: u32 = 1;
+pub const CLOCK_INT: u32 = 2;
+pub const CLOCK_TXINT: u32 = 3;
+pub const CLOCK_TXFROMRX: u32 = 4;
+pub const ENCODING_DEFAULT: u32 = 0;
+pub const ENCODING_NRZ: u32 = 1;
+pub const ENCODING_NRZI: u32 = 2;
+pub const ENCODING_FM_MARK: u32 = 3;
+pub const ENCODING_FM_SPACE: u32 = 4;
+pub const ENCODING_MANCHESTER: u32 = 5;
+pub const PARITY_DEFAULT: u32 = 0;
+pub const PARITY_NONE: u32 = 1;
+pub const PARITY_CRC16_PR0: u32 = 2;
+pub const PARITY_CRC16_PR1: u32 = 3;
+pub const PARITY_CRC16_PR0_CCITT: u32 = 4;
+pub const PARITY_CRC16_PR1_CCITT: u32 = 5;
+pub const PARITY_CRC32_PR0_CCITT: u32 = 6;
+pub const PARITY_CRC32_PR1_CCITT: u32 = 7;
+pub const LMI_DEFAULT: u32 = 0;
+pub const LMI_NONE: u32 = 1;
+pub const LMI_ANSI: u32 = 2;
+pub const LMI_CCITT: u32 = 3;
+pub const LMI_CISCO: u32 = 4;
+pub const IF_GET_IFACE: u32 = 1;
+pub const IF_GET_PROTO: u32 = 2;
+pub const IF_IFACE_V35: u32 = 4096;
+pub const IF_IFACE_V24: u32 = 4097;
+pub const IF_IFACE_X21: u32 = 4098;
+pub const IF_IFACE_T1: u32 = 4099;
+pub const IF_IFACE_E1: u32 = 4100;
+pub const IF_IFACE_SYNC_SERIAL: u32 = 4101;
+pub const IF_IFACE_X21D: u32 = 4102;
+pub const IF_PROTO_HDLC: u32 = 8192;
+pub const IF_PROTO_PPP: u32 = 8193;
+pub const IF_PROTO_CISCO: u32 = 8194;
+pub const IF_PROTO_FR: u32 = 8195;
+pub const IF_PROTO_FR_ADD_PVC: u32 = 8196;
+pub const IF_PROTO_FR_DEL_PVC: u32 = 8197;
+pub const IF_PROTO_X25: u32 = 8198;
+pub const IF_PROTO_HDLC_ETH: u32 = 8199;
+pub const IF_PROTO_FR_ADD_ETH_PVC: u32 = 8200;
+pub const IF_PROTO_FR_DEL_ETH_PVC: u32 = 8201;
+pub const IF_PROTO_FR_PVC: u32 = 8202;
+pub const IF_PROTO_FR_ETH_PVC: u32 = 8203;
+pub const IF_PROTO_RAW: u32 = 8204;
+pub const IFHWADDRLEN: u32 = 6;
+pub type __s8 = ::std::os::raw::c_schar;
+pub type __u8 = ::std::os::raw::c_uchar;
+pub type __s16 = ::std::os::raw::c_short;
+pub type __u16 = ::std::os::raw::c_ushort;
+pub type __s32 = ::std::os::raw::c_int;
+pub type __u32 = ::std::os::raw::c_uint;
+pub type __s64 = ::std::os::raw::c_longlong;
+pub type __u64 = ::std::os::raw::c_ulonglong;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct __kernel_fd_set {
+    pub fds_bits: [::std::os::raw::c_ulong; 16usize],
+}
+pub type __kernel_sighandler_t =
+    ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
+pub type __kernel_key_t = ::std::os::raw::c_int;
+pub type __kernel_mqd_t = ::std::os::raw::c_int;
+pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
+pub type __kernel_long_t = ::std::os::raw::c_long;
+pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
+pub type __kernel_ino_t = __kernel_ulong_t;
+pub type __kernel_mode_t = ::std::os::raw::c_uint;
+pub type __kernel_pid_t = ::std::os::raw::c_int;
+pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
+pub type __kernel_uid_t = ::std::os::raw::c_uint;
+pub type __kernel_gid_t = ::std::os::raw::c_uint;
+pub type __kernel_suseconds_t = __kernel_long_t;
+pub type __kernel_daddr_t = ::std::os::raw::c_int;
+pub type __kernel_uid32_t = ::std::os::raw::c_uint;
+pub type __kernel_gid32_t = ::std::os::raw::c_uint;
+pub type __kernel_size_t = __kernel_ulong_t;
+pub type __kernel_ssize_t = __kernel_long_t;
+pub type __kernel_ptrdiff_t = __kernel_long_t;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct __kernel_fsid_t {
+    pub val: [::std::os::raw::c_int; 2usize],
+}
+pub type __kernel_off_t = __kernel_long_t;
+pub type __kernel_loff_t = ::std::os::raw::c_longlong;
+pub type __kernel_time_t = __kernel_long_t;
+pub type __kernel_clock_t = __kernel_long_t;
+pub type __kernel_timer_t = ::std::os::raw::c_int;
+pub type __kernel_clockid_t = ::std::os::raw::c_int;
+pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
+pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
+pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
+pub type __le16 = __u16;
+pub type __be16 = __u16;
+pub type __le32 = __u32;
+pub type __be32 = __u32;
+pub type __le64 = __u64;
+pub type __be64 = __u64;
+pub type __sum16 = __u16;
+pub type __wsum = __u32;
+pub type __kernel_sa_family_t = ::std::os::raw::c_ushort;
+#[repr(C)]
+#[repr(align(8))]
+#[derive(Copy, Clone)]
+pub struct __kernel_sockaddr_storage {
+    pub ss_family: __kernel_sa_family_t,
+    pub __data: [::std::os::raw::c_char; 126usize],
+}
+impl Default for __kernel_sockaddr_storage {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct iovec {
+    pub iov_base: *mut ::std::os::raw::c_void,
+    pub iov_len: usize,
+}
+impl Default for iovec {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+pub type __u_char = ::std::os::raw::c_uchar;
+pub type __u_short = ::std::os::raw::c_ushort;
+pub type __u_int = ::std::os::raw::c_uint;
+pub type __u_long = ::std::os::raw::c_ulong;
+pub type __int8_t = ::std::os::raw::c_schar;
+pub type __uint8_t = ::std::os::raw::c_uchar;
+pub type __int16_t = ::std::os::raw::c_short;
+pub type __uint16_t = ::std::os::raw::c_ushort;
+pub type __int32_t = ::std::os::raw::c_int;
+pub type __uint32_t = ::std::os::raw::c_uint;
+pub type __int64_t = ::std::os::raw::c_long;
+pub type __uint64_t = ::std::os::raw::c_ulong;
+pub type __quad_t = ::std::os::raw::c_long;
+pub type __u_quad_t = ::std::os::raw::c_ulong;
+pub type __intmax_t = ::std::os::raw::c_long;
+pub type __uintmax_t = ::std::os::raw::c_ulong;
+pub type __dev_t = ::std::os::raw::c_ulong;
+pub type __uid_t = ::std::os::raw::c_uint;
+pub type __gid_t = ::std::os::raw::c_uint;
+pub type __ino_t = ::std::os::raw::c_ulong;
+pub type __ino64_t = ::std::os::raw::c_ulong;
+pub type __mode_t = ::std::os::raw::c_uint;
+pub type __nlink_t = ::std::os::raw::c_ulong;
+pub type __off_t = ::std::os::raw::c_long;
+pub type __off64_t = ::std::os::raw::c_long;
+pub type __pid_t = ::std::os::raw::c_int;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct __fsid_t {
+    pub __val: [::std::os::raw::c_int; 2usize],
+}
+pub type __clock_t = ::std::os::raw::c_long;
+pub type __rlim_t = ::std::os::raw::c_ulong;
+pub type __rlim64_t = ::std::os::raw::c_ulong;
+pub type __id_t = ::std::os::raw::c_uint;
+pub type __time_t = ::std::os::raw::c_long;
+pub type __useconds_t = ::std::os::raw::c_uint;
+pub type __suseconds_t = ::std::os::raw::c_long;
+pub type __daddr_t = ::std::os::raw::c_int;
+pub type __key_t = ::std::os::raw::c_int;
+pub type __clockid_t = ::std::os::raw::c_int;
+pub type __timer_t = *mut ::std::os::raw::c_void;
+pub type __blksize_t = ::std::os::raw::c_long;
+pub type __blkcnt_t = ::std::os::raw::c_long;
+pub type __blkcnt64_t = ::std::os::raw::c_long;
+pub type __fsblkcnt_t = ::std::os::raw::c_ulong;
+pub type __fsblkcnt64_t = ::std::os::raw::c_ulong;
+pub type __fsfilcnt_t = ::std::os::raw::c_ulong;
+pub type __fsfilcnt64_t = ::std::os::raw::c_ulong;
+pub type __fsword_t = ::std::os::raw::c_long;
+pub type __ssize_t = ::std::os::raw::c_long;
+pub type __syscall_slong_t = ::std::os::raw::c_long;
+pub type __syscall_ulong_t = ::std::os::raw::c_ulong;
+pub type __loff_t = __off64_t;
+pub type __caddr_t = *mut ::std::os::raw::c_char;
+pub type __intptr_t = ::std::os::raw::c_long;
+pub type __socklen_t = ::std::os::raw::c_uint;
+pub type __sig_atomic_t = ::std::os::raw::c_int;
+pub type u_char = __u_char;
+pub type u_short = __u_short;
+pub type u_int = __u_int;
+pub type u_long = __u_long;
+pub type quad_t = __quad_t;
+pub type u_quad_t = __u_quad_t;
+pub type fsid_t = __fsid_t;
+pub type loff_t = __loff_t;
+pub type ino_t = __ino_t;
+pub type dev_t = __dev_t;
+pub type gid_t = __gid_t;
+pub type mode_t = __mode_t;
+pub type nlink_t = __nlink_t;
+pub type uid_t = __uid_t;
+pub type off_t = __off_t;
+pub type pid_t = __pid_t;
+pub type id_t = __id_t;
+pub type daddr_t = __daddr_t;
+pub type caddr_t = __caddr_t;
+pub type key_t = __key_t;
+pub type clock_t = __clock_t;
+pub type clockid_t = __clockid_t;
+pub type time_t = __time_t;
+pub type timer_t = __timer_t;
+pub type ulong = ::std::os::raw::c_ulong;
+pub type ushort = ::std::os::raw::c_ushort;
+pub type uint = ::std::os::raw::c_uint;
+pub type u_int8_t = ::std::os::raw::c_uchar;
+pub type u_int16_t = ::std::os::raw::c_ushort;
+pub type u_int32_t = ::std::os::raw::c_uint;
+pub type u_int64_t = ::std::os::raw::c_ulong;
+pub type register_t = ::std::os::raw::c_long;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct __sigset_t {
+    pub __val: [::std::os::raw::c_ulong; 16usize],
+}
+pub type sigset_t = __sigset_t;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct timeval {
+    pub tv_sec: __time_t,
+    pub tv_usec: __suseconds_t,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct timespec {
+    pub tv_sec: __time_t,
+    pub tv_nsec: __syscall_slong_t,
+}
+pub type suseconds_t = __suseconds_t;
+pub type __fd_mask = ::std::os::raw::c_long;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct fd_set {
+    pub __fds_bits: [__fd_mask; 16usize],
+}
+pub type fd_mask = __fd_mask;
+extern "C" {
+    pub fn select(
+        __nfds: ::std::os::raw::c_int,
+        __readfds: *mut fd_set,
+        __writefds: *mut fd_set,
+        __exceptfds: *mut fd_set,
+        __timeout: *mut timeval,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn pselect(
+        __nfds: ::std::os::raw::c_int,
+        __readfds: *mut fd_set,
+        __writefds: *mut fd_set,
+        __exceptfds: *mut fd_set,
+        __timeout: *const timespec,
+        __sigmask: *const __sigset_t,
+    ) -> ::std::os::raw::c_int;
+}
+pub type blksize_t = __blksize_t;
+pub type blkcnt_t = __blkcnt_t;
+pub type fsblkcnt_t = __fsblkcnt_t;
+pub type fsfilcnt_t = __fsfilcnt_t;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct __pthread_rwlock_arch_t {
+    pub __readers: ::std::os::raw::c_uint,
+    pub __writers: ::std::os::raw::c_uint,
+    pub __wrphase_futex: ::std::os::raw::c_uint,
+    pub __writers_futex: ::std::os::raw::c_uint,
+    pub __pad3: ::std::os::raw::c_uint,
+    pub __pad4: ::std::os::raw::c_uint,
+    pub __cur_writer: ::std::os::raw::c_int,
+    pub __shared: ::std::os::raw::c_int,
+    pub __rwelision: ::std::os::raw::c_schar,
+    pub __pad1: [::std::os::raw::c_uchar; 7usize],
+    pub __pad2: ::std::os::raw::c_ulong,
+    pub __flags: ::std::os::raw::c_uint,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __pthread_internal_list {
+    pub __prev: *mut __pthread_internal_list,
+    pub __next: *mut __pthread_internal_list,
+}
+impl Default for __pthread_internal_list {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+pub type __pthread_list_t = __pthread_internal_list;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __pthread_mutex_s {
+    pub __lock: ::std::os::raw::c_int,
+    pub __count: ::std::os::raw::c_uint,
+    pub __owner: ::std::os::raw::c_int,
+    pub __nusers: ::std::os::raw::c_uint,
+    pub __kind: ::std::os::raw::c_int,
+    pub __spins: ::std::os::raw::c_short,
+    pub __elision: ::std::os::raw::c_short,
+    pub __list: __pthread_list_t,
+}
+impl Default for __pthread_mutex_s {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct __pthread_cond_s {
+    pub __bindgen_anon_1: __pthread_cond_s__bindgen_ty_1,
+    pub __bindgen_anon_2: __pthread_cond_s__bindgen_ty_2,
+    pub __g_refs: [::std::os::raw::c_uint; 2usize],
+    pub __g_size: [::std::os::raw::c_uint; 2usize],
+    pub __g1_orig_size: ::std::os::raw::c_uint,
+    pub __wrefs: ::std::os::raw::c_uint,
+    pub __g_signals: [::std::os::raw::c_uint; 2usize],
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union __pthread_cond_s__bindgen_ty_1 {
+    pub __wseq: ::std::os::raw::c_ulonglong,
+    pub __wseq32: __pthread_cond_s__bindgen_ty_1__bindgen_ty_1,
+    _bindgen_union_align: u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct __pthread_cond_s__bindgen_ty_1__bindgen_ty_1 {
+    pub __low: ::std::os::raw::c_uint,
+    pub __high: ::std::os::raw::c_uint,
+}
+impl Default for __pthread_cond_s__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union __pthread_cond_s__bindgen_ty_2 {
+    pub __g1_start: ::std::os::raw::c_ulonglong,
+    pub __g1_start32: __pthread_cond_s__bindgen_ty_2__bindgen_ty_1,
+    _bindgen_union_align: u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct __pthread_cond_s__bindgen_ty_2__bindgen_ty_1 {
+    pub __low: ::std::os::raw::c_uint,
+    pub __high: ::std::os::raw::c_uint,
+}
+impl Default for __pthread_cond_s__bindgen_ty_2 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+impl Default for __pthread_cond_s {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+pub type pthread_t = ::std::os::raw::c_ulong;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_mutexattr_t {
+    pub __size: [::std::os::raw::c_char; 4usize],
+    pub __align: ::std::os::raw::c_int,
+    _bindgen_union_align: u32,
+}
+impl Default for pthread_mutexattr_t {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_condattr_t {
+    pub __size: [::std::os::raw::c_char; 4usize],
+    pub __align: ::std::os::raw::c_int,
+    _bindgen_union_align: u32,
+}
+impl Default for pthread_condattr_t {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+pub type pthread_key_t = ::std::os::raw::c_uint;
+pub type pthread_once_t = ::std::os::raw::c_int;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_attr_t {
+    pub __size: [::std::os::raw::c_char; 56usize],
+    pub __align: ::std::os::raw::c_long,
+    _bindgen_union_align: [u64; 7usize],
+}
+impl Default for pthread_attr_t {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_mutex_t {
+    pub __data: __pthread_mutex_s,
+    pub __size: [::std::os::raw::c_char; 40usize],
+    pub __align: ::std::os::raw::c_long,
+    _bindgen_union_align: [u64; 5usize],
+}
+impl Default for pthread_mutex_t {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_cond_t {
+    pub __data: __pthread_cond_s,
+    pub __size: [::std::os::raw::c_char; 48usize],
+    pub __align: ::std::os::raw::c_longlong,
+    _bindgen_union_align: [u64; 6usize],
+}
+impl Default for pthread_cond_t {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_rwlock_t {
+    pub __data: __pthread_rwlock_arch_t,
+    pub __size: [::std::os::raw::c_char; 56usize],
+    pub __align: ::std::os::raw::c_long,
+    _bindgen_union_align: [u64; 7usize],
+}
+impl Default for pthread_rwlock_t {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_rwlockattr_t {
+    pub __size: [::std::os::raw::c_char; 8usize],
+    pub __align: ::std::os::raw::c_long,
+    _bindgen_union_align: u64,
+}
+impl Default for pthread_rwlockattr_t {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+pub type pthread_spinlock_t = ::std::os::raw::c_int;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_barrier_t {
+    pub __size: [::std::os::raw::c_char; 32usize],
+    pub __align: ::std::os::raw::c_long,
+    _bindgen_union_align: [u64; 4usize],
+}
+impl Default for pthread_barrier_t {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_barrierattr_t {
+    pub __size: [::std::os::raw::c_char; 4usize],
+    pub __align: ::std::os::raw::c_int,
+    _bindgen_union_align: u32,
+}
+impl Default for pthread_barrierattr_t {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+pub type socklen_t = __socklen_t;
+pub const __socket_type_SOCK_STREAM: __socket_type = 1;
+pub const __socket_type_SOCK_DGRAM: __socket_type = 2;
+pub const __socket_type_SOCK_RAW: __socket_type = 3;
+pub const __socket_type_SOCK_RDM: __socket_type = 4;
+pub const __socket_type_SOCK_SEQPACKET: __socket_type = 5;
+pub const __socket_type_SOCK_DCCP: __socket_type = 6;
+pub const __socket_type_SOCK_PACKET: __socket_type = 10;
+pub const __socket_type_SOCK_CLOEXEC: __socket_type = 524288;
+pub const __socket_type_SOCK_NONBLOCK: __socket_type = 2048;
+pub type __socket_type = u32;
+pub type sa_family_t = ::std::os::raw::c_ushort;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct sockaddr {
+    pub sa_family: sa_family_t,
+    pub sa_data: [::std::os::raw::c_char; 14usize],
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct sockaddr_storage {
+    pub ss_family: sa_family_t,
+    pub __ss_padding: [::std::os::raw::c_char; 118usize],
+    pub __ss_align: ::std::os::raw::c_ulong,
+}
+impl Default for sockaddr_storage {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+pub const MSG_OOB: _bindgen_ty_1 = 1;
+pub const MSG_PEEK: _bindgen_ty_1 = 2;
+pub const MSG_DONTROUTE: _bindgen_ty_1 = 4;
+pub const MSG_CTRUNC: _bindgen_ty_1 = 8;
+pub const MSG_PROXY: _bindgen_ty_1 = 16;
+pub const MSG_TRUNC: _bindgen_ty_1 = 32;
+pub const MSG_DONTWAIT: _bindgen_ty_1 = 64;
+pub const MSG_EOR: _bindgen_ty_1 = 128;
+pub const MSG_WAITALL: _bindgen_ty_1 = 256;
+pub const MSG_FIN: _bindgen_ty_1 = 512;
+pub const MSG_SYN: _bindgen_ty_1 = 1024;
+pub const MSG_CONFIRM: _bindgen_ty_1 = 2048;
+pub const MSG_RST: _bindgen_ty_1 = 4096;
+pub const MSG_ERRQUEUE: _bindgen_ty_1 = 8192;
+pub const MSG_NOSIGNAL: _bindgen_ty_1 = 16384;
+pub const MSG_MORE: _bindgen_ty_1 = 32768;
+pub const MSG_WAITFORONE: _bindgen_ty_1 = 65536;
+pub const MSG_BATCH: _bindgen_ty_1 = 262144;
+pub const MSG_ZEROCOPY: _bindgen_ty_1 = 67108864;
+pub const MSG_FASTOPEN: _bindgen_ty_1 = 536870912;
+pub const MSG_CMSG_CLOEXEC: _bindgen_ty_1 = 1073741824;
+pub type _bindgen_ty_1 = u32;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct msghdr {
+    pub msg_name: *mut ::std::os::raw::c_void,
+    pub msg_namelen: socklen_t,
+    pub msg_iov: *mut iovec,
+    pub msg_iovlen: usize,
+    pub msg_control: *mut ::std::os::raw::c_void,
+    pub msg_controllen: usize,
+    pub msg_flags: ::std::os::raw::c_int,
+}
+impl Default for msghdr {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct cmsghdr {
+    pub cmsg_len: usize,
+    pub cmsg_level: ::std::os::raw::c_int,
+    pub cmsg_type: ::std::os::raw::c_int,
+    pub __cmsg_data: __IncompleteArrayField<::std::os::raw::c_uchar>,
+}
+extern "C" {
+    pub fn __cmsg_nxthdr(__mhdr: *mut msghdr, __cmsg: *mut cmsghdr) -> *mut cmsghdr;
+}
+pub const SCM_RIGHTS: _bindgen_ty_2 = 1;
+pub type _bindgen_ty_2 = u32;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct linger {
+    pub l_onoff: ::std::os::raw::c_int,
+    pub l_linger: ::std::os::raw::c_int,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct osockaddr {
+    pub sa_family: ::std::os::raw::c_ushort,
+    pub sa_data: [::std::os::raw::c_uchar; 14usize],
+}
+pub const SHUT_RD: _bindgen_ty_3 = 0;
+pub const SHUT_WR: _bindgen_ty_3 = 1;
+pub const SHUT_RDWR: _bindgen_ty_3 = 2;
+pub type _bindgen_ty_3 = u32;
+extern "C" {
+    pub fn socket(
+        __domain: ::std::os::raw::c_int,
+        __type: ::std::os::raw::c_int,
+        __protocol: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn socketpair(
+        __domain: ::std::os::raw::c_int,
+        __type: ::std::os::raw::c_int,
+        __protocol: ::std::os::raw::c_int,
+        __fds: *mut ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn bind(
+        __fd: ::std::os::raw::c_int,
+        __addr: *const sockaddr,
+        __len: socklen_t,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn getsockname(
+        __fd: ::std::os::raw::c_int,
+        __addr: *mut sockaddr,
+        __len: *mut socklen_t,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn connect(
+        __fd: ::std::os::raw::c_int,
+        __addr: *const sockaddr,
+        __len: socklen_t,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn getpeername(
+        __fd: ::std::os::raw::c_int,
+        __addr: *mut sockaddr,
+        __len: *mut socklen_t,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn send(
+        __fd: ::std::os::raw::c_int,
+        __buf: *const ::std::os::raw::c_void,
+        __n: usize,
+        __flags: ::std::os::raw::c_int,
+    ) -> isize;
+}
+extern "C" {
+    pub fn recv(
+        __fd: ::std::os::raw::c_int,
+        __buf: *mut ::std::os::raw::c_void,
+        __n: usize,
+        __flags: ::std::os::raw::c_int,
+    ) -> isize;
+}
+extern "C" {
+    pub fn sendto(
+        __fd: ::std::os::raw::c_int,
+        __buf: *const ::std::os::raw::c_void,
+        __n: usize,
+        __flags: ::std::os::raw::c_int,
+        __addr: *const sockaddr,
+        __addr_len: socklen_t,
+    ) -> isize;
+}
+extern "C" {
+    pub fn recvfrom(
+        __fd: ::std::os::raw::c_int,
+        __buf: *mut ::std::os::raw::c_void,
+        __n: usize,
+        __flags: ::std::os::raw::c_int,
+        __addr: *mut sockaddr,
+        __addr_len: *mut socklen_t,
+    ) -> isize;
+}
+extern "C" {
+    pub fn sendmsg(
+        __fd: ::std::os::raw::c_int,
+        __message: *const msghdr,
+        __flags: ::std::os::raw::c_int,
+    ) -> isize;
+}
+extern "C" {
+    pub fn recvmsg(
+        __fd: ::std::os::raw::c_int,
+        __message: *mut msghdr,
+        __flags: ::std::os::raw::c_int,
+    ) -> isize;
+}
+extern "C" {
+    pub fn getsockopt(
+        __fd: ::std::os::raw::c_int,
+        __level: ::std::os::raw::c_int,
+        __optname: ::std::os::raw::c_int,
+        __optval: *mut ::std::os::raw::c_void,
+        __optlen: *mut socklen_t,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn setsockopt(
+        __fd: ::std::os::raw::c_int,
+        __level: ::std::os::raw::c_int,
+        __optname: ::std::os::raw::c_int,
+        __optval: *const ::std::os::raw::c_void,
+        __optlen: socklen_t,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn listen(__fd: ::std::os::raw::c_int, __n: ::std::os::raw::c_int)
+        -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn accept(
+        __fd: ::std::os::raw::c_int,
+        __addr: *mut sockaddr,
+        __addr_len: *mut socklen_t,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn shutdown(
+        __fd: ::std::os::raw::c_int,
+        __how: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn sockatmark(__fd: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn isfdtype(
+        __fd: ::std::os::raw::c_int,
+        __fdtype: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct sync_serial_settings {
+    pub clock_rate: ::std::os::raw::c_uint,
+    pub clock_type: ::std::os::raw::c_uint,
+    pub loopback: ::std::os::raw::c_ushort,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct te1_settings {
+    pub clock_rate: ::std::os::raw::c_uint,
+    pub clock_type: ::std::os::raw::c_uint,
+    pub loopback: ::std::os::raw::c_ushort,
+    pub slot_map: ::std::os::raw::c_uint,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct raw_hdlc_proto {
+    pub encoding: ::std::os::raw::c_ushort,
+    pub parity: ::std::os::raw::c_ushort,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct fr_proto {
+    pub t391: ::std::os::raw::c_uint,
+    pub t392: ::std::os::raw::c_uint,
+    pub n391: ::std::os::raw::c_uint,
+    pub n392: ::std::os::raw::c_uint,
+    pub n393: ::std::os::raw::c_uint,
+    pub lmi: ::std::os::raw::c_ushort,
+    pub dce: ::std::os::raw::c_ushort,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct fr_proto_pvc {
+    pub dlci: ::std::os::raw::c_uint,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct fr_proto_pvc_info {
+    pub dlci: ::std::os::raw::c_uint,
+    pub master: [::std::os::raw::c_char; 16usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct cisco_proto {
+    pub interval: ::std::os::raw::c_uint,
+    pub timeout: ::std::os::raw::c_uint,
+}
+pub const net_device_flags_IFF_UP: net_device_flags = 1;
+pub const net_device_flags_IFF_BROADCAST: net_device_flags = 2;
+pub const net_device_flags_IFF_DEBUG: net_device_flags = 4;
+pub const net_device_flags_IFF_LOOPBACK: net_device_flags = 8;
+pub const net_device_flags_IFF_POINTOPOINT: net_device_flags = 16;
+pub const net_device_flags_IFF_NOTRAILERS: net_device_flags = 32;
+pub const net_device_flags_IFF_RUNNING: net_device_flags = 64;
+pub const net_device_flags_IFF_NOARP: net_device_flags = 128;
+pub const net_device_flags_IFF_PROMISC: net_device_flags = 256;
+pub const net_device_flags_IFF_ALLMULTI: net_device_flags = 512;
+pub const net_device_flags_IFF_MASTER: net_device_flags = 1024;
+pub const net_device_flags_IFF_SLAVE: net_device_flags = 2048;
+pub const net_device_flags_IFF_MULTICAST: net_device_flags = 4096;
+pub const net_device_flags_IFF_PORTSEL: net_device_flags = 8192;
+pub const net_device_flags_IFF_AUTOMEDIA: net_device_flags = 16384;
+pub const net_device_flags_IFF_DYNAMIC: net_device_flags = 32768;
+pub const net_device_flags_IFF_LOWER_UP: net_device_flags = 65536;
+pub const net_device_flags_IFF_DORMANT: net_device_flags = 131072;
+pub const net_device_flags_IFF_ECHO: net_device_flags = 262144;
+pub type net_device_flags = u32;
+pub const IF_OPER_UNKNOWN: _bindgen_ty_4 = 0;
+pub const IF_OPER_NOTPRESENT: _bindgen_ty_4 = 1;
+pub const IF_OPER_DOWN: _bindgen_ty_4 = 2;
+pub const IF_OPER_LOWERLAYERDOWN: _bindgen_ty_4 = 3;
+pub const IF_OPER_TESTING: _bindgen_ty_4 = 4;
+pub const IF_OPER_DORMANT: _bindgen_ty_4 = 5;
+pub const IF_OPER_UP: _bindgen_ty_4 = 6;
+pub type _bindgen_ty_4 = u32;
+pub const IF_LINK_MODE_DEFAULT: _bindgen_ty_5 = 0;
+pub const IF_LINK_MODE_DORMANT: _bindgen_ty_5 = 1;
+pub type _bindgen_ty_5 = u32;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct ifmap {
+    pub mem_start: ::std::os::raw::c_ulong,
+    pub mem_end: ::std::os::raw::c_ulong,
+    pub base_addr: ::std::os::raw::c_ushort,
+    pub irq: ::std::os::raw::c_uchar,
+    pub dma: ::std::os::raw::c_uchar,
+    pub port: ::std::os::raw::c_uchar,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct if_settings {
+    pub type_: ::std::os::raw::c_uint,
+    pub size: ::std::os::raw::c_uint,
+    pub ifs_ifsu: if_settings__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union if_settings__bindgen_ty_1 {
+    pub raw_hdlc: *mut raw_hdlc_proto,
+    pub cisco: *mut cisco_proto,
+    pub fr: *mut fr_proto,
+    pub fr_pvc: *mut fr_proto_pvc,
+    pub fr_pvc_info: *mut fr_proto_pvc_info,
+    pub sync: *mut sync_serial_settings,
+    pub te1: *mut te1_settings,
+    _bindgen_union_align: u64,
+}
+impl Default for if_settings__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+impl Default for if_settings {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct ifreq {
+    pub ifr_ifrn: ifreq__bindgen_ty_1,
+    pub ifr_ifru: ifreq__bindgen_ty_2,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union ifreq__bindgen_ty_1 {
+    pub ifrn_name: [::std::os::raw::c_char; 16usize],
+    _bindgen_union_align: [u8; 16usize],
+}
+impl Default for ifreq__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union ifreq__bindgen_ty_2 {
+    pub ifru_addr: sockaddr,
+    pub ifru_dstaddr: sockaddr,
+    pub ifru_broadaddr: sockaddr,
+    pub ifru_netmask: sockaddr,
+    pub ifru_hwaddr: sockaddr,
+    pub ifru_flags: ::std::os::raw::c_short,
+    pub ifru_ivalue: ::std::os::raw::c_int,
+    pub ifru_mtu: ::std::os::raw::c_int,
+    pub ifru_map: ifmap,
+    pub ifru_slave: [::std::os::raw::c_char; 16usize],
+    pub ifru_newname: [::std::os::raw::c_char; 16usize],
+    pub ifru_data: *mut ::std::os::raw::c_void,
+    pub ifru_settings: if_settings,
+    _bindgen_union_align: [u64; 3usize],
+}
+impl Default for ifreq__bindgen_ty_2 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+impl Default for ifreq {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct ifconf {
+    pub ifc_len: ::std::os::raw::c_int,
+    pub ifc_ifcu: ifconf__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union ifconf__bindgen_ty_1 {
+    pub ifcu_buf: *mut ::std::os::raw::c_char,
+    pub ifcu_req: *mut ifreq,
+    _bindgen_union_align: u64,
+}
+impl Default for ifconf__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+impl Default for ifconf {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
diff --git a/net_sys/src/inn.rs b/net_sys/src/inn.rs
new file mode 100644
index 0000000..2214fdd
--- /dev/null
+++ b/net_sys/src/inn.rs
@@ -0,0 +1,843 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+pub const __BITS_PER_LONG: ::std::os::raw::c_uint = 64;
+pub const __FD_SETSIZE: ::std::os::raw::c_uint = 1024;
+pub const __UAPI_DEF_IN_ADDR: ::std::os::raw::c_uint = 1;
+pub const __UAPI_DEF_IN_IPPROTO: ::std::os::raw::c_uint = 1;
+pub const __UAPI_DEF_IN_PKTINFO: ::std::os::raw::c_uint = 1;
+pub const __UAPI_DEF_IP_MREQ: ::std::os::raw::c_uint = 1;
+pub const __UAPI_DEF_SOCKADDR_IN: ::std::os::raw::c_uint = 1;
+pub const __UAPI_DEF_IN_CLASS: ::std::os::raw::c_uint = 1;
+pub const __UAPI_DEF_IN6_ADDR: ::std::os::raw::c_uint = 1;
+pub const __UAPI_DEF_IN6_ADDR_ALT: ::std::os::raw::c_uint = 1;
+pub const __UAPI_DEF_SOCKADDR_IN6: ::std::os::raw::c_uint = 1;
+pub const __UAPI_DEF_IPV6_MREQ: ::std::os::raw::c_uint = 1;
+pub const __UAPI_DEF_IPPROTO_V6: ::std::os::raw::c_uint = 1;
+pub const __UAPI_DEF_IPV6_OPTIONS: ::std::os::raw::c_uint = 1;
+pub const __UAPI_DEF_IN6_PKTINFO: ::std::os::raw::c_uint = 1;
+pub const __UAPI_DEF_IP6_MTUINFO: ::std::os::raw::c_uint = 1;
+pub const __UAPI_DEF_XATTR: ::std::os::raw::c_uint = 1;
+pub const _K_SS_MAXSIZE: ::std::os::raw::c_uint = 128;
+pub const IP_TOS: ::std::os::raw::c_uint = 1;
+pub const IP_TTL: ::std::os::raw::c_uint = 2;
+pub const IP_HDRINCL: ::std::os::raw::c_uint = 3;
+pub const IP_OPTIONS: ::std::os::raw::c_uint = 4;
+pub const IP_ROUTER_ALERT: ::std::os::raw::c_uint = 5;
+pub const IP_RECVOPTS: ::std::os::raw::c_uint = 6;
+pub const IP_RETOPTS: ::std::os::raw::c_uint = 7;
+pub const IP_PKTINFO: ::std::os::raw::c_uint = 8;
+pub const IP_PKTOPTIONS: ::std::os::raw::c_uint = 9;
+pub const IP_MTU_DISCOVER: ::std::os::raw::c_uint = 10;
+pub const IP_RECVERR: ::std::os::raw::c_uint = 11;
+pub const IP_RECVTTL: ::std::os::raw::c_uint = 12;
+pub const IP_RECVTOS: ::std::os::raw::c_uint = 13;
+pub const IP_MTU: ::std::os::raw::c_uint = 14;
+pub const IP_FREEBIND: ::std::os::raw::c_uint = 15;
+pub const IP_IPSEC_POLICY: ::std::os::raw::c_uint = 16;
+pub const IP_XFRM_POLICY: ::std::os::raw::c_uint = 17;
+pub const IP_PASSSEC: ::std::os::raw::c_uint = 18;
+pub const IP_TRANSPARENT: ::std::os::raw::c_uint = 19;
+pub const IP_RECVRETOPTS: ::std::os::raw::c_uint = 7;
+pub const IP_ORIGDSTADDR: ::std::os::raw::c_uint = 20;
+pub const IP_RECVORIGDSTADDR: ::std::os::raw::c_uint = 20;
+pub const IP_MINTTL: ::std::os::raw::c_uint = 21;
+pub const IP_NODEFRAG: ::std::os::raw::c_uint = 22;
+pub const IP_CHECKSUM: ::std::os::raw::c_uint = 23;
+pub const IP_BIND_ADDRESS_NO_PORT: ::std::os::raw::c_uint = 24;
+pub const IP_RECVFRAGSIZE: ::std::os::raw::c_uint = 25;
+pub const IP_PMTUDISC_DONT: ::std::os::raw::c_uint = 0;
+pub const IP_PMTUDISC_WANT: ::std::os::raw::c_uint = 1;
+pub const IP_PMTUDISC_DO: ::std::os::raw::c_uint = 2;
+pub const IP_PMTUDISC_PROBE: ::std::os::raw::c_uint = 3;
+pub const IP_PMTUDISC_INTERFACE: ::std::os::raw::c_uint = 4;
+pub const IP_PMTUDISC_OMIT: ::std::os::raw::c_uint = 5;
+pub const IP_MULTICAST_IF: ::std::os::raw::c_uint = 32;
+pub const IP_MULTICAST_TTL: ::std::os::raw::c_uint = 33;
+pub const IP_MULTICAST_LOOP: ::std::os::raw::c_uint = 34;
+pub const IP_ADD_MEMBERSHIP: ::std::os::raw::c_uint = 35;
+pub const IP_DROP_MEMBERSHIP: ::std::os::raw::c_uint = 36;
+pub const IP_UNBLOCK_SOURCE: ::std::os::raw::c_uint = 37;
+pub const IP_BLOCK_SOURCE: ::std::os::raw::c_uint = 38;
+pub const IP_ADD_SOURCE_MEMBERSHIP: ::std::os::raw::c_uint = 39;
+pub const IP_DROP_SOURCE_MEMBERSHIP: ::std::os::raw::c_uint = 40;
+pub const IP_MSFILTER: ::std::os::raw::c_uint = 41;
+pub const MCAST_JOIN_GROUP: ::std::os::raw::c_uint = 42;
+pub const MCAST_BLOCK_SOURCE: ::std::os::raw::c_uint = 43;
+pub const MCAST_UNBLOCK_SOURCE: ::std::os::raw::c_uint = 44;
+pub const MCAST_LEAVE_GROUP: ::std::os::raw::c_uint = 45;
+pub const MCAST_JOIN_SOURCE_GROUP: ::std::os::raw::c_uint = 46;
+pub const MCAST_LEAVE_SOURCE_GROUP: ::std::os::raw::c_uint = 47;
+pub const MCAST_MSFILTER: ::std::os::raw::c_uint = 48;
+pub const IP_MULTICAST_ALL: ::std::os::raw::c_uint = 49;
+pub const IP_UNICAST_IF: ::std::os::raw::c_uint = 50;
+pub const MCAST_EXCLUDE: ::std::os::raw::c_uint = 0;
+pub const MCAST_INCLUDE: ::std::os::raw::c_uint = 1;
+pub const IP_DEFAULT_MULTICAST_TTL: ::std::os::raw::c_uint = 1;
+pub const IP_DEFAULT_MULTICAST_LOOP: ::std::os::raw::c_uint = 1;
+pub const __SOCK_SIZE__: ::std::os::raw::c_uint = 16;
+pub const IN_CLASSA_NET: ::std::os::raw::c_uint = 4278190080;
+pub const IN_CLASSA_NSHIFT: ::std::os::raw::c_uint = 24;
+pub const IN_CLASSA_HOST: ::std::os::raw::c_uint = 16777215;
+pub const IN_CLASSA_MAX: ::std::os::raw::c_uint = 128;
+pub const IN_CLASSB_NET: ::std::os::raw::c_uint = 4294901760;
+pub const IN_CLASSB_NSHIFT: ::std::os::raw::c_uint = 16;
+pub const IN_CLASSB_HOST: ::std::os::raw::c_uint = 65535;
+pub const IN_CLASSB_MAX: ::std::os::raw::c_uint = 65536;
+pub const IN_CLASSC_NET: ::std::os::raw::c_uint = 4294967040;
+pub const IN_CLASSC_NSHIFT: ::std::os::raw::c_uint = 8;
+pub const IN_CLASSC_HOST: ::std::os::raw::c_uint = 255;
+pub const IN_MULTICAST_NET: ::std::os::raw::c_uint = 4026531840;
+pub const IN_LOOPBACKNET: ::std::os::raw::c_uint = 127;
+pub const INADDR_LOOPBACK: ::std::os::raw::c_uint = 2130706433;
+pub const INADDR_UNSPEC_GROUP: ::std::os::raw::c_uint = 3758096384;
+pub const INADDR_ALLHOSTS_GROUP: ::std::os::raw::c_uint = 3758096385;
+pub const INADDR_ALLRTRS_GROUP: ::std::os::raw::c_uint = 3758096386;
+pub const INADDR_MAX_LOCAL_GROUP: ::std::os::raw::c_uint = 3758096639;
+pub const __LITTLE_ENDIAN: ::std::os::raw::c_uint = 1234;
+pub type __s8 = ::std::os::raw::c_schar;
+pub type __u8 = ::std::os::raw::c_uchar;
+pub type __s16 = ::std::os::raw::c_short;
+pub type __u16 = ::std::os::raw::c_ushort;
+pub type __s32 = ::std::os::raw::c_int;
+pub type __u32 = ::std::os::raw::c_uint;
+pub type __s64 = ::std::os::raw::c_longlong;
+pub type __u64 = ::std::os::raw::c_ulonglong;
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct __kernel_fd_set {
+    pub fds_bits: [::std::os::raw::c_ulong; 16usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fd_set() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fd_set>(),
+        128usize,
+        concat!("Size of: ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fd_set>(),
+        8usize,
+        concat!("Alignment of ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const __kernel_fd_set)).fds_bits as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(__kernel_fd_set),
+            "::",
+            stringify!(fds_bits)
+        )
+    );
+}
+impl Clone for __kernel_fd_set {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+pub type __kernel_sighandler_t =
+    ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
+pub type __kernel_key_t = ::std::os::raw::c_int;
+pub type __kernel_mqd_t = ::std::os::raw::c_int;
+pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
+pub type __kernel_long_t = ::std::os::raw::c_long;
+pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
+pub type __kernel_ino_t = __kernel_ulong_t;
+pub type __kernel_mode_t = ::std::os::raw::c_uint;
+pub type __kernel_pid_t = ::std::os::raw::c_int;
+pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
+pub type __kernel_uid_t = ::std::os::raw::c_uint;
+pub type __kernel_gid_t = ::std::os::raw::c_uint;
+pub type __kernel_suseconds_t = __kernel_long_t;
+pub type __kernel_daddr_t = ::std::os::raw::c_int;
+pub type __kernel_uid32_t = ::std::os::raw::c_uint;
+pub type __kernel_gid32_t = ::std::os::raw::c_uint;
+pub type __kernel_size_t = __kernel_ulong_t;
+pub type __kernel_ssize_t = __kernel_long_t;
+pub type __kernel_ptrdiff_t = __kernel_long_t;
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct __kernel_fsid_t {
+    pub val: [::std::os::raw::c_int; 2usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fsid_t() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fsid_t>(),
+        8usize,
+        concat!("Size of: ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fsid_t>(),
+        4usize,
+        concat!("Alignment of ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const __kernel_fsid_t)).val as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(__kernel_fsid_t),
+            "::",
+            stringify!(val)
+        )
+    );
+}
+impl Clone for __kernel_fsid_t {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+pub type __kernel_off_t = __kernel_long_t;
+pub type __kernel_loff_t = ::std::os::raw::c_longlong;
+pub type __kernel_time_t = __kernel_long_t;
+pub type __kernel_clock_t = __kernel_long_t;
+pub type __kernel_timer_t = ::std::os::raw::c_int;
+pub type __kernel_clockid_t = ::std::os::raw::c_int;
+pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
+pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
+pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
+pub type __le16 = __u16;
+pub type __be16 = __u16;
+pub type __le32 = __u32;
+pub type __be32 = __u32;
+pub type __le64 = __u64;
+pub type __be64 = __u64;
+pub type __sum16 = __u16;
+pub type __wsum = __u32;
+pub type __kernel_sa_family_t = ::std::os::raw::c_ushort;
+#[repr(C)]
+pub struct __kernel_sockaddr_storage {
+    pub ss_family: __kernel_sa_family_t,
+    pub __data: [::std::os::raw::c_char; 126usize],
+    pub __bindgen_align: [u64; 0usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_sockaddr_storage() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_sockaddr_storage>(),
+        128usize,
+        concat!("Size of: ", stringify!(__kernel_sockaddr_storage))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_sockaddr_storage>(),
+        8usize,
+        concat!("Alignment of ", stringify!(__kernel_sockaddr_storage))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const __kernel_sockaddr_storage)).ss_family as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(__kernel_sockaddr_storage),
+            "::",
+            stringify!(ss_family)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const __kernel_sockaddr_storage)).__data as *const _ as usize },
+        2usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(__kernel_sockaddr_storage),
+            "::",
+            stringify!(__data)
+        )
+    );
+}
+impl Default for __kernel_sockaddr_storage {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+pub const IPPROTO_IP: _bindgen_ty_1 = 0;
+pub const IPPROTO_ICMP: _bindgen_ty_1 = 1;
+pub const IPPROTO_IGMP: _bindgen_ty_1 = 2;
+pub const IPPROTO_IPIP: _bindgen_ty_1 = 4;
+pub const IPPROTO_TCP: _bindgen_ty_1 = 6;
+pub const IPPROTO_EGP: _bindgen_ty_1 = 8;
+pub const IPPROTO_PUP: _bindgen_ty_1 = 12;
+pub const IPPROTO_UDP: _bindgen_ty_1 = 17;
+pub const IPPROTO_IDP: _bindgen_ty_1 = 22;
+pub const IPPROTO_TP: _bindgen_ty_1 = 29;
+pub const IPPROTO_DCCP: _bindgen_ty_1 = 33;
+pub const IPPROTO_IPV6: _bindgen_ty_1 = 41;
+pub const IPPROTO_RSVP: _bindgen_ty_1 = 46;
+pub const IPPROTO_GRE: _bindgen_ty_1 = 47;
+pub const IPPROTO_ESP: _bindgen_ty_1 = 50;
+pub const IPPROTO_AH: _bindgen_ty_1 = 51;
+pub const IPPROTO_MTP: _bindgen_ty_1 = 92;
+pub const IPPROTO_BEETPH: _bindgen_ty_1 = 94;
+pub const IPPROTO_ENCAP: _bindgen_ty_1 = 98;
+pub const IPPROTO_PIM: _bindgen_ty_1 = 103;
+pub const IPPROTO_COMP: _bindgen_ty_1 = 108;
+pub const IPPROTO_SCTP: _bindgen_ty_1 = 132;
+pub const IPPROTO_UDPLITE: _bindgen_ty_1 = 136;
+pub const IPPROTO_MPLS: _bindgen_ty_1 = 137;
+pub const IPPROTO_RAW: _bindgen_ty_1 = 255;
+pub const IPPROTO_MAX: _bindgen_ty_1 = 256;
+pub type _bindgen_ty_1 = ::std::os::raw::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct in_addr {
+    pub s_addr: __be32,
+}
+#[test]
+fn bindgen_test_layout_in_addr() {
+    assert_eq!(
+        ::std::mem::size_of::<in_addr>(),
+        4usize,
+        concat!("Size of: ", stringify!(in_addr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<in_addr>(),
+        4usize,
+        concat!("Alignment of ", stringify!(in_addr))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const in_addr)).s_addr as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(in_addr),
+            "::",
+            stringify!(s_addr)
+        )
+    );
+}
+impl Clone for in_addr {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct ip_mreq {
+    pub imr_multiaddr: in_addr,
+    pub imr_interface: in_addr,
+}
+#[test]
+fn bindgen_test_layout_ip_mreq() {
+    assert_eq!(
+        ::std::mem::size_of::<ip_mreq>(),
+        8usize,
+        concat!("Size of: ", stringify!(ip_mreq))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<ip_mreq>(),
+        4usize,
+        concat!("Alignment of ", stringify!(ip_mreq))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ip_mreq)).imr_multiaddr as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ip_mreq),
+            "::",
+            stringify!(imr_multiaddr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ip_mreq)).imr_interface as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ip_mreq),
+            "::",
+            stringify!(imr_interface)
+        )
+    );
+}
+impl Clone for ip_mreq {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct ip_mreqn {
+    pub imr_multiaddr: in_addr,
+    pub imr_address: in_addr,
+    pub imr_ifindex: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_ip_mreqn() {
+    assert_eq!(
+        ::std::mem::size_of::<ip_mreqn>(),
+        12usize,
+        concat!("Size of: ", stringify!(ip_mreqn))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<ip_mreqn>(),
+        4usize,
+        concat!("Alignment of ", stringify!(ip_mreqn))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ip_mreqn)).imr_multiaddr as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ip_mreqn),
+            "::",
+            stringify!(imr_multiaddr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ip_mreqn)).imr_address as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ip_mreqn),
+            "::",
+            stringify!(imr_address)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ip_mreqn)).imr_ifindex as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ip_mreqn),
+            "::",
+            stringify!(imr_ifindex)
+        )
+    );
+}
+impl Clone for ip_mreqn {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct ip_mreq_source {
+    pub imr_multiaddr: __be32,
+    pub imr_interface: __be32,
+    pub imr_sourceaddr: __be32,
+}
+#[test]
+fn bindgen_test_layout_ip_mreq_source() {
+    assert_eq!(
+        ::std::mem::size_of::<ip_mreq_source>(),
+        12usize,
+        concat!("Size of: ", stringify!(ip_mreq_source))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<ip_mreq_source>(),
+        4usize,
+        concat!("Alignment of ", stringify!(ip_mreq_source))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ip_mreq_source)).imr_multiaddr as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ip_mreq_source),
+            "::",
+            stringify!(imr_multiaddr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ip_mreq_source)).imr_interface as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ip_mreq_source),
+            "::",
+            stringify!(imr_interface)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ip_mreq_source)).imr_sourceaddr as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ip_mreq_source),
+            "::",
+            stringify!(imr_sourceaddr)
+        )
+    );
+}
+impl Clone for ip_mreq_source {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct ip_msfilter {
+    pub imsf_multiaddr: __be32,
+    pub imsf_interface: __be32,
+    pub imsf_fmode: __u32,
+    pub imsf_numsrc: __u32,
+    pub imsf_slist: [__be32; 1usize],
+}
+#[test]
+fn bindgen_test_layout_ip_msfilter() {
+    assert_eq!(
+        ::std::mem::size_of::<ip_msfilter>(),
+        20usize,
+        concat!("Size of: ", stringify!(ip_msfilter))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<ip_msfilter>(),
+        4usize,
+        concat!("Alignment of ", stringify!(ip_msfilter))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ip_msfilter)).imsf_multiaddr as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ip_msfilter),
+            "::",
+            stringify!(imsf_multiaddr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ip_msfilter)).imsf_interface as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ip_msfilter),
+            "::",
+            stringify!(imsf_interface)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ip_msfilter)).imsf_fmode as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ip_msfilter),
+            "::",
+            stringify!(imsf_fmode)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ip_msfilter)).imsf_numsrc as *const _ as usize },
+        12usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ip_msfilter),
+            "::",
+            stringify!(imsf_numsrc)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ip_msfilter)).imsf_slist as *const _ as usize },
+        16usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ip_msfilter),
+            "::",
+            stringify!(imsf_slist)
+        )
+    );
+}
+impl Clone for ip_msfilter {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+pub struct group_req {
+    pub gr_interface: __u32,
+    pub gr_group: __kernel_sockaddr_storage,
+}
+#[test]
+fn bindgen_test_layout_group_req() {
+    assert_eq!(
+        ::std::mem::size_of::<group_req>(),
+        136usize,
+        concat!("Size of: ", stringify!(group_req))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<group_req>(),
+        8usize,
+        concat!("Alignment of ", stringify!(group_req))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const group_req)).gr_interface as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(group_req),
+            "::",
+            stringify!(gr_interface)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const group_req)).gr_group as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(group_req),
+            "::",
+            stringify!(gr_group)
+        )
+    );
+}
+impl Default for group_req {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+pub struct group_source_req {
+    pub gsr_interface: __u32,
+    pub gsr_group: __kernel_sockaddr_storage,
+    pub gsr_source: __kernel_sockaddr_storage,
+}
+#[test]
+fn bindgen_test_layout_group_source_req() {
+    assert_eq!(
+        ::std::mem::size_of::<group_source_req>(),
+        264usize,
+        concat!("Size of: ", stringify!(group_source_req))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<group_source_req>(),
+        8usize,
+        concat!("Alignment of ", stringify!(group_source_req))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const group_source_req)).gsr_interface as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(group_source_req),
+            "::",
+            stringify!(gsr_interface)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const group_source_req)).gsr_group as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(group_source_req),
+            "::",
+            stringify!(gsr_group)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const group_source_req)).gsr_source as *const _ as usize },
+        136usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(group_source_req),
+            "::",
+            stringify!(gsr_source)
+        )
+    );
+}
+impl Default for group_source_req {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+pub struct group_filter {
+    pub gf_interface: __u32,
+    pub gf_group: __kernel_sockaddr_storage,
+    pub gf_fmode: __u32,
+    pub gf_numsrc: __u32,
+    pub gf_slist: [__kernel_sockaddr_storage; 1usize],
+}
+#[test]
+fn bindgen_test_layout_group_filter() {
+    assert_eq!(
+        ::std::mem::size_of::<group_filter>(),
+        272usize,
+        concat!("Size of: ", stringify!(group_filter))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<group_filter>(),
+        8usize,
+        concat!("Alignment of ", stringify!(group_filter))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const group_filter)).gf_interface as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(group_filter),
+            "::",
+            stringify!(gf_interface)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const group_filter)).gf_group as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(group_filter),
+            "::",
+            stringify!(gf_group)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const group_filter)).gf_fmode as *const _ as usize },
+        136usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(group_filter),
+            "::",
+            stringify!(gf_fmode)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const group_filter)).gf_numsrc as *const _ as usize },
+        140usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(group_filter),
+            "::",
+            stringify!(gf_numsrc)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const group_filter)).gf_slist as *const _ as usize },
+        144usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(group_filter),
+            "::",
+            stringify!(gf_slist)
+        )
+    );
+}
+impl Default for group_filter {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct in_pktinfo {
+    pub ipi_ifindex: ::std::os::raw::c_int,
+    pub ipi_spec_dst: in_addr,
+    pub ipi_addr: in_addr,
+}
+#[test]
+fn bindgen_test_layout_in_pktinfo() {
+    assert_eq!(
+        ::std::mem::size_of::<in_pktinfo>(),
+        12usize,
+        concat!("Size of: ", stringify!(in_pktinfo))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<in_pktinfo>(),
+        4usize,
+        concat!("Alignment of ", stringify!(in_pktinfo))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const in_pktinfo)).ipi_ifindex as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(in_pktinfo),
+            "::",
+            stringify!(ipi_ifindex)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const in_pktinfo)).ipi_spec_dst as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(in_pktinfo),
+            "::",
+            stringify!(ipi_spec_dst)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const in_pktinfo)).ipi_addr as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(in_pktinfo),
+            "::",
+            stringify!(ipi_addr)
+        )
+    );
+}
+impl Clone for in_pktinfo {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct sockaddr_in {
+    pub sin_family: __kernel_sa_family_t,
+    pub sin_port: __be16,
+    pub sin_addr: in_addr,
+    pub __pad: [::std::os::raw::c_uchar; 8usize],
+}
+#[test]
+fn bindgen_test_layout_sockaddr_in() {
+    assert_eq!(
+        ::std::mem::size_of::<sockaddr_in>(),
+        16usize,
+        concat!("Size of: ", stringify!(sockaddr_in))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<sockaddr_in>(),
+        4usize,
+        concat!("Alignment of ", stringify!(sockaddr_in))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const sockaddr_in)).sin_family as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(sockaddr_in),
+            "::",
+            stringify!(sin_family)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const sockaddr_in)).sin_port as *const _ as usize },
+        2usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(sockaddr_in),
+            "::",
+            stringify!(sin_port)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const sockaddr_in)).sin_addr as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(sockaddr_in),
+            "::",
+            stringify!(sin_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const sockaddr_in)).__pad as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(sockaddr_in),
+            "::",
+            stringify!(__pad)
+        )
+    );
+}
+impl Clone for sockaddr_in {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
diff --git a/net_sys/src/lib.rs b/net_sys/src/lib.rs
new file mode 100644
index 0000000..32013fc
--- /dev/null
+++ b/net_sys/src/lib.rs
@@ -0,0 +1,62 @@
+// Copyright TUNTAP, 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+use sys_util::{ioctl_ior_nr, ioctl_iow_nr};
+
+// generated with bindgen /usr/include/linux/if.h --no-unstable-rust
+// --constified-enum '*' --with-derive-default -- -D __UAPI_DEF_IF_IFNAMSIZ -D
+// __UAPI_DEF_IF_NET_DEVICE_FLAGS -D __UAPI_DEF_IF_IFREQ -D __UAPI_DEF_IF_IFMAP
+// Name is "iff" to avoid conflicting with "if" keyword.
+// Generated against Linux 4.11 to include fix "uapi: fix linux/if.h userspace
+// compilation errors".
+// Manual fixup of ifrn_name to be of type c_uchar instead of c_char.
+#[allow(clippy::all)]
+pub mod iff;
+// generated with bindgen /usr/include/linux/if_tun.h --no-unstable-rust
+// --constified-enum '*' --with-derive-default
+pub mod if_tun;
+// generated with bindgen /usr/include/linux/in.h --no-unstable-rust
+// --constified-enum '*' --with-derive-default
+// Name is "inn" to avoid conflicting with "in" keyword.
+pub mod inn;
+// generated with bindgen /usr/include/linux/sockios.h --no-unstable-rust
+// --constified-enum '*' --with-derive-default
+pub mod sockios;
+pub use crate::if_tun::*;
+pub use crate::iff::*;
+pub use crate::inn::*;
+pub use crate::sockios::*;
+
+pub const TUNTAP: ::std::os::raw::c_uint = 84;
+
+pub const ARPHRD_ETHER: sa_family_t = 1;
+
+ioctl_iow_nr!(TUNSETNOCSUM, TUNTAP, 200, ::std::os::raw::c_int);
+ioctl_iow_nr!(TUNSETDEBUG, TUNTAP, 201, ::std::os::raw::c_int);
+ioctl_iow_nr!(TUNSETIFF, TUNTAP, 202, ::std::os::raw::c_int);
+ioctl_iow_nr!(TUNSETPERSIST, TUNTAP, 203, ::std::os::raw::c_int);
+ioctl_iow_nr!(TUNSETOWNER, TUNTAP, 204, ::std::os::raw::c_int);
+ioctl_iow_nr!(TUNSETLINK, TUNTAP, 205, ::std::os::raw::c_int);
+ioctl_iow_nr!(TUNSETGROUP, TUNTAP, 206, ::std::os::raw::c_int);
+ioctl_ior_nr!(TUNGETFEATURES, TUNTAP, 207, ::std::os::raw::c_uint);
+ioctl_iow_nr!(TUNSETOFFLOAD, TUNTAP, 208, ::std::os::raw::c_uint);
+ioctl_iow_nr!(TUNSETTXFILTER, TUNTAP, 209, ::std::os::raw::c_uint);
+ioctl_ior_nr!(TUNGETIFF, TUNTAP, 210, ::std::os::raw::c_uint);
+ioctl_ior_nr!(TUNGETSNDBUF, TUNTAP, 211, ::std::os::raw::c_int);
+ioctl_iow_nr!(TUNSETSNDBUF, TUNTAP, 212, ::std::os::raw::c_int);
+ioctl_iow_nr!(TUNATTACHFILTER, TUNTAP, 213, sock_fprog);
+ioctl_iow_nr!(TUNDETACHFILTER, TUNTAP, 214, sock_fprog);
+ioctl_ior_nr!(TUNGETVNETHDRSZ, TUNTAP, 215, ::std::os::raw::c_int);
+ioctl_iow_nr!(TUNSETVNETHDRSZ, TUNTAP, 216, ::std::os::raw::c_int);
+ioctl_iow_nr!(TUNSETQUEUE, TUNTAP, 217, ::std::os::raw::c_int);
+ioctl_iow_nr!(TUNSETIFINDEX, TUNTAP, 218, ::std::os::raw::c_uint);
+ioctl_ior_nr!(TUNGETFILTER, TUNTAP, 219, sock_fprog);
+ioctl_iow_nr!(TUNSETVNETLE, TUNTAP, 220, ::std::os::raw::c_int);
+ioctl_ior_nr!(TUNGETVNETLE, TUNTAP, 221, ::std::os::raw::c_int);
+ioctl_iow_nr!(TUNSETVNETBE, TUNTAP, 222, ::std::os::raw::c_int);
+ioctl_ior_nr!(TUNGETVNETBE, TUNTAP, 223, ::std::os::raw::c_int);
diff --git a/net_sys/src/sockios.rs b/net_sys/src/sockios.rs
new file mode 100644
index 0000000..0c0af76
--- /dev/null
+++ b/net_sys/src/sockios.rs
@@ -0,0 +1,89 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+pub const FIOSETOWN: ::std::os::raw::c_uint = 35073;
+pub const SIOCSPGRP: ::std::os::raw::c_uint = 35074;
+pub const FIOGETOWN: ::std::os::raw::c_uint = 35075;
+pub const SIOCGPGRP: ::std::os::raw::c_uint = 35076;
+pub const SIOCATMARK: ::std::os::raw::c_uint = 35077;
+pub const SIOCGSTAMP: ::std::os::raw::c_uint = 35078;
+pub const SIOCGSTAMPNS: ::std::os::raw::c_uint = 35079;
+pub const SOCK_IOC_TYPE: ::std::os::raw::c_uint = 137;
+pub const SIOCADDRT: ::std::os::raw::c_uint = 35083;
+pub const SIOCDELRT: ::std::os::raw::c_uint = 35084;
+pub const SIOCRTMSG: ::std::os::raw::c_uint = 35085;
+pub const SIOCGIFNAME: ::std::os::raw::c_uint = 35088;
+pub const SIOCSIFLINK: ::std::os::raw::c_uint = 35089;
+pub const SIOCGIFCONF: ::std::os::raw::c_uint = 35090;
+pub const SIOCGIFFLAGS: ::std::os::raw::c_uint = 35091;
+pub const SIOCSIFFLAGS: ::std::os::raw::c_uint = 35092;
+pub const SIOCGIFADDR: ::std::os::raw::c_uint = 35093;
+pub const SIOCSIFADDR: ::std::os::raw::c_uint = 35094;
+pub const SIOCGIFDSTADDR: ::std::os::raw::c_uint = 35095;
+pub const SIOCSIFDSTADDR: ::std::os::raw::c_uint = 35096;
+pub const SIOCGIFBRDADDR: ::std::os::raw::c_uint = 35097;
+pub const SIOCSIFBRDADDR: ::std::os::raw::c_uint = 35098;
+pub const SIOCGIFNETMASK: ::std::os::raw::c_uint = 35099;
+pub const SIOCSIFNETMASK: ::std::os::raw::c_uint = 35100;
+pub const SIOCGIFMETRIC: ::std::os::raw::c_uint = 35101;
+pub const SIOCSIFMETRIC: ::std::os::raw::c_uint = 35102;
+pub const SIOCGIFMEM: ::std::os::raw::c_uint = 35103;
+pub const SIOCSIFMEM: ::std::os::raw::c_uint = 35104;
+pub const SIOCGIFMTU: ::std::os::raw::c_uint = 35105;
+pub const SIOCSIFMTU: ::std::os::raw::c_uint = 35106;
+pub const SIOCSIFNAME: ::std::os::raw::c_uint = 35107;
+pub const SIOCSIFHWADDR: ::std::os::raw::c_uint = 35108;
+pub const SIOCGIFENCAP: ::std::os::raw::c_uint = 35109;
+pub const SIOCSIFENCAP: ::std::os::raw::c_uint = 35110;
+pub const SIOCGIFHWADDR: ::std::os::raw::c_uint = 35111;
+pub const SIOCGIFSLAVE: ::std::os::raw::c_uint = 35113;
+pub const SIOCSIFSLAVE: ::std::os::raw::c_uint = 35120;
+pub const SIOCADDMULTI: ::std::os::raw::c_uint = 35121;
+pub const SIOCDELMULTI: ::std::os::raw::c_uint = 35122;
+pub const SIOCGIFINDEX: ::std::os::raw::c_uint = 35123;
+pub const SIOGIFINDEX: ::std::os::raw::c_uint = 35123;
+pub const SIOCSIFPFLAGS: ::std::os::raw::c_uint = 35124;
+pub const SIOCGIFPFLAGS: ::std::os::raw::c_uint = 35125;
+pub const SIOCDIFADDR: ::std::os::raw::c_uint = 35126;
+pub const SIOCSIFHWBROADCAST: ::std::os::raw::c_uint = 35127;
+pub const SIOCGIFCOUNT: ::std::os::raw::c_uint = 35128;
+pub const SIOCGIFBR: ::std::os::raw::c_uint = 35136;
+pub const SIOCSIFBR: ::std::os::raw::c_uint = 35137;
+pub const SIOCGIFTXQLEN: ::std::os::raw::c_uint = 35138;
+pub const SIOCSIFTXQLEN: ::std::os::raw::c_uint = 35139;
+pub const SIOCETHTOOL: ::std::os::raw::c_uint = 35142;
+pub const SIOCGMIIPHY: ::std::os::raw::c_uint = 35143;
+pub const SIOCGMIIREG: ::std::os::raw::c_uint = 35144;
+pub const SIOCSMIIREG: ::std::os::raw::c_uint = 35145;
+pub const SIOCWANDEV: ::std::os::raw::c_uint = 35146;
+pub const SIOCOUTQNSD: ::std::os::raw::c_uint = 35147;
+pub const SIOCGSKNS: ::std::os::raw::c_uint = 35148;
+pub const SIOCDARP: ::std::os::raw::c_uint = 35155;
+pub const SIOCGARP: ::std::os::raw::c_uint = 35156;
+pub const SIOCSARP: ::std::os::raw::c_uint = 35157;
+pub const SIOCDRARP: ::std::os::raw::c_uint = 35168;
+pub const SIOCGRARP: ::std::os::raw::c_uint = 35169;
+pub const SIOCSRARP: ::std::os::raw::c_uint = 35170;
+pub const SIOCGIFMAP: ::std::os::raw::c_uint = 35184;
+pub const SIOCSIFMAP: ::std::os::raw::c_uint = 35185;
+pub const SIOCADDDLCI: ::std::os::raw::c_uint = 35200;
+pub const SIOCDELDLCI: ::std::os::raw::c_uint = 35201;
+pub const SIOCGIFVLAN: ::std::os::raw::c_uint = 35202;
+pub const SIOCSIFVLAN: ::std::os::raw::c_uint = 35203;
+pub const SIOCBONDENSLAVE: ::std::os::raw::c_uint = 35216;
+pub const SIOCBONDRELEASE: ::std::os::raw::c_uint = 35217;
+pub const SIOCBONDSETHWADDR: ::std::os::raw::c_uint = 35218;
+pub const SIOCBONDSLAVEINFOQUERY: ::std::os::raw::c_uint = 35219;
+pub const SIOCBONDINFOQUERY: ::std::os::raw::c_uint = 35220;
+pub const SIOCBONDCHANGEACTIVE: ::std::os::raw::c_uint = 35221;
+pub const SIOCBRADDBR: ::std::os::raw::c_uint = 35232;
+pub const SIOCBRDELBR: ::std::os::raw::c_uint = 35233;
+pub const SIOCBRADDIF: ::std::os::raw::c_uint = 35234;
+pub const SIOCBRDELIF: ::std::os::raw::c_uint = 35235;
+pub const SIOCSHWTSTAMP: ::std::os::raw::c_uint = 35248;
+pub const SIOCGHWTSTAMP: ::std::os::raw::c_uint = 35249;
+pub const SIOCDEVPRIVATE: ::std::os::raw::c_uint = 35312;
+pub const SIOCPROTOPRIVATE: ::std::os::raw::c_uint = 35296;
diff --git a/net_util/Cargo.toml b/net_util/Cargo.toml
new file mode 100644
index 0000000..bfa3bc8
--- /dev/null
+++ b/net_util/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "net_util"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+libc = "*"
+net_sys = { path = "../net_sys" }
+sys_util = { path = "../sys_util" }
diff --git a/net_util/src/lib.rs b/net_util/src/lib.rs
new file mode 100644
index 0000000..9508dcc
--- /dev/null
+++ b/net_util/src/lib.rs
@@ -0,0 +1,645 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::io::{Read, Result as IoResult, Write};
+use std::mem;
+use std::net;
+use std::num::ParseIntError;
+use std::os::raw::*;
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::str::FromStr;
+
+use libc::EPERM;
+
+use sys_util::Error as SysError;
+use sys_util::{ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val};
+
+#[derive(Debug)]
+pub enum Error {
+    /// Failed to create a socket.
+    CreateSocket(SysError),
+    /// Couldn't open /dev/net/tun.
+    OpenTun(SysError),
+    /// Unable to create tap interface.
+    CreateTap(SysError),
+    /// ioctl failed.
+    IoctlError(SysError),
+}
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            CreateSocket(e) => write!(f, "failed to create a socket: {}", e),
+            OpenTun(e) => write!(f, "failed to open /dev/net/tun: {}", e),
+            CreateTap(e) => write!(f, "failed to create tap interface: {}", e),
+            IoctlError(e) => write!(f, "ioctl failed: {}", e),
+        }
+    }
+}
+
+impl Error {
+    pub fn sys_error(&self) -> SysError {
+        match *self {
+            Error::CreateSocket(e) => e,
+            Error::OpenTun(e) => e,
+            Error::CreateTap(e) => e,
+            Error::IoctlError(e) => e,
+        }
+    }
+}
+
+/// Create a sockaddr_in from an IPv4 address, and expose it as
+/// an opaque sockaddr suitable for usage by socket ioctls.
+fn create_sockaddr(ip_addr: net::Ipv4Addr) -> net_sys::sockaddr {
+    // IPv4 addresses big-endian (network order), but Ipv4Addr will give us
+    // a view of those bytes directly so we can avoid any endian trickiness.
+    let addr_in = net_sys::sockaddr_in {
+        sin_family: net_sys::AF_INET as u16,
+        sin_port: 0,
+        sin_addr: unsafe { mem::transmute(ip_addr.octets()) },
+        __pad: [0; 8usize],
+    };
+
+    unsafe { mem::transmute(addr_in) }
+}
+
+/// Extract the IPv4 address from a sockaddr. Assumes the sockaddr is a sockaddr_in.
+fn read_ipv4_addr(addr: &net_sys::sockaddr) -> net::Ipv4Addr {
+    debug_assert_eq!(addr.sa_family as u32, net_sys::AF_INET);
+    // This is safe because sockaddr and sockaddr_in are the same size, and we've checked that
+    // this address is AF_INET.
+    let in_addr: net_sys::sockaddr_in = unsafe { mem::transmute(*addr) };
+    net::Ipv4Addr::from(in_addr.sin_addr.s_addr)
+}
+
+fn create_socket() -> Result<net::UdpSocket> {
+    // This is safe since we check the return value.
+    let sock = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
+    if sock < 0 {
+        return Err(Error::CreateSocket(SysError::last()));
+    }
+
+    // This is safe; nothing else will use or hold onto the raw sock fd.
+    Ok(unsafe { net::UdpSocket::from_raw_fd(sock) })
+}
+
+#[derive(Debug)]
+pub enum MacAddressError {
+    /// Invalid number of octets.
+    InvalidNumOctets(usize),
+    /// Failed to parse octet.
+    ParseOctet(ParseIntError),
+}
+
+impl Display for MacAddressError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::MacAddressError::*;
+
+        match self {
+            InvalidNumOctets(n) => write!(f, "invalid number of octets: {}", n),
+            ParseOctet(e) => write!(f, "failed to parse octet: {}", e),
+        }
+    }
+}
+
+/// An Ethernet mac address. This struct is compatible with the C `struct sockaddr`.
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct MacAddress {
+    family: net_sys::sa_family_t,
+    addr: [u8; 6usize],
+    __pad: [u8; 8usize],
+}
+
+impl MacAddress {
+    pub fn octets(&self) -> [u8; 6usize] {
+        self.addr
+    }
+}
+
+impl FromStr for MacAddress {
+    type Err = MacAddressError;
+
+    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+        let octets: Vec<&str> = s.split(':').collect();
+        if octets.len() != 6usize {
+            return Err(MacAddressError::InvalidNumOctets(octets.len()));
+        }
+
+        let mut result = MacAddress {
+            family: net_sys::ARPHRD_ETHER,
+            addr: [0; 6usize],
+            __pad: [0; 8usize],
+        };
+
+        for (i, octet) in octets.iter().enumerate() {
+            result.addr[i] = u8::from_str_radix(octet, 16).map_err(MacAddressError::ParseOctet)?;
+        }
+
+        Ok(result)
+    }
+}
+
+impl Display for MacAddress {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            f,
+            "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
+            self.addr[0], self.addr[1], self.addr[2], self.addr[3], self.addr[4], self.addr[5]
+        )
+    }
+}
+
+/// Handle for a network tap interface.
+///
+/// For now, this simply wraps the file descriptor for the tap device so methods
+/// can run ioctls on the interface. The tap interface fd will be closed when
+/// Tap goes out of scope, and the kernel will clean up the interface
+/// automatically.
+#[derive(Debug)]
+pub struct Tap {
+    tap_file: File,
+    if_name: [c_char; 16usize],
+    if_flags: ::std::os::raw::c_short,
+}
+
+impl Tap {
+    pub unsafe fn from_raw_fd(fd: RawFd) -> Result<Tap> {
+        let tap_file = File::from_raw_fd(fd);
+
+        // Get the interface name since we will need it for some ioctls.
+        let mut ifreq: net_sys::ifreq = Default::default();
+        let ret = ioctl_with_mut_ref(&tap_file, net_sys::TUNGETIFF(), &mut ifreq);
+
+        if ret < 0 {
+            return Err(Error::IoctlError(SysError::last()));
+        }
+
+        Ok(Tap {
+            tap_file,
+            if_name: ifreq.ifr_ifrn.ifrn_name,
+            if_flags: ifreq.ifr_ifru.ifru_flags,
+        })
+    }
+}
+
+pub trait TapT: Read + Write + AsRawFd + Send + Sized {
+    /// Create a new tap interface. Set the `vnet_hdr` flag to true to allow offloading on this tap,
+    /// which will add an extra 12 byte virtio net header to incoming frames. Offloading cannot
+    /// be used if `vnet_hdr` is false.
+    fn new(vnet_hdr: bool) -> Result<Self>;
+
+    /// Get the host-side IP address for the tap interface.
+    fn ip_addr(&self) -> Result<net::Ipv4Addr>;
+
+    /// Set the host-side IP address for the tap interface.
+    fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()>;
+
+    /// Get the netmask for the tap interface's subnet.
+    fn netmask(&self) -> Result<net::Ipv4Addr>;
+
+    /// Set the netmask for the subnet that the tap interface will exist on.
+    fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()>;
+
+    /// Get the mac address for the tap interface.
+    fn mac_address(&self) -> Result<MacAddress>;
+
+    /// Set the mac address for the tap interface.
+    fn set_mac_address(&self, mac_addr: MacAddress) -> Result<()>;
+
+    /// Set the offload flags for the tap interface.
+    fn set_offload(&self, flags: c_uint) -> Result<()>;
+
+    /// Enable the tap interface.
+    fn enable(&self) -> Result<()>;
+
+    /// Set the size of the vnet hdr.
+    fn set_vnet_hdr_size(&self, size: c_int) -> Result<()>;
+
+    fn get_ifreq(&self) -> net_sys::ifreq;
+
+    /// Get the interface flags
+    fn if_flags(&self) -> u32;
+}
+
+impl TapT for Tap {
+    fn new(vnet_hdr: bool) -> Result<Tap> {
+        // Open calls are safe because we give a constant nul-terminated
+        // string and verify the result.
+        let fd = unsafe {
+            libc::open(
+                b"/dev/net/tun\0".as_ptr() as *const c_char,
+                libc::O_RDWR | libc::O_NONBLOCK | libc::O_CLOEXEC,
+            )
+        };
+        if fd < 0 {
+            return Err(Error::OpenTun(SysError::last()));
+        }
+
+        // We just checked that the fd is valid.
+        let tuntap = unsafe { File::from_raw_fd(fd) };
+
+        const TUNTAP_DEV_FORMAT: &[u8; 8usize] = b"vmtap%d\0";
+
+        // This is pretty messy because of the unions used by ifreq. Since we
+        // don't call as_mut on the same union field more than once, this block
+        // is safe.
+        let mut ifreq: net_sys::ifreq = Default::default();
+        unsafe {
+            let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
+            let name_slice = &mut ifrn_name[..TUNTAP_DEV_FORMAT.len()];
+            for (dst, src) in name_slice.iter_mut().zip(TUNTAP_DEV_FORMAT.iter()) {
+                *dst = *src as c_char;
+            }
+            ifreq.ifr_ifru.ifru_flags = (net_sys::IFF_TAP
+                | net_sys::IFF_NO_PI
+                | if vnet_hdr { net_sys::IFF_VNET_HDR } else { 0 })
+                as c_short;
+        }
+
+        // ioctl is safe since we call it with a valid tap fd and check the return
+        // value.
+        let ret = unsafe { ioctl_with_mut_ref(&tuntap, net_sys::TUNSETIFF(), &mut ifreq) };
+
+        if ret < 0 {
+            let error = SysError::last();
+
+            // In a non-root, test environment, we won't have permission to call this; allow
+            if !(cfg!(test) && error.errno() == EPERM) {
+                return Err(Error::CreateTap(error));
+            }
+        }
+
+        // Safe since only the name is accessed, and it's copied out.
+        Ok(Tap {
+            tap_file: tuntap,
+            if_name: unsafe { ifreq.ifr_ifrn.ifrn_name },
+            if_flags: unsafe { ifreq.ifr_ifru.ifru_flags },
+        })
+    }
+
+    fn ip_addr(&self) -> Result<net::Ipv4Addr> {
+        let sock = create_socket()?;
+        let mut ifreq = self.get_ifreq();
+
+        // ioctl is safe. Called with a valid sock fd, and we check the return.
+        let ret = unsafe {
+            ioctl_with_mut_ref(&sock, net_sys::sockios::SIOCGIFADDR as c_ulong, &mut ifreq)
+        };
+        if ret < 0 {
+            return Err(Error::IoctlError(SysError::last()));
+        }
+
+        // We only access one field of the ifru union, hence this is safe.
+        let addr = unsafe { ifreq.ifr_ifru.ifru_addr };
+
+        Ok(read_ipv4_addr(&addr))
+    }
+
+    fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()> {
+        let sock = create_socket()?;
+        let addr = create_sockaddr(ip_addr);
+
+        let mut ifreq = self.get_ifreq();
+        ifreq.ifr_ifru.ifru_addr = addr;
+
+        // ioctl is safe. Called with a valid sock fd, and we check the return.
+        let ret =
+            unsafe { ioctl_with_ref(&sock, net_sys::sockios::SIOCSIFADDR as c_ulong, &ifreq) };
+        if ret < 0 {
+            return Err(Error::IoctlError(SysError::last()));
+        }
+
+        Ok(())
+    }
+
+    fn netmask(&self) -> Result<net::Ipv4Addr> {
+        let sock = create_socket()?;
+        let mut ifreq = self.get_ifreq();
+
+        // ioctl is safe. Called with a valid sock fd, and we check the return.
+        let ret = unsafe {
+            ioctl_with_mut_ref(
+                &sock,
+                net_sys::sockios::SIOCGIFNETMASK as c_ulong,
+                &mut ifreq,
+            )
+        };
+        if ret < 0 {
+            return Err(Error::IoctlError(SysError::last()));
+        }
+
+        // We only access one field of the ifru union, hence this is safe.
+        let addr = unsafe { ifreq.ifr_ifru.ifru_netmask };
+
+        Ok(read_ipv4_addr(&addr))
+    }
+
+    fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()> {
+        let sock = create_socket()?;
+        let addr = create_sockaddr(netmask);
+
+        let mut ifreq = self.get_ifreq();
+        ifreq.ifr_ifru.ifru_netmask = addr;
+
+        // ioctl is safe. Called with a valid sock fd, and we check the return.
+        let ret =
+            unsafe { ioctl_with_ref(&sock, net_sys::sockios::SIOCSIFNETMASK as c_ulong, &ifreq) };
+        if ret < 0 {
+            return Err(Error::IoctlError(SysError::last()));
+        }
+
+        Ok(())
+    }
+
+    fn mac_address(&self) -> Result<MacAddress> {
+        let sock = create_socket()?;
+        let mut ifreq = self.get_ifreq();
+
+        // ioctl is safe. Called with a valid sock fd, and we check the return.
+        let ret = unsafe {
+            ioctl_with_mut_ref(
+                &sock,
+                net_sys::sockios::SIOCGIFHWADDR as c_ulong,
+                &mut ifreq,
+            )
+        };
+        if ret < 0 {
+            return Err(Error::IoctlError(SysError::last()));
+        }
+
+        // We only access one field of the ifru union, hence this is safe.
+        // This is safe since the MacAddress struct is already sized to match the C sockaddr
+        // struct. The address family has also been checked.
+        Ok(unsafe { mem::transmute(ifreq.ifr_ifru.ifru_hwaddr) })
+    }
+
+    fn set_mac_address(&self, mac_addr: MacAddress) -> Result<()> {
+        let sock = create_socket()?;
+
+        let mut ifreq = self.get_ifreq();
+
+        // We only access one field of the ifru union, hence this is safe.
+        unsafe {
+            // This is safe since the MacAddress struct is already sized to match the C sockaddr
+            // struct.
+            ifreq.ifr_ifru.ifru_hwaddr = std::mem::transmute(mac_addr);
+        }
+
+        // ioctl is safe. Called with a valid sock fd, and we check the return.
+        let ret =
+            unsafe { ioctl_with_ref(&sock, net_sys::sockios::SIOCSIFHWADDR as c_ulong, &ifreq) };
+        if ret < 0 {
+            return Err(Error::IoctlError(SysError::last()));
+        }
+
+        Ok(())
+    }
+
+    fn set_offload(&self, flags: c_uint) -> Result<()> {
+        // ioctl is safe. Called with a valid tap fd, and we check the return.
+        let ret =
+            unsafe { ioctl_with_val(&self.tap_file, net_sys::TUNSETOFFLOAD(), flags as c_ulong) };
+        if ret < 0 {
+            return Err(Error::IoctlError(SysError::last()));
+        }
+
+        Ok(())
+    }
+
+    fn enable(&self) -> Result<()> {
+        let sock = create_socket()?;
+
+        let mut ifreq = self.get_ifreq();
+        ifreq.ifr_ifru.ifru_flags =
+            (net_sys::net_device_flags_IFF_UP | net_sys::net_device_flags_IFF_RUNNING) as i16;
+
+        // ioctl is safe. Called with a valid sock fd, and we check the return.
+        let ret =
+            unsafe { ioctl_with_ref(&sock, net_sys::sockios::SIOCSIFFLAGS as c_ulong, &ifreq) };
+        if ret < 0 {
+            return Err(Error::IoctlError(SysError::last()));
+        }
+
+        Ok(())
+    }
+
+    fn set_vnet_hdr_size(&self, size: c_int) -> Result<()> {
+        // ioctl is safe. Called with a valid tap fd, and we check the return.
+        let ret = unsafe { ioctl_with_ref(&self.tap_file, net_sys::TUNSETVNETHDRSZ(), &size) };
+        if ret < 0 {
+            return Err(Error::IoctlError(SysError::last()));
+        }
+
+        Ok(())
+    }
+
+    fn get_ifreq(&self) -> net_sys::ifreq {
+        let mut ifreq: net_sys::ifreq = Default::default();
+
+        // This sets the name of the interface, which is the only entry
+        // in a single-field union.
+        unsafe {
+            let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
+            ifrn_name.clone_from_slice(&self.if_name);
+        }
+
+        // This sets the flags with which the interface was created, which is the only entry we set
+        // on the second union.
+        ifreq.ifr_ifru.ifru_flags = self.if_flags;
+
+        ifreq
+    }
+
+    fn if_flags(&self) -> u32 {
+        self.if_flags as u32
+    }
+}
+
+impl Read for Tap {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
+        self.tap_file.read(buf)
+    }
+}
+
+impl Write for Tap {
+    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
+        self.tap_file.write(&buf)
+    }
+
+    fn flush(&mut self) -> IoResult<()> {
+        Ok(())
+    }
+}
+
+impl AsRawFd for Tap {
+    fn as_raw_fd(&self) -> RawFd {
+        self.tap_file.as_raw_fd()
+    }
+}
+
+pub mod fakes {
+    use super::*;
+    use std::fs::remove_file;
+    use std::fs::OpenOptions;
+
+    const TMP_FILE: &str = "/tmp/crosvm_tap_test_file";
+
+    pub struct FakeTap {
+        tap_file: File,
+    }
+
+    impl TapT for FakeTap {
+        fn new(_: bool) -> Result<FakeTap> {
+            Ok(FakeTap {
+                tap_file: OpenOptions::new()
+                    .read(true)
+                    .append(true)
+                    .create(true)
+                    .open(TMP_FILE)
+                    .unwrap(),
+            })
+        }
+
+        fn ip_addr(&self) -> Result<net::Ipv4Addr> {
+            Ok(net::Ipv4Addr::new(1, 2, 3, 4))
+        }
+
+        fn set_ip_addr(&self, _: net::Ipv4Addr) -> Result<()> {
+            Ok(())
+        }
+
+        fn netmask(&self) -> Result<net::Ipv4Addr> {
+            Ok(net::Ipv4Addr::new(255, 255, 255, 252))
+        }
+
+        fn set_netmask(&self, _: net::Ipv4Addr) -> Result<()> {
+            Ok(())
+        }
+
+        fn mac_address(&self) -> Result<MacAddress> {
+            Ok("01:02:03:04:05:06".parse().unwrap())
+        }
+
+        fn set_mac_address(&self, _: MacAddress) -> Result<()> {
+            Ok(())
+        }
+
+        fn set_offload(&self, _: c_uint) -> Result<()> {
+            Ok(())
+        }
+
+        fn enable(&self) -> Result<()> {
+            Ok(())
+        }
+
+        fn set_vnet_hdr_size(&self, _: c_int) -> Result<()> {
+            Ok(())
+        }
+
+        fn get_ifreq(&self) -> net_sys::ifreq {
+            let ifreq: net_sys::ifreq = Default::default();
+            ifreq
+        }
+
+        fn if_flags(&self) -> u32 {
+            net_sys::IFF_TAP
+        }
+    }
+
+    impl Drop for FakeTap {
+        fn drop(&mut self) {
+            let _ = remove_file(TMP_FILE);
+        }
+    }
+
+    impl Read for FakeTap {
+        fn read(&mut self, _: &mut [u8]) -> IoResult<usize> {
+            Ok(0)
+        }
+    }
+
+    impl Write for FakeTap {
+        fn write(&mut self, _: &[u8]) -> IoResult<usize> {
+            Ok(0)
+        }
+
+        fn flush(&mut self) -> IoResult<()> {
+            Ok(())
+        }
+    }
+
+    impl AsRawFd for FakeTap {
+        fn as_raw_fd(&self) -> RawFd {
+            self.tap_file.as_raw_fd()
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn parse_mac_address() {
+        assert!("01:02:03:04:05:06".parse::<MacAddress>().is_ok());
+        assert!("01:06".parse::<MacAddress>().is_err());
+        assert!("01:02:03:04:05:06:07:08:09".parse::<MacAddress>().is_err());
+        assert!("not a mac address".parse::<MacAddress>().is_err());
+    }
+
+    #[test]
+    fn tap_create() {
+        Tap::new(true).unwrap();
+    }
+
+    #[test]
+    fn tap_configure() {
+        let tap = Tap::new(true).unwrap();
+        let ip_addr: net::Ipv4Addr = "100.115.92.5".parse().unwrap();
+        let netmask: net::Ipv4Addr = "255.255.255.252".parse().unwrap();
+        let mac_addr: MacAddress = "a2:06:b9:3d:68:4d".parse().unwrap();
+
+        let ret = tap.set_ip_addr(ip_addr);
+        assert_ok_or_perm_denied(ret);
+        let ret = tap.set_netmask(netmask);
+        assert_ok_or_perm_denied(ret);
+        let ret = tap.set_mac_address(mac_addr);
+        assert_ok_or_perm_denied(ret);
+    }
+
+    /// This test will only work if the test is run with root permissions and, unlike other tests
+    /// in this file, do not return PermissionDenied. They fail because the TAP FD is not
+    /// initialized (as opposed to permission denial). Run this with "cargo test -- --ignored".
+    #[test]
+    #[ignore]
+    fn root_only_tests() {
+        // This line will fail to provide an initialized FD if the test is not run as root.
+        let tap = Tap::new(true).unwrap();
+        tap.set_vnet_hdr_size(16).unwrap();
+        tap.set_offload(0).unwrap();
+    }
+
+    #[test]
+    fn tap_enable() {
+        let tap = Tap::new(true).unwrap();
+
+        let ret = tap.enable();
+        assert_ok_or_perm_denied(ret);
+    }
+
+    fn assert_ok_or_perm_denied<T>(res: Result<T>) {
+        match res {
+            // We won't have permission in test environments; allow that
+            Ok(_t) => {}
+            Err(Error::IoctlError(e)) if e.errno() == EPERM => {}
+            Err(e) => panic!("Unexpected Error:\n{}", e),
+        }
+    }
+}
diff --git a/p9/Cargo.toml b/p9/Cargo.toml
new file mode 100644
index 0000000..40b5d62
--- /dev/null
+++ b/p9/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "p9"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+libc = "*"
+wire_format_derive = { path = "wire_format_derive" }
+
+[features]
+trace = []
diff --git a/p9/src/lib.rs b/p9/src/lib.rs
new file mode 100644
index 0000000..56195f1
--- /dev/null
+++ b/p9/src/lib.rs
@@ -0,0 +1,8 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+mod protocol;
+mod server;
+
+pub use crate::server::Server;
diff --git a/p9/src/protocol/messages.rs b/p9/src/protocol/messages.rs
new file mode 100644
index 0000000..c8429bb
--- /dev/null
+++ b/p9/src/protocol/messages.rs
@@ -0,0 +1,842 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use wire_format_derive::P9WireFormat;
+
+use std::io::{self, ErrorKind, Read, Write};
+use std::mem;
+use std::string::String;
+use std::vec::Vec;
+
+use crate::protocol::wire_format::{Data, WireFormat};
+
+// Message type constants.  Taken from "include/net/9p/9p.h" in the linux kernel
+// tree.  The protocol specifies each R* message to be the corresponding T*
+// message plus one.
+const TLERROR: u8 = 6;
+const RLERROR: u8 = TLERROR + 1;
+const TSTATFS: u8 = 8;
+const RSTATFS: u8 = TSTATFS + 1;
+const TLOPEN: u8 = 12;
+const RLOPEN: u8 = TLOPEN + 1;
+const TLCREATE: u8 = 14;
+const RLCREATE: u8 = TLCREATE + 1;
+const TSYMLINK: u8 = 16;
+const RSYMLINK: u8 = TSYMLINK + 1;
+const TMKNOD: u8 = 18;
+const RMKNOD: u8 = TMKNOD + 1;
+const TRENAME: u8 = 20;
+const RRENAME: u8 = TRENAME + 1;
+const TREADLINK: u8 = 22;
+const RREADLINK: u8 = TREADLINK + 1;
+const TGETATTR: u8 = 24;
+const RGETATTR: u8 = TGETATTR + 1;
+const TSETATTR: u8 = 26;
+const RSETATTR: u8 = TSETATTR + 1;
+const TXATTRWALK: u8 = 30;
+const RXATTRWALK: u8 = TXATTRWALK + 1;
+const TXATTRCREATE: u8 = 32;
+const RXATTRCREATE: u8 = TXATTRCREATE + 1;
+const TREADDIR: u8 = 40;
+const RREADDIR: u8 = TREADDIR + 1;
+const TFSYNC: u8 = 50;
+const RFSYNC: u8 = TFSYNC + 1;
+const TLOCK: u8 = 52;
+const RLOCK: u8 = TLOCK + 1;
+const TGETLOCK: u8 = 54;
+const RGETLOCK: u8 = TGETLOCK + 1;
+const TLINK: u8 = 70;
+const RLINK: u8 = TLINK + 1;
+const TMKDIR: u8 = 72;
+const RMKDIR: u8 = TMKDIR + 1;
+const TRENAMEAT: u8 = 74;
+const RRENAMEAT: u8 = TRENAMEAT + 1;
+const TUNLINKAT: u8 = 76;
+const RUNLINKAT: u8 = TUNLINKAT + 1;
+const TVERSION: u8 = 100;
+const RVERSION: u8 = TVERSION + 1;
+const TAUTH: u8 = 102;
+const RAUTH: u8 = TAUTH + 1;
+const TATTACH: u8 = 104;
+const RATTACH: u8 = TATTACH + 1;
+const _TERROR: u8 = 106;
+const _RERROR: u8 = _TERROR + 1;
+const TFLUSH: u8 = 108;
+const RFLUSH: u8 = TFLUSH + 1;
+const TWALK: u8 = 110;
+const RWALK: u8 = TWALK + 1;
+const _TOPEN: u8 = 112;
+const _ROPEN: u8 = _TOPEN + 1;
+const _TCREATE: u8 = 114;
+const _RCREATE: u8 = _TCREATE + 1;
+const TREAD: u8 = 116;
+const RREAD: u8 = TREAD + 1;
+const TWRITE: u8 = 118;
+const RWRITE: u8 = TWRITE + 1;
+const TCLUNK: u8 = 120;
+const RCLUNK: u8 = TCLUNK + 1;
+const TREMOVE: u8 = 122;
+const RREMOVE: u8 = TREMOVE + 1;
+const _TSTAT: u8 = 124;
+const _RSTAT: u8 = _TSTAT + 1;
+const _TWSTAT: u8 = 126;
+const _RWSTAT: u8 = _TWSTAT + 1;
+
+/// A message sent from a 9P client to a 9P server.
+#[derive(Debug)]
+pub enum Tmessage {
+    Version(Tversion),
+    Flush(Tflush),
+    Walk(Twalk),
+    Read(Tread),
+    Write(Twrite),
+    Clunk(Tclunk),
+    Remove(Tremove),
+    Attach(Tattach),
+    Auth(Tauth),
+    Statfs(Tstatfs),
+    Lopen(Tlopen),
+    Lcreate(Tlcreate),
+    Symlink(Tsymlink),
+    Mknod(Tmknod),
+    Rename(Trename),
+    Readlink(Treadlink),
+    GetAttr(Tgetattr),
+    SetAttr(Tsetattr),
+    XattrWalk(Txattrwalk),
+    XattrCreate(Txattrcreate),
+    Readdir(Treaddir),
+    Fsync(Tfsync),
+    Lock(Tlock),
+    GetLock(Tgetlock),
+    Link(Tlink),
+    Mkdir(Tmkdir),
+    RenameAt(Trenameat),
+    UnlinkAt(Tunlinkat),
+}
+
+#[derive(Debug)]
+pub struct Tframe {
+    pub tag: u16,
+    pub msg: Tmessage,
+}
+
+impl WireFormat for Tframe {
+    fn byte_size(&self) -> u32 {
+        let msg_size = match &self.msg {
+            Tmessage::Version(version) => version.byte_size(),
+            Tmessage::Flush(flush) => flush.byte_size(),
+            Tmessage::Walk(walk) => walk.byte_size(),
+            Tmessage::Read(read) => read.byte_size(),
+            Tmessage::Write(write) => write.byte_size(),
+            Tmessage::Clunk(clunk) => clunk.byte_size(),
+            Tmessage::Remove(remove) => remove.byte_size(),
+            Tmessage::Attach(attach) => attach.byte_size(),
+            Tmessage::Auth(auth) => auth.byte_size(),
+            Tmessage::Statfs(statfs) => statfs.byte_size(),
+            Tmessage::Lopen(lopen) => lopen.byte_size(),
+            Tmessage::Lcreate(lcreate) => lcreate.byte_size(),
+            Tmessage::Symlink(symlink) => symlink.byte_size(),
+            Tmessage::Mknod(mknod) => mknod.byte_size(),
+            Tmessage::Rename(rename) => rename.byte_size(),
+            Tmessage::Readlink(readlink) => readlink.byte_size(),
+            Tmessage::GetAttr(getattr) => getattr.byte_size(),
+            Tmessage::SetAttr(setattr) => setattr.byte_size(),
+            Tmessage::XattrWalk(xattrwalk) => xattrwalk.byte_size(),
+            Tmessage::XattrCreate(xattrcreate) => xattrcreate.byte_size(),
+            Tmessage::Readdir(readdir) => readdir.byte_size(),
+            Tmessage::Fsync(fsync) => fsync.byte_size(),
+            Tmessage::Lock(lock) => lock.byte_size(),
+            Tmessage::GetLock(getlock) => getlock.byte_size(),
+            Tmessage::Link(link) => link.byte_size(),
+            Tmessage::Mkdir(mkdir) => mkdir.byte_size(),
+            Tmessage::RenameAt(renameat) => renameat.byte_size(),
+            Tmessage::UnlinkAt(unlinkat) => unlinkat.byte_size(),
+        };
+
+        // size + type + tag + message size
+        (mem::size_of::<u32>() + mem::size_of::<u8>() + mem::size_of::<u16>()) as u32 + msg_size
+    }
+
+    fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
+        self.byte_size().encode(writer)?;
+
+        let ty = match self.msg {
+            Tmessage::Version(_) => TVERSION,
+            Tmessage::Flush(_) => TFLUSH,
+            Tmessage::Walk(_) => TWALK,
+            Tmessage::Read(_) => TREAD,
+            Tmessage::Write(_) => TWRITE,
+            Tmessage::Clunk(_) => TCLUNK,
+            Tmessage::Remove(_) => TREMOVE,
+            Tmessage::Attach(_) => TATTACH,
+            Tmessage::Auth(_) => TAUTH,
+            Tmessage::Statfs(_) => TSTATFS,
+            Tmessage::Lopen(_) => TLOPEN,
+            Tmessage::Lcreate(_) => TLCREATE,
+            Tmessage::Symlink(_) => TSYMLINK,
+            Tmessage::Mknod(_) => TMKNOD,
+            Tmessage::Rename(_) => TRENAME,
+            Tmessage::Readlink(_) => TREADLINK,
+            Tmessage::GetAttr(_) => TGETATTR,
+            Tmessage::SetAttr(_) => TSETATTR,
+            Tmessage::XattrWalk(_) => TXATTRWALK,
+            Tmessage::XattrCreate(_) => TXATTRCREATE,
+            Tmessage::Readdir(_) => TREADDIR,
+            Tmessage::Fsync(_) => TFSYNC,
+            Tmessage::Lock(_) => TLOCK,
+            Tmessage::GetLock(_) => TGETLOCK,
+            Tmessage::Link(_) => TLINK,
+            Tmessage::Mkdir(_) => TMKDIR,
+            Tmessage::RenameAt(_) => TRENAMEAT,
+            Tmessage::UnlinkAt(_) => TUNLINKAT,
+        };
+
+        ty.encode(writer)?;
+        self.tag.encode(writer)?;
+
+        match &self.msg {
+            Tmessage::Version(version) => version.encode(writer),
+            Tmessage::Flush(flush) => flush.encode(writer),
+            Tmessage::Walk(walk) => walk.encode(writer),
+            Tmessage::Read(read) => read.encode(writer),
+            Tmessage::Write(write) => write.encode(writer),
+            Tmessage::Clunk(clunk) => clunk.encode(writer),
+            Tmessage::Remove(remove) => remove.encode(writer),
+            Tmessage::Attach(attach) => attach.encode(writer),
+            Tmessage::Auth(auth) => auth.encode(writer),
+            Tmessage::Statfs(statfs) => statfs.encode(writer),
+            Tmessage::Lopen(lopen) => lopen.encode(writer),
+            Tmessage::Lcreate(lcreate) => lcreate.encode(writer),
+            Tmessage::Symlink(symlink) => symlink.encode(writer),
+            Tmessage::Mknod(mknod) => mknod.encode(writer),
+            Tmessage::Rename(rename) => rename.encode(writer),
+            Tmessage::Readlink(readlink) => readlink.encode(writer),
+            Tmessage::GetAttr(getattr) => getattr.encode(writer),
+            Tmessage::SetAttr(setattr) => setattr.encode(writer),
+            Tmessage::XattrWalk(xattrwalk) => xattrwalk.encode(writer),
+            Tmessage::XattrCreate(xattrcreate) => xattrcreate.encode(writer),
+            Tmessage::Readdir(readdir) => readdir.encode(writer),
+            Tmessage::Fsync(fsync) => fsync.encode(writer),
+            Tmessage::Lock(lock) => lock.encode(writer),
+            Tmessage::GetLock(getlock) => getlock.encode(writer),
+            Tmessage::Link(link) => link.encode(writer),
+            Tmessage::Mkdir(mkdir) => mkdir.encode(writer),
+            Tmessage::RenameAt(renameat) => renameat.encode(writer),
+            Tmessage::UnlinkAt(unlinkat) => unlinkat.encode(writer),
+        }
+    }
+
+    fn decode<R: Read>(reader: &mut R) -> io::Result<Self> {
+        let byte_size: u32 = WireFormat::decode(reader)?;
+
+        // byte_size includes the size of byte_size so remove that from the
+        // expected length of the message.  Also make sure that byte_size is at least
+        // that long to begin with.
+        if byte_size < mem::size_of::<u32>() as u32 {
+            return Err(io::Error::new(
+                ErrorKind::InvalidData,
+                format!("byte_size(= {}) is less than 4 bytes", byte_size),
+            ));
+        }
+
+        let reader = &mut reader.take((byte_size - mem::size_of::<u32>() as u32) as u64);
+
+        let mut ty = [0u8];
+        reader.read_exact(&mut ty)?;
+
+        let tag: u16 = WireFormat::decode(reader)?;
+
+        let msg = match ty[0] {
+            TVERSION => Ok(Tmessage::Version(WireFormat::decode(reader)?)),
+            TFLUSH => Ok(Tmessage::Flush(WireFormat::decode(reader)?)),
+            TWALK => Ok(Tmessage::Walk(WireFormat::decode(reader)?)),
+            TREAD => Ok(Tmessage::Read(WireFormat::decode(reader)?)),
+            TWRITE => Ok(Tmessage::Write(WireFormat::decode(reader)?)),
+            TCLUNK => Ok(Tmessage::Clunk(WireFormat::decode(reader)?)),
+            TREMOVE => Ok(Tmessage::Remove(WireFormat::decode(reader)?)),
+            TATTACH => Ok(Tmessage::Attach(WireFormat::decode(reader)?)),
+            TAUTH => Ok(Tmessage::Auth(WireFormat::decode(reader)?)),
+            TSTATFS => Ok(Tmessage::Statfs(WireFormat::decode(reader)?)),
+            TLOPEN => Ok(Tmessage::Lopen(WireFormat::decode(reader)?)),
+            TLCREATE => Ok(Tmessage::Lcreate(WireFormat::decode(reader)?)),
+            TSYMLINK => Ok(Tmessage::Symlink(WireFormat::decode(reader)?)),
+            TMKNOD => Ok(Tmessage::Mknod(WireFormat::decode(reader)?)),
+            TRENAME => Ok(Tmessage::Rename(WireFormat::decode(reader)?)),
+            TREADLINK => Ok(Tmessage::Readlink(WireFormat::decode(reader)?)),
+            TGETATTR => Ok(Tmessage::GetAttr(WireFormat::decode(reader)?)),
+            TSETATTR => Ok(Tmessage::SetAttr(WireFormat::decode(reader)?)),
+            TXATTRWALK => Ok(Tmessage::XattrWalk(WireFormat::decode(reader)?)),
+            TXATTRCREATE => Ok(Tmessage::XattrCreate(WireFormat::decode(reader)?)),
+            TREADDIR => Ok(Tmessage::Readdir(WireFormat::decode(reader)?)),
+            TFSYNC => Ok(Tmessage::Fsync(WireFormat::decode(reader)?)),
+            TLOCK => Ok(Tmessage::Lock(WireFormat::decode(reader)?)),
+            TGETLOCK => Ok(Tmessage::GetLock(WireFormat::decode(reader)?)),
+            TLINK => Ok(Tmessage::Link(WireFormat::decode(reader)?)),
+            TMKDIR => Ok(Tmessage::Mkdir(WireFormat::decode(reader)?)),
+            TRENAMEAT => Ok(Tmessage::RenameAt(WireFormat::decode(reader)?)),
+            TUNLINKAT => Ok(Tmessage::UnlinkAt(WireFormat::decode(reader)?)),
+            err => Err(io::Error::new(
+                ErrorKind::InvalidData,
+                format!("unknown message type {}", err),
+            )),
+        }?;
+
+        Ok(Tframe { tag, msg })
+    }
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tversion {
+    pub msize: u32,
+    pub version: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tflush {
+    pub oldtag: u16,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Twalk {
+    pub fid: u32,
+    pub newfid: u32,
+    pub wnames: Vec<String>,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tread {
+    pub fid: u32,
+    pub offset: u64,
+    pub count: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Twrite {
+    pub fid: u32,
+    pub offset: u64,
+    pub data: Data,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tclunk {
+    pub fid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tremove {
+    pub fid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tauth {
+    pub afid: u32,
+    pub uname: String,
+    pub aname: String,
+    pub n_uname: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tattach {
+    pub fid: u32,
+    pub afid: u32,
+    pub uname: String,
+    pub aname: String,
+    pub n_uname: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tstatfs {
+    pub fid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tlopen {
+    pub fid: u32,
+    pub flags: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tlcreate {
+    pub fid: u32,
+    pub name: String,
+    pub flags: u32,
+    pub mode: u32,
+    pub gid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tsymlink {
+    pub fid: u32,
+    pub name: String,
+    pub symtgt: String,
+    pub gid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tmknod {
+    pub dfid: u32,
+    pub name: String,
+    pub mode: u32,
+    pub major: u32,
+    pub minor: u32,
+    pub gid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Trename {
+    pub fid: u32,
+    pub dfid: u32,
+    pub name: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Treadlink {
+    pub fid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tgetattr {
+    pub fid: u32,
+    pub request_mask: u64,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tsetattr {
+    pub fid: u32,
+    pub valid: u32,
+    pub mode: u32,
+    pub uid: u32,
+    pub gid: u32,
+    pub size: u64,
+    pub atime_sec: u64,
+    pub atime_nsec: u64,
+    pub mtime_sec: u64,
+    pub mtime_nsec: u64,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Txattrwalk {
+    pub fid: u32,
+    pub newfid: u32,
+    pub name: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Txattrcreate {
+    pub fid: u32,
+    pub name: String,
+    pub attr_size: u64,
+    pub flags: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Treaddir {
+    pub fid: u32,
+    pub offset: u64,
+    pub count: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tfsync {
+    pub fid: u32,
+    pub datasync: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tlock {
+    pub fid: u32,
+    pub type_: u8,
+    pub flags: u32,
+    pub start: u64,
+    pub length: u64,
+    pub proc_id: u32,
+    pub client_id: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tgetlock {
+    pub fid: u32,
+    pub type_: u8,
+    pub start: u64,
+    pub length: u64,
+    pub proc_id: u32,
+    pub client_id: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tlink {
+    pub dfid: u32,
+    pub fid: u32,
+    pub name: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tmkdir {
+    pub dfid: u32,
+    pub name: String,
+    pub mode: u32,
+    pub gid: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Trenameat {
+    pub olddirfid: u32,
+    pub oldname: String,
+    pub newdirfid: u32,
+    pub newname: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Tunlinkat {
+    pub dirfd: u32,
+    pub name: String,
+    pub flags: u32,
+}
+
+/// A message sent from a 9P server to a 9P client in response to a request from
+/// that client.  Encapsulates a full frame.
+#[derive(Debug)]
+pub enum Rmessage {
+    Version(Rversion),
+    Flush,
+    Walk(Rwalk),
+    Read(Rread),
+    Write(Rwrite),
+    Clunk,
+    Remove,
+    Attach(Rattach),
+    Auth(Rauth),
+    Statfs(Rstatfs),
+    Lopen(Rlopen),
+    Lcreate(Rlcreate),
+    Symlink(Rsymlink),
+    Mknod(Rmknod),
+    Rename,
+    Readlink(Rreadlink),
+    GetAttr(Rgetattr),
+    SetAttr,
+    XattrWalk(Rxattrwalk),
+    XattrCreate,
+    Readdir(Rreaddir),
+    Fsync,
+    Lock(Rlock),
+    GetLock(Rgetlock),
+    Link,
+    Mkdir(Rmkdir),
+    RenameAt,
+    UnlinkAt,
+    Lerror(Rlerror),
+}
+
+#[derive(Debug)]
+pub struct Rframe {
+    pub tag: u16,
+    pub msg: Rmessage,
+}
+
+impl WireFormat for Rframe {
+    fn byte_size(&self) -> u32 {
+        let msg_size = match &self.msg {
+            Rmessage::Version(version) => version.byte_size(),
+            Rmessage::Flush => 0,
+            Rmessage::Walk(walk) => walk.byte_size(),
+            Rmessage::Read(read) => read.byte_size(),
+            Rmessage::Write(write) => write.byte_size(),
+            Rmessage::Clunk => 0,
+            Rmessage::Remove => 0,
+            Rmessage::Attach(attach) => attach.byte_size(),
+            Rmessage::Auth(auth) => auth.byte_size(),
+            Rmessage::Statfs(statfs) => statfs.byte_size(),
+            Rmessage::Lopen(lopen) => lopen.byte_size(),
+            Rmessage::Lcreate(lcreate) => lcreate.byte_size(),
+            Rmessage::Symlink(symlink) => symlink.byte_size(),
+            Rmessage::Mknod(mknod) => mknod.byte_size(),
+            Rmessage::Rename => 0,
+            Rmessage::Readlink(readlink) => readlink.byte_size(),
+            Rmessage::GetAttr(getattr) => getattr.byte_size(),
+            Rmessage::SetAttr => 0,
+            Rmessage::XattrWalk(xattrwalk) => xattrwalk.byte_size(),
+            Rmessage::XattrCreate => 0,
+            Rmessage::Readdir(readdir) => readdir.byte_size(),
+            Rmessage::Fsync => 0,
+            Rmessage::Lock(lock) => lock.byte_size(),
+            Rmessage::GetLock(getlock) => getlock.byte_size(),
+            Rmessage::Link => 0,
+            Rmessage::Mkdir(mkdir) => mkdir.byte_size(),
+            Rmessage::RenameAt => 0,
+            Rmessage::UnlinkAt => 0,
+            Rmessage::Lerror(lerror) => lerror.byte_size(),
+        };
+
+        // size + type + tag + message size
+        (mem::size_of::<u32>() + mem::size_of::<u8>() + mem::size_of::<u16>()) as u32 + msg_size
+    }
+
+    fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
+        self.byte_size().encode(writer)?;
+
+        let ty = match self.msg {
+            Rmessage::Version(_) => RVERSION,
+            Rmessage::Flush => RFLUSH,
+            Rmessage::Walk(_) => RWALK,
+            Rmessage::Read(_) => RREAD,
+            Rmessage::Write(_) => RWRITE,
+            Rmessage::Clunk => RCLUNK,
+            Rmessage::Remove => RREMOVE,
+            Rmessage::Attach(_) => RATTACH,
+            Rmessage::Auth(_) => RAUTH,
+            Rmessage::Statfs(_) => RSTATFS,
+            Rmessage::Lopen(_) => RLOPEN,
+            Rmessage::Lcreate(_) => RLCREATE,
+            Rmessage::Symlink(_) => RSYMLINK,
+            Rmessage::Mknod(_) => RMKNOD,
+            Rmessage::Rename => RRENAME,
+            Rmessage::Readlink(_) => RREADLINK,
+            Rmessage::GetAttr(_) => RGETATTR,
+            Rmessage::SetAttr => RSETATTR,
+            Rmessage::XattrWalk(_) => RXATTRWALK,
+            Rmessage::XattrCreate => RXATTRCREATE,
+            Rmessage::Readdir(_) => RREADDIR,
+            Rmessage::Fsync => RFSYNC,
+            Rmessage::Lock(_) => RLOCK,
+            Rmessage::GetLock(_) => RGETLOCK,
+            Rmessage::Link => RLINK,
+            Rmessage::Mkdir(_) => RMKDIR,
+            Rmessage::RenameAt => RRENAMEAT,
+            Rmessage::UnlinkAt => RUNLINKAT,
+            Rmessage::Lerror(_) => RLERROR,
+        };
+
+        ty.encode(writer)?;
+        self.tag.encode(writer)?;
+
+        match &self.msg {
+            Rmessage::Version(version) => version.encode(writer),
+            Rmessage::Flush => Ok(()),
+            Rmessage::Walk(walk) => walk.encode(writer),
+            Rmessage::Read(read) => read.encode(writer),
+            Rmessage::Write(write) => write.encode(writer),
+            Rmessage::Clunk => Ok(()),
+            Rmessage::Remove => Ok(()),
+            Rmessage::Attach(attach) => attach.encode(writer),
+            Rmessage::Auth(auth) => auth.encode(writer),
+            Rmessage::Statfs(statfs) => statfs.encode(writer),
+            Rmessage::Lopen(lopen) => lopen.encode(writer),
+            Rmessage::Lcreate(lcreate) => lcreate.encode(writer),
+            Rmessage::Symlink(symlink) => symlink.encode(writer),
+            Rmessage::Mknod(mknod) => mknod.encode(writer),
+            Rmessage::Rename => Ok(()),
+            Rmessage::Readlink(readlink) => readlink.encode(writer),
+            Rmessage::GetAttr(getattr) => getattr.encode(writer),
+            Rmessage::SetAttr => Ok(()),
+            Rmessage::XattrWalk(xattrwalk) => xattrwalk.encode(writer),
+            Rmessage::XattrCreate => Ok(()),
+            Rmessage::Readdir(readdir) => readdir.encode(writer),
+            Rmessage::Fsync => Ok(()),
+            Rmessage::Lock(lock) => lock.encode(writer),
+            Rmessage::GetLock(getlock) => getlock.encode(writer),
+            Rmessage::Link => Ok(()),
+            Rmessage::Mkdir(mkdir) => mkdir.encode(writer),
+            Rmessage::RenameAt => Ok(()),
+            Rmessage::UnlinkAt => Ok(()),
+            Rmessage::Lerror(lerror) => lerror.encode(writer),
+        }
+    }
+
+    fn decode<R: Read>(reader: &mut R) -> io::Result<Self> {
+        let byte_size: u32 = WireFormat::decode(reader)?;
+
+        // byte_size includes the size of byte_size so remove that from the
+        // expected length of the message.
+        let reader = &mut reader.take((byte_size - mem::size_of::<u32>() as u32) as u64);
+
+        let mut ty = [0u8];
+        reader.read_exact(&mut ty)?;
+
+        let tag: u16 = WireFormat::decode(reader)?;
+
+        let msg = match ty[0] {
+            RVERSION => Ok(Rmessage::Version(WireFormat::decode(reader)?)),
+            RFLUSH => Ok(Rmessage::Flush),
+            RWALK => Ok(Rmessage::Walk(WireFormat::decode(reader)?)),
+            RREAD => Ok(Rmessage::Read(WireFormat::decode(reader)?)),
+            RWRITE => Ok(Rmessage::Write(WireFormat::decode(reader)?)),
+            RCLUNK => Ok(Rmessage::Clunk),
+            RREMOVE => Ok(Rmessage::Remove),
+            RATTACH => Ok(Rmessage::Attach(WireFormat::decode(reader)?)),
+            RAUTH => Ok(Rmessage::Auth(WireFormat::decode(reader)?)),
+            RSTATFS => Ok(Rmessage::Statfs(WireFormat::decode(reader)?)),
+            RLOPEN => Ok(Rmessage::Lopen(WireFormat::decode(reader)?)),
+            RLCREATE => Ok(Rmessage::Lcreate(WireFormat::decode(reader)?)),
+            RSYMLINK => Ok(Rmessage::Symlink(WireFormat::decode(reader)?)),
+            RMKNOD => Ok(Rmessage::Mknod(WireFormat::decode(reader)?)),
+            RRENAME => Ok(Rmessage::Rename),
+            RREADLINK => Ok(Rmessage::Readlink(WireFormat::decode(reader)?)),
+            RGETATTR => Ok(Rmessage::GetAttr(WireFormat::decode(reader)?)),
+            RSETATTR => Ok(Rmessage::SetAttr),
+            RXATTRWALK => Ok(Rmessage::XattrWalk(WireFormat::decode(reader)?)),
+            RXATTRCREATE => Ok(Rmessage::XattrCreate),
+            RREADDIR => Ok(Rmessage::Readdir(WireFormat::decode(reader)?)),
+            RFSYNC => Ok(Rmessage::Fsync),
+            RLOCK => Ok(Rmessage::Lock(WireFormat::decode(reader)?)),
+            RGETLOCK => Ok(Rmessage::GetLock(WireFormat::decode(reader)?)),
+            RLINK => Ok(Rmessage::Link),
+            RMKDIR => Ok(Rmessage::Mkdir(WireFormat::decode(reader)?)),
+            RRENAMEAT => Ok(Rmessage::RenameAt),
+            RUNLINKAT => Ok(Rmessage::UnlinkAt),
+            RLERROR => Ok(Rmessage::Lerror(WireFormat::decode(reader)?)),
+            err => Err(io::Error::new(
+                ErrorKind::InvalidData,
+                format!("unknown message type {}", err),
+            )),
+        }?;
+
+        Ok(Rframe { tag, msg })
+    }
+}
+
+#[derive(Debug, Copy, Clone, P9WireFormat)]
+pub struct Qid {
+    pub ty: u8,
+    pub version: u32,
+    pub path: u64,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Dirent {
+    pub qid: Qid,
+    pub offset: u64,
+    pub ty: u8,
+    pub name: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rversion {
+    pub msize: u32,
+    pub version: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rwalk {
+    pub wqids: Vec<Qid>,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rread {
+    pub data: Data,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rwrite {
+    pub count: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rauth {
+    pub aqid: Qid,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rattach {
+    pub qid: Qid,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rlerror {
+    pub ecode: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rstatfs {
+    pub ty: u32,
+    pub bsize: u32,
+    pub blocks: u64,
+    pub bfree: u64,
+    pub bavail: u64,
+    pub files: u64,
+    pub ffree: u64,
+    pub fsid: u64,
+    pub namelen: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rlopen {
+    pub qid: Qid,
+    pub iounit: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rlcreate {
+    pub qid: Qid,
+    pub iounit: u32,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rsymlink {
+    pub qid: Qid,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rmknod {
+    pub qid: Qid,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rreadlink {
+    pub target: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rgetattr {
+    pub valid: u64,
+    pub qid: Qid,
+    pub mode: u32,
+    pub uid: u32,
+    pub gid: u32,
+    pub nlink: u64,
+    pub rdev: u64,
+    pub size: u64,
+    pub blksize: u64,
+    pub blocks: u64,
+    pub atime_sec: u64,
+    pub atime_nsec: u64,
+    pub mtime_sec: u64,
+    pub mtime_nsec: u64,
+    pub ctime_sec: u64,
+    pub ctime_nsec: u64,
+    pub btime_sec: u64,
+    pub btime_nsec: u64,
+    pub gen: u64,
+    pub data_version: u64,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rxattrwalk {
+    pub size: u64,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rreaddir {
+    pub data: Data,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rlock {
+    pub status: u8,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rgetlock {
+    pub ty: u8,
+    pub start: u64,
+    pub length: u64,
+    pub proc_id: u32,
+    pub client_id: String,
+}
+
+#[derive(Debug, P9WireFormat)]
+pub struct Rmkdir {
+    pub qid: Qid,
+}
diff --git a/p9/src/protocol/mod.rs b/p9/src/protocol/mod.rs
new file mode 100644
index 0000000..9c278ee
--- /dev/null
+++ b/p9/src/protocol/mod.rs
@@ -0,0 +1,9 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+mod messages;
+mod wire_format;
+
+pub use self::messages::*;
+pub use self::wire_format::{Data, WireFormat};
diff --git a/p9/src/protocol/wire_format.rs b/p9/src/protocol/wire_format.rs
new file mode 100644
index 0000000..84408e2
--- /dev/null
+++ b/p9/src/protocol/wire_format.rs
@@ -0,0 +1,716 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std;
+use std::fmt;
+use std::io;
+use std::io::{ErrorKind, Read, Write};
+use std::mem;
+use std::ops::{Deref, DerefMut};
+use std::string::String;
+use std::vec::Vec;
+
+/// A type that can be encoded on the wire using the 9P protocol.
+pub trait WireFormat: std::marker::Sized {
+    /// Returns the number of bytes necessary to fully encode `self`.
+    fn byte_size(&self) -> u32;
+
+    /// Encodes `self` into `writer`.
+    fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()>;
+
+    /// Decodes `Self` from `reader`.
+    fn decode<R: Read>(reader: &mut R) -> io::Result<Self>;
+}
+
+// This doesn't really _need_ to be a macro but unfortunately there is no trait bound to
+// express "can be casted to another type", which means we can't write `T as u8` in a trait
+// based implementation.  So instead we have this macro, which is implemented for all the
+// stable unsigned types with the added benefit of not being implemented for the signed
+// types which are not allowed by the protocol.
+macro_rules! uint_wire_format_impl {
+    ($Ty:ty) => {
+        impl WireFormat for $Ty {
+            fn byte_size(&self) -> u32 {
+                mem::size_of::<$Ty>() as u32
+            }
+
+            fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
+                let mut buf = [0u8; mem::size_of::<$Ty>()];
+
+                // Encode the bytes into the buffer in little endian order.
+                for idx in 0..mem::size_of::<$Ty>() {
+                    buf[idx] = (self >> (8 * idx)) as u8;
+                }
+
+                writer.write_all(&buf)
+            }
+
+            fn decode<R: Read>(reader: &mut R) -> io::Result<Self> {
+                let mut buf = [0u8; mem::size_of::<$Ty>()];
+                reader.read_exact(&mut buf)?;
+
+                // Read bytes from the buffer in little endian order.
+                let mut result = 0;
+                for idx in 0..mem::size_of::<$Ty>() {
+                    result |= (buf[idx] as $Ty) << (8 * idx);
+                }
+
+                Ok(result)
+            }
+        }
+    };
+}
+uint_wire_format_impl!(u8);
+uint_wire_format_impl!(u16);
+uint_wire_format_impl!(u32);
+uint_wire_format_impl!(u64);
+
+// The 9P protocol requires that strings are UTF-8 encoded.  The wire format is a u16
+// count |N|, encoded in little endian, followed by |N| bytes of UTF-8 data.
+impl WireFormat for String {
+    fn byte_size(&self) -> u32 {
+        (mem::size_of::<u16>() + self.len()) as u32
+    }
+
+    fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
+        if self.len() > std::u16::MAX as usize {
+            return Err(io::Error::new(
+                ErrorKind::InvalidInput,
+                "string is too long",
+            ));
+        }
+
+        (self.len() as u16).encode(writer)?;
+        writer.write_all(self.as_bytes())
+    }
+
+    fn decode<R: Read>(reader: &mut R) -> io::Result<Self> {
+        let len: u16 = WireFormat::decode(reader)?;
+        let mut result = String::with_capacity(len as usize);
+        reader.take(len as u64).read_to_string(&mut result)?;
+        Ok(result)
+    }
+}
+
+// The wire format for repeated types is similar to that of strings: a little endian
+// encoded u16 |N|, followed by |N| instances of the given type.
+impl<T: WireFormat> WireFormat for Vec<T> {
+    fn byte_size(&self) -> u32 {
+        mem::size_of::<u16>() as u32 + self.iter().map(|elem| elem.byte_size()).sum::<u32>()
+    }
+
+    fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
+        if self.len() > std::u16::MAX as usize {
+            return Err(io::Error::new(
+                ErrorKind::InvalidInput,
+                "too many elements in vector",
+            ));
+        }
+
+        (self.len() as u16).encode(writer)?;
+        for elem in self {
+            elem.encode(writer)?;
+        }
+
+        Ok(())
+    }
+
+    fn decode<R: Read>(reader: &mut R) -> io::Result<Self> {
+        let len: u16 = WireFormat::decode(reader)?;
+        let mut result = Vec::with_capacity(len as usize);
+
+        for _ in 0..len {
+            result.push(WireFormat::decode(reader)?);
+        }
+
+        Ok(result)
+    }
+}
+
+/// A type that encodes an arbitrary number of bytes of data.  Typically used for Rread
+/// Twrite messages.  This differs from a `Vec<u8>` in that it encodes the number of bytes
+/// using a `u32` instead of a `u16`.
+#[derive(PartialEq)]
+pub struct Data(pub Vec<u8>);
+
+// The maximum length of a data buffer that we support.  In practice the server's max message
+// size should prevent us from reading too much data so this check is mainly to ensure a
+// malicious client cannot trick us into allocating massive amounts of memory.
+const MAX_DATA_LENGTH: u32 = 32 * 1024 * 1024;
+
+impl fmt::Debug for Data {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // There may be a lot of data and we don't want to spew it all out in a trace.  Instead
+        // just print out the number of bytes in the buffer.
+        write!(f, "Data({} bytes)", self.len())
+    }
+}
+
+// Implement Deref and DerefMut so that we don't have to use self.0 everywhere.
+impl Deref for Data {
+    type Target = Vec<u8>;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl DerefMut for Data {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+// Same as Vec<u8> except that it encodes the length as a u32 instead of a u16.
+impl WireFormat for Data {
+    fn byte_size(&self) -> u32 {
+        mem::size_of::<u32>() as u32 + self.iter().map(|elem| elem.byte_size()).sum::<u32>()
+    }
+
+    fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
+        if self.len() > std::u32::MAX as usize {
+            return Err(io::Error::new(ErrorKind::InvalidInput, "data is too large"));
+        }
+        (self.len() as u32).encode(writer)?;
+        writer.write_all(self)
+    }
+
+    fn decode<R: Read>(reader: &mut R) -> io::Result<Self> {
+        let len: u32 = WireFormat::decode(reader)?;
+        if len > MAX_DATA_LENGTH {
+            return Err(io::Error::new(
+                ErrorKind::InvalidData,
+                format!("data length ({} bytes) is too large", len),
+            ));
+        }
+
+        let mut buf = Vec::with_capacity(len as usize);
+        reader.take(len as u64).read_to_end(&mut buf)?;
+
+        if buf.len() == len as usize {
+            Ok(Data(buf))
+        } else {
+            Err(io::Error::new(
+                ErrorKind::UnexpectedEof,
+                format!(
+                    "unexpected end of data: want: {} bytes, got: {} bytes",
+                    len,
+                    buf.len()
+                ),
+            ))
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::io::Cursor;
+    use std::mem;
+    use std::string::String;
+    use wire_format_derive::P9WireFormat;
+
+    #[test]
+    fn integer_byte_size() {
+        assert_eq!(1, 0u8.byte_size());
+        assert_eq!(2, 0u16.byte_size());
+        assert_eq!(4, 0u32.byte_size());
+        assert_eq!(8, 0u64.byte_size());
+    }
+
+    #[test]
+    fn integer_decode() {
+        let buf: [u8; 8] = [0xef, 0xbe, 0xad, 0xde, 0x0d, 0xf0, 0xad, 0x8b];
+
+        assert_eq!(
+            0xef as u8,
+            WireFormat::decode(&mut Cursor::new(&buf)).unwrap()
+        );
+        assert_eq!(
+            0xbeef as u16,
+            WireFormat::decode(&mut Cursor::new(&buf)).unwrap()
+        );
+        assert_eq!(
+            0xdeadbeef as u32,
+            WireFormat::decode(&mut Cursor::new(&buf)).unwrap()
+        );
+        assert_eq!(
+            0x8badf00d_deadbeef as u64,
+            WireFormat::decode(&mut Cursor::new(&buf)).unwrap()
+        );
+    }
+
+    #[test]
+    fn integer_encode() {
+        let value: u64 = 0x8badf00d_deadbeef;
+        let expected: [u8; 8] = [0xef, 0xbe, 0xad, 0xde, 0x0d, 0xf0, 0xad, 0x8b];
+
+        let mut buf = Vec::with_capacity(8);
+        buf.resize(8, 0);
+
+        (value as u8).encode(&mut Cursor::new(&mut *buf)).unwrap();
+        assert_eq!(expected[0..1], buf[0..1]);
+
+        (value as u16).encode(&mut Cursor::new(&mut *buf)).unwrap();
+        assert_eq!(expected[0..2], buf[0..2]);
+
+        (value as u32).encode(&mut Cursor::new(&mut *buf)).unwrap();
+        assert_eq!(expected[0..4], buf[0..4]);
+
+        value.encode(&mut Cursor::new(&mut *buf)).unwrap();
+        assert_eq!(expected[0..8], buf[0..8]);
+    }
+
+    #[test]
+    fn string_byte_size() {
+        let values = [
+            String::from("Google Video"),
+            String::from("网页 图片 资讯更多 »"),
+            String::from("Παγκόσμιος Ιστός"),
+            String::from("Поиск страниц на русском"),
+            String::from("전체서비스"),
+        ];
+
+        let exp = values
+            .iter()
+            .map(|v| (mem::size_of::<u16>() + v.len()) as u32);
+
+        for (value, expected) in values.iter().zip(exp) {
+            assert_eq!(expected, value.byte_size());
+        }
+    }
+
+    #[test]
+    fn zero_length_string() {
+        let s = String::from("");
+        assert_eq!(s.byte_size(), mem::size_of::<u16>() as u32);
+
+        let mut buf = [0xffu8; 4];
+
+        s.encode(&mut Cursor::new(&mut buf[..]))
+            .expect("failed to encode empty string");
+        assert_eq!(&[0, 0, 0xff, 0xff], &buf);
+
+        assert_eq!(
+            s,
+            <String as WireFormat>::decode(&mut Cursor::new(&[0, 0, 0x61, 0x61][..]))
+                .expect("failed to decode empty string")
+        );
+    }
+
+    #[test]
+    fn string_encode() {
+        let values = [
+            String::from("Google Video"),
+            String::from("网页 图片 资讯更多 »"),
+            String::from("Παγκόσμιος Ιστός"),
+            String::from("Поиск страниц на русском"),
+            String::from("전체서비스"),
+        ];
+
+        let expected = values.iter().map(|v| {
+            let len = v.as_bytes().len();
+            let mut buf = Vec::with_capacity(len + mem::size_of::<u16>());
+
+            buf.push(len as u8);
+            buf.push((len >> 8) as u8);
+
+            buf.extend_from_slice(v.as_bytes());
+
+            buf
+        });
+
+        for (val, exp) in values.iter().zip(expected) {
+            let mut buf = Vec::with_capacity(exp.len());
+            buf.resize(exp.len(), 0);
+
+            WireFormat::encode(val, &mut Cursor::new(&mut *buf)).unwrap();
+            assert_eq!(exp, buf);
+        }
+    }
+
+    #[test]
+    fn string_decode() {
+        assert_eq!(
+            String::from("Google Video"),
+            <String as WireFormat>::decode(&mut Cursor::new(
+                &[
+                    0x0c, 0x00, 0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x20, 0x56, 0x69, 0x64, 0x65,
+                    0x6F,
+                ][..]
+            ))
+            .unwrap()
+        );
+        assert_eq!(
+            String::from("网页 图片 资讯更多 »"),
+            <String as WireFormat>::decode(&mut Cursor::new(
+                &[
+                    0x1d, 0x00, 0xE7, 0xBD, 0x91, 0xE9, 0xA1, 0xB5, 0x20, 0xE5, 0x9B, 0xBE, 0xE7,
+                    0x89, 0x87, 0x20, 0xE8, 0xB5, 0x84, 0xE8, 0xAE, 0xAF, 0xE6, 0x9B, 0xB4, 0xE5,
+                    0xA4, 0x9A, 0x20, 0xC2, 0xBB,
+                ][..]
+            ))
+            .unwrap()
+        );
+        assert_eq!(
+            String::from("Παγκόσμιος Ιστός"),
+            <String as WireFormat>::decode(&mut Cursor::new(
+                &[
+                    0x1f, 0x00, 0xCE, 0xA0, 0xCE, 0xB1, 0xCE, 0xB3, 0xCE, 0xBA, 0xCF, 0x8C, 0xCF,
+                    0x83, 0xCE, 0xBC, 0xCE, 0xB9, 0xCE, 0xBF, 0xCF, 0x82, 0x20, 0xCE, 0x99, 0xCF,
+                    0x83, 0xCF, 0x84, 0xCF, 0x8C, 0xCF, 0x82,
+                ][..]
+            ))
+            .unwrap()
+        );
+        assert_eq!(
+            String::from("Поиск страниц на русском"),
+            <String as WireFormat>::decode(&mut Cursor::new(
+                &[
+                    0x2d, 0x00, 0xD0, 0x9F, 0xD0, 0xBE, 0xD0, 0xB8, 0xD1, 0x81, 0xD0, 0xBA, 0x20,
+                    0xD1, 0x81, 0xD1, 0x82, 0xD1, 0x80, 0xD0, 0xB0, 0xD0, 0xBD, 0xD0, 0xB8, 0xD1,
+                    0x86, 0x20, 0xD0, 0xBD, 0xD0, 0xB0, 0x20, 0xD1, 0x80, 0xD1, 0x83, 0xD1, 0x81,
+                    0xD1, 0x81, 0xD0, 0xBA, 0xD0, 0xBE, 0xD0, 0xBC,
+                ][..]
+            ))
+            .unwrap()
+        );
+        assert_eq!(
+            String::from("전체서비스"),
+            <String as WireFormat>::decode(&mut Cursor::new(
+                &[
+                    0x0f, 0x00, 0xEC, 0xA0, 0x84, 0xEC, 0xB2, 0xB4, 0xEC, 0x84, 0x9C, 0xEB, 0xB9,
+                    0x84, 0xEC, 0x8A, 0xA4,
+                ][..]
+            ))
+            .unwrap()
+        );
+    }
+
+    #[test]
+    fn invalid_string_decode() {
+        let _ = <String as WireFormat>::decode(&mut Cursor::new(&[
+            0x06, 0x00, 0xed, 0xa0, 0x80, 0xed, 0xbf, 0xbf,
+        ]))
+        .expect_err("surrogate code point");
+
+        let _ = <String as WireFormat>::decode(&mut Cursor::new(&[
+            0x05, 0x00, 0xf8, 0x80, 0x80, 0x80, 0xbf,
+        ]))
+        .expect_err("overlong sequence");
+
+        let _ =
+            <String as WireFormat>::decode(&mut Cursor::new(&[0x04, 0x00, 0xf4, 0x90, 0x80, 0x80]))
+                .expect_err("out of range");
+
+        let _ =
+            <String as WireFormat>::decode(&mut Cursor::new(&[0x04, 0x00, 0x63, 0x61, 0x66, 0xe9]))
+                .expect_err("ISO-8859-1");
+
+        let _ =
+            <String as WireFormat>::decode(&mut Cursor::new(&[0x04, 0x00, 0xb0, 0xa1, 0xb0, 0xa2]))
+                .expect_err("EUC-KR");
+    }
+
+    #[test]
+    fn vector_encode() {
+        let values: Vec<u32> = vec![291, 18_916, 2_497, 22, 797_162, 2_119_732, 3_213_929_716];
+        let mut expected: Vec<u8> =
+            Vec::with_capacity(values.len() * mem::size_of::<u32>() + mem::size_of::<u16>());
+        expected.push(values.len() as u8);
+        expected.push((values.len() >> 8) as u8);
+
+        const MASK: u32 = 0xff;
+        for val in &values {
+            expected.push((val & MASK) as u8);
+            expected.push(((val >> 8) & MASK) as u8);
+            expected.push(((val >> 16) & MASK) as u8);
+            expected.push(((val >> 24) & MASK) as u8);
+        }
+
+        let mut actual: Vec<u8> = Vec::with_capacity(expected.len());
+        actual.resize(expected.len(), 0);
+
+        WireFormat::encode(&values, &mut Cursor::new(&mut *actual))
+            .expect("failed to encode vector");
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn vector_decode() {
+        let expected: Vec<u32> = vec![
+            2_498,
+            24,
+            897,
+            4_097_789_579,
+            8_498_119,
+            684_279,
+            961_189_198,
+            7,
+        ];
+        let mut input: Vec<u8> =
+            Vec::with_capacity(expected.len() * mem::size_of::<u32>() + mem::size_of::<u16>());
+        input.push(expected.len() as u8);
+        input.push((expected.len() >> 8) as u8);
+
+        const MASK: u32 = 0xff;
+        for val in &expected {
+            input.push((val & MASK) as u8);
+            input.push(((val >> 8) & MASK) as u8);
+            input.push(((val >> 16) & MASK) as u8);
+            input.push(((val >> 24) & MASK) as u8);
+        }
+
+        assert_eq!(
+            expected,
+            <Vec<u32> as WireFormat>::decode(&mut Cursor::new(&*input))
+                .expect("failed to decode vector")
+        );
+    }
+
+    #[test]
+    fn data_encode() {
+        let values = Data(vec![169, 155, 79, 67, 182, 199, 25, 73, 129, 200]);
+        let mut expected: Vec<u8> =
+            Vec::with_capacity(values.len() * mem::size_of::<u8>() + mem::size_of::<u32>());
+        expected.push(values.len() as u8);
+        expected.push((values.len() >> 8) as u8);
+        expected.push((values.len() >> 16) as u8);
+        expected.push((values.len() >> 24) as u8);
+        expected.extend_from_slice(&values);
+
+        let mut actual: Vec<u8> = Vec::with_capacity(expected.len());
+        actual.resize(expected.len(), 0);
+
+        WireFormat::encode(&values, &mut Cursor::new(&mut *actual))
+            .expect("failed to encode datar");
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn data_decode() {
+        let expected = Data(vec![219, 15, 8, 155, 194, 129, 79, 91, 46, 53, 173]);
+        let mut input: Vec<u8> =
+            Vec::with_capacity(expected.len() * mem::size_of::<u8>() + mem::size_of::<u32>());
+        input.push(expected.len() as u8);
+        input.push((expected.len() >> 8) as u8);
+        input.push((expected.len() >> 16) as u8);
+        input.push((expected.len() >> 24) as u8);
+        input.extend_from_slice(&expected);
+
+        assert_eq!(
+            expected,
+            <Data as WireFormat>::decode(&mut Cursor::new(&mut *input))
+                .expect("failed to decode data")
+        );
+    }
+
+    #[test]
+    fn error_cases() {
+        // string is too long.
+        let mut foo = String::with_capacity(std::u16::MAX as usize);
+        while foo.len() < std::u16::MAX as usize {
+            foo.push_str("long");
+        }
+        foo.push_str("!");
+
+        let count = foo.len() + mem::size_of::<u16>();
+        let mut buf = Vec::with_capacity(count);
+        buf.resize(count, 0);
+
+        foo.encode(&mut Cursor::new(&mut *buf))
+            .expect_err("long string");
+
+        // vector is too long.
+        let mut bar: Vec<u32> = Vec::with_capacity(std::u16::MAX as usize);
+        while bar.len() < std::u16::MAX as usize {
+            bar.push(0x8bad_f00d);
+        }
+        bar.push(0x00ba_b10c);
+
+        let count = bar.len() * mem::size_of::<u32>();
+        let mut buf = Vec::with_capacity(count);
+        buf.resize(count, 0);
+
+        WireFormat::encode(&bar, &mut Cursor::new(&mut *buf)).expect_err("long vector");
+    }
+
+    #[derive(Debug, PartialEq, P9WireFormat)]
+    struct Item {
+        foo: u64,
+        bar: String,
+        baz: Vec<u16>,
+        buf: Data,
+    }
+
+    #[test]
+    fn struct_encode() {
+        let item = Item {
+            foo: 0xdead10cc_00bab10c,
+            bar: String::from("冻住,不许走!"),
+            baz: vec![359, 492, 8891],
+            buf: Data(vec![254, 129, 0, 62, 49, 172]),
+        };
+
+        let mut expected: Vec<u8> = vec![0x0c, 0xb1, 0xba, 0x00, 0xcc, 0x10, 0xad, 0xde];
+        let strlen = item.bar.len() as u16;
+        expected.push(strlen as u8);
+        expected.push((strlen >> 8) as u8);
+        expected.extend_from_slice(item.bar.as_bytes());
+
+        let veclen = item.baz.len() as u16;
+        expected.push(veclen as u8);
+        expected.push((veclen >> 8) as u8);
+        for val in &item.baz {
+            expected.push(*val as u8);
+            expected.push((val >> 8) as u8);
+        }
+
+        let buflen = item.buf.len() as u32;
+        expected.push(buflen as u8);
+        expected.push((buflen >> 8) as u8);
+        expected.push((buflen >> 16) as u8);
+        expected.push((buflen >> 24) as u8);
+        expected.extend_from_slice(&item.buf);
+
+        let mut actual = Vec::with_capacity(expected.len());
+        actual.resize(expected.len(), 0);
+
+        WireFormat::encode(&item, &mut Cursor::new(&mut *actual)).expect("failed to encode item");
+
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn struct_decode() {
+        let expected = Item {
+            foo: 0xface_b00c_0404_4b1d,
+            bar: String::from("Огонь по готовности!"),
+            baz: vec![20067, 32449, 549, 4972, 77, 1987],
+            buf: Data(vec![126, 236, 79, 59, 6, 159]),
+        };
+
+        let mut input: Vec<u8> = vec![0x1d, 0x4b, 0x04, 0x04, 0x0c, 0xb0, 0xce, 0xfa];
+        let strlen = expected.bar.len() as u16;
+        input.push(strlen as u8);
+        input.push((strlen >> 8) as u8);
+        input.extend_from_slice(expected.bar.as_bytes());
+
+        let veclen = expected.baz.len() as u16;
+        input.push(veclen as u8);
+        input.push((veclen >> 8) as u8);
+        for val in &expected.baz {
+            input.push(*val as u8);
+            input.push((val >> 8) as u8);
+        }
+
+        let buflen = expected.buf.len() as u32;
+        input.push(buflen as u8);
+        input.push((buflen >> 8) as u8);
+        input.push((buflen >> 16) as u8);
+        input.push((buflen >> 24) as u8);
+        input.extend_from_slice(&expected.buf);
+
+        let actual: Item =
+            WireFormat::decode(&mut Cursor::new(input)).expect("failed to decode item");
+
+        assert_eq!(expected, actual);
+    }
+
+    #[derive(Debug, PartialEq, P9WireFormat)]
+    struct Nested {
+        item: Item,
+        val: Vec<u64>,
+    }
+
+    fn build_encoded_buffer(value: &Nested) -> Vec<u8> {
+        let mut result: Vec<u8> = Vec::new();
+
+        // encode foo
+        result.push(value.item.foo as u8);
+        result.push((value.item.foo >> 8) as u8);
+        result.push((value.item.foo >> 16) as u8);
+        result.push((value.item.foo >> 24) as u8);
+        result.push((value.item.foo >> 32) as u8);
+        result.push((value.item.foo >> 40) as u8);
+        result.push((value.item.foo >> 48) as u8);
+        result.push((value.item.foo >> 56) as u8);
+
+        // encode bar
+        result.push(value.item.bar.len() as u8);
+        result.push((value.item.bar.len() >> 8) as u8);
+        result.extend_from_slice(value.item.bar.as_bytes());
+
+        // encode baz
+        result.push(value.item.baz.len() as u8);
+        result.push((value.item.baz.len() >> 8) as u8);
+        for val in &value.item.baz {
+            result.push((val & 0xffu16) as u8);
+            result.push(((val >> 8) & 0xffu16) as u8);
+        }
+
+        // encode buf
+        result.push(value.item.buf.len() as u8);
+        result.push((value.item.buf.len() >> 8) as u8);
+        result.push((value.item.buf.len() >> 16) as u8);
+        result.push((value.item.buf.len() >> 24) as u8);
+        result.extend_from_slice(&value.item.buf);
+
+        // encode val
+        result.push(value.val.len() as u8);
+        result.push((value.val.len() >> 8) as u8);
+        for val in &value.val {
+            result.push(*val as u8);
+            result.push((val >> 8) as u8);
+            result.push((val >> 16) as u8);
+            result.push((val >> 24) as u8);
+            result.push((val >> 32) as u8);
+            result.push((val >> 40) as u8);
+            result.push((val >> 48) as u8);
+            result.push((val >> 56) as u8);
+        }
+
+        result
+    }
+
+    #[test]
+    fn nested_encode() {
+        let value = Nested {
+            item: Item {
+                foo: 0xcafe_d00d_8bad_f00d,
+                bar: String::from("龍が我が敵を喰らう!"),
+                baz: vec![2679, 55_919, 44, 38_819, 792],
+                buf: Data(vec![129, 55, 200, 93, 7, 68]),
+            },
+            val: vec![1954978, 59, 4519, 15679],
+        };
+
+        let expected = build_encoded_buffer(&value);
+
+        let mut actual = Vec::with_capacity(expected.len());
+        actual.resize(expected.len(), 0);
+
+        WireFormat::encode(&value, &mut Cursor::new(&mut *actual)).expect("failed to encode value");
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn nested_decode() {
+        let expected = Nested {
+            item: Item {
+                foo: 0x0ff1ce,
+                bar: String::from("龍神の剣を喰らえ!"),
+                baz: vec![21687, 159, 55, 9217, 192],
+                buf: Data(vec![189, 22, 7, 59, 235]),
+            },
+            val: vec![15679, 8619196, 319746, 123957, 77, 0, 492],
+        };
+
+        let input = build_encoded_buffer(&expected);
+
+        assert_eq!(
+            expected,
+            <Nested as WireFormat>::decode(&mut Cursor::new(&*input))
+                .expect("failed to decode value")
+        );
+    }
+}
diff --git a/p9/src/server.rs b/p9/src/server.rs
new file mode 100644
index 0000000..b8a026f
--- /dev/null
+++ b/p9/src/server.rs
@@ -0,0 +1,949 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use libc;
+
+use std::cmp::min;
+use std::collections::{btree_map, BTreeMap};
+use std::ffi::CString;
+use std::fs;
+use std::io::{self, Cursor, Read, Write};
+use std::mem;
+use std::os::linux::fs::MetadataExt;
+use std::os::unix::fs::{DirBuilderExt, FileExt, OpenOptionsExt};
+use std::os::unix::io::AsRawFd;
+use std::path::{Component, Path, PathBuf};
+
+use crate::protocol::*;
+
+// Tlopen and Tlcreate flags.  Taken from "include/net/9p/9p.h" in the linux tree.
+const _P9_RDONLY: u32 = 0o00000000;
+const P9_WRONLY: u32 = 0o00000001;
+const P9_RDWR: u32 = 0o00000002;
+const P9_NOACCESS: u32 = 0o00000003;
+const P9_CREATE: u32 = 0o00000100;
+const P9_EXCL: u32 = 0o00000200;
+const P9_NOCTTY: u32 = 0o00000400;
+const P9_TRUNC: u32 = 0o00001000;
+const P9_APPEND: u32 = 0o00002000;
+const P9_NONBLOCK: u32 = 0o00004000;
+const P9_DSYNC: u32 = 0o00010000;
+const P9_FASYNC: u32 = 0o00020000;
+const P9_DIRECT: u32 = 0o00040000;
+const P9_LARGEFILE: u32 = 0o00100000;
+const P9_DIRECTORY: u32 = 0o00200000;
+const P9_NOFOLLOW: u32 = 0o00400000;
+const P9_NOATIME: u32 = 0o01000000;
+const _P9_CLOEXEC: u32 = 0o02000000;
+const P9_SYNC: u32 = 0o04000000;
+
+// Mapping from 9P flags to libc flags.
+const MAPPED_FLAGS: [(u32, i32); 10] = [
+    (P9_NOCTTY, libc::O_NOCTTY),
+    (P9_NONBLOCK, libc::O_NONBLOCK),
+    (P9_DSYNC, libc::O_DSYNC),
+    (P9_FASYNC, 0), // Unsupported
+    (P9_DIRECT, libc::O_DIRECT),
+    (P9_LARGEFILE, libc::O_LARGEFILE),
+    (P9_DIRECTORY, libc::O_DIRECTORY),
+    (P9_NOFOLLOW, libc::O_NOFOLLOW),
+    (P9_NOATIME, libc::O_NOATIME),
+    (P9_SYNC, libc::O_SYNC),
+];
+
+// 9P Qid types.  Taken from "include/net/9p/9p.h" in the linux tree.
+const P9_QTDIR: u8 = 0x80;
+const _P9_QTAPPEND: u8 = 0x40;
+const _P9_QTEXCL: u8 = 0x20;
+const _P9_QTMOUNT: u8 = 0x10;
+const _P9_QTAUTH: u8 = 0x08;
+const _P9_QTTMP: u8 = 0x04;
+const _P9_QTSYMLINK: u8 = 0x02;
+const _P9_QTLINK: u8 = 0x01;
+const P9_QTFILE: u8 = 0x00;
+
+// Bitmask values for the getattr request.
+const _P9_GETATTR_MODE: u64 = 0x00000001;
+const _P9_GETATTR_NLINK: u64 = 0x00000002;
+const _P9_GETATTR_UID: u64 = 0x00000004;
+const _P9_GETATTR_GID: u64 = 0x00000008;
+const _P9_GETATTR_RDEV: u64 = 0x00000010;
+const _P9_GETATTR_ATIME: u64 = 0x00000020;
+const _P9_GETATTR_MTIME: u64 = 0x00000040;
+const _P9_GETATTR_CTIME: u64 = 0x00000080;
+const _P9_GETATTR_INO: u64 = 0x00000100;
+const _P9_GETATTR_SIZE: u64 = 0x00000200;
+const _P9_GETATTR_BLOCKS: u64 = 0x00000400;
+
+const _P9_GETATTR_BTIME: u64 = 0x00000800;
+const _P9_GETATTR_GEN: u64 = 0x00001000;
+const _P9_GETATTR_DATA_VERSION: u64 = 0x00002000;
+
+const P9_GETATTR_BASIC: u64 = 0x000007ff; /* Mask for fields up to BLOCKS */
+const _P9_GETATTR_ALL: u64 = 0x00003fff; /* Mask for All fields above */
+
+// Bitmask values for the setattr request.
+const P9_SETATTR_MODE: u32 = 0x00000001;
+const P9_SETATTR_UID: u32 = 0x00000002;
+const P9_SETATTR_GID: u32 = 0x00000004;
+const P9_SETATTR_SIZE: u32 = 0x00000008;
+const P9_SETATTR_ATIME: u32 = 0x00000010;
+const P9_SETATTR_MTIME: u32 = 0x00000020;
+const P9_SETATTR_CTIME: u32 = 0x00000040;
+const P9_SETATTR_ATIME_SET: u32 = 0x00000080;
+const P9_SETATTR_MTIME_SET: u32 = 0x00000100;
+
+// Minimum and maximum message size that we'll expect from the client.
+const MIN_MESSAGE_SIZE: u32 = 256;
+const MAX_MESSAGE_SIZE: u32 = ::std::u16::MAX as u32;
+
+// Represents state that the server is holding on behalf of a client. Fids are somewhat like file
+// descriptors but are not restricted to open files and directories. Fids are identified by a unique
+// 32-bit number chosen by the client. Most messages sent by clients include a fid on which to
+// operate. The fid in a Tattach message represents the root of the file system tree that the client
+// is allowed to access. A client can create more fids by walking the directory tree from that fid.
+struct Fid {
+    path: Box<Path>,
+    metadata: fs::Metadata,
+    file: Option<fs::File>,
+    dirents: Option<Vec<Dirent>>,
+}
+
+fn metadata_to_qid(metadata: &fs::Metadata) -> Qid {
+    let ty = if metadata.is_dir() {
+        P9_QTDIR
+    } else if metadata.is_file() {
+        P9_QTFILE
+    } else {
+        // Unknown file type...
+        0
+    };
+
+    Qid {
+        ty,
+        // TODO: deal with the 2038 problem before 2038
+        version: metadata.st_mtime() as u32,
+        path: metadata.st_ino(),
+    }
+}
+
+fn error_to_rmessage(err: io::Error) -> Rmessage {
+    let errno = if let Some(errno) = err.raw_os_error() {
+        errno
+    } else {
+        // Make a best-effort guess based on the kind.
+        match err.kind() {
+            io::ErrorKind::NotFound => libc::ENOENT,
+            io::ErrorKind::PermissionDenied => libc::EPERM,
+            io::ErrorKind::ConnectionRefused => libc::ECONNREFUSED,
+            io::ErrorKind::ConnectionReset => libc::ECONNRESET,
+            io::ErrorKind::ConnectionAborted => libc::ECONNABORTED,
+            io::ErrorKind::NotConnected => libc::ENOTCONN,
+            io::ErrorKind::AddrInUse => libc::EADDRINUSE,
+            io::ErrorKind::AddrNotAvailable => libc::EADDRNOTAVAIL,
+            io::ErrorKind::BrokenPipe => libc::EPIPE,
+            io::ErrorKind::AlreadyExists => libc::EEXIST,
+            io::ErrorKind::WouldBlock => libc::EWOULDBLOCK,
+            io::ErrorKind::InvalidInput => libc::EINVAL,
+            io::ErrorKind::InvalidData => libc::EINVAL,
+            io::ErrorKind::TimedOut => libc::ETIMEDOUT,
+            io::ErrorKind::WriteZero => libc::EIO,
+            io::ErrorKind::Interrupted => libc::EINTR,
+            io::ErrorKind::Other => libc::EIO,
+            io::ErrorKind::UnexpectedEof => libc::EIO,
+            _ => libc::EIO,
+        }
+    };
+
+    Rmessage::Lerror(Rlerror {
+        ecode: errno as u32,
+    })
+}
+
+// Joins `path` to `buf`.  If `path` is '..', removes the last component from `buf`
+// only if `buf` != `root` but does nothing if `buf` == `root`.  Pushes `path` onto
+// `buf` if it is a normal path component.
+//
+// Returns an error if `path` is absolute, has more than one component, or contains
+// a '.' component.
+fn join_path<P: AsRef<Path>, R: AsRef<Path>>(
+    mut buf: PathBuf,
+    path: P,
+    root: R,
+) -> io::Result<PathBuf> {
+    let path = path.as_ref();
+    let root = root.as_ref();
+    debug_assert!(buf.starts_with(root));
+
+    if path.components().count() > 1 {
+        return Err(io::Error::from_raw_os_error(libc::EINVAL));
+    }
+
+    for component in path.components() {
+        match component {
+            // Prefix should only appear on windows systems.
+            Component::Prefix(_) => return Err(io::Error::from_raw_os_error(libc::EINVAL)),
+            // Absolute paths are not allowed.
+            Component::RootDir => return Err(io::Error::from_raw_os_error(libc::EINVAL)),
+            // '.' elements are not allowed.
+            Component::CurDir => return Err(io::Error::from_raw_os_error(libc::EINVAL)),
+            Component::ParentDir => {
+                // We only remove the parent path if we are not already at the root of the
+                // file system.
+                if buf != root {
+                    buf.pop();
+                }
+            }
+            Component::Normal(element) => buf.push(element),
+        }
+    }
+
+    Ok(buf)
+}
+
+pub struct Server {
+    root: Box<Path>,
+    msize: u32,
+    fids: BTreeMap<u32, Fid>,
+}
+
+impl Server {
+    pub fn new<P: AsRef<Path>>(root: P) -> Server {
+        Server {
+            root: root.as_ref().into(),
+            msize: MAX_MESSAGE_SIZE,
+            fids: BTreeMap::new(),
+        }
+    }
+
+    pub fn handle_message<R: Read, W: Write>(
+        &mut self,
+        reader: &mut R,
+        writer: &mut W,
+    ) -> io::Result<()> {
+        let request: Tframe = WireFormat::decode(&mut reader.take(self.msize as u64))?;
+
+        if cfg!(feature = "trace") {
+            println!("{:?}", &request);
+        }
+
+        let rmsg = match &request.msg {
+            Tmessage::Version(version) => self.version(version),
+            Tmessage::Flush(flush) => self.flush(flush),
+            Tmessage::Walk(walk) => self.walk(walk),
+            Tmessage::Read(read) => self.read(read),
+            Tmessage::Write(write) => self.write(write),
+            Tmessage::Clunk(clunk) => self.clunk(clunk),
+            Tmessage::Remove(remove) => self.remove(remove),
+            Tmessage::Attach(attach) => self.attach(attach),
+            Tmessage::Auth(auth) => self.auth(auth),
+            Tmessage::Statfs(statfs) => self.statfs(statfs),
+            Tmessage::Lopen(lopen) => self.lopen(lopen),
+            Tmessage::Lcreate(lcreate) => self.lcreate(lcreate),
+            Tmessage::Symlink(symlink) => self.symlink(symlink),
+            Tmessage::Mknod(mknod) => self.mknod(mknod),
+            Tmessage::Rename(rename) => self.rename(rename),
+            Tmessage::Readlink(readlink) => self.readlink(readlink),
+            Tmessage::GetAttr(get_attr) => self.get_attr(get_attr),
+            Tmessage::SetAttr(set_attr) => self.set_attr(set_attr),
+            Tmessage::XattrWalk(xattr_walk) => self.xattr_walk(xattr_walk),
+            Tmessage::XattrCreate(xattr_create) => self.xattr_create(xattr_create),
+            Tmessage::Readdir(readdir) => self.readdir(readdir),
+            Tmessage::Fsync(fsync) => self.fsync(fsync),
+            Tmessage::Lock(lock) => self.lock(lock),
+            Tmessage::GetLock(get_lock) => self.get_lock(get_lock),
+            Tmessage::Link(link) => self.link(link),
+            Tmessage::Mkdir(mkdir) => self.mkdir(mkdir),
+            Tmessage::RenameAt(rename_at) => self.rename_at(rename_at),
+            Tmessage::UnlinkAt(unlink_at) => self.unlink_at(unlink_at),
+        };
+
+        // Errors while handling requests are never fatal.
+        let response = Rframe {
+            tag: request.tag,
+            msg: rmsg.unwrap_or_else(error_to_rmessage),
+        };
+
+        if cfg!(feature = "trace") {
+            println!("{:?}", &response);
+        }
+
+        response.encode(writer)?;
+        writer.flush()
+    }
+
+    fn auth(&mut self, _auth: &Tauth) -> io::Result<Rmessage> {
+        // Returning an error for the auth message means that the server does not require
+        // authentication.
+        Err(io::Error::from_raw_os_error(libc::EOPNOTSUPP))
+    }
+
+    fn attach(&mut self, attach: &Tattach) -> io::Result<Rmessage> {
+        // TODO: Check attach parameters
+        match self.fids.entry(attach.fid) {
+            btree_map::Entry::Vacant(entry) => {
+                let fid = Fid {
+                    path: self.root.to_path_buf().into_boxed_path(),
+                    metadata: fs::metadata(&self.root)?,
+                    file: None,
+                    dirents: None,
+                };
+                let response = Rattach {
+                    qid: metadata_to_qid(&fid.metadata),
+                };
+                entry.insert(fid);
+                Ok(Rmessage::Attach(response))
+            }
+            btree_map::Entry::Occupied(_) => Err(io::Error::from_raw_os_error(libc::EBADF)),
+        }
+    }
+
+    fn version(&mut self, version: &Tversion) -> io::Result<Rmessage> {
+        if version.msize < MIN_MESSAGE_SIZE {
+            return Err(io::Error::from_raw_os_error(libc::EINVAL));
+        }
+
+        // A Tversion request clunks all open fids and terminates any pending I/O.
+        self.fids.clear();
+        self.msize = min(MAX_MESSAGE_SIZE, version.msize);
+
+        Ok(Rmessage::Version(Rversion {
+            msize: self.msize,
+            version: if version.version == "9P2000.L" {
+                String::from("9P2000.L")
+            } else {
+                String::from("unknown")
+            },
+        }))
+    }
+
+    fn flush(&mut self, _flush: &Tflush) -> io::Result<Rmessage> {
+        // TODO: Since everything is synchronous we can't actually flush requests.
+        Ok(Rmessage::Flush)
+    }
+
+    fn do_walk(
+        &self,
+        wnames: &[String],
+        mut buf: PathBuf,
+        mds: &mut Vec<fs::Metadata>,
+    ) -> io::Result<PathBuf> {
+        for wname in wnames {
+            let name = Path::new(wname);
+            buf = join_path(buf, name, &*self.root)?;
+            mds.push(fs::metadata(&buf)?);
+        }
+
+        Ok(buf)
+    }
+
+    fn walk(&mut self, walk: &Twalk) -> io::Result<Rmessage> {
+        // `newfid` must not currently be in use unless it is the same as `fid`.
+        if walk.fid != walk.newfid && self.fids.contains_key(&walk.newfid) {
+            return Err(io::Error::from_raw_os_error(libc::EBADF));
+        }
+
+        // We need to walk the tree.  First get the starting path.
+        let (buf, oldmd) = self
+            .fids
+            .get(&walk.fid)
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))
+            .map(|fid| (fid.path.to_path_buf(), fid.metadata.clone()))?;
+
+        // Now walk the tree and break on the first error, if any.
+        let mut mds = Vec::with_capacity(walk.wnames.len());
+        match self.do_walk(&walk.wnames, buf, &mut mds) {
+            Ok(buf) => {
+                // Store the new fid if the full walk succeeded.
+                if mds.len() == walk.wnames.len() {
+                    // This could just be a duplication operation.
+                    let md = if let Some(md) = mds.last() {
+                        md.clone()
+                    } else {
+                        oldmd
+                    };
+
+                    self.fids.insert(
+                        walk.newfid,
+                        Fid {
+                            path: buf.into_boxed_path(),
+                            metadata: md,
+                            file: None,
+                            dirents: None,
+                        },
+                    );
+                }
+            }
+            Err(e) => {
+                // Only return an error if it occurred on the first component.
+                if mds.is_empty() {
+                    return Err(e);
+                }
+            }
+        }
+
+        Ok(Rmessage::Walk(Rwalk {
+            wqids: mds.iter().map(metadata_to_qid).collect(),
+        }))
+    }
+
+    fn read(&mut self, read: &Tread) -> io::Result<Rmessage> {
+        // Thankfully, `read` cannot be used to read directories in 9P2000.L.
+        let file = self
+            .fids
+            .get_mut(&read.fid)
+            .and_then(|fid| fid.file.as_mut())
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+
+        // Use an empty Rread struct to figure out the overhead of the header.
+        let header_size = Rframe {
+            tag: 0,
+            msg: Rmessage::Read(Rread {
+                data: Data(Vec::new()),
+            }),
+        }
+        .byte_size();
+
+        let capacity = min(self.msize - header_size, read.count);
+        let mut buf = Data(Vec::with_capacity(capacity as usize));
+        buf.resize(capacity as usize, 0);
+
+        let count = file.read_at(&mut buf, read.offset)?;
+        buf.resize(count, 0);
+
+        Ok(Rmessage::Read(Rread { data: buf }))
+    }
+
+    fn write(&mut self, write: &Twrite) -> io::Result<Rmessage> {
+        let file = self
+            .fids
+            .get_mut(&write.fid)
+            .and_then(|fid| fid.file.as_mut())
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+
+        let count = file.write_at(&write.data, write.offset)?;
+        Ok(Rmessage::Write(Rwrite {
+            count: count as u32,
+        }))
+    }
+
+    fn clunk(&mut self, clunk: &Tclunk) -> io::Result<Rmessage> {
+        match self.fids.entry(clunk.fid) {
+            btree_map::Entry::Vacant(_) => Err(io::Error::from_raw_os_error(libc::EBADF)),
+            btree_map::Entry::Occupied(entry) => {
+                entry.remove();
+                Ok(Rmessage::Clunk)
+            }
+        }
+    }
+
+    fn remove(&mut self, remove: &Tremove) -> io::Result<Rmessage> {
+        match self.fids.entry(remove.fid) {
+            btree_map::Entry::Vacant(_) => Err(io::Error::from_raw_os_error(libc::EBADF)),
+            btree_map::Entry::Occupied(o) => {
+                let (_, fid) = o.remove_entry();
+
+                if fid.metadata.is_dir() {
+                    fs::remove_dir(&fid.path)?;
+                } else {
+                    fs::remove_file(&fid.path)?;
+                }
+
+                Ok(Rmessage::Remove)
+            }
+        }
+    }
+
+    fn statfs(&mut self, statfs: &Tstatfs) -> io::Result<Rmessage> {
+        let fid = self
+            .fids
+            .get(&statfs.fid)
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+        let path = fid
+            .path
+            .to_str()
+            .and_then(|path| CString::new(path).ok())
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EINVAL))?;
+
+        // Safe because we are zero-initializing a C struct with only primitive
+        // data members.
+        let mut out: libc::statfs64 = unsafe { mem::zeroed() };
+
+        // Safe because we know that `path` is valid and we have already initialized `out`.
+        let ret = unsafe { libc::statfs64(path.as_ptr(), &mut out) };
+        if ret != 0 {
+            return Err(io::Error::last_os_error());
+        }
+
+        Ok(Rmessage::Statfs(Rstatfs {
+            ty: out.f_type as u32,
+            bsize: out.f_bsize as u32,
+            blocks: out.f_blocks,
+            bfree: out.f_bfree,
+            bavail: out.f_bavail,
+            files: out.f_files,
+            ffree: out.f_ffree,
+            fsid: 0, // No way to get the fields of a libc::fsid_t
+            namelen: out.f_namelen as u32,
+        }))
+    }
+
+    fn lopen(&mut self, lopen: &Tlopen) -> io::Result<Rmessage> {
+        let fid = self
+            .fids
+            .get_mut(&lopen.fid)
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+        // We always open files with O_CLOEXEC.
+        let mut custom_flags: i32 = libc::O_CLOEXEC;
+        for &(p9f, of) in &MAPPED_FLAGS {
+            if (lopen.flags & p9f) != 0 {
+                custom_flags |= of;
+            }
+        }
+
+        let file = fs::OpenOptions::new()
+            .read((lopen.flags & P9_NOACCESS) == 0 || (lopen.flags & P9_RDWR) != 0)
+            .write((lopen.flags & P9_WRONLY) != 0 || (lopen.flags & P9_RDWR) != 0)
+            .append((lopen.flags & P9_APPEND) != 0)
+            .truncate((lopen.flags & P9_TRUNC) != 0)
+            .create((lopen.flags & P9_CREATE) != 0)
+            .create_new((lopen.flags & P9_CREATE) != 0 && (lopen.flags & P9_EXCL) != 0)
+            .custom_flags(custom_flags)
+            .open(&fid.path)?;
+
+        fid.metadata = file.metadata()?;
+        fid.file = Some(file);
+
+        Ok(Rmessage::Lopen(Rlopen {
+            qid: metadata_to_qid(&fid.metadata),
+            iounit: 0,
+        }))
+    }
+
+    fn lcreate(&mut self, lcreate: &Tlcreate) -> io::Result<Rmessage> {
+        let fid = self
+            .fids
+            .get_mut(&lcreate.fid)
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+
+        if !fid.metadata.is_dir() {
+            return Err(io::Error::from_raw_os_error(libc::ENOTDIR));
+        }
+
+        let name = Path::new(&lcreate.name);
+        let path = join_path(fid.path.to_path_buf(), name, &*self.root)?;
+
+        let mut custom_flags: i32 = libc::O_CLOEXEC;
+        for &(p9f, of) in &MAPPED_FLAGS {
+            if (lcreate.flags & p9f) != 0 {
+                custom_flags |= of;
+            }
+        }
+
+        let file = fs::OpenOptions::new()
+            .read(false)
+            .write(true)
+            .truncate(true)
+            .create(true)
+            .append((lcreate.flags & P9_APPEND) != 0)
+            .create_new((lcreate.flags & P9_EXCL) != 0)
+            .custom_flags(custom_flags)
+            .mode(lcreate.mode & 0o755)
+            .open(&path)?;
+
+        fid.metadata = file.metadata()?;
+        fid.file = Some(file);
+        fid.path = path.into_boxed_path();
+
+        Ok(Rmessage::Lcreate(Rlcreate {
+            qid: metadata_to_qid(&fid.metadata),
+            iounit: 0,
+        }))
+    }
+
+    fn symlink(&mut self, _symlink: &Tsymlink) -> io::Result<Rmessage> {
+        // symlinks are not allowed.
+        Err(io::Error::from_raw_os_error(libc::EACCES))
+    }
+
+    fn mknod(&mut self, _mknod: &Tmknod) -> io::Result<Rmessage> {
+        // No nodes either.
+        Err(io::Error::from_raw_os_error(libc::EACCES))
+    }
+
+    fn rename(&mut self, rename: &Trename) -> io::Result<Rmessage> {
+        let newname = Path::new(&rename.name);
+        let buf = self
+            .fids
+            .get(&rename.dfid)
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))
+            .map(|dfid| dfid.path.to_path_buf())?;
+        let newpath = join_path(buf, newname, &*self.root)?;
+
+        let fid = self
+            .fids
+            .get_mut(&rename.fid)
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EINVAL))?;
+
+        fs::rename(&fid.path, &newpath)?;
+
+        // TODO: figure out if the client expects |fid.path| to point to
+        // the renamed path.
+        fid.path = newpath.into_boxed_path();
+        Ok(Rmessage::Rename)
+    }
+
+    fn readlink(&mut self, _readlink: &Treadlink) -> io::Result<Rmessage> {
+        // symlinks are not allowed
+        Err(io::Error::from_raw_os_error(libc::EACCES))
+    }
+
+    fn get_attr(&mut self, get_attr: &Tgetattr) -> io::Result<Rmessage> {
+        let fid = self
+            .fids
+            .get_mut(&get_attr.fid)
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+
+        // Refresh the metadata since we were explicitly asked for it.
+        fid.metadata = fs::metadata(&fid.path)?;
+
+        Ok(Rmessage::GetAttr(Rgetattr {
+            valid: P9_GETATTR_BASIC,
+            qid: metadata_to_qid(&fid.metadata),
+            mode: fid.metadata.st_mode(),
+            uid: fid.metadata.st_uid(),
+            gid: fid.metadata.st_gid(),
+            nlink: fid.metadata.st_nlink(),
+            rdev: fid.metadata.st_rdev(),
+            size: fid.metadata.st_size(),
+            blksize: fid.metadata.st_blksize(),
+            blocks: fid.metadata.st_blocks(),
+            atime_sec: fid.metadata.st_atime() as u64,
+            atime_nsec: fid.metadata.st_atime_nsec() as u64,
+            mtime_sec: fid.metadata.st_mtime() as u64,
+            mtime_nsec: fid.metadata.st_mtime_nsec() as u64,
+            ctime_sec: fid.metadata.st_ctime() as u64,
+            ctime_nsec: fid.metadata.st_ctime_nsec() as u64,
+            btime_sec: 0,
+            btime_nsec: 0,
+            gen: 0,
+            data_version: 0,
+        }))
+    }
+
+    fn set_attr(&mut self, set_attr: &Tsetattr) -> io::Result<Rmessage> {
+        let blocked_ops = P9_SETATTR_MODE | P9_SETATTR_UID | P9_SETATTR_GID;
+        if set_attr.valid & blocked_ops != 0 {
+            return Err(io::Error::from_raw_os_error(libc::EPERM));
+        }
+
+        let fid = self
+            .fids
+            .get_mut(&set_attr.fid)
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+        let file = fs::OpenOptions::new().write(true).open(&fid.path)?;
+
+        if set_attr.valid & P9_SETATTR_SIZE != 0 {
+            file.set_len(set_attr.size)?;
+        }
+
+        if set_attr.valid & (P9_SETATTR_ATIME | P9_SETATTR_MTIME) != 0 {
+            let times = [
+                libc::timespec {
+                    tv_sec: set_attr.atime_sec as _,
+                    tv_nsec: if set_attr.valid & P9_SETATTR_ATIME == 0 {
+                        libc::UTIME_OMIT
+                    } else if set_attr.valid & P9_SETATTR_ATIME_SET == 0 {
+                        libc::UTIME_NOW
+                    } else {
+                        set_attr.atime_nsec as _
+                    },
+                },
+                libc::timespec {
+                    tv_sec: set_attr.mtime_sec as _,
+                    tv_nsec: if set_attr.valid & P9_SETATTR_MTIME == 0 {
+                        libc::UTIME_OMIT
+                    } else if set_attr.valid & P9_SETATTR_MTIME_SET == 0 {
+                        libc::UTIME_NOW
+                    } else {
+                        set_attr.mtime_nsec as _
+                    },
+                },
+            ];
+
+            // Safe because file is valid and we have initialized times fully.
+            let ret = unsafe { libc::futimens(file.as_raw_fd(), &times as *const libc::timespec) };
+            if ret < 0 {
+                return Err(io::Error::last_os_error());
+            }
+        }
+
+        // The ctime would have been updated by any of the above operations so we only
+        // need to change it if it was the only option given.
+        if set_attr.valid & P9_SETATTR_CTIME != 0 && set_attr.valid & (!P9_SETATTR_CTIME) == 0 {
+            // Setting -1 as the uid and gid will not actually change anything but will
+            // still update the ctime.
+            let ret = unsafe {
+                libc::fchown(
+                    file.as_raw_fd(),
+                    libc::uid_t::max_value(),
+                    libc::gid_t::max_value(),
+                )
+            };
+            if ret < 0 {
+                return Err(io::Error::last_os_error());
+            }
+        }
+
+        Ok(Rmessage::SetAttr)
+    }
+
+    fn xattr_walk(&mut self, _xattr_walk: &Txattrwalk) -> io::Result<Rmessage> {
+        Err(io::Error::from_raw_os_error(libc::EOPNOTSUPP))
+    }
+
+    fn xattr_create(&mut self, _xattr_create: &Txattrcreate) -> io::Result<Rmessage> {
+        Err(io::Error::from_raw_os_error(libc::EOPNOTSUPP))
+    }
+
+    fn readdir(&mut self, readdir: &Treaddir) -> io::Result<Rmessage> {
+        let fid = self
+            .fids
+            .get_mut(&readdir.fid)
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+
+        if !fid.metadata.is_dir() {
+            return Err(io::Error::from_raw_os_error(libc::ENOTDIR));
+        }
+
+        // The p9 client implementation in the kernel doesn't fully read all the contents
+        // of the directory.  This means that if some application performs a getdents()
+        // call, followed by removing some files, followed by another getdents() call,
+        // the offset that we get from the kernel is completely meaningless.  Instead
+        // we fully read the contents of the directory here and only re-read the directory
+        // if the offset we get from the client is 0.  Any other offset is served from the
+        // directory entries in memory.  This ensures consistency even if the directory
+        // changes in between Treaddir messages.
+        if readdir.offset == 0 {
+            let mut offset = 0;
+            let iter = fs::read_dir(&fid.path)?;
+            let dirents = iter.map(|item| -> io::Result<Dirent> {
+                let entry = item?;
+
+                let md = entry.metadata()?;
+                let qid = metadata_to_qid(&md);
+
+                let ty = if md.is_dir() {
+                    libc::DT_DIR
+                } else if md.is_file() {
+                    libc::DT_REG
+                } else {
+                    libc::DT_UNKNOWN
+                };
+
+                let name = entry
+                    .file_name()
+                    .into_string()
+                    .map_err(|_| io::Error::from_raw_os_error(libc::EINVAL))?;
+
+                let mut out = Dirent {
+                    qid,
+                    offset: 0, // set below
+                    ty,
+                    name,
+                };
+
+                offset += out.byte_size() as u64;
+                out.offset = offset;
+
+                Ok(out)
+            });
+
+            // This is taking advantage of the fact that we can turn a Iterator of Result<T, E>
+            // into a Result<FromIterator<T>, E> since Result implements FromIterator<Result<T, E>>.
+            fid.dirents = Some(dirents.collect::<io::Result<Vec<Dirent>>>()?);
+        }
+
+        let mut entries = fid
+            .dirents
+            .as_ref()
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?
+            .iter()
+            .skip_while(|entry| entry.offset <= readdir.offset)
+            .peekable();
+
+        // Use an empty Rreaddir struct to figure out the maximum number of bytes that
+        // can be returned.
+        let header_size = Rframe {
+            tag: 0,
+            msg: Rmessage::Readdir(Rreaddir {
+                data: Data(Vec::new()),
+            }),
+        }
+        .byte_size();
+        let count = min(self.msize - header_size, readdir.count);
+        let mut cursor = Cursor::new(Vec::with_capacity(count as usize));
+
+        while let Some(entry) = entries.peek() {
+            let byte_size = entry.byte_size() as usize;
+
+            if cursor.get_ref().capacity() - cursor.get_ref().len() < byte_size {
+                // No more room in the buffer.
+                break;
+            }
+
+            // Safe because we just checked that the iterator contains at least one more item.
+            entries.next().unwrap().encode(&mut cursor)?;
+        }
+
+        Ok(Rmessage::Readdir(Rreaddir {
+            data: Data(cursor.into_inner()),
+        }))
+    }
+
+    fn fsync(&mut self, fsync: &Tfsync) -> io::Result<Rmessage> {
+        let file = self
+            .fids
+            .get(&fsync.fid)
+            .and_then(|fid| fid.file.as_ref())
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+
+        if fsync.datasync == 0 {
+            file.sync_all()?;
+        } else {
+            file.sync_data()?;
+        }
+        Ok(Rmessage::Fsync)
+    }
+
+    fn lock(&mut self, _lock: &Tlock) -> io::Result<Rmessage> {
+        // File locking is not supported.
+        Err(io::Error::from_raw_os_error(libc::EOPNOTSUPP))
+    }
+    fn get_lock(&mut self, _get_lock: &Tgetlock) -> io::Result<Rmessage> {
+        // File locking is not supported.
+        Err(io::Error::from_raw_os_error(libc::EOPNOTSUPP))
+    }
+
+    fn link(&mut self, link: &Tlink) -> io::Result<Rmessage> {
+        let newname = Path::new(&link.name);
+        let buf = self
+            .fids
+            .get(&link.dfid)
+            .map(|dfid| dfid.path.to_path_buf())
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+        let newpath = join_path(buf, newname, &*self.root)?;
+
+        let path = self
+            .fids
+            .get(&link.fid)
+            .map(|fid| &fid.path)
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+
+        fs::hard_link(path, &newpath)?;
+        Ok(Rmessage::Link)
+    }
+
+    fn mkdir(&mut self, mkdir: &Tmkdir) -> io::Result<Rmessage> {
+        let fid = self
+            .fids
+            .get(&mkdir.dfid)
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+
+        let name = Path::new(&mkdir.name);
+        let newpath = join_path(fid.path.to_path_buf(), name, &*self.root)?;
+
+        fs::DirBuilder::new()
+            .recursive(false)
+            .mode(mkdir.mode & 0o755)
+            .create(&newpath)?;
+
+        Ok(Rmessage::Mkdir(Rmkdir {
+            qid: metadata_to_qid(&fs::metadata(&newpath)?),
+        }))
+    }
+
+    fn rename_at(&mut self, rename_at: &Trenameat) -> io::Result<Rmessage> {
+        let oldname = Path::new(&rename_at.oldname);
+        let oldbuf = self
+            .fids
+            .get(&rename_at.olddirfid)
+            .map(|dfid| dfid.path.to_path_buf())
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+        let oldpath = join_path(oldbuf, oldname, &*self.root)?;
+
+        let newname = Path::new(&rename_at.newname);
+        let newbuf = self
+            .fids
+            .get(&rename_at.newdirfid)
+            .map(|dfid| dfid.path.to_path_buf())
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+        let newpath = join_path(newbuf, newname, &*self.root)?;
+
+        fs::rename(&oldpath, &newpath)?;
+        Ok(Rmessage::RenameAt)
+    }
+
+    fn unlink_at(&mut self, unlink_at: &Tunlinkat) -> io::Result<Rmessage> {
+        let name = Path::new(&unlink_at.name);
+        let buf = self
+            .fids
+            .get(&unlink_at.dirfd)
+            .map(|fid| fid.path.to_path_buf())
+            .ok_or_else(|| io::Error::from_raw_os_error(libc::EBADF))?;
+        let path = join_path(buf, name, &*self.root)?;
+
+        let md = fs::metadata(&path)?;
+        if md.is_dir() && (unlink_at.flags & (libc::AT_REMOVEDIR as u32)) == 0 {
+            return Err(io::Error::from_raw_os_error(libc::EISDIR));
+        }
+
+        if md.is_dir() {
+            fs::remove_dir(&path)?;
+        } else {
+            fs::remove_file(&path)?;
+        }
+
+        Ok(Rmessage::UnlinkAt)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    // Most of the server implementation is tested via integration tests.
+    use super::*;
+
+    #[test]
+    fn path_joins() {
+        let root = PathBuf::from("/a/b/c");
+        let path = PathBuf::from("/a/b/c/d/e/f");
+
+        assert_eq!(
+            &join_path(path.clone(), "nested", &root).expect("normal"),
+            Path::new("/a/b/c/d/e/f/nested")
+        );
+
+        let p1 = join_path(path.clone(), "..", &root).expect("parent 1");
+        assert_eq!(&p1, Path::new("/a/b/c/d/e/"));
+
+        let p2 = join_path(p1, "..", &root).expect("parent 2");
+        assert_eq!(&p2, Path::new("/a/b/c/d/"));
+
+        let p3 = join_path(p2, "..", &root).expect("parent 3");
+        assert_eq!(&p3, Path::new("/a/b/c/"));
+
+        let p4 = join_path(p3, "..", &root).expect("parent of root");
+        assert_eq!(&p4, Path::new("/a/b/c/"));
+    }
+
+    #[test]
+    fn invalid_joins() {
+        let root = PathBuf::from("/a");
+        let path = PathBuf::from("/a/b");
+
+        join_path(path.clone(), ".", &root).expect_err("current directory");
+        join_path(path.clone(), "c/d/e", &root).expect_err("too many components");
+        join_path(path.clone(), "/c/d/e", &root).expect_err("absolute path");
+    }
+}
diff --git a/p9/wire_format_derive/Cargo.toml b/p9/wire_format_derive/Cargo.toml
new file mode 100644
index 0000000..da6cc52
--- /dev/null
+++ b/p9/wire_format_derive/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "wire_format_derive"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+proc-macro2 = "=0.4"
+quote = "=0.6"
+syn = "=0.15"
+
+[lib]
+proc-macro = true
+path = "wire_format_derive.rs"
diff --git a/p9/wire_format_derive/wire_format_derive.rs b/p9/wire_format_derive/wire_format_derive.rs
new file mode 100644
index 0000000..6d369ae
--- /dev/null
+++ b/p9/wire_format_derive/wire_format_derive.rs
@@ -0,0 +1,296 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Derives a 9P wire format encoding for a struct by recursively calling
+//! `WireFormat::encode` or `WireFormat::decode` on the fields of the struct.
+//! This is only intended to be used from within the `p9` crate.
+
+#![recursion_limit = "256"]
+
+extern crate proc_macro;
+
+use proc_macro2::{Span, TokenStream};
+use quote::{quote, quote_spanned};
+use syn::spanned::Spanned;
+use syn::{parse_macro_input, Data, DeriveInput, Fields, Ident};
+
+/// The function that derives the actual implementation.
+#[proc_macro_derive(P9WireFormat)]
+pub fn p9_wire_format(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let input = parse_macro_input!(input as DeriveInput);
+    p9_wire_format_inner(input).into()
+}
+
+fn p9_wire_format_inner(input: DeriveInput) -> TokenStream {
+    if !input.generics.params.is_empty() {
+        return quote! {
+            compile_error!("derive(P9WireFormat) does not support generic parameters");
+        };
+    }
+
+    let container = input.ident;
+
+    let byte_size_impl = byte_size_sum(&input.data);
+    let encode_impl = encode_wire_format(&input.data);
+    let decode_impl = decode_wire_format(&input.data, &container);
+
+    let scope = format!("wire_format_{}", container).to_lowercase();
+    let scope = Ident::new(&scope, Span::call_site());
+    quote! {
+        mod #scope {
+            use std::io;
+            use std::result::Result::Ok;
+
+            use super::#container;
+
+            use crate::protocol::WireFormat;
+
+            impl WireFormat for #container {
+                fn byte_size(&self) -> u32 {
+                    #byte_size_impl
+                }
+
+                fn encode<W: io::Write>(&self, _writer: &mut W) -> io::Result<()> {
+                    #encode_impl
+                }
+
+                fn decode<R: io::Read>(_reader: &mut R) -> io::Result<Self> {
+                    #decode_impl
+                }
+            }
+        }
+    }
+}
+
+// Generate code that recursively calls byte_size on every field in the struct.
+fn byte_size_sum(data: &Data) -> TokenStream {
+    if let Data::Struct(data) = data {
+        if let Fields::Named(fields) = &data.fields {
+            let fields = fields.named.iter().map(|f| {
+                let field = &f.ident;
+                let span = field.span();
+                quote_spanned! {span=>
+                    WireFormat::byte_size(&self.#field)
+                }
+            });
+
+            quote! {
+                0 #(+ #fields)*
+            }
+        } else {
+            unimplemented!();
+        }
+    } else {
+        unimplemented!();
+    }
+}
+
+// Generate code that recursively calls encode on every field in the struct.
+fn encode_wire_format(data: &Data) -> TokenStream {
+    if let Data::Struct(data) = data {
+        if let Fields::Named(fields) = &data.fields {
+            let fields = fields.named.iter().map(|f| {
+                let field = &f.ident;
+                let span = field.span();
+                quote_spanned! {span=>
+                    WireFormat::encode(&self.#field, _writer)?;
+                }
+            });
+
+            quote! {
+                #(#fields)*
+
+                Ok(())
+            }
+        } else {
+            unimplemented!();
+        }
+    } else {
+        unimplemented!();
+    }
+}
+
+// Generate code that recursively calls decode on every field in the struct.
+fn decode_wire_format(data: &Data, container: &Ident) -> TokenStream {
+    if let Data::Struct(data) = data {
+        if let Fields::Named(fields) = &data.fields {
+            let values = fields.named.iter().map(|f| {
+                let field = &f.ident;
+                let span = field.span();
+                quote_spanned! {span=>
+                    let #field = WireFormat::decode(_reader)?;
+                }
+            });
+
+            let members = fields.named.iter().map(|f| {
+                let field = &f.ident;
+                quote! {
+                    #field: #field,
+                }
+            });
+
+            quote! {
+                #(#values)*
+
+                Ok(#container {
+                    #(#members)*
+                })
+            }
+        } else {
+            unimplemented!();
+        }
+    } else {
+        unimplemented!();
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use syn::parse_quote;
+
+    #[test]
+    fn byte_size() {
+        let input: DeriveInput = parse_quote! {
+            struct Item {
+                ident: u32,
+                with_underscores: String,
+                other: u8,
+            }
+        };
+
+        let expected = quote! {
+            0
+                + WireFormat::byte_size(&self.ident)
+                + WireFormat::byte_size(&self.with_underscores)
+                + WireFormat::byte_size(&self.other)
+        };
+
+        assert_eq!(byte_size_sum(&input.data).to_string(), expected.to_string());
+    }
+
+    #[test]
+    fn encode() {
+        let input: DeriveInput = parse_quote! {
+            struct Item {
+                ident: u32,
+                with_underscores: String,
+                other: u8,
+            }
+        };
+
+        let expected = quote! {
+            WireFormat::encode(&self.ident, _writer)?;
+            WireFormat::encode(&self.with_underscores, _writer)?;
+            WireFormat::encode(&self.other, _writer)?;
+            Ok(())
+        };
+
+        assert_eq!(
+            encode_wire_format(&input.data).to_string(),
+            expected.to_string(),
+        );
+    }
+
+    #[test]
+    fn decode() {
+        let input: DeriveInput = parse_quote! {
+            struct Item {
+                ident: u32,
+                with_underscores: String,
+                other: u8,
+            }
+        };
+
+        let container = Ident::new("Item", Span::call_site());
+        let expected = quote! {
+            let ident = WireFormat::decode(_reader)?;
+            let with_underscores = WireFormat::decode(_reader)?;
+            let other = WireFormat::decode(_reader)?;
+            Ok(Item {
+                ident: ident,
+                with_underscores: with_underscores,
+                other: other,
+            })
+        };
+
+        assert_eq!(
+            decode_wire_format(&input.data, &container).to_string(),
+            expected.to_string(),
+        );
+    }
+
+    #[test]
+    fn end_to_end() {
+        let input: DeriveInput = parse_quote! {
+            struct Niijima_先輩 {
+                a: u8,
+                b: u16,
+                c: u32,
+                d: u64,
+                e: String,
+                f: Vec<String>,
+                g: Nested,
+            }
+        };
+
+        let expected = quote! {
+            mod wire_format_niijima_先輩 {
+                use std::io;
+                use std::result::Result::Ok;
+
+                use super::Niijima_先輩;
+
+                use crate::protocol::WireFormat;
+
+                impl WireFormat for Niijima_先輩 {
+                    fn byte_size(&self) -> u32 {
+                        0
+                        + WireFormat::byte_size(&self.a)
+                        + WireFormat::byte_size(&self.b)
+                        + WireFormat::byte_size(&self.c)
+                        + WireFormat::byte_size(&self.d)
+                        + WireFormat::byte_size(&self.e)
+                        + WireFormat::byte_size(&self.f)
+                        + WireFormat::byte_size(&self.g)
+                    }
+
+                    fn encode<W: io::Write>(&self, _writer: &mut W) -> io::Result<()> {
+                        WireFormat::encode(&self.a, _writer)?;
+                        WireFormat::encode(&self.b, _writer)?;
+                        WireFormat::encode(&self.c, _writer)?;
+                        WireFormat::encode(&self.d, _writer)?;
+                        WireFormat::encode(&self.e, _writer)?;
+                        WireFormat::encode(&self.f, _writer)?;
+                        WireFormat::encode(&self.g, _writer)?;
+                        Ok(())
+                    }
+                    fn decode<R: io::Read>(_reader: &mut R) -> io::Result<Self> {
+                        let a = WireFormat::decode(_reader)?;
+                        let b = WireFormat::decode(_reader)?;
+                        let c = WireFormat::decode(_reader)?;
+                        let d = WireFormat::decode(_reader)?;
+                        let e = WireFormat::decode(_reader)?;
+                        let f = WireFormat::decode(_reader)?;
+                        let g = WireFormat::decode(_reader)?;
+                        Ok(Niijima_先輩 {
+                            a: a,
+                            b: b,
+                            c: c,
+                            d: d,
+                            e: e,
+                            f: f,
+                            g: g,
+                        })
+                    }
+                }
+            }
+        };
+
+        assert_eq!(
+            p9_wire_format_inner(input).to_string(),
+            expected.to_string(),
+        );
+    }
+}
diff --git a/protos/Cargo.toml b/protos/Cargo.toml
new file mode 100644
index 0000000..9fd0e5a
--- /dev/null
+++ b/protos/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "protos"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[features]
+plugin = ["kvm_sys"]
+trunks = []
+
+[dependencies]
+kvm_sys = { path = "../kvm_sys", optional = true }
+protobuf = "2.3"
+
+[build-dependencies]
+protoc-rust = "2.3"
diff --git a/protos/build.rs b/protos/build.rs
new file mode 100644
index 0000000..b510e54
--- /dev/null
+++ b/protos/build.rs
@@ -0,0 +1,112 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::env;
+use std::error::Error;
+use std::fs::{self, File};
+use std::io::Write;
+use std::path::{Path, PathBuf};
+
+type Result<T> = std::result::Result<T, Box<dyn Error>>;
+
+struct ExternalProto {
+    // Where to find protos during builds within cros_sdk. Relative to
+    // $SYSROOT environment variable set by emerge builds.
+    dir_relative_to_sysroot: &'static str,
+
+    // Where to find protos during "cargo build" in a local developer
+    // environment. Relative to the platform/crosvm/protos directory.
+    dir_relative_to_us: &'static str,
+
+    // *.proto file expected to exist in both of the above directories.
+    proto_file_name: &'static str,
+
+    // Code generated by proto compiler will be placed under
+    // protos::generated::$module_name.
+    module: &'static str,
+}
+
+// Rustfmt bug: https://github.com/rust-lang/rustfmt/issues/3498
+#[rustfmt::skip]
+static EXTERNAL_PROTOS: &[ExternalProto] = &[
+    #[cfg(feature = "trunks")]
+    ExternalProto {
+        dir_relative_to_sysroot: "usr/include/chromeos/dbus/trunks",
+        dir_relative_to_us: "../../../platform2/trunks",
+        proto_file_name: "interface.proto",
+        module: "trunks",
+    },
+];
+
+struct LocalProto {
+    // Corresponding to the input file src/$module.proto.
+    module: &'static str,
+}
+
+#[rustfmt::skip]
+static LOCAL_PROTOS: &[LocalProto] = &[
+    #[cfg(feature = "plugin")]
+    LocalProto { module: "plugin" },
+];
+
+fn main() -> Result<()> {
+    let out_dir = env::var("OUT_DIR")?;
+    let sysroot = env::var_os("SYSROOT");
+
+    // Write out a Rust module that imports the modules generated by protoc.
+    let generated = PathBuf::from(&out_dir).join("generated.rs");
+    let out = File::create(generated)?;
+
+    // Compile external protos.
+    for proto in EXTERNAL_PROTOS {
+        let dir = match &sysroot {
+            Some(dir) => PathBuf::from(dir).join(proto.dir_relative_to_sysroot),
+            None => PathBuf::from(proto.dir_relative_to_us),
+        };
+        let input_path = dir.join(proto.proto_file_name);
+        protoc(proto.module, input_path, &out)?;
+    }
+
+    // Compile protos from the local src directory.
+    for proto in LOCAL_PROTOS {
+        let input_path = format!("src/{}.proto", proto.module);
+        protoc(proto.module, input_path, &out)?;
+    }
+
+    Ok(())
+}
+
+// Compile a single proto file located at $input_path, placing the generated
+// code at $OUT_DIR/$module and emitting the right `pub mod $module` into the
+// output file.
+fn protoc<P: AsRef<Path>>(module: &str, input_path: P, mut out: &File) -> Result<()> {
+    let input_path = input_path.as_ref();
+    let input_dir = input_path.parent().unwrap();
+
+    // Place output in a subdirectory so that different protos with the same
+    // common filename (like interface.proto) do not conflict.
+    let out_dir = format!("{}/{}", env::var("OUT_DIR")?, module);
+    fs::create_dir_all(&out_dir)?;
+
+    // Invoke protobuf compiler.
+    protoc_rust::run(protoc_rust::Args {
+        out_dir: &out_dir,
+        includes: &[input_dir.as_os_str().to_str().unwrap()],
+        input: &[input_path.as_os_str().to_str().unwrap()],
+        ..Default::default()
+    })?;
+
+    // Write out a `mod` that refers to the generated module.
+    //
+    // The lint suppression is because protoc-rust emits
+    //   #![cfg_attr(feature = "cargo-clippy", allow(clippy))]
+    // which still works but is deprecated in favor of tool attributes:
+    //   #![allow(clippy::all)].
+    let file_stem = input_path.file_stem().unwrap().to_str().unwrap();
+    writeln!(out, "#[path = \"{}/{}.rs\"]", out_dir, file_stem)?;
+    writeln!(out, "#[allow(renamed_and_removed_lints)]")?;
+    writeln!(out, "pub mod {};", module)?;
+
+    Ok(())
+}
diff --git a/protos/src/lib.rs b/protos/src/lib.rs
new file mode 100644
index 0000000..3fdbdc0
--- /dev/null
+++ b/protos/src/lib.rs
@@ -0,0 +1,13 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+mod generated {
+    include!(concat!(env!("OUT_DIR"), "/generated.rs"));
+}
+
+#[cfg(feature = "plugin")]
+pub mod plugin;
+
+#[cfg(feature = "trunks")]
+pub use generated::trunks;
diff --git a/protos/src/plugin.proto b/protos/src/plugin.proto
new file mode 100644
index 0000000..de76089
--- /dev/null
+++ b/protos/src/plugin.proto
@@ -0,0 +1,409 @@
+syntax = "proto3";
+
+// The protocol defined here is actually two sub-protocols, one protocol for control of the main
+// process (MainRequest/MainResponse), and one for control of each VCPU thread
+// (VcpuRequest/VcpuResponse). Each protocol works the same: the client creates a protobuf of either
+// a MainRequest or VcpuRequest, sends it encoded over the main socket or one of the vcpu sockets,
+// reads the the MainResponse or VcpuResponse over the same socket and decodes it as a protobuf. For
+// specific information on the purpose of each request, see the C API in crosvm.h. Most requests
+// here map 1:1 to a function in that API. Only the intricacies unique to the wire protocol are
+// commented on here.
+
+enum AddressSpace {
+    IOPORT = 0;
+    MMIO = 1;
+ }
+
+message CpuidEntry  {
+    uint32 function = 1;
+    bool has_index = 3;
+    uint32 index = 4;
+    uint32 eax = 5;
+    uint32 ebx = 6;
+    uint32 ecx = 7;
+    uint32 edx = 8;
+}
+
+// A request made to the crosvm main process that affects the global aspects of the VM.
+message MainRequest {
+    // Every message under the Create namespace will instantiate an object with the given ID. The
+    // type of object is determined by the oneof constructor field.
+    message Create {
+        message IoEvent {
+            AddressSpace space = 1;
+            uint64 address = 2;
+            uint32 length = 3;
+            uint64 datamatch = 4;
+        }
+
+        message Memory {
+            uint64 offset = 1;
+            uint64 start = 2;
+            uint64 length = 3;
+            bool read_only = 4;
+            // Must be true for the MemoryDirtyLog method to work on this object.
+            bool dirty_log = 5;
+        }
+
+        message IrqEvent {
+            uint32 irq_id = 1;
+            bool resample = 2;
+        }
+
+        uint32 id = 1;
+        oneof constructor {
+            IoEvent io_event = 2;
+            // This message also requires a memfd sent over the socket.
+            Memory memory = 3;
+            IrqEvent irq_event = 4;
+        }
+    }
+
+    // No matter what the type an object is, it can be destroyed using this common method.
+    message Destroy {
+        uint32 id = 1;
+    }
+
+    message NewConnection {}
+
+    message GetShutdownEventfd {}
+
+    message CheckExtension {
+        uint32 extension = 1;
+    }
+
+    message CpuidRequest {
+    }
+
+    message MsrListRequest {
+    }
+
+    message GetNetConfig {}
+
+    message ReserveRange {
+        AddressSpace space = 1;
+        uint64 start = 2;
+        uint64 length = 3;
+    }
+
+    message SetIrq {
+        uint32 irq_id = 1;
+        bool active = 2;
+    }
+
+    message SetIrqRouting {
+        message Route {
+            message Irqchip {
+                uint32 irqchip = 1;
+                uint32 pin = 2;
+            }
+
+            message Msi {
+                uint64 address = 1;
+                uint32 data = 2;
+            }
+
+            uint32 irq_id = 1;
+            oneof route {
+                Irqchip irqchip = 2;
+                Msi msi = 3;
+            }
+        }
+
+        repeated Route routes = 1;
+    }
+
+    // Each type refers to certain piece of VM state (such as PIT state).
+    // The structure of the data corresponds to the kvm structure.
+    enum StateSet {
+        // struct kvm_pic_state
+        PIC0 = 0;
+        // struct kvm_pic_state
+        PIC1 = 1;
+        // struct kvm_ioapic_state
+        IOAPIC = 2;
+        // struct kvm_pit_state2
+        PIT = 3;
+        // struct kvm_clock_data
+        CLOCK = 4;
+    }
+
+    message GetState {
+        StateSet set = 1;
+    }
+
+    message SetState {
+        StateSet set = 1;
+        // The in memory representation of certain state, depending on the value
+        // of the StateSet.
+        bytes state = 2;
+    }
+
+    message SetIdentityMapAddr {
+        uint32 address = 1;
+    }
+
+    message PauseVcpus {
+        uint64 cpu_mask = 1;
+        uint64 user = 2;
+    }
+
+    message GetVcpus {}
+    message Start {}
+
+    message MemoryDirtyLog {
+        uint32 id = 1;
+    }
+
+    // The type of the message is determined by which of these oneof fields is present in the
+    // protobuf.
+    oneof message {
+        // Common method for instantiating a new object of any type.
+        Create create = 1;
+        // Common method for destroying an object of any type.
+        Destroy destroy = 2;
+        NewConnection new_connection = 3;
+        GetShutdownEventfd get_shutdown_eventfd = 4;
+        CheckExtension check_extension = 5;
+        CpuidRequest get_supported_cpuid = 6;
+        CpuidRequest get_emulated_cpuid = 7;
+        MsrListRequest get_msr_index_list = 8;
+        GetNetConfig get_net_config = 9;
+        ReserveRange reserve_range = 10;
+        SetIrq set_irq = 11;
+        SetIrqRouting set_irq_routing = 12;
+        GetState get_state = 13;
+        SetState set_state = 14;
+        SetIdentityMapAddr set_identity_map_addr = 15;
+        PauseVcpus pause_vcpus = 16;
+        GetVcpus get_vcpus = 17;
+        Start start = 18;
+        // Method for a Memory type object for retrieving the dirty bitmap. Only valid if the memory
+        // object was created with dirty_log set.
+        MemoryDirtyLog dirty_log = 101;
+    }
+}
+
+message MainResponse {
+    // Depending on the object that was created, an fd might also come from the socket.
+    message Create {}
+    message Destroy {}
+    // NewMessage receives a socket fd along with the data from reading this socket.
+    // The returned socket can be used totally independently of the original socket, and can perform
+    // requests and responses independent of the other sockets.
+    message NewConnection {}
+    message GetShutdownEventfd {}
+    message CheckExtension {
+        bool has_extension = 1;
+    }
+    message CpuidResponse {
+        repeated CpuidEntry entries = 1;
+    }
+    message MsrListResponse {
+        repeated uint32 indices = 1;
+    }
+
+    // GetNetConfig messages also return a file descriptor for the tap device.
+    message GetNetConfig {
+        bytes host_mac_address = 1;
+        fixed32 host_ipv4_address = 2;
+        fixed32 netmask = 3;
+    }
+
+    message ReserveRange {}
+    message SetIrq {}
+    message SetIrqRouting {}
+    message GetState {
+        // The in memory representation of a state, depending on what StateSet was
+        // requested in GetState.
+        bytes state = 1;
+    }
+    message SetState {}
+    message SetIdentityMapAddr {}
+    message PauseVcpus {}
+    // This message should also receive a socket fd per VCPU along with the data from reading this
+    // socket. The VcpuRequest/VcpuResponse protocol is run over each of the returned fds.
+    message GetVcpus {}
+    message Start {}
+    message MemoryDirtyLog {
+        bytes bitmap = 1;
+    }
+
+    // This is zero on success, and a negative integer on failure.
+    sint32 errno = 1;
+    // The field present here is always the same as the one present in the corresponding
+    // MainRequest.
+    oneof message {
+        Create create = 2;
+        Destroy destroy = 3;
+        NewConnection new_connection = 4;
+        GetShutdownEventfd get_shutdown_eventfd = 5;
+        CheckExtension check_extension = 6;
+        CpuidResponse get_supported_cpuid = 7;
+        CpuidResponse get_emulated_cpuid = 8;
+        MsrListResponse get_msr_index_list = 9;
+        GetNetConfig get_net_config = 10;
+        ReserveRange reserve_range = 11;
+        SetIrq set_irq = 12;
+        SetIrqRouting set_irq_routing = 13;
+        GetState get_state = 14;
+        SetState set_state = 15;
+        SetIdentityMapAddr set_identity_map_addr = 16;
+        PauseVcpus pause_vcpus = 17;
+        GetVcpus get_vcpus = 18;
+        Start start = 19;
+        MemoryDirtyLog dirty_log = 101;
+    }
+}
+
+// A request made for a specific VCPU. These requests are sent over the sockets returned from the
+// GetVcpu MainRequest.
+message VcpuRequest {
+    // This message will block until a non-empty response can be sent. The first response will
+    // always be an Init wait reason.
+    message Wait {
+    }
+
+    message Resume {
+        // The data is only necessary for non-write (read) I/O accesses. In all other cases, data is
+        // ignored.
+        bytes data = 1;
+    }
+
+    // Each type refers to certain piece of VCPU state (a set registers, or something else).
+    // The structure of the data corresponds to the kvm structure.
+    enum StateSet {
+        // struct kvm_regs
+        REGS = 0;
+        // struct kvm_sregs
+        SREGS = 1;
+        // struct kvm_fpu
+        FPU = 2;
+        // struct kvm_debugregs
+        DEBUGREGS = 3;
+        // struct kvm_lapic_state
+        LAPIC = 4;
+        // struct kvm_mp_state
+        MP = 5;
+        // struct kvm_xcrs
+        XCREGS = 6;
+        // struct kvm_vcpu_events
+        EVENTS = 7;
+    }
+
+    message GetState {
+        StateSet set = 1;
+    }
+
+    message SetState {
+        StateSet set = 1;
+        // The in memory representation of a struct kvm_regs, struct kvm_sregs,
+        // struct kvm_fpu, struct kvm_debugregs, struct kvm_lapic_state,
+        // struct kvm_mp_state, struct kvm_xcrs or struct kvm_vcpu_events
+        // depending on the value of the StateSet.
+        bytes state = 2;
+    }
+
+    message GetMsrs {
+        // The entry data will be returned in the same order as this in the
+        // VcpuResponse::GetMsrs::entry_data array.
+        repeated uint32 entry_indices = 1;
+    }
+
+    message MsrEntry {
+        uint32 index = 1;
+        uint64 data = 2;
+    }
+
+    message SetMsrs {
+        repeated MsrEntry entries = 1;
+    }
+
+    message SetCpuid {
+        repeated CpuidEntry entries = 1;
+    }
+
+    message Shutdown {
+    }
+
+    // The type of the message is determined by which of these oneof fields is present in the
+    // protobuf.
+    oneof message {
+        Wait wait = 1;
+        Resume resume = 2;
+        GetState get_state = 3;
+        SetState set_state = 4;
+        GetMsrs get_msrs = 5;
+        SetMsrs set_msrs = 6;
+        SetCpuid set_cpuid = 7;
+        Shutdown shutdown = 8;
+    }
+}
+
+
+message VcpuResponse  {
+    // Depending on the reason a VCPU has exited, the Wait request will unblock and return a field
+    // in the oneof exit. This is called the "wait reason."
+    message Wait {
+        // This request will always be the first wait reason returend by the first wait request.
+        message Init {
+        }
+
+        // This type of wait reason is only generated if the access occurred on this VCPU on an
+        // address previously reserved by a ReserveRange main request.
+        message Io {
+            AddressSpace space = 1;
+            uint64 address = 2;
+            bool is_write = 3;
+            bytes data = 4;
+        }
+
+        // This type of wait reason is only generated after a PuaseVcpus request on this VCPU.
+        message User {
+            uint64 user = 1;
+        }
+
+        oneof exit {
+            Init init = 1;
+            Io io = 2;
+            User user = 3;
+        }
+    }
+
+    message Resume {}
+
+    message GetState {
+        // The in memory representation of a struct kvm_regs, struct kvm_sregs,
+        // struct kvm_fpu, struct kvm_debugregs, struct kvm_lapic_state,
+        // struct kvm_mp_state, struct kvm_xcrs or struct kvm_vcpu_events
+        // depending on the value of the StateSet.
+        bytes state = 1;
+    }
+
+    message SetState {
+    }
+
+    message GetMsrs {
+        // The order of the entry_data values is the same order as the array of indices given in the
+        // corresponding request.
+        repeated uint64 entry_data = 1;
+    }
+
+    message SetMsrs {}
+
+    message SetCpuid {}
+
+    // This is zero on success, and a negative integer on failure.
+    sint32 errno = 1;
+    // The field present here is always the same as the one present in the corresponding
+    // VcpuRequest.
+    oneof message {
+        Wait wait = 2;
+        Resume resume = 3;
+        GetState get_state = 4;
+        SetState set_state = 5;
+        GetMsrs get_msrs = 6;
+        SetMsrs set_msrs = 7;
+        SetCpuid set_cpuid = 8;
+    }
+}
diff --git a/protos/src/plugin.rs b/protos/src/plugin.rs
new file mode 100644
index 0000000..ce491e7
--- /dev/null
+++ b/protos/src/plugin.rs
@@ -0,0 +1,36 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+pub use crate::generated::plugin::*;
+
+/// Converts protobuf representation of CpuId data into KVM format.
+pub fn cpuid_proto_to_kvm(entry: &CpuidEntry) -> kvm_sys::kvm_cpuid_entry2 {
+    // Safe: C structures are expected to be zero-initialized.
+    let mut e: kvm_sys::kvm_cpuid_entry2 = unsafe { std::mem::zeroed() };
+    e.function = entry.function;
+    if entry.has_index {
+        e.flags = kvm_sys::KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+    }
+    e.index = entry.index;
+    e.eax = entry.eax;
+    e.ebx = entry.ebx;
+    e.ecx = entry.ecx;
+    e.edx = entry.edx;
+
+    e
+}
+
+/// Converts KVM representation of CpuId data into protobuf format.
+pub fn cpuid_kvm_to_proto(entry: &kvm_sys::kvm_cpuid_entry2) -> CpuidEntry {
+    let mut e = CpuidEntry::new();
+    e.function = entry.function;
+    e.has_index = entry.flags & kvm_sys::KVM_CPUID_FLAG_SIGNIFCANT_INDEX != 0;
+    e.index = entry.index;
+    e.eax = entry.eax;
+    e.ebx = entry.ebx;
+    e.ecx = entry.ecx;
+    e.edx = entry.edx;
+
+    e
+}
diff --git a/protos/tests/common/mod.rs b/protos/tests/common/mod.rs
new file mode 100644
index 0000000..a5aaf07
--- /dev/null
+++ b/protos/tests/common/mod.rs
@@ -0,0 +1,35 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use protobuf::Message;
+
+/// Asserts that a given protobuf message object can be serialized to bytes and
+/// read back into a value of the same type, preserving equality between the
+/// original object and the one read back.
+///
+/// This is helpful for confirming that proto files have been compiled
+/// successfully and are exposed as intended by the public API of the parent
+/// crate. It also lets us exercise the full set of methods we intend to use for
+/// building particular proto objects so that we notice breakage early in the
+/// event that a proto external to this repository would make a breaking change.
+///
+/// Note: assumes that the given `message` is not just `T::new` so that we can
+/// tell that deserialization has happened successfully.
+///
+/// # Example
+///
+/// ```ignore
+/// let mut request = SendCommandRequest::new();
+/// request.set_command(b"...".to_vec());
+/// test_round_trip(request);
+/// ```
+pub fn test_round_trip<T: Message + PartialEq>(message: T) {
+    let serialized = message.write_to_bytes().unwrap();
+
+    let mut back = T::new();
+    assert_ne!(message, back);
+
+    back.merge_from_bytes(&serialized).unwrap();
+    assert_eq!(message, back);
+}
diff --git a/protos/tests/trunks.rs b/protos/tests/trunks.rs
new file mode 100644
index 0000000..39723ae
--- /dev/null
+++ b/protos/tests/trunks.rs
@@ -0,0 +1,24 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![cfg(feature = "trunks")]
+
+mod common;
+
+use crate::common::test_round_trip;
+use protos::trunks::{SendCommandRequest, SendCommandResponse};
+
+#[test]
+fn send_command_request() {
+    let mut request = SendCommandRequest::new();
+    request.set_command(b"...".to_vec());
+    test_round_trip(request);
+}
+
+#[test]
+fn send_command_response() {
+    let mut response = SendCommandResponse::new();
+    response.set_response(b"...".to_vec());
+    test_round_trip(response);
+}
diff --git a/qcow/Cargo.toml b/qcow/Cargo.toml
new file mode 100644
index 0000000..0c521fd
--- /dev/null
+++ b/qcow/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "qcow"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[lib]
+path = "src/qcow.rs"
+
+[dependencies]
+byteorder = "*"
+libc = "*"
+remain = "*"
+sys_util = { path = "../sys_util" }
+data_model = { path = "../data_model" }
\ No newline at end of file
diff --git a/qcow/src/qcow.rs b/qcow/src/qcow.rs
new file mode 100644
index 0000000..4aeb7e3
--- /dev/null
+++ b/qcow/src/qcow.rs
@@ -0,0 +1,2483 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+mod qcow_raw_file;
+mod refcount;
+mod vec_cache;
+
+use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
+use data_model::{VolatileMemory, VolatileSlice};
+use libc::{EINVAL, ENOSPC, ENOTSUP};
+use remain::sorted;
+use sys_util::{
+    error, FileReadWriteVolatile, FileSetLen, FileSync, PunchHole, SeekHole, WriteZeroes,
+};
+
+use std::cmp::min;
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::io::{self, Read, Seek, SeekFrom, Write};
+use std::mem::size_of;
+use std::os::unix::io::{AsRawFd, RawFd};
+
+use crate::qcow_raw_file::QcowRawFile;
+use crate::refcount::RefCount;
+use crate::vec_cache::{CacheMap, Cacheable, VecCache};
+
+#[sorted]
+#[derive(Debug)]
+pub enum Error {
+    BackingFilesNotSupported,
+    CompressedBlocksNotSupported,
+    EvictingCache(io::Error),
+    FileTooBig(u64),
+    GettingFileSize(io::Error),
+    GettingRefcount(refcount::Error),
+    InvalidClusterIndex,
+    InvalidClusterSize,
+    InvalidIndex,
+    InvalidL1TableOffset,
+    InvalidMagic,
+    InvalidOffset(u64),
+    InvalidRefcountTableOffset,
+    InvalidRefcountTableSize(u64),
+    NoFreeClusters,
+    NoRefcountClusters,
+    NotEnoughSpaceForRefcounts,
+    OpeningFile(io::Error),
+    ReadingData(io::Error),
+    ReadingHeader(io::Error),
+    ReadingPointers(io::Error),
+    ReadingRefCountBlock(refcount::Error),
+    ReadingRefCounts(io::Error),
+    RebuildingRefCounts(io::Error),
+    SeekingFile(io::Error),
+    SettingFileSize(io::Error),
+    SettingRefcountRefcount(io::Error),
+    SizeTooSmallForNumberOfClusters,
+    TooManyL1Entries(u64),
+    TooManyRefcounts(u64),
+    UnsupportedRefcountOrder,
+    UnsupportedVersion(u32),
+    WritingData(io::Error),
+    WritingHeader(io::Error),
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    #[remain::check]
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        #[sorted]
+        match self {
+            BackingFilesNotSupported => write!(f, "backing files not supported"),
+            CompressedBlocksNotSupported => write!(f, "compressed blocks not supported"),
+            EvictingCache(e) => write!(f, "failed to evict cache: {}", e),
+            FileTooBig(size) => write!(f, "file larger than max of 1TB: {}", size),
+            GettingFileSize(e) => write!(f, "failed to get file size: {}", e),
+            GettingRefcount(e) => write!(f, "failed to get refcount: {}", e),
+            InvalidClusterIndex => write!(f, "invalid cluster index"),
+            InvalidClusterSize => write!(f, "invalid cluster size"),
+            InvalidIndex => write!(f, "invalid index"),
+            InvalidL1TableOffset => write!(f, "invalid L1 table offset"),
+            InvalidMagic => write!(f, "invalid magic"),
+            InvalidOffset(_) => write!(f, "invalid offset"),
+            InvalidRefcountTableOffset => write!(f, "invalid refcount table offset"),
+            InvalidRefcountTableSize(size) => write!(f, "invalid refcount table size: {}", size),
+            NoFreeClusters => write!(f, "no free clusters"),
+            NoRefcountClusters => write!(f, "no refcount clusters"),
+            NotEnoughSpaceForRefcounts => write!(f, "not enough space for refcounts"),
+            OpeningFile(e) => write!(f, "failed to open file: {}", e),
+            ReadingData(e) => write!(f, "failed to read data: {}", e),
+            ReadingHeader(e) => write!(f, "failed to read header: {}", e),
+            ReadingPointers(e) => write!(f, "failed to read pointers: {}", e),
+            ReadingRefCountBlock(e) => write!(f, "failed to read ref count block: {}", e),
+            ReadingRefCounts(e) => write!(f, "failed to read ref counts: {}", e),
+            RebuildingRefCounts(e) => write!(f, "failed to rebuild ref counts: {}", e),
+            SeekingFile(e) => write!(f, "failed to seek file: {}", e),
+            SettingFileSize(e) => write!(f, "failed to set file size: {}", e),
+            SettingRefcountRefcount(e) => write!(f, "failed to set refcount refcount: {}", e),
+            SizeTooSmallForNumberOfClusters => write!(f, "size too small for number of clusters"),
+            TooManyL1Entries(count) => write!(f, "l1 entry table too large: {}", count),
+            TooManyRefcounts(count) => write!(f, "ref count table too large: {}", count),
+            UnsupportedRefcountOrder => write!(f, "unsupported refcount order"),
+            UnsupportedVersion(v) => write!(f, "unsupported version: {}", v),
+            WritingData(e) => write!(f, "failed to write data: {}", e),
+            WritingHeader(e) => write!(f, "failed to write header: {}", e),
+        }
+    }
+}
+
+pub enum ImageType {
+    Raw,
+    Qcow2,
+}
+
+// QCOW magic constant that starts the header.
+const QCOW_MAGIC: u32 = 0x5146_49fb;
+// Default to a cluster size of 2^DEFAULT_CLUSTER_BITS
+const DEFAULT_CLUSTER_BITS: u32 = 16;
+// Limit clusters to reasonable sizes. Choose the same limits as qemu. Making the clusters smaller
+// increases the amount of overhead for book keeping.
+const MIN_CLUSTER_BITS: u32 = 9;
+const MAX_CLUSTER_BITS: u32 = 21;
+// The L1 and RefCount table are kept in RAM, only handle files that require less than 35M entries.
+// This easily covers 1 TB files. When support for bigger files is needed the assumptions made to
+// keep these tables in RAM needs to be thrown out.
+const MAX_RAM_POINTER_TABLE_SIZE: u64 = 35_000_000;
+// Only support 2 byte refcounts, 2^refcount_order bits.
+const DEFAULT_REFCOUNT_ORDER: u32 = 4;
+
+const V3_BARE_HEADER_SIZE: u32 = 104;
+
+// bits 0-8 and 56-63 are reserved.
+const L1_TABLE_OFFSET_MASK: u64 = 0x00ff_ffff_ffff_fe00;
+const L2_TABLE_OFFSET_MASK: u64 = 0x00ff_ffff_ffff_fe00;
+// Flags
+const COMPRESSED_FLAG: u64 = 1 << 62;
+const CLUSTER_USED_FLAG: u64 = 1 << 63;
+const COMPATIBLE_FEATURES_LAZY_REFCOUNTS: u64 = 1 << 0;
+
+/// Contains the information from the header of a qcow file.
+#[derive(Copy, Clone, Debug)]
+pub struct QcowHeader {
+    pub magic: u32,
+    pub version: u32,
+
+    pub backing_file_offset: u64,
+    pub backing_file_size: u32,
+
+    pub cluster_bits: u32,
+    pub size: u64,
+    pub crypt_method: u32,
+
+    pub l1_size: u32,
+    pub l1_table_offset: u64,
+
+    pub refcount_table_offset: u64,
+    pub refcount_table_clusters: u32,
+
+    pub nb_snapshots: u32,
+    pub snapshots_offset: u64,
+
+    // v3 entries
+    pub incompatible_features: u64,
+    pub compatible_features: u64,
+    pub autoclear_features: u64,
+    pub refcount_order: u32,
+    pub header_size: u32,
+}
+
+impl QcowHeader {
+    /// Creates a QcowHeader from a reference to a file.
+    pub fn new(f: &mut File) -> Result<QcowHeader> {
+        f.seek(SeekFrom::Start(0)).map_err(Error::ReadingHeader)?;
+        let magic = f.read_u32::<BigEndian>().map_err(Error::ReadingHeader)?;
+        if magic != QCOW_MAGIC {
+            return Err(Error::InvalidMagic);
+        }
+
+        // Reads the next u32 from the file.
+        fn read_u32_from_file(f: &mut File) -> Result<u32> {
+            f.read_u32::<BigEndian>().map_err(Error::ReadingHeader)
+        }
+
+        // Reads the next u64 from the file.
+        fn read_u64_from_file(f: &mut File) -> Result<u64> {
+            f.read_u64::<BigEndian>().map_err(Error::ReadingHeader)
+        }
+
+        Ok(QcowHeader {
+            magic,
+            version: read_u32_from_file(f)?,
+            backing_file_offset: read_u64_from_file(f)?,
+            backing_file_size: read_u32_from_file(f)?,
+            cluster_bits: read_u32_from_file(f)?,
+            size: read_u64_from_file(f)?,
+            crypt_method: read_u32_from_file(f)?,
+            l1_size: read_u32_from_file(f)?,
+            l1_table_offset: read_u64_from_file(f)?,
+            refcount_table_offset: read_u64_from_file(f)?,
+            refcount_table_clusters: read_u32_from_file(f)?,
+            nb_snapshots: read_u32_from_file(f)?,
+            snapshots_offset: read_u64_from_file(f)?,
+            incompatible_features: read_u64_from_file(f)?,
+            compatible_features: read_u64_from_file(f)?,
+            autoclear_features: read_u64_from_file(f)?,
+            refcount_order: read_u32_from_file(f)?,
+            header_size: read_u32_from_file(f)?,
+        })
+    }
+
+    /// Create a header for the given `size`.
+    pub fn create_for_size(size: u64) -> QcowHeader {
+        let cluster_bits: u32 = DEFAULT_CLUSTER_BITS;
+        let cluster_size: u32 = 0x01 << cluster_bits;
+        // L2 blocks are always one cluster long. They contain cluster_size/sizeof(u64) addresses.
+        let l2_size: u32 = cluster_size / size_of::<u64>() as u32;
+        let num_clusters: u32 = div_round_up_u64(size, u64::from(cluster_size)) as u32;
+        let num_l2_clusters: u32 = div_round_up_u32(num_clusters, l2_size);
+        let l1_clusters: u32 = div_round_up_u32(num_l2_clusters, cluster_size);
+        let header_clusters = div_round_up_u32(size_of::<QcowHeader>() as u32, cluster_size);
+        QcowHeader {
+            magic: QCOW_MAGIC,
+            version: 3,
+            backing_file_offset: 0,
+            backing_file_size: 0,
+            cluster_bits: DEFAULT_CLUSTER_BITS,
+            size,
+            crypt_method: 0,
+            l1_size: num_l2_clusters,
+            l1_table_offset: u64::from(cluster_size),
+            // The refcount table is after l1 + header.
+            refcount_table_offset: u64::from(cluster_size * (l1_clusters + 1)),
+            refcount_table_clusters: {
+                // Pre-allocate enough clusters for the entire refcount table as it must be
+                // continuous in the file. Allocate enough space to refcount all clusters, including
+                // the refcount clusters.
+                let max_refcount_clusters = max_refcount_clusters(
+                    DEFAULT_REFCOUNT_ORDER,
+                    cluster_size,
+                    num_clusters + l1_clusters + num_l2_clusters + header_clusters,
+                ) as u32;
+                // The refcount table needs to store the offset of each refcount cluster.
+                div_round_up_u32(
+                    max_refcount_clusters * size_of::<u64>() as u32,
+                    cluster_size,
+                )
+            },
+            nb_snapshots: 0,
+            snapshots_offset: 0,
+            incompatible_features: 0,
+            compatible_features: 0,
+            autoclear_features: 0,
+            refcount_order: DEFAULT_REFCOUNT_ORDER,
+            header_size: V3_BARE_HEADER_SIZE,
+        }
+    }
+
+    /// Write the header to `file`.
+    pub fn write_to<F: Write + Seek>(&self, file: &mut F) -> Result<()> {
+        // Writes the next u32 to the file.
+        fn write_u32_to_file<F: Write>(f: &mut F, value: u32) -> Result<()> {
+            f.write_u32::<BigEndian>(value)
+                .map_err(Error::WritingHeader)
+        }
+
+        // Writes the next u64 to the file.
+        fn write_u64_to_file<F: Write>(f: &mut F, value: u64) -> Result<()> {
+            f.write_u64::<BigEndian>(value)
+                .map_err(Error::WritingHeader)
+        }
+
+        write_u32_to_file(file, self.magic)?;
+        write_u32_to_file(file, self.version)?;
+        write_u64_to_file(file, self.backing_file_offset)?;
+        write_u32_to_file(file, self.backing_file_size)?;
+        write_u32_to_file(file, self.cluster_bits)?;
+        write_u64_to_file(file, self.size)?;
+        write_u32_to_file(file, self.crypt_method)?;
+        write_u32_to_file(file, self.l1_size)?;
+        write_u64_to_file(file, self.l1_table_offset)?;
+        write_u64_to_file(file, self.refcount_table_offset)?;
+        write_u32_to_file(file, self.refcount_table_clusters)?;
+        write_u32_to_file(file, self.nb_snapshots)?;
+        write_u64_to_file(file, self.snapshots_offset)?;
+        write_u64_to_file(file, self.incompatible_features)?;
+        write_u64_to_file(file, self.compatible_features)?;
+        write_u64_to_file(file, self.autoclear_features)?;
+        write_u32_to_file(file, self.refcount_order)?;
+        write_u32_to_file(file, self.header_size)?;
+
+        // Set the file length by seeking and writing a zero to the last byte. This avoids needing
+        // a `File` instead of anything that implements seek as the `file` argument.
+        // Zeros out the l1 and refcount table clusters.
+        let cluster_size = 0x01u64 << self.cluster_bits;
+        let refcount_blocks_size = u64::from(self.refcount_table_clusters) * cluster_size;
+        file.seek(SeekFrom::Start(
+            self.refcount_table_offset + refcount_blocks_size - 2,
+        ))
+        .map_err(Error::WritingHeader)?;
+        file.write(&[0u8]).map_err(Error::WritingHeader)?;
+
+        Ok(())
+    }
+}
+
+fn max_refcount_clusters(refcount_order: u32, cluster_size: u32, num_clusters: u32) -> u64 {
+    // Use u64 as the product of the u32 inputs can overflow.
+    let refcount_bytes = (0x01 << refcount_order as u64) / 8;
+    let for_data = div_round_up_u64(num_clusters as u64 * refcount_bytes, cluster_size as u64);
+    let for_refcounts = div_round_up_u64(for_data * refcount_bytes, cluster_size as u64);
+    for_data + for_refcounts
+}
+
+/// Represents a qcow2 file. This is a sparse file format maintained by the qemu project.
+/// Full documentation of the format can be found in the qemu repository.
+///
+/// # Example
+///
+/// ```
+/// # use std::io::{Read, Seek, SeekFrom};
+/// # use qcow::{self, QcowFile};
+/// # fn test(file: std::fs::File) -> std::io::Result<()> {
+///     let mut q = QcowFile::from(file).expect("Can't open qcow file");
+///     let mut buf = [0u8; 12];
+///     q.seek(SeekFrom::Start(10 as u64))?;
+///     q.read(&mut buf[..])?;
+/// #   Ok(())
+/// # }
+/// ```
+#[derive(Debug)]
+pub struct QcowFile {
+    raw_file: QcowRawFile,
+    header: QcowHeader,
+    l1_table: VecCache<u64>,
+    l2_entries: u64,
+    l2_cache: CacheMap<VecCache<u64>>,
+    refcounts: RefCount,
+    current_offset: u64,
+    unref_clusters: Vec<u64>, // List of freshly unreferenced clusters.
+    // List of unreferenced clusters available to be used. unref clusters become available once the
+    // removal of references to them have been synced to disk.
+    avail_clusters: Vec<u64>,
+    //TODO(dgreid) Add support for backing files. - backing_file: Option<Box<QcowFile<T>>>,
+}
+
+impl QcowFile {
+    /// Creates a QcowFile from `file`. File must be a valid qcow2 image.
+    pub fn from(mut file: File) -> Result<QcowFile> {
+        let header = QcowHeader::new(&mut file)?;
+
+        // Only v3 files are supported.
+        if header.version != 3 {
+            return Err(Error::UnsupportedVersion(header.version));
+        }
+
+        let cluster_bits: u32 = header.cluster_bits;
+        if cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS {
+            return Err(Error::InvalidClusterSize);
+        }
+        let cluster_size = 0x01u64 << cluster_bits;
+
+        // No current support for backing files.
+        if header.backing_file_offset != 0 {
+            return Err(Error::BackingFilesNotSupported);
+        }
+
+        // Only support two byte refcounts.
+        let refcount_bits: u64 = 0x01u64
+            .checked_shl(header.refcount_order)
+            .ok_or(Error::UnsupportedRefcountOrder)?;
+        if refcount_bits != 16 {
+            return Err(Error::UnsupportedRefcountOrder);
+        }
+        let refcount_bytes = (refcount_bits + 7) / 8;
+
+        // Need at least one refcount cluster
+        if header.refcount_table_clusters == 0 {
+            return Err(Error::NoRefcountClusters);
+        }
+        offset_is_cluster_boundary(header.backing_file_offset, header.cluster_bits)?;
+        offset_is_cluster_boundary(header.l1_table_offset, header.cluster_bits)?;
+        offset_is_cluster_boundary(header.refcount_table_offset, header.cluster_bits)?;
+        offset_is_cluster_boundary(header.snapshots_offset, header.cluster_bits)?;
+
+        // The first cluster should always have a non-zero refcount, so if it is 0,
+        // this is an old file with broken refcounts, which requires a rebuild.
+        let mut refcount_rebuild_required = true;
+        file.seek(SeekFrom::Start(header.refcount_table_offset))
+            .map_err(Error::SeekingFile)?;
+        let first_refblock_addr = file.read_u64::<BigEndian>().map_err(Error::ReadingHeader)?;
+        if first_refblock_addr != 0 {
+            file.seek(SeekFrom::Start(first_refblock_addr))
+                .map_err(Error::SeekingFile)?;
+            let first_cluster_refcount =
+                file.read_u16::<BigEndian>().map_err(Error::ReadingHeader)?;
+            if first_cluster_refcount != 0 {
+                refcount_rebuild_required = false;
+            }
+        }
+
+        if (header.compatible_features & COMPATIBLE_FEATURES_LAZY_REFCOUNTS) != 0 {
+            refcount_rebuild_required = true;
+        }
+
+        let mut raw_file =
+            QcowRawFile::from(file, cluster_size).ok_or(Error::InvalidClusterSize)?;
+        if refcount_rebuild_required {
+            QcowFile::rebuild_refcounts(&mut raw_file, header)?;
+        }
+
+        let l2_size = cluster_size / size_of::<u64>() as u64;
+        let num_clusters = div_round_up_u64(header.size, cluster_size);
+        let num_l2_clusters = div_round_up_u64(num_clusters, l2_size);
+        let l1_clusters = div_round_up_u64(num_l2_clusters, cluster_size);
+        let header_clusters = div_round_up_u64(size_of::<QcowHeader>() as u64, cluster_size);
+        if num_l2_clusters > MAX_RAM_POINTER_TABLE_SIZE {
+            return Err(Error::TooManyL1Entries(num_l2_clusters));
+        }
+        let l1_table = VecCache::from_vec(
+            raw_file
+                .read_pointer_table(
+                    header.l1_table_offset,
+                    num_l2_clusters,
+                    Some(L1_TABLE_OFFSET_MASK),
+                )
+                .map_err(Error::ReadingHeader)?,
+        );
+
+        let num_clusters = div_round_up_u64(header.size, cluster_size);
+        let refcount_clusters = max_refcount_clusters(
+            header.refcount_order,
+            cluster_size as u32,
+            (num_clusters + l1_clusters + num_l2_clusters + header_clusters) as u32,
+        );
+        if l1_clusters + refcount_clusters > MAX_RAM_POINTER_TABLE_SIZE {
+            return Err(Error::TooManyRefcounts(refcount_clusters));
+        }
+        let refcount_block_entries = cluster_size / refcount_bytes;
+        let refcounts = RefCount::new(
+            &mut raw_file,
+            header.refcount_table_offset,
+            refcount_clusters,
+            refcount_block_entries,
+            cluster_size,
+        )
+        .map_err(Error::ReadingRefCounts)?;
+
+        let l2_entries = cluster_size / size_of::<u64>() as u64;
+
+        let mut qcow = QcowFile {
+            raw_file,
+            header,
+            l1_table,
+            l2_entries,
+            l2_cache: CacheMap::new(100),
+            refcounts,
+            current_offset: 0,
+            unref_clusters: Vec::new(),
+            avail_clusters: Vec::new(),
+        };
+
+        // Check that the L1 and refcount tables fit in a 64bit address space.
+        qcow.header
+            .l1_table_offset
+            .checked_add(qcow.l1_address_offset(qcow.virtual_size()))
+            .ok_or(Error::InvalidL1TableOffset)?;
+        qcow.header
+            .refcount_table_offset
+            .checked_add(u64::from(qcow.header.refcount_table_clusters) * cluster_size)
+            .ok_or(Error::InvalidRefcountTableOffset)?;
+
+        qcow.find_avail_clusters()?;
+
+        Ok(qcow)
+    }
+
+    /// Creates a new QcowFile at the given path.
+    pub fn new(mut file: File, virtual_size: u64) -> Result<QcowFile> {
+        let header = QcowHeader::create_for_size(virtual_size);
+        file.seek(SeekFrom::Start(0)).map_err(Error::SeekingFile)?;
+        header.write_to(&mut file)?;
+
+        let mut qcow = Self::from(file)?;
+
+        // Set the refcount for each refcount table cluster.
+        let cluster_size = 0x01u64 << qcow.header.cluster_bits;
+        let refcount_table_base = qcow.header.refcount_table_offset as u64;
+        let end_cluster_addr =
+            refcount_table_base + u64::from(qcow.header.refcount_table_clusters) * cluster_size;
+
+        let mut cluster_addr = 0;
+        while cluster_addr < end_cluster_addr {
+            let mut unref_clusters = qcow
+                .set_cluster_refcount(cluster_addr, 1)
+                .map_err(Error::SettingRefcountRefcount)?;
+            qcow.unref_clusters.append(&mut unref_clusters);
+            cluster_addr += cluster_size;
+        }
+
+        Ok(qcow)
+    }
+
+    /// Returns the `QcowHeader` for this file.
+    pub fn header(&self) -> &QcowHeader {
+        &self.header
+    }
+
+    /// Returns the L1 lookup table for this file. This is only useful for debugging.
+    pub fn l1_table(&self) -> &[u64] {
+        &self.l1_table.get_values()
+    }
+
+    /// Returns an L2_table of cluster addresses, only used for debugging.
+    pub fn l2_table(&mut self, l1_index: usize) -> Result<Option<&[u64]>> {
+        let l2_addr_disk = *self.l1_table.get(l1_index).ok_or(Error::InvalidIndex)?;
+
+        if l2_addr_disk == 0 {
+            // Reading from an unallocated cluster will return zeros.
+            return Ok(None);
+        }
+
+        if !self.l2_cache.contains_key(&l1_index) {
+            // Not in the cache.
+            let table = VecCache::from_vec(
+                Self::read_l2_cluster(&mut self.raw_file, l2_addr_disk)
+                    .map_err(Error::ReadingPointers)?,
+            );
+            let l1_table = &self.l1_table;
+            let raw_file = &mut self.raw_file;
+            self.l2_cache
+                .insert(l1_index, table, |index, evicted| {
+                    raw_file.write_pointer_table(
+                        l1_table[index],
+                        evicted.get_values(),
+                        CLUSTER_USED_FLAG,
+                    )
+                })
+                .map_err(Error::EvictingCache)?;
+        }
+
+        // The index must exist as it was just inserted if it didn't already.
+        Ok(Some(self.l2_cache.get(&l1_index).unwrap().get_values()))
+    }
+
+    /// Returns the refcount table for this file. This is only useful for debugging.
+    pub fn ref_table(&self) -> &[u64] {
+        &self.refcounts.ref_table()
+    }
+
+    /// Returns the `index`th refcount block from the file.
+    pub fn refcount_block(&mut self, index: usize) -> Result<Option<&[u16]>> {
+        self.refcounts
+            .refcount_block(&mut self.raw_file, index)
+            .map_err(Error::ReadingRefCountBlock)
+    }
+
+    /// Returns the first cluster in the file with a 0 refcount. Used for testing.
+    pub fn first_zero_refcount(&mut self) -> Result<Option<u64>> {
+        let file_size = self
+            .raw_file
+            .file_mut()
+            .metadata()
+            .map_err(Error::GettingFileSize)?
+            .len();
+        let cluster_size = 0x01u64 << self.header.cluster_bits;
+
+        let mut cluster_addr = 0;
+        while cluster_addr < file_size {
+            let cluster_refcount = self
+                .refcounts
+                .get_cluster_refcount(&mut self.raw_file, cluster_addr)
+                .map_err(Error::GettingRefcount)?;
+            if cluster_refcount == 0 {
+                return Ok(Some(cluster_addr));
+            }
+            cluster_addr += cluster_size;
+        }
+        Ok(None)
+    }
+
+    fn find_avail_clusters(&mut self) -> Result<()> {
+        let cluster_size = self.raw_file.cluster_size();
+
+        let file_size = self
+            .raw_file
+            .file_mut()
+            .metadata()
+            .map_err(Error::GettingFileSize)?
+            .len();
+
+        for i in (0..file_size).step_by(cluster_size as usize) {
+            let refcount = self
+                .refcounts
+                .get_cluster_refcount(&mut self.raw_file, i)
+                .map_err(Error::GettingRefcount)?;
+            if refcount == 0 {
+                self.avail_clusters.push(i);
+            }
+        }
+
+        Ok(())
+    }
+
+    /// Rebuild the reference count tables.
+    fn rebuild_refcounts(raw_file: &mut QcowRawFile, header: QcowHeader) -> Result<()> {
+        fn add_ref(refcounts: &mut [u16], cluster_size: u64, cluster_address: u64) -> Result<()> {
+            let idx = (cluster_address / cluster_size) as usize;
+            if idx >= refcounts.len() {
+                return Err(Error::InvalidClusterIndex);
+            }
+            refcounts[idx] += 1;
+            Ok(())
+        }
+
+        // Add a reference to the first cluster (header plus extensions).
+        fn set_header_refcount(refcounts: &mut [u16], cluster_size: u64) -> Result<()> {
+            add_ref(refcounts, cluster_size, 0)
+        }
+
+        // Add references to the L1 table clusters.
+        fn set_l1_refcounts(
+            refcounts: &mut [u16],
+            header: QcowHeader,
+            cluster_size: u64,
+        ) -> Result<()> {
+            let l1_clusters = div_round_up_u64(header.l1_size as u64, cluster_size);
+            let l1_table_offset = header.l1_table_offset;
+            for i in 0..l1_clusters {
+                add_ref(refcounts, cluster_size, l1_table_offset + i * cluster_size)?;
+            }
+            Ok(())
+        }
+
+        // Traverse the L1 and L2 tables to find all reachable data clusters.
+        fn set_data_refcounts(
+            refcounts: &mut [u16],
+            header: QcowHeader,
+            cluster_size: u64,
+            raw_file: &mut QcowRawFile,
+        ) -> Result<()> {
+            let l1_table = raw_file
+                .read_pointer_table(
+                    header.l1_table_offset,
+                    header.l1_size as u64,
+                    Some(L1_TABLE_OFFSET_MASK),
+                )
+                .map_err(Error::ReadingPointers)?;
+            for l1_index in 0..header.l1_size as usize {
+                let l2_addr_disk = *l1_table.get(l1_index).ok_or(Error::InvalidIndex)?;
+                if l2_addr_disk != 0 {
+                    // Add a reference to the L2 table cluster itself.
+                    add_ref(refcounts, cluster_size, l2_addr_disk)?;
+
+                    // Read the L2 table and find all referenced data clusters.
+                    let l2_table = raw_file
+                        .read_pointer_table(
+                            l2_addr_disk,
+                            cluster_size / size_of::<u64>() as u64,
+                            Some(L2_TABLE_OFFSET_MASK),
+                        )
+                        .map_err(Error::ReadingPointers)?;
+                    for data_cluster_addr in l2_table {
+                        if data_cluster_addr != 0 {
+                            add_ref(refcounts, cluster_size, data_cluster_addr)?;
+                        }
+                    }
+                }
+            }
+
+            Ok(())
+        }
+
+        // Add references to the top-level refcount table clusters.
+        fn set_refcount_table_refcounts(
+            refcounts: &mut [u16],
+            header: QcowHeader,
+            cluster_size: u64,
+        ) -> Result<()> {
+            let refcount_table_offset = header.refcount_table_offset;
+            for i in 0..header.refcount_table_clusters as u64 {
+                add_ref(
+                    refcounts,
+                    cluster_size,
+                    refcount_table_offset + i * cluster_size,
+                )?;
+            }
+            Ok(())
+        }
+
+        // Allocate clusters for refblocks.
+        // This needs to be done last so that we have the correct refcounts for all other
+        // clusters.
+        fn alloc_refblocks(
+            refcounts: &mut [u16],
+            cluster_size: u64,
+            refblock_clusters: u64,
+            pointers_per_cluster: u64,
+        ) -> Result<Vec<u64>> {
+            let refcount_table_entries = div_round_up_u64(refblock_clusters, pointers_per_cluster);
+            let mut ref_table = vec![0; refcount_table_entries as usize];
+            let mut first_free_cluster: u64 = 0;
+            for refblock_addr in &mut ref_table {
+                while refcounts[first_free_cluster as usize] != 0 {
+                    first_free_cluster += 1;
+                    if first_free_cluster >= refcounts.len() as u64 {
+                        return Err(Error::NotEnoughSpaceForRefcounts);
+                    }
+                }
+
+                *refblock_addr = first_free_cluster * cluster_size;
+                add_ref(refcounts, cluster_size, *refblock_addr)?;
+
+                first_free_cluster += 1;
+            }
+
+            Ok(ref_table)
+        }
+
+        // Write the updated reference count blocks and reftable.
+        fn write_refblocks(
+            refcounts: &[u16],
+            mut header: QcowHeader,
+            ref_table: &[u64],
+            raw_file: &mut QcowRawFile,
+            refcount_block_entries: u64,
+        ) -> Result<()> {
+            // Rewrite the header with lazy refcounts enabled while we are rebuilding the tables.
+            header.compatible_features |= COMPATIBLE_FEATURES_LAZY_REFCOUNTS;
+            raw_file
+                .file_mut()
+                .seek(SeekFrom::Start(0))
+                .map_err(Error::SeekingFile)?;
+            header.write_to(raw_file.file_mut())?;
+
+            for (i, refblock_addr) in ref_table.iter().enumerate() {
+                // Write a block of refcounts to the location indicated by refblock_addr.
+                let refblock_start = i * (refcount_block_entries as usize);
+                let refblock_end = min(
+                    refcounts.len(),
+                    refblock_start + refcount_block_entries as usize,
+                );
+                let refblock = &refcounts[refblock_start..refblock_end];
+                raw_file
+                    .write_refcount_block(*refblock_addr, refblock)
+                    .map_err(Error::WritingHeader)?;
+
+                // If this is the last (partial) cluster, pad it out to a full refblock cluster.
+                if refblock.len() < refcount_block_entries as usize {
+                    let refblock_padding =
+                        vec![0u16; refcount_block_entries as usize - refblock.len()];
+                    raw_file
+                        .write_refcount_block(
+                            *refblock_addr + refblock.len() as u64 * 2,
+                            &refblock_padding,
+                        )
+                        .map_err(Error::WritingHeader)?;
+                }
+            }
+
+            // Rewrite the top-level refcount table.
+            raw_file
+                .write_pointer_table(header.refcount_table_offset, &ref_table, 0)
+                .map_err(Error::WritingHeader)?;
+
+            // Rewrite the header again, now with lazy refcounts disabled.
+            header.compatible_features &= !COMPATIBLE_FEATURES_LAZY_REFCOUNTS;
+            raw_file
+                .file_mut()
+                .seek(SeekFrom::Start(0))
+                .map_err(Error::SeekingFile)?;
+            header.write_to(raw_file.file_mut())?;
+
+            Ok(())
+        }
+
+        let cluster_size = raw_file.cluster_size();
+
+        let file_size = raw_file
+            .file_mut()
+            .metadata()
+            .map_err(Error::GettingFileSize)?
+            .len();
+
+        let refcount_bits = 1u64 << header.refcount_order;
+        let refcount_bytes = div_round_up_u64(refcount_bits, 8);
+        let refcount_block_entries = cluster_size / refcount_bytes;
+        let pointers_per_cluster = cluster_size / size_of::<u64>() as u64;
+        let data_clusters = div_round_up_u64(header.size, cluster_size);
+        let l2_clusters = div_round_up_u64(data_clusters, pointers_per_cluster);
+        let l1_clusters = div_round_up_u64(l2_clusters, cluster_size);
+        let header_clusters = div_round_up_u64(size_of::<QcowHeader>() as u64, cluster_size);
+        let max_clusters = data_clusters + l2_clusters + l1_clusters + header_clusters;
+        let mut max_valid_cluster_index = max_clusters;
+        let refblock_clusters = div_round_up_u64(max_valid_cluster_index, refcount_block_entries);
+        let reftable_clusters = div_round_up_u64(refblock_clusters, pointers_per_cluster);
+        // Account for refblocks and the ref table size needed to address them.
+        let refblocks_for_refs = div_round_up_u64(
+            refblock_clusters + reftable_clusters,
+            refcount_block_entries,
+        );
+        let reftable_clusters_for_refs =
+            div_round_up_u64(refblocks_for_refs, refcount_block_entries);
+        max_valid_cluster_index += refblock_clusters + reftable_clusters;
+        max_valid_cluster_index += refblocks_for_refs + reftable_clusters_for_refs;
+
+        if max_valid_cluster_index > MAX_RAM_POINTER_TABLE_SIZE {
+            return Err(Error::InvalidRefcountTableSize(max_valid_cluster_index));
+        }
+
+        let max_valid_cluster_offset = max_valid_cluster_index * cluster_size;
+        if max_valid_cluster_offset < file_size - cluster_size {
+            return Err(Error::InvalidRefcountTableSize(max_valid_cluster_offset));
+        }
+
+        let mut refcounts = vec![0; max_valid_cluster_index as usize];
+
+        // Find all references clusters and rebuild refcounts.
+        set_header_refcount(&mut refcounts, cluster_size)?;
+        set_l1_refcounts(&mut refcounts, header, cluster_size)?;
+        set_data_refcounts(&mut refcounts, header, cluster_size, raw_file)?;
+        set_refcount_table_refcounts(&mut refcounts, header, cluster_size)?;
+
+        // Allocate clusters to store the new reference count blocks.
+        let ref_table = alloc_refblocks(
+            &mut refcounts,
+            cluster_size,
+            refblock_clusters,
+            pointers_per_cluster,
+        )?;
+
+        // Write updated reference counts and point the reftable at them.
+        write_refblocks(
+            &refcounts,
+            header,
+            &ref_table,
+            raw_file,
+            refcount_block_entries,
+        )
+    }
+
+    // Limits the range so that it doesn't exceed the virtual size of the file.
+    fn limit_range_file(&self, address: u64, count: usize) -> usize {
+        if address.checked_add(count as u64).is_none() || address > self.virtual_size() {
+            return 0;
+        }
+        min(count as u64, self.virtual_size() - address) as usize
+    }
+
+    // Limits the range so that it doesn't overflow the end of a cluster.
+    fn limit_range_cluster(&self, address: u64, count: usize) -> usize {
+        let offset: u64 = self.raw_file.cluster_offset(address);
+        let limit = self.raw_file.cluster_size() - offset;
+        min(count as u64, limit) as usize
+    }
+
+    // Gets the maximum virtual size of this image.
+    fn virtual_size(&self) -> u64 {
+        self.header.size
+    }
+
+    // Gets the offset of `address` in the L1 table.
+    fn l1_address_offset(&self, address: u64) -> u64 {
+        let l1_index = self.l1_table_index(address);
+        l1_index * size_of::<u64>() as u64
+    }
+
+    // Gets the offset of `address` in the L1 table.
+    fn l1_table_index(&self, address: u64) -> u64 {
+        (address / self.raw_file.cluster_size()) / self.l2_entries
+    }
+
+    // Gets the offset of `address` in the L2 table.
+    fn l2_table_index(&self, address: u64) -> u64 {
+        (address / self.raw_file.cluster_size()) % self.l2_entries
+    }
+
+    // Gets the offset of the given guest address in the host file. If L1, L2, or data clusters have
+    // yet to be allocated, return None.
+    fn file_offset_read(&mut self, address: u64) -> std::io::Result<Option<u64>> {
+        if address >= self.virtual_size() as u64 {
+            return Err(std::io::Error::from_raw_os_error(EINVAL));
+        }
+
+        let l1_index = self.l1_table_index(address) as usize;
+        let l2_addr_disk = *self
+            .l1_table
+            .get(l1_index)
+            .ok_or(std::io::Error::from_raw_os_error(EINVAL))?;
+
+        if l2_addr_disk == 0 {
+            // Reading from an unallocated cluster will return zeros.
+            return Ok(None);
+        }
+
+        let l2_index = self.l2_table_index(address) as usize;
+
+        if !self.l2_cache.contains_key(&l1_index) {
+            // Not in the cache.
+            let table =
+                VecCache::from_vec(Self::read_l2_cluster(&mut self.raw_file, l2_addr_disk)?);
+
+            let l1_table = &self.l1_table;
+            let raw_file = &mut self.raw_file;
+            self.l2_cache.insert(l1_index, table, |index, evicted| {
+                raw_file.write_pointer_table(
+                    l1_table[index],
+                    evicted.get_values(),
+                    CLUSTER_USED_FLAG,
+                )
+            })?;
+        };
+
+        let cluster_addr = self.l2_cache.get(&l1_index).unwrap()[l2_index];
+        if cluster_addr == 0 {
+            return Ok(None);
+        }
+        Ok(Some(cluster_addr + self.raw_file.cluster_offset(address)))
+    }
+
+    // Gets the offset of the given guest address in the host file. If L1, L2, or data clusters need
+    // to be allocated, they will be.
+    fn file_offset_write(&mut self, address: u64) -> std::io::Result<u64> {
+        if address >= self.virtual_size() as u64 {
+            return Err(std::io::Error::from_raw_os_error(EINVAL));
+        }
+
+        let l1_index = self.l1_table_index(address) as usize;
+        let l2_addr_disk = *self
+            .l1_table
+            .get(l1_index)
+            .ok_or(std::io::Error::from_raw_os_error(EINVAL))?;
+        let l2_index = self.l2_table_index(address) as usize;
+
+        let mut set_refcounts = Vec::new();
+
+        if !self.l2_cache.contains_key(&l1_index) {
+            // Not in the cache.
+            let l2_table = if l2_addr_disk == 0 {
+                // Allocate a new cluster to store the L2 table and update the L1 table to point
+                // to the new table.
+                let new_addr: u64 = self.get_new_cluster()?;
+                // The cluster refcount starts at one meaning it is used but doesn't need COW.
+                set_refcounts.push((new_addr, 1));
+                self.l1_table[l1_index] = new_addr;
+                VecCache::new(self.l2_entries as usize)
+            } else {
+                VecCache::from_vec(Self::read_l2_cluster(&mut self.raw_file, l2_addr_disk)?)
+            };
+            let l1_table = &self.l1_table;
+            let raw_file = &mut self.raw_file;
+            self.l2_cache.insert(l1_index, l2_table, |index, evicted| {
+                raw_file.write_pointer_table(
+                    l1_table[index],
+                    evicted.get_values(),
+                    CLUSTER_USED_FLAG,
+                )
+            })?;
+        }
+
+        let cluster_addr = match self.l2_cache.get(&l1_index).unwrap()[l2_index] {
+            0 => {
+                // Need to allocate a data cluster
+                let cluster_addr = self.append_data_cluster()?;
+                self.update_cluster_addr(l1_index, l2_index, cluster_addr, &mut set_refcounts)?;
+                cluster_addr
+            }
+            a => a,
+        };
+
+        for (addr, count) in set_refcounts {
+            let mut newly_unref = self.set_cluster_refcount(addr, count)?;
+            self.unref_clusters.append(&mut newly_unref);
+        }
+
+        Ok(cluster_addr + self.raw_file.cluster_offset(address))
+    }
+
+    // Updates the l1 and l2 tables to point to the new `cluster_addr`.
+    fn update_cluster_addr(
+        &mut self,
+        l1_index: usize,
+        l2_index: usize,
+        cluster_addr: u64,
+        set_refcounts: &mut Vec<(u64, u16)>,
+    ) -> io::Result<()> {
+        if !self.l2_cache.get(&l1_index).unwrap().dirty() {
+            // Free the previously used cluster if one exists. Modified tables are always
+            // witten to new clusters so the L1 table can be committed to disk after they
+            // are and L1 never points at an invalid table.
+            // The index must be valid from when it was insterted.
+            let addr = self.l1_table[l1_index];
+            if addr != 0 {
+                self.unref_clusters.push(addr);
+                set_refcounts.push((addr, 0));
+            }
+
+            // Allocate a new cluster to store the L2 table and update the L1 table to point
+            // to the new table. The cluster will be written when the cache is flushed, no
+            // need to copy the data now.
+            let new_addr: u64 = self.get_new_cluster()?;
+            // The cluster refcount starts at one indicating it is used but doesn't need
+            // COW.
+            set_refcounts.push((new_addr, 1));
+            self.l1_table[l1_index] = new_addr;
+        }
+        // 'unwrap' is OK because it was just added.
+        self.l2_cache.get_mut(&l1_index).unwrap()[l2_index] = cluster_addr;
+        Ok(())
+    }
+
+    // Allocate a new cluster and return its offset within the raw file.
+    fn get_new_cluster(&mut self) -> std::io::Result<u64> {
+        // First use a pre allocated cluster if one is available.
+        if let Some(free_cluster) = self.avail_clusters.pop() {
+            let cluster_size = self.raw_file.cluster_size() as usize;
+            self.raw_file
+                .file_mut()
+                .seek(SeekFrom::Start(free_cluster))?;
+            self.raw_file.file_mut().write_zeroes(cluster_size)?;
+            return Ok(free_cluster);
+        }
+
+        let max_valid_cluster_offset = self.refcounts.max_valid_cluster_offset();
+        if let Some(new_cluster) = self.raw_file.add_cluster_end(max_valid_cluster_offset)? {
+            return Ok(new_cluster);
+        } else {
+            error!("No free clusters in get_new_cluster()");
+            return Err(std::io::Error::from_raw_os_error(ENOSPC));
+        }
+    }
+
+    // Allocate and initialize a new data cluster. Returns the offset of the
+    // cluster in to the file on success.
+    fn append_data_cluster(&mut self) -> std::io::Result<u64> {
+        let new_addr: u64 = self.get_new_cluster()?;
+        // The cluster refcount starts at one indicating it is used but doesn't need COW.
+        let mut newly_unref = self.set_cluster_refcount(new_addr, 1)?;
+        self.unref_clusters.append(&mut newly_unref);
+        Ok(new_addr)
+    }
+
+    // Returns true if the cluster containing `address` is already allocated.
+    fn cluster_allocated(&mut self, address: u64) -> std::io::Result<bool> {
+        if address >= self.virtual_size() as u64 {
+            return Err(std::io::Error::from_raw_os_error(EINVAL));
+        }
+
+        let l1_index = self.l1_table_index(address) as usize;
+        let l2_addr_disk = *self
+            .l1_table
+            .get(l1_index)
+            .ok_or(std::io::Error::from_raw_os_error(EINVAL))?;
+        let l2_index = self.l2_table_index(address) as usize;
+
+        if l2_addr_disk == 0 {
+            // The whole L2 table for this address is not allocated yet,
+            // so the cluster must also be unallocated.
+            return Ok(false);
+        }
+
+        if !self.l2_cache.contains_key(&l1_index) {
+            // Not in the cache.
+            let table =
+                VecCache::from_vec(Self::read_l2_cluster(&mut self.raw_file, l2_addr_disk)?);
+            let l1_table = &self.l1_table;
+            let raw_file = &mut self.raw_file;
+            self.l2_cache.insert(l1_index, table, |index, evicted| {
+                raw_file.write_pointer_table(
+                    l1_table[index],
+                    evicted.get_values(),
+                    CLUSTER_USED_FLAG,
+                )
+            })?;
+        }
+
+        let cluster_addr = self.l2_cache.get(&l1_index).unwrap()[l2_index];
+        // If cluster_addr != 0, the cluster is allocated.
+        Ok(cluster_addr != 0)
+    }
+
+    // Find the first guest address greater than or equal to `address` whose allocation state
+    // matches `allocated`.
+    fn find_allocated_cluster(
+        &mut self,
+        address: u64,
+        allocated: bool,
+    ) -> std::io::Result<Option<u64>> {
+        let size = self.virtual_size();
+        if address >= size {
+            return Ok(None);
+        }
+
+        // If offset is already within a hole, return it.
+        if self.cluster_allocated(address)? == allocated {
+            return Ok(Some(address));
+        }
+
+        // Skip to the next cluster boundary.
+        let cluster_size = self.raw_file.cluster_size();
+        let mut cluster_addr = (address / cluster_size + 1) * cluster_size;
+
+        // Search for clusters with the desired allocation state.
+        while cluster_addr < size {
+            if self.cluster_allocated(cluster_addr)? == allocated {
+                return Ok(Some(cluster_addr));
+            }
+            cluster_addr += cluster_size;
+        }
+
+        Ok(None)
+    }
+
+    // Deallocate the storage for the cluster starting at `address`.
+    // Any future reads of this cluster will return all zeroes.
+    fn deallocate_cluster(&mut self, address: u64) -> std::io::Result<()> {
+        if address >= self.virtual_size() as u64 {
+            return Err(std::io::Error::from_raw_os_error(EINVAL));
+        }
+
+        let l1_index = self.l1_table_index(address) as usize;
+        let l2_addr_disk = *self
+            .l1_table
+            .get(l1_index)
+            .ok_or(std::io::Error::from_raw_os_error(EINVAL))?;
+        let l2_index = self.l2_table_index(address) as usize;
+
+        if l2_addr_disk == 0 {
+            // The whole L2 table for this address is not allocated yet,
+            // so the cluster must also be unallocated.
+            return Ok(());
+        }
+
+        if !self.l2_cache.contains_key(&l1_index) {
+            // Not in the cache.
+            let table =
+                VecCache::from_vec(Self::read_l2_cluster(&mut self.raw_file, l2_addr_disk)?);
+            let l1_table = &self.l1_table;
+            let raw_file = &mut self.raw_file;
+            self.l2_cache.insert(l1_index, table, |index, evicted| {
+                raw_file.write_pointer_table(
+                    l1_table[index],
+                    evicted.get_values(),
+                    CLUSTER_USED_FLAG,
+                )
+            })?;
+        }
+
+        let cluster_addr = self.l2_cache.get(&l1_index).unwrap()[l2_index];
+        if cluster_addr == 0 {
+            // This cluster is already unallocated; nothing to do.
+            return Ok(());
+        }
+
+        // Decrement the refcount.
+        let refcount = self
+            .refcounts
+            .get_cluster_refcount(&mut self.raw_file, cluster_addr)
+            .map_err(|_| std::io::Error::from_raw_os_error(EINVAL))?;
+        if refcount == 0 {
+            return Err(std::io::Error::from_raw_os_error(EINVAL));
+        }
+
+        let new_refcount = refcount - 1;
+        let mut newly_unref = self.set_cluster_refcount(cluster_addr, new_refcount)?;
+        self.unref_clusters.append(&mut newly_unref);
+
+        // Rewrite the L2 entry to remove the cluster mapping.
+        // unwrap is safe as we just checked/inserted this entry.
+        self.l2_cache.get_mut(&l1_index).unwrap()[l2_index] = 0;
+
+        if new_refcount == 0 {
+            let cluster_size = self.raw_file.cluster_size();
+            // This cluster is no longer in use; deallocate the storage.
+            // The underlying FS may not support FALLOC_FL_PUNCH_HOLE,
+            // so don't treat an error as fatal.  Future reads will return zeros anyways.
+            let _ = self
+                .raw_file
+                .file_mut()
+                .punch_hole(cluster_addr, cluster_size);
+            self.unref_clusters.push(cluster_addr);
+        }
+        Ok(())
+    }
+
+    // Deallocate the storage for `length` bytes starting at `address`.
+    // Any future reads of this range will return all zeroes.
+    fn deallocate_bytes(&mut self, address: u64, length: usize) -> std::io::Result<()> {
+        let write_count: usize = self.limit_range_file(address, length);
+
+        let mut nwritten: usize = 0;
+        while nwritten < write_count {
+            let curr_addr = address + nwritten as u64;
+            let count = self.limit_range_cluster(curr_addr, write_count - nwritten);
+
+            if count == self.raw_file.cluster_size() as usize {
+                // Full cluster - deallocate the storage.
+                self.deallocate_cluster(curr_addr)?;
+            } else {
+                // Partial cluster - zero out the relevant bytes if it was allocated.
+                // Any space in unallocated clusters can be left alone, since
+                // unallocated clusters already read back as zeroes.
+                if let Some(offset) = self.file_offset_read(curr_addr)? {
+                    // Partial cluster - zero it out.
+                    self.raw_file.file_mut().seek(SeekFrom::Start(offset))?;
+                    self.raw_file.file_mut().write_zeroes(count)?;
+                }
+            }
+
+            nwritten += count;
+        }
+        Ok(())
+    }
+
+    // Reads an L2 cluster from the disk, returning an error if the file can't be read or if any
+    // cluster is compressed.
+    fn read_l2_cluster(raw_file: &mut QcowRawFile, cluster_addr: u64) -> std::io::Result<Vec<u64>> {
+        let file_values = raw_file.read_pointer_cluster(cluster_addr, None)?;
+        if file_values.iter().any(|entry| entry & COMPRESSED_FLAG != 0) {
+            return Err(std::io::Error::from_raw_os_error(ENOTSUP));
+        }
+        Ok(file_values
+            .iter()
+            .map(|entry| *entry & L2_TABLE_OFFSET_MASK)
+            .collect())
+    }
+
+    // Set the refcount for a cluster with the given address.
+    // Returns a list of any refblocks that can be reused, this happens when a refblock is moved,
+    // the old location can be reused.
+    fn set_cluster_refcount(&mut self, address: u64, refcount: u16) -> std::io::Result<Vec<u64>> {
+        let mut added_clusters = Vec::new();
+        let mut unref_clusters = Vec::new();
+        let mut refcount_set = false;
+        let mut new_cluster = None;
+
+        while !refcount_set {
+            match self.refcounts.set_cluster_refcount(
+                &mut self.raw_file,
+                address,
+                refcount,
+                new_cluster.take(),
+            ) {
+                Ok(None) => {
+                    refcount_set = true;
+                }
+                Ok(Some(freed_cluster)) => {
+                    unref_clusters.push(freed_cluster);
+                    refcount_set = true;
+                }
+                Err(refcount::Error::EvictingRefCounts(e)) => {
+                    return Err(e);
+                }
+                Err(refcount::Error::InvalidIndex) => {
+                    return Err(std::io::Error::from_raw_os_error(EINVAL));
+                }
+                Err(refcount::Error::NeedCluster(addr)) => {
+                    // Read the address and call set_cluster_refcount again.
+                    new_cluster = Some((
+                        addr,
+                        VecCache::from_vec(self.raw_file.read_refcount_block(addr)?),
+                    ));
+                }
+                Err(refcount::Error::NeedNewCluster) => {
+                    // Allocate the cluster and call set_cluster_refcount again.
+                    let addr = self.get_new_cluster()?;
+                    added_clusters.push(addr);
+                    new_cluster = Some((
+                        addr,
+                        VecCache::new(self.refcounts.refcounts_per_block() as usize),
+                    ));
+                }
+                Err(refcount::Error::ReadingRefCounts(e)) => {
+                    return Err(e);
+                }
+            }
+        }
+
+        for addr in added_clusters {
+            self.set_cluster_refcount(addr, 1)?;
+        }
+        Ok(unref_clusters)
+    }
+
+    fn sync_caches(&mut self) -> std::io::Result<()> {
+        // Write out all dirty L2 tables.
+        for (l1_index, l2_table) in self.l2_cache.iter_mut().filter(|(_k, v)| v.dirty()) {
+            // The index must be valid from when we insterted it.
+            let addr = self.l1_table[*l1_index];
+            if addr != 0 {
+                self.raw_file.write_pointer_table(
+                    addr,
+                    l2_table.get_values(),
+                    CLUSTER_USED_FLAG,
+                )?;
+            } else {
+                return Err(std::io::Error::from_raw_os_error(EINVAL));
+            }
+            l2_table.mark_clean();
+        }
+        // Write the modified refcount blocks.
+        self.refcounts.flush_blocks(&mut self.raw_file)?;
+        // Make sure metadata(file len) and all data clusters are written.
+        self.raw_file.file_mut().sync_all()?;
+
+        // Push L1 table and refcount table last as all the clusters they point to are now
+        // guaranteed to be valid.
+        let mut sync_required = false;
+        if self.l1_table.dirty() {
+            self.raw_file.write_pointer_table(
+                self.header.l1_table_offset,
+                &self.l1_table.get_values(),
+                0,
+            )?;
+            self.l1_table.mark_clean();
+            sync_required = true;
+        }
+        sync_required |= self.refcounts.flush_table(&mut self.raw_file)?;
+        if sync_required {
+            self.raw_file.file_mut().sync_data()?;
+        }
+        Ok(())
+    }
+
+    // Reads `count` bytes from the cursor position, calling `cb` repeatedly with the backing file,
+    // number of bytes read so far, and number of bytes to read from the file in that invocation. If
+    // None is given to `cb` in place of the backing file, the `cb` should infer zeros would have
+    // been read.
+    fn read_cb<F>(&mut self, count: usize, mut cb: F) -> std::io::Result<usize>
+    where
+        F: FnMut(Option<&mut File>, usize, usize) -> std::io::Result<()>,
+    {
+        let address: u64 = self.current_offset as u64;
+        let read_count: usize = self.limit_range_file(address, count);
+
+        let mut nread: usize = 0;
+        while nread < read_count {
+            let curr_addr = address + nread as u64;
+            let file_offset = self.file_offset_read(curr_addr)?;
+            let count = self.limit_range_cluster(curr_addr, read_count - nread);
+
+            if let Some(offset) = file_offset {
+                self.raw_file.file_mut().seek(SeekFrom::Start(offset))?;
+                cb(Some(self.raw_file.file_mut()), nread, count)?;
+            } else {
+                cb(None, nread, count)?;
+            }
+
+            nread += count;
+        }
+        self.current_offset += read_count as u64;
+        Ok(read_count)
+    }
+
+    // Writes `count` bytes to the cursor position, calling `cb` repeatedly with the backing file,
+    // number of bytes written so far, and number of bytes to write to the file in that invocation.
+    fn write_cb<F>(&mut self, count: usize, mut cb: F) -> std::io::Result<usize>
+    where
+        F: FnMut(&mut File, usize, usize) -> std::io::Result<()>,
+    {
+        let address: u64 = self.current_offset as u64;
+        let write_count: usize = self.limit_range_file(address, count);
+
+        let mut nwritten: usize = 0;
+        while nwritten < write_count {
+            let curr_addr = address + nwritten as u64;
+            let offset = self.file_offset_write(curr_addr)?;
+            let count = self.limit_range_cluster(curr_addr, write_count - nwritten);
+
+            if let Err(e) = self.raw_file.file_mut().seek(SeekFrom::Start(offset)) {
+                return Err(e);
+            }
+            if let Err(e) = cb(self.raw_file.file_mut(), nwritten, count) {
+                return Err(e);
+            }
+
+            nwritten += count;
+        }
+        self.current_offset += write_count as u64;
+        Ok(write_count)
+    }
+}
+
+impl Drop for QcowFile {
+    fn drop(&mut self) {
+        let _ = self.sync_caches();
+    }
+}
+
+impl AsRawFd for QcowFile {
+    fn as_raw_fd(&self) -> RawFd {
+        self.raw_file.file().as_raw_fd()
+    }
+}
+
+impl Read for QcowFile {
+    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+        self.read_cb(buf.len(), |file, offset, count| match file {
+            Some(f) => f.read_exact(&mut buf[offset..(offset + count)]),
+            None => {
+                for b in &mut buf[offset..(offset + count)] {
+                    *b = 0;
+                }
+                Ok(())
+            }
+        })
+    }
+}
+
+impl Seek for QcowFile {
+    fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
+        let new_offset: Option<u64> = match pos {
+            SeekFrom::Start(off) => Some(off),
+            SeekFrom::End(off) => {
+                if off < 0 {
+                    0i64.checked_sub(off)
+                        .and_then(|increment| self.virtual_size().checked_sub(increment as u64))
+                } else {
+                    self.virtual_size().checked_add(off as u64)
+                }
+            }
+            SeekFrom::Current(off) => {
+                if off < 0 {
+                    0i64.checked_sub(off)
+                        .and_then(|increment| self.current_offset.checked_sub(increment as u64))
+                } else {
+                    self.current_offset.checked_add(off as u64)
+                }
+            }
+        };
+
+        if let Some(o) = new_offset {
+            if o <= self.virtual_size() {
+                self.current_offset = o;
+                return Ok(o);
+            }
+        }
+        Err(std::io::Error::from_raw_os_error(EINVAL))
+    }
+}
+
+impl Write for QcowFile {
+    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+        self.write_cb(buf.len(), |file, offset, count| {
+            file.write_all(&buf[offset..(offset + count)])
+        })
+    }
+
+    fn flush(&mut self) -> std::io::Result<()> {
+        self.sync_caches()?;
+        self.avail_clusters.append(&mut self.unref_clusters);
+        Ok(())
+    }
+}
+
+impl FileReadWriteVolatile for QcowFile {
+    fn read_volatile(&mut self, slice: VolatileSlice) -> io::Result<usize> {
+        self.read_cb(slice.size() as usize, |file, offset, count| {
+            let sub_slice = slice.get_slice(offset as u64, count as u64).unwrap();
+            match file {
+                Some(f) => f.read_exact_volatile(sub_slice),
+                None => {
+                    sub_slice.write_bytes(0);
+                    Ok(())
+                }
+            }
+        })
+    }
+
+    fn write_volatile(&mut self, slice: VolatileSlice) -> io::Result<usize> {
+        self.write_cb(slice.size() as usize, |file, offset, count| {
+            let sub_slice = slice.get_slice(offset as u64, count as u64).unwrap();
+            file.write_all_volatile(sub_slice)
+        })
+    }
+}
+
+impl FileSync for QcowFile {
+    fn fsync(&mut self) -> std::io::Result<()> {
+        self.flush()
+    }
+}
+
+impl FileSetLen for QcowFile {
+    fn set_len(&self, _len: u64) -> std::io::Result<()> {
+        Err(std::io::Error::new(
+            std::io::ErrorKind::Other,
+            "set_len() not supported for QcowFile",
+        ))
+    }
+}
+
+impl PunchHole for QcowFile {
+    fn punch_hole(&mut self, offset: u64, length: u64) -> std::io::Result<()> {
+        let mut remaining = length;
+        let mut offset = offset;
+        while remaining > 0 {
+            let chunk_length = min(remaining, std::usize::MAX as u64) as usize;
+            self.deallocate_bytes(offset, chunk_length)?;
+            remaining -= chunk_length as u64;
+            offset += chunk_length as u64;
+        }
+        Ok(())
+    }
+}
+
+impl SeekHole for QcowFile {
+    fn seek_hole(&mut self, offset: u64) -> io::Result<Option<u64>> {
+        match self.find_allocated_cluster(offset, false) {
+            Err(e) => Err(e),
+            Ok(None) => {
+                if offset < self.virtual_size() {
+                    Ok(Some(self.seek(SeekFrom::End(0))?))
+                } else {
+                    Ok(None)
+                }
+            }
+            Ok(Some(o)) => {
+                self.seek(SeekFrom::Start(o))?;
+                Ok(Some(o))
+            }
+        }
+    }
+
+    fn seek_data(&mut self, offset: u64) -> io::Result<Option<u64>> {
+        match self.find_allocated_cluster(offset, true) {
+            Err(e) => Err(e),
+            Ok(None) => Ok(None),
+            Ok(Some(o)) => {
+                self.seek(SeekFrom::Start(o))?;
+                Ok(Some(o))
+            }
+        }
+    }
+}
+
+// Returns an Error if the given offset doesn't align to a cluster boundary.
+fn offset_is_cluster_boundary(offset: u64, cluster_bits: u32) -> Result<()> {
+    if offset & ((0x01 << cluster_bits) - 1) != 0 {
+        return Err(Error::InvalidOffset(offset));
+    }
+    Ok(())
+}
+
+// Ceiling of the division of `dividend`/`divisor`.
+fn div_round_up_u64(dividend: u64, divisor: u64) -> u64 {
+    (dividend + divisor - 1) / divisor
+}
+
+// Ceiling of the division of `dividend`/`divisor`.
+fn div_round_up_u32(dividend: u32, divisor: u32) -> u32 {
+    (dividend + divisor - 1) / divisor
+}
+
+fn convert_copy<R, W>(reader: &mut R, writer: &mut W, offset: u64, size: u64) -> Result<()>
+where
+    R: Read + Seek,
+    W: Write + Seek,
+{
+    const CHUNK_SIZE: usize = 65536;
+    let mut buf = [0; CHUNK_SIZE];
+    let mut read_count = 0;
+    reader
+        .seek(SeekFrom::Start(offset))
+        .map_err(Error::SeekingFile)?;
+    writer
+        .seek(SeekFrom::Start(offset))
+        .map_err(Error::SeekingFile)?;
+    loop {
+        let this_count = min(CHUNK_SIZE as u64, size - read_count) as usize;
+        let nread = reader
+            .read(&mut buf[..this_count])
+            .map_err(Error::ReadingData)?;
+        writer.write(&buf[..nread]).map_err(Error::WritingData)?;
+        read_count += nread as u64;
+        if nread == 0 || read_count == size {
+            break;
+        }
+    }
+
+    Ok(())
+}
+
+fn convert_reader_writer<R, W>(reader: &mut R, writer: &mut W, size: u64) -> Result<()>
+where
+    R: Read + Seek + SeekHole,
+    W: Write + Seek,
+{
+    let mut offset = 0;
+    while offset < size {
+        // Find the next range of data.
+        let next_data = match reader.seek_data(offset).map_err(Error::SeekingFile)? {
+            Some(o) => o,
+            None => {
+                // No more data in the file.
+                break;
+            }
+        };
+        let next_hole = match reader.seek_hole(next_data).map_err(Error::SeekingFile)? {
+            Some(o) => o,
+            None => {
+                // This should not happen - there should always be at least one hole
+                // after any data.
+                return Err(Error::SeekingFile(io::Error::from_raw_os_error(EINVAL)));
+            }
+        };
+        let count = next_hole - next_data;
+        convert_copy(reader, writer, next_data, count)?;
+        offset = next_hole;
+    }
+
+    Ok(())
+}
+
+fn convert_reader<R>(reader: &mut R, dst_file: File, dst_type: ImageType) -> Result<()>
+where
+    R: Read + Seek + SeekHole,
+{
+    let src_size = reader.seek(SeekFrom::End(0)).map_err(Error::SeekingFile)?;
+    reader
+        .seek(SeekFrom::Start(0))
+        .map_err(Error::SeekingFile)?;
+
+    // Ensure the destination file is empty before writing to it.
+    dst_file.set_len(0).map_err(Error::SettingFileSize)?;
+
+    match dst_type {
+        ImageType::Qcow2 => {
+            let mut dst_writer = QcowFile::new(dst_file, src_size)?;
+            convert_reader_writer(reader, &mut dst_writer, src_size)
+        }
+        ImageType::Raw => {
+            let mut dst_writer = dst_file;
+            // Set the length of the destination file to convert it into a sparse file
+            // of the desired size.
+            dst_writer
+                .set_len(src_size)
+                .map_err(Error::SettingFileSize)?;
+            convert_reader_writer(reader, &mut dst_writer, src_size)
+        }
+    }
+}
+
+/// Copy the contents of a disk image in `src_file` into `dst_file`.
+/// The type of `src_file` is automatically detected, and the output file type is
+/// determined by `dst_type`.
+pub fn convert(src_file: File, dst_file: File, dst_type: ImageType) -> Result<()> {
+    let src_type = detect_image_type(&src_file)?;
+    match src_type {
+        ImageType::Qcow2 => {
+            let mut src_reader = QcowFile::from(src_file)?;
+            convert_reader(&mut src_reader, dst_file, dst_type)
+        }
+        ImageType::Raw => {
+            // src_file is a raw file.
+            let mut src_reader = src_file;
+            convert_reader(&mut src_reader, dst_file, dst_type)
+        }
+    }
+}
+
+/// Detect the type of an image file by checking for a valid qcow2 header.
+pub fn detect_image_type(file: &File) -> Result<ImageType> {
+    let mut f = file;
+    let orig_seek = f.seek(SeekFrom::Current(0)).map_err(Error::SeekingFile)?;
+    f.seek(SeekFrom::Start(0)).map_err(Error::SeekingFile)?;
+    let magic = f.read_u32::<BigEndian>().map_err(Error::ReadingHeader)?;
+    let image_type = if magic == QCOW_MAGIC {
+        ImageType::Qcow2
+    } else {
+        ImageType::Raw
+    };
+    f.seek(SeekFrom::Start(orig_seek))
+        .map_err(Error::SeekingFile)?;
+    Ok(image_type)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::fs::File;
+    use std::io::{Read, Seek, SeekFrom, Write};
+    use sys_util::SharedMemory;
+
+    fn valid_header() -> Vec<u8> {
+        vec![
+            0x51u8, 0x46, 0x49, 0xfb, // magic
+            0x00, 0x00, 0x00, 0x03, // version
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // backing file offset
+            0x00, 0x00, 0x00, 0x00, // backing file size
+            0x00, 0x00, 0x00, 0x10, // cluster_bits
+            0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, // size
+            0x00, 0x00, 0x00, 0x00, // crypt method
+            0x00, 0x00, 0x01, 0x00, // L1 size
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, // L1 table offset
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // refcount table offset
+            0x00, 0x00, 0x00, 0x03, // refcount table clusters
+            0x00, 0x00, 0x00, 0x00, // nb snapshots
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, // snapshots offset
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // incompatible_features
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // compatible_features
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // autoclear_features
+            0x00, 0x00, 0x00, 0x04, // refcount_order
+            0x00, 0x00, 0x00, 0x68, // header_length
+        ]
+    }
+
+    // Test case found by clusterfuzz to allocate excessive memory.
+    fn test_huge_header() -> Vec<u8> {
+        vec![
+            0x51, 0x46, 0x49, 0xfb, // magic
+            0x00, 0x00, 0x00, 0x03, // version
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // backing file offset
+            0x00, 0x00, 0x00, 0x00, // backing file size
+            0x00, 0x00, 0x00, 0x09, // cluster_bits
+            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, // size
+            0x00, 0x00, 0x00, 0x00, // crypt method
+            0x00, 0x00, 0x01, 0x00, // L1 size
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, // L1 table offset
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // refcount table offset
+            0x00, 0x00, 0x00, 0x03, // refcount table clusters
+            0x00, 0x00, 0x00, 0x00, // nb snapshots
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, // snapshots offset
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // incompatible_features
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // compatible_features
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // autoclear_features
+            0x00, 0x00, 0x00, 0x04, // refcount_order
+            0x00, 0x00, 0x00, 0x68, // header_length
+        ]
+    }
+
+    fn with_basic_file<F>(header: &[u8], mut testfn: F)
+    where
+        F: FnMut(File),
+    {
+        let shm = SharedMemory::new(None).unwrap();
+        let mut disk_file: File = shm.into();
+        disk_file.write_all(&header).unwrap();
+        disk_file.set_len(0x1_0000_0000).unwrap();
+        disk_file.seek(SeekFrom::Start(0)).unwrap();
+
+        testfn(disk_file); // File closed when the function exits.
+    }
+
+    fn with_default_file<F>(file_size: u64, mut testfn: F)
+    where
+        F: FnMut(QcowFile),
+    {
+        let shm = SharedMemory::new(None).unwrap();
+        let qcow_file = QcowFile::new(shm.into(), file_size).unwrap();
+
+        testfn(qcow_file); // File closed when the function exits.
+    }
+
+    #[test]
+    fn default_header() {
+        let header = QcowHeader::create_for_size(0x10_0000);
+        let shm = SharedMemory::new(None).unwrap();
+        let mut disk_file: File = shm.into();
+        header
+            .write_to(&mut disk_file)
+            .expect("Failed to write header to shm.");
+        disk_file.seek(SeekFrom::Start(0)).unwrap();
+        QcowFile::from(disk_file).expect("Failed to create Qcow from default Header");
+    }
+
+    #[test]
+    fn header_read() {
+        with_basic_file(&valid_header(), |mut disk_file: File| {
+            QcowHeader::new(&mut disk_file).expect("Failed to create Header.");
+        });
+    }
+
+    #[test]
+    fn invalid_magic() {
+        let invalid_header = vec![0x51u8, 0x46, 0x4a, 0xfb];
+        with_basic_file(&invalid_header, |mut disk_file: File| {
+            QcowHeader::new(&mut disk_file).expect_err("Invalid header worked.");
+        });
+    }
+
+    #[test]
+    fn invalid_refcount_order() {
+        let mut header = valid_header();
+        header[99] = 2;
+        with_basic_file(&header, |disk_file: File| {
+            QcowFile::from(disk_file).expect_err("Invalid refcount order worked.");
+        });
+    }
+
+    #[test]
+    fn invalid_cluster_bits() {
+        let mut header = test_huge_header();
+        header[23] = 3;
+        with_basic_file(&test_huge_header(), |disk_file: File| {
+            QcowFile::from(disk_file).expect_err("Failed to create file.");
+        });
+    }
+
+    #[test]
+    fn test_header_huge_file() {
+        let header = test_huge_header();
+        with_basic_file(&header, |disk_file: File| {
+            QcowFile::from(disk_file).expect_err("Failed to create file.");
+        });
+    }
+
+    #[test]
+    fn test_header_1_tb_file_min_cluster() {
+        let mut header = test_huge_header();
+        header[24] = 0;
+        header[26] = 1;
+        header[31] = 0;
+        // 1 TB with the min cluster size makes the arrays too big, it should fail.
+        with_basic_file(&header, |disk_file: File| {
+            QcowFile::from(disk_file).expect_err("Failed to create file.");
+        });
+    }
+
+    #[test]
+    fn test_header_1_tb_file() {
+        let mut header = test_huge_header();
+        // reset to 1 TB size.
+        header[24] = 0;
+        header[26] = 1;
+        header[31] = 0;
+        // set cluster_bits
+        header[23] = 16;
+        with_basic_file(&header, |disk_file: File| {
+            let mut qcow = QcowFile::from(disk_file).expect("Failed to create file.");
+            qcow.seek(SeekFrom::Start(0x100_0000_0000 - 8))
+                .expect("Failed to seek.");
+            let value = 0x0000_0040_3f00_ffffu64;
+            qcow.write_all(&value.to_le_bytes())
+                .expect("failed to write data");
+        });
+    }
+
+    #[test]
+    fn write_read_start() {
+        with_basic_file(&valid_header(), |disk_file: File| {
+            let mut q = QcowFile::from(disk_file).unwrap();
+            q.write(b"test first bytes")
+                .expect("Failed to write test string.");
+            let mut buf = [0u8; 4];
+            q.seek(SeekFrom::Start(0)).expect("Failed to seek.");
+            q.read(&mut buf).expect("Failed to read.");
+            assert_eq!(&buf, b"test");
+        });
+    }
+
+    #[test]
+    fn offset_write_read() {
+        with_basic_file(&valid_header(), |disk_file: File| {
+            let mut q = QcowFile::from(disk_file).unwrap();
+            let b = [0x55u8; 0x1000];
+            q.seek(SeekFrom::Start(0xfff2000)).expect("Failed to seek.");
+            q.write(&b).expect("Failed to write test string.");
+            let mut buf = [0u8; 4];
+            q.seek(SeekFrom::Start(0xfff2000)).expect("Failed to seek.");
+            q.read(&mut buf).expect("Failed to read.");
+            assert_eq!(buf[0], 0x55);
+        });
+    }
+
+    #[test]
+    fn write_zeroes_read() {
+        with_basic_file(&valid_header(), |disk_file: File| {
+            let mut q = QcowFile::from(disk_file).unwrap();
+            // Write some test data.
+            let b = [0x55u8; 0x1000];
+            q.seek(SeekFrom::Start(0xfff2000)).expect("Failed to seek.");
+            q.write(&b).expect("Failed to write test string.");
+            // Overwrite the test data with zeroes.
+            q.seek(SeekFrom::Start(0xfff2000)).expect("Failed to seek.");
+            let nwritten = q.write_zeroes(0x200).expect("Failed to write zeroes.");
+            assert_eq!(nwritten, 0x200);
+            // Verify that the correct part of the data was zeroed out.
+            let mut buf = [0u8; 0x1000];
+            q.seek(SeekFrom::Start(0xfff2000)).expect("Failed to seek.");
+            q.read(&mut buf).expect("Failed to read.");
+            assert_eq!(buf[0], 0);
+            assert_eq!(buf[0x1FF], 0);
+            assert_eq!(buf[0x200], 0x55);
+            assert_eq!(buf[0xFFF], 0x55);
+        });
+    }
+
+    #[test]
+    fn write_zeroes_full_cluster() {
+        // Choose a size that is larger than a cluster.
+        // valid_header uses cluster_bits = 12, which corresponds to a cluster size of 4096.
+        const CHUNK_SIZE: usize = 4096 * 2 + 512;
+        with_basic_file(&valid_header(), |disk_file: File| {
+            let mut q = QcowFile::from(disk_file).unwrap();
+            // Write some test data.
+            let b = [0x55u8; CHUNK_SIZE];
+            q.seek(SeekFrom::Start(0)).expect("Failed to seek.");
+            q.write(&b).expect("Failed to write test string.");
+            // Overwrite the full cluster with zeroes.
+            q.seek(SeekFrom::Start(0)).expect("Failed to seek.");
+            let nwritten = q.write_zeroes(CHUNK_SIZE).expect("Failed to write zeroes.");
+            assert_eq!(nwritten, CHUNK_SIZE);
+            // Verify that the data was zeroed out.
+            let mut buf = [0u8; CHUNK_SIZE];
+            q.seek(SeekFrom::Start(0)).expect("Failed to seek.");
+            q.read(&mut buf).expect("Failed to read.");
+            assert_eq!(buf[0], 0);
+            assert_eq!(buf[CHUNK_SIZE - 1], 0);
+        });
+    }
+
+    #[test]
+    fn test_header() {
+        with_basic_file(&valid_header(), |disk_file: File| {
+            let q = QcowFile::from(disk_file).unwrap();
+            assert_eq!(q.virtual_size(), 0x20_0000_0000);
+        });
+    }
+
+    #[test]
+    fn read_small_buffer() {
+        with_basic_file(&valid_header(), |disk_file: File| {
+            let mut q = QcowFile::from(disk_file).unwrap();
+            let mut b = [5u8; 16];
+            q.seek(SeekFrom::Start(1000)).expect("Failed to seek.");
+            q.read(&mut b).expect("Failed to read.");
+            assert_eq!(0, b[0]);
+            assert_eq!(0, b[15]);
+        });
+    }
+
+    #[test]
+    fn replay_ext4() {
+        with_basic_file(&valid_header(), |disk_file: File| {
+            let mut q = QcowFile::from(disk_file).unwrap();
+            const BUF_SIZE: usize = 0x1000;
+            let mut b = [0u8; BUF_SIZE];
+
+            struct Transfer {
+                pub write: bool,
+                pub addr: u64,
+            };
+
+            // Write transactions from mkfs.ext4.
+            let xfers: Vec<Transfer> = vec![
+                Transfer {
+                    write: false,
+                    addr: 0xfff0000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xfffe000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x0,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x1000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xffff000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xffdf000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xfff8000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xffe0000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xffce000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xffb6000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xffab000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xffa4000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xff8e000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xff86000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xff84000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xff89000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xfe7e000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x100000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x3000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x7000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xf000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x2000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x4000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x5000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x6000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x8000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x9000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xa000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xb000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xc000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xd000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0xe000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x10000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x11000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x12000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x13000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x14000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x15000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x16000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x17000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x18000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x19000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x1a000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x1b000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x1c000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x1d000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x1e000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x1f000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x21000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x22000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x24000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x40000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x0,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x3000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x7000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x0,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x1000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x2000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x3000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x0,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x449000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x48000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x48000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x448000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x44a000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x48000,
+                },
+                Transfer {
+                    write: false,
+                    addr: 0x48000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0x0,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0x448000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0x449000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0x44a000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfff0000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfff1000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfff2000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfff3000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfff4000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfff5000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfff6000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfff7000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfff8000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfff9000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfffa000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfffb000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfffc000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfffd000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xfffe000,
+                },
+                Transfer {
+                    write: true,
+                    addr: 0xffff000,
+                },
+            ];
+
+            for xfer in &xfers {
+                q.seek(SeekFrom::Start(xfer.addr)).expect("Failed to seek.");
+                if xfer.write {
+                    q.write(&b).expect("Failed to write.");
+                } else {
+                    let read_count: usize = q.read(&mut b).expect("Failed to read.");
+                    assert_eq!(read_count, BUF_SIZE);
+                }
+            }
+        });
+    }
+
+    #[test]
+    fn combo_write_read() {
+        with_default_file(1024 * 1024 * 1024 * 256, |mut qcow_file| {
+            const NUM_BLOCKS: usize = 555;
+            const BLOCK_SIZE: usize = 0x1_0000;
+            const OFFSET: usize = 0x1_0000_0020;
+            let data = [0x55u8; BLOCK_SIZE];
+            let mut readback = [0u8; BLOCK_SIZE];
+            for i in 0..NUM_BLOCKS {
+                let seek_offset = OFFSET + i * BLOCK_SIZE;
+                qcow_file
+                    .seek(SeekFrom::Start(seek_offset as u64))
+                    .expect("Failed to seek.");
+                let nwritten = qcow_file.write(&data).expect("Failed to write test data.");
+                assert_eq!(nwritten, BLOCK_SIZE);
+                // Read back the data to check it was written correctly.
+                qcow_file
+                    .seek(SeekFrom::Start(seek_offset as u64))
+                    .expect("Failed to seek.");
+                let nread = qcow_file.read(&mut readback).expect("Failed to read.");
+                assert_eq!(nread, BLOCK_SIZE);
+                for (orig, read) in data.iter().zip(readback.iter()) {
+                    assert_eq!(orig, read);
+                }
+            }
+            // Check that address 0 is still zeros.
+            qcow_file.seek(SeekFrom::Start(0)).expect("Failed to seek.");
+            let nread = qcow_file.read(&mut readback).expect("Failed to read.");
+            assert_eq!(nread, BLOCK_SIZE);
+            for read in readback.iter() {
+                assert_eq!(*read, 0);
+            }
+            // Check the data again after the writes have happened.
+            for i in 0..NUM_BLOCKS {
+                let seek_offset = OFFSET + i * BLOCK_SIZE;
+                qcow_file
+                    .seek(SeekFrom::Start(seek_offset as u64))
+                    .expect("Failed to seek.");
+                let nread = qcow_file.read(&mut readback).expect("Failed to read.");
+                assert_eq!(nread, BLOCK_SIZE);
+                for (orig, read) in data.iter().zip(readback.iter()) {
+                    assert_eq!(orig, read);
+                }
+            }
+
+            assert_eq!(qcow_file.first_zero_refcount().unwrap(), None);
+        });
+    }
+
+    fn seek_cur(file: &mut QcowFile) -> u64 {
+        file.seek(SeekFrom::Current(0)).unwrap()
+    }
+
+    #[test]
+    fn seek_data() {
+        with_default_file(0x30000, |mut file| {
+            // seek_data at or after the end of the file should return None
+            assert_eq!(file.seek_data(0x10000).unwrap(), None);
+            assert_eq!(seek_cur(&mut file), 0);
+            assert_eq!(file.seek_data(0x10001).unwrap(), None);
+            assert_eq!(seek_cur(&mut file), 0);
+
+            // Write some data to [0x10000, 0x20000)
+            let b = [0x55u8; 0x10000];
+            file.seek(SeekFrom::Start(0x10000)).unwrap();
+            file.write_all(&b).unwrap();
+            assert_eq!(file.seek_data(0).unwrap(), Some(0x10000));
+            assert_eq!(seek_cur(&mut file), 0x10000);
+
+            // seek_data within data should return the same offset
+            assert_eq!(file.seek_data(0x10000).unwrap(), Some(0x10000));
+            assert_eq!(seek_cur(&mut file), 0x10000);
+            assert_eq!(file.seek_data(0x10001).unwrap(), Some(0x10001));
+            assert_eq!(seek_cur(&mut file), 0x10001);
+            assert_eq!(file.seek_data(0x1FFFF).unwrap(), Some(0x1FFFF));
+            assert_eq!(seek_cur(&mut file), 0x1FFFF);
+
+            assert_eq!(file.seek_data(0).unwrap(), Some(0x10000));
+            assert_eq!(seek_cur(&mut file), 0x10000);
+            assert_eq!(file.seek_data(0x1FFFF).unwrap(), Some(0x1FFFF));
+            assert_eq!(seek_cur(&mut file), 0x1FFFF);
+            assert_eq!(file.seek_data(0x20000).unwrap(), None);
+            assert_eq!(seek_cur(&mut file), 0x1FFFF);
+        });
+    }
+
+    #[test]
+    fn seek_hole() {
+        with_default_file(0x30000, |mut file| {
+            // File consisting entirely of a hole
+            assert_eq!(file.seek_hole(0).unwrap(), Some(0));
+            assert_eq!(seek_cur(&mut file), 0);
+            assert_eq!(file.seek_hole(0xFFFF).unwrap(), Some(0xFFFF));
+            assert_eq!(seek_cur(&mut file), 0xFFFF);
+
+            // seek_hole at or after the end of the file should return None
+            file.seek(SeekFrom::Start(0)).unwrap();
+            assert_eq!(file.seek_hole(0x30000).unwrap(), None);
+            assert_eq!(seek_cur(&mut file), 0);
+            assert_eq!(file.seek_hole(0x30001).unwrap(), None);
+            assert_eq!(seek_cur(&mut file), 0);
+
+            // Write some data to [0x10000, 0x20000)
+            let b = [0x55u8; 0x10000];
+            file.seek(SeekFrom::Start(0x10000)).unwrap();
+            file.write_all(&b).unwrap();
+
+            // seek_hole within a hole should return the same offset
+            assert_eq!(file.seek_hole(0).unwrap(), Some(0));
+            assert_eq!(seek_cur(&mut file), 0);
+            assert_eq!(file.seek_hole(0xFFFF).unwrap(), Some(0xFFFF));
+            assert_eq!(seek_cur(&mut file), 0xFFFF);
+
+            // seek_hole within data should return the next hole
+            file.seek(SeekFrom::Start(0)).unwrap();
+            assert_eq!(file.seek_hole(0x10000).unwrap(), Some(0x20000));
+            assert_eq!(seek_cur(&mut file), 0x20000);
+            file.seek(SeekFrom::Start(0)).unwrap();
+            assert_eq!(file.seek_hole(0x10001).unwrap(), Some(0x20000));
+            assert_eq!(seek_cur(&mut file), 0x20000);
+            file.seek(SeekFrom::Start(0)).unwrap();
+            assert_eq!(file.seek_hole(0x1FFFF).unwrap(), Some(0x20000));
+            assert_eq!(seek_cur(&mut file), 0x20000);
+            file.seek(SeekFrom::Start(0)).unwrap();
+            assert_eq!(file.seek_hole(0xFFFF).unwrap(), Some(0xFFFF));
+            assert_eq!(seek_cur(&mut file), 0xFFFF);
+            file.seek(SeekFrom::Start(0)).unwrap();
+            assert_eq!(file.seek_hole(0x10000).unwrap(), Some(0x20000));
+            assert_eq!(seek_cur(&mut file), 0x20000);
+            file.seek(SeekFrom::Start(0)).unwrap();
+            assert_eq!(file.seek_hole(0x1FFFF).unwrap(), Some(0x20000));
+            assert_eq!(seek_cur(&mut file), 0x20000);
+            file.seek(SeekFrom::Start(0)).unwrap();
+            assert_eq!(file.seek_hole(0x20000).unwrap(), Some(0x20000));
+            assert_eq!(seek_cur(&mut file), 0x20000);
+            file.seek(SeekFrom::Start(0)).unwrap();
+            assert_eq!(file.seek_hole(0x20001).unwrap(), Some(0x20001));
+            assert_eq!(seek_cur(&mut file), 0x20001);
+
+            // seek_hole at EOF should return None
+            file.seek(SeekFrom::Start(0)).unwrap();
+            assert_eq!(file.seek_hole(0x30000).unwrap(), None);
+            assert_eq!(seek_cur(&mut file), 0);
+
+            // Write some data to [0x20000, 0x30000)
+            file.seek(SeekFrom::Start(0x20000)).unwrap();
+            file.write_all(&b).unwrap();
+
+            // seek_hole within [0x20000, 0x30000) should now find the hole at EOF
+            assert_eq!(file.seek_hole(0x20000).unwrap(), Some(0x30000));
+            assert_eq!(seek_cur(&mut file), 0x30000);
+            file.seek(SeekFrom::Start(0)).unwrap();
+            assert_eq!(file.seek_hole(0x20001).unwrap(), Some(0x30000));
+            assert_eq!(seek_cur(&mut file), 0x30000);
+            file.seek(SeekFrom::Start(0)).unwrap();
+            assert_eq!(file.seek_hole(0x30000).unwrap(), None);
+            assert_eq!(seek_cur(&mut file), 0);
+        });
+    }
+
+    #[test]
+    fn rebuild_refcounts() {
+        with_basic_file(&valid_header(), |mut disk_file: File| {
+            let header = QcowHeader::new(&mut disk_file).expect("Failed to create Header.");
+            let cluster_size = 65536;
+            let mut raw_file =
+                QcowRawFile::from(disk_file, cluster_size).expect("Failed to create QcowRawFile.");
+            QcowFile::rebuild_refcounts(&mut raw_file, header)
+                .expect("Failed to rebuild recounts.");
+        });
+    }
+}
diff --git a/qcow/src/qcow_raw_file.rs b/qcow/src/qcow_raw_file.rs
new file mode 100644
index 0000000..456b986
--- /dev/null
+++ b/qcow/src/qcow_raw_file.rs
@@ -0,0 +1,136 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fs::File;
+use std::io::{self, BufWriter, Seek, SeekFrom};
+use std::mem::size_of;
+
+use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
+
+/// A qcow file. Allows reading/writing clusters and appending clusters.
+#[derive(Debug)]
+pub struct QcowRawFile {
+    file: File,
+    cluster_size: u64,
+    cluster_mask: u64,
+}
+
+impl QcowRawFile {
+    /// Creates a `QcowRawFile` from the given `File`, `None` is returned if `cluster_size` is not
+    /// a power of two.
+    pub fn from(file: File, cluster_size: u64) -> Option<Self> {
+        if cluster_size.count_ones() != 1 {
+            return None;
+        }
+        Some(QcowRawFile {
+            file,
+            cluster_size,
+            cluster_mask: cluster_size - 1,
+        })
+    }
+
+    /// Reads `count` 64 bit offsets and returns them as a vector.
+    /// `mask` optionally ands out some of the bits on the file.
+    pub fn read_pointer_table(
+        &mut self,
+        offset: u64,
+        count: u64,
+        mask: Option<u64>,
+    ) -> io::Result<Vec<u64>> {
+        let mut table = vec![0; count as usize];
+        self.file.seek(SeekFrom::Start(offset))?;
+        self.file.read_u64_into::<BigEndian>(&mut table)?;
+        if let Some(m) = mask {
+            for ptr in &mut table {
+                *ptr &= m;
+            }
+        }
+        Ok(table)
+    }
+
+    /// Reads a cluster's worth of 64 bit offsets and returns them as a vector.
+    /// `mask` optionally ands out some of the bits on the file.
+    pub fn read_pointer_cluster(&mut self, offset: u64, mask: Option<u64>) -> io::Result<Vec<u64>> {
+        let count = self.cluster_size / size_of::<u64>() as u64;
+        self.read_pointer_table(offset, count, mask)
+    }
+
+    /// Writes `table` of u64 pointers to `offset` in the file.
+    /// `non_zero_flags` will be ORed with all non-zero values in `table`.
+    /// writing.
+    pub fn write_pointer_table(
+        &mut self,
+        offset: u64,
+        table: &[u64],
+        non_zero_flags: u64,
+    ) -> io::Result<()> {
+        self.file.seek(SeekFrom::Start(offset))?;
+        let mut buffer = BufWriter::with_capacity(table.len() * size_of::<u64>(), &self.file);
+        for addr in table {
+            let val = if *addr == 0 {
+                0
+            } else {
+                *addr | non_zero_flags
+            };
+            buffer.write_u64::<BigEndian>(val)?;
+        }
+        Ok(())
+    }
+
+    /// Read a refcount block from the file and returns a Vec containing the block.
+    /// Always returns a cluster's worth of data.
+    pub fn read_refcount_block(&mut self, offset: u64) -> io::Result<Vec<u16>> {
+        let count = self.cluster_size / size_of::<u16>() as u64;
+        let mut table = vec![0; count as usize];
+        self.file.seek(SeekFrom::Start(offset))?;
+        self.file.read_u16_into::<BigEndian>(&mut table)?;
+        Ok(table)
+    }
+
+    /// Writes a refcount block to the file.
+    pub fn write_refcount_block(&mut self, offset: u64, table: &[u16]) -> io::Result<()> {
+        self.file.seek(SeekFrom::Start(offset))?;
+        let mut buffer = BufWriter::with_capacity(table.len() * size_of::<u16>(), &self.file);
+        for count in table {
+            buffer.write_u16::<BigEndian>(*count)?;
+        }
+        Ok(())
+    }
+
+    /// Allocates a new cluster at the end of the current file, return the address.
+    pub fn add_cluster_end(&mut self, max_valid_cluster_offset: u64) -> io::Result<Option<u64>> {
+        // Determine where the new end of the file should be and set_len, which
+        // translates to truncate(2).
+        let file_end: u64 = self.file.seek(SeekFrom::End(0))?;
+        let new_cluster_address: u64 = (file_end + self.cluster_size - 1) & !self.cluster_mask;
+
+        if new_cluster_address > max_valid_cluster_offset {
+            return Ok(None);
+        }
+
+        self.file.set_len(new_cluster_address + self.cluster_size)?;
+
+        Ok(Some(new_cluster_address))
+    }
+
+    /// Returns a reference to the underlying file.
+    pub fn file(&self) -> &File {
+        &self.file
+    }
+
+    /// Returns a mutable reference to the underlying file.
+    pub fn file_mut(&mut self) -> &mut File {
+        &mut self.file
+    }
+
+    /// Returns the size of the file's clusters.
+    pub fn cluster_size(&self) -> u64 {
+        self.cluster_size
+    }
+
+    /// Returns the offset of `address` within a cluster.
+    pub fn cluster_offset(&self, address: u64) -> u64 {
+        address & self.cluster_mask
+    }
+}
diff --git a/qcow/src/refcount.rs b/qcow/src/refcount.rs
new file mode 100644
index 0000000..5a87d86
--- /dev/null
+++ b/qcow/src/refcount.rs
@@ -0,0 +1,253 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std;
+use std::fmt::{self, Display};
+use std::io;
+
+use libc::EINVAL;
+
+use crate::qcow_raw_file::QcowRawFile;
+use crate::vec_cache::{CacheMap, Cacheable, VecCache};
+
+#[derive(Debug)]
+pub enum Error {
+    /// `EvictingCache` - Error writing a refblock from the cache to disk.
+    EvictingRefCounts(io::Error),
+    /// `InvalidIndex` - Address requested isn't within the range of the disk.
+    InvalidIndex,
+    /// `NeedCluster` - Handle this error by reading the cluster and calling the function again.
+    NeedCluster(u64),
+    /// `NeedNewCluster` - Handle this error by allocating a cluster and calling the function again.
+    NeedNewCluster,
+    /// `ReadingRefCounts` - Error reading the file in to the refcount cache.
+    ReadingRefCounts(io::Error),
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            EvictingRefCounts(e) => write!(
+                f,
+                "failed to write a refblock from the cache to disk: {}",
+                e
+            ),
+            InvalidIndex => write!(f, "address requested is not within the range of the disk"),
+            NeedCluster(addr) => write!(f, "cluster with addr={} needs to be read", addr),
+            NeedNewCluster => write!(f, "new cluster needs to be allocated for refcounts"),
+            ReadingRefCounts(e) => {
+                write!(f, "failed to read the file into the refcount cache: {}", e)
+            }
+        }
+    }
+}
+
+/// Represents the refcount entries for an open qcow file.
+#[derive(Debug)]
+pub struct RefCount {
+    ref_table: VecCache<u64>,
+    refcount_table_offset: u64,
+    refblock_cache: CacheMap<VecCache<u16>>,
+    refcount_block_entries: u64, // number of refcounts in a cluster.
+    cluster_size: u64,
+    max_valid_cluster_offset: u64,
+}
+
+impl RefCount {
+    /// Creates a `RefCount` from `file`, reading the refcount table from `refcount_table_offset`.
+    /// `refcount_table_entries` specifies the number of refcount blocks used by this image.
+    /// `refcount_block_entries` indicates the number of refcounts in each refcount block.
+    /// Each refcount table entry points to a refcount block.
+    pub fn new(
+        raw_file: &mut QcowRawFile,
+        refcount_table_offset: u64,
+        refcount_table_entries: u64,
+        refcount_block_entries: u64,
+        cluster_size: u64,
+    ) -> io::Result<RefCount> {
+        let ref_table = VecCache::from_vec(raw_file.read_pointer_table(
+            refcount_table_offset,
+            refcount_table_entries,
+            None,
+        )?);
+        let max_valid_cluster_index = (ref_table.len() as u64) * refcount_block_entries - 1;
+        let max_valid_cluster_offset = max_valid_cluster_index * cluster_size;
+        Ok(RefCount {
+            ref_table,
+            refcount_table_offset,
+            refblock_cache: CacheMap::new(50),
+            refcount_block_entries,
+            cluster_size,
+            max_valid_cluster_offset,
+        })
+    }
+
+    /// Returns the number of refcounts per block.
+    pub fn refcounts_per_block(&self) -> u64 {
+        self.refcount_block_entries
+    }
+
+    /// Returns the maximum valid cluster offset in the raw file for this refcount table.
+    pub fn max_valid_cluster_offset(&self) -> u64 {
+        self.max_valid_cluster_offset
+    }
+
+    /// Returns `NeedNewCluster` if a new cluster needs to be allocated for refcounts. If an
+    /// existing cluster needs to be read, `NeedCluster(addr)` is returned. The Caller should
+    /// allocate a cluster or read the required one and call this function again with the cluster.
+    /// On success, an optional address of a dropped cluster is returned. The dropped cluster can
+    /// be reused for other purposes.
+    pub fn set_cluster_refcount(
+        &mut self,
+        raw_file: &mut QcowRawFile,
+        cluster_address: u64,
+        refcount: u16,
+        mut new_cluster: Option<(u64, VecCache<u16>)>,
+    ) -> Result<Option<u64>> {
+        let (table_index, block_index) = self.get_refcount_index(cluster_address);
+
+        let block_addr_disk = *self.ref_table.get(table_index).ok_or(Error::InvalidIndex)?;
+
+        // Fill the cache if this block isn't yet there.
+        if !self.refblock_cache.contains_key(&table_index) {
+            // Need a new cluster
+            if let Some((addr, table)) = new_cluster.take() {
+                self.ref_table[table_index] = addr;
+                let ref_table = &self.ref_table;
+                self.refblock_cache
+                    .insert(table_index, table, |index, evicted| {
+                        raw_file.write_refcount_block(ref_table[index], evicted.get_values())
+                    })
+                    .map_err(Error::EvictingRefCounts)?;
+            } else {
+                if block_addr_disk == 0 {
+                    return Err(Error::NeedNewCluster);
+                }
+                return Err(Error::NeedCluster(block_addr_disk));
+            }
+        }
+
+        // Unwrap is safe here as the entry was filled directly above.
+        let dropped_cluster = if !self.refblock_cache.get(&table_index).unwrap().dirty() {
+            // Free the previously used block and use a new one. Writing modified counts to new
+            // blocks keeps the on-disk state consistent even if it's out of date.
+            if let Some((addr, _)) = new_cluster.take() {
+                self.ref_table[table_index] = addr;
+                Some(block_addr_disk)
+            } else {
+                return Err(Error::NeedNewCluster);
+            }
+        } else {
+            None
+        };
+
+        self.refblock_cache.get_mut(&table_index).unwrap()[block_index] = refcount;
+        Ok(dropped_cluster)
+    }
+
+    /// Flush the dirty refcount blocks. This must be done before flushing the table that points to
+    /// the blocks.
+    pub fn flush_blocks(&mut self, raw_file: &mut QcowRawFile) -> io::Result<()> {
+        // Write out all dirty L2 tables.
+        for (table_index, block) in self.refblock_cache.iter_mut().filter(|(_k, v)| v.dirty()) {
+            let addr = self.ref_table[*table_index];
+            if addr != 0 {
+                raw_file.write_refcount_block(addr, block.get_values())?;
+            } else {
+                return Err(std::io::Error::from_raw_os_error(EINVAL));
+            }
+            block.mark_clean();
+        }
+        Ok(())
+    }
+
+    /// Flush the refcount table that keeps the address of the refcounts blocks.
+    /// Returns true if the table changed since the previous `flush_table()` call.
+    pub fn flush_table(&mut self, raw_file: &mut QcowRawFile) -> io::Result<bool> {
+        if self.ref_table.dirty() {
+            raw_file.write_pointer_table(
+                self.refcount_table_offset,
+                &self.ref_table.get_values(),
+                0,
+            )?;
+            self.ref_table.mark_clean();
+            Ok(true)
+        } else {
+            Ok(false)
+        }
+    }
+
+    /// Gets the refcount for a cluster with the given address.
+    pub fn get_cluster_refcount(
+        &mut self,
+        raw_file: &mut QcowRawFile,
+        address: u64,
+    ) -> Result<u16> {
+        let (table_index, block_index) = self.get_refcount_index(address);
+        let block_addr_disk = *self.ref_table.get(table_index).ok_or(Error::InvalidIndex)?;
+        if block_addr_disk == 0 {
+            return Ok(0);
+        }
+        if !self.refblock_cache.contains_key(&table_index) {
+            let table = VecCache::from_vec(
+                raw_file
+                    .read_refcount_block(block_addr_disk)
+                    .map_err(Error::ReadingRefCounts)?,
+            );
+            let ref_table = &self.ref_table;
+            self.refblock_cache
+                .insert(table_index, table, |index, evicted| {
+                    raw_file.write_refcount_block(ref_table[index], evicted.get_values())
+                })
+                .map_err(Error::EvictingRefCounts)?;
+        }
+        Ok(self.refblock_cache.get(&table_index).unwrap()[block_index])
+    }
+
+    /// Returns the refcount table for this file. This is only useful for debugging.
+    pub fn ref_table(&self) -> &[u64] {
+        &self.ref_table.get_values()
+    }
+
+    /// Returns the refcounts stored in the given block.
+    pub fn refcount_block(
+        &mut self,
+        raw_file: &mut QcowRawFile,
+        table_index: usize,
+    ) -> Result<Option<&[u16]>> {
+        let block_addr_disk = *self.ref_table.get(table_index).ok_or(Error::InvalidIndex)?;
+        if block_addr_disk == 0 {
+            return Ok(None);
+        }
+        if !self.refblock_cache.contains_key(&table_index) {
+            let table = VecCache::from_vec(
+                raw_file
+                    .read_refcount_block(block_addr_disk)
+                    .map_err(Error::ReadingRefCounts)?,
+            );
+            // TODO(dgreid) - closure needs to return an error.
+            let ref_table = &self.ref_table;
+            self.refblock_cache
+                .insert(table_index, table, |index, evicted| {
+                    raw_file.write_refcount_block(ref_table[index], evicted.get_values())
+                })
+                .map_err(Error::EvictingRefCounts)?;
+        }
+        // The index must exist as it was just inserted if it didn't already.
+        Ok(Some(
+            self.refblock_cache.get(&table_index).unwrap().get_values(),
+        ))
+    }
+
+    // Gets the address of the refcount block and the index into the block for the given address.
+    fn get_refcount_index(&self, address: u64) -> (usize, usize) {
+        let block_index = (address / self.cluster_size) % self.refcount_block_entries;
+        let refcount_table_index = (address / self.cluster_size) / self.refcount_block_entries;
+        (refcount_table_index as usize, block_index as usize)
+    }
+}
diff --git a/qcow/src/vec_cache.rs b/qcow/src/vec_cache.rs
new file mode 100644
index 0000000..ecd7673
--- /dev/null
+++ b/qcow/src/vec_cache.rs
@@ -0,0 +1,185 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::collections::hash_map::IterMut;
+use std::collections::HashMap;
+use std::io;
+use std::ops::{Index, IndexMut};
+use std::slice::SliceIndex;
+
+/// Trait that allows for checking if an implementor is dirty. Useful for types that are cached so
+/// it can be checked if they need to be committed to disk.
+pub trait Cacheable {
+    /// Used to check if the item needs to be written out or if it can be discarded.
+    fn dirty(&self) -> bool;
+}
+
+#[derive(Debug)]
+/// Represents a vector that implements the `Cacheable` trait so it can be held in a cache.
+pub struct VecCache<T: 'static + Copy + Default> {
+    vec: Box<[T]>,
+    dirty: bool,
+}
+
+impl<T: 'static + Copy + Default> VecCache<T> {
+    /// Creates a `VecCache` that can hold `count` elements.
+    pub fn new(count: usize) -> VecCache<T> {
+        VecCache {
+            vec: vec![Default::default(); count].into_boxed_slice(),
+            dirty: true,
+        }
+    }
+
+    /// Creates a `VecCache` from the passed in `vec`.
+    pub fn from_vec(vec: Vec<T>) -> VecCache<T> {
+        VecCache {
+            vec: vec.into_boxed_slice(),
+            dirty: false,
+        }
+    }
+
+    pub fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output>
+    where
+        I: SliceIndex<[T]>,
+    {
+        self.vec.get(index)
+    }
+
+    /// Gets a reference to the underlying vector.
+    pub fn get_values(&self) -> &[T] {
+        &self.vec
+    }
+
+    /// Mark this cache element as clean.
+    pub fn mark_clean(&mut self) {
+        self.dirty = false;
+    }
+
+    /// Returns the number of elements in the vector.
+    pub fn len(&self) -> usize {
+        self.vec.len()
+    }
+}
+
+impl<T: 'static + Copy + Default> Cacheable for VecCache<T> {
+    fn dirty(&self) -> bool {
+        self.dirty
+    }
+}
+
+impl<T: 'static + Copy + Default> Index<usize> for VecCache<T> {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &T {
+        self.vec.index(index)
+    }
+}
+
+impl<T: 'static + Copy + Default> IndexMut<usize> for VecCache<T> {
+    fn index_mut(&mut self, index: usize) -> &mut T {
+        self.dirty = true;
+        self.vec.index_mut(index)
+    }
+}
+
+#[derive(Debug)]
+pub struct CacheMap<T: Cacheable> {
+    capacity: usize,
+    map: HashMap<usize, T>,
+}
+
+impl<T: Cacheable> CacheMap<T> {
+    pub fn new(capacity: usize) -> Self {
+        CacheMap {
+            capacity,
+            map: HashMap::with_capacity(capacity),
+        }
+    }
+
+    pub fn contains_key(&self, key: &usize) -> bool {
+        self.map.contains_key(key)
+    }
+
+    pub fn get(&self, index: &usize) -> Option<&T> {
+        self.map.get(index)
+    }
+
+    pub fn get_mut(&mut self, index: &usize) -> Option<&mut T> {
+        self.map.get_mut(index)
+    }
+
+    pub fn iter_mut(&mut self) -> IterMut<usize, T> {
+        self.map.iter_mut()
+    }
+
+    // Check if the refblock cache is full and we need to evict.
+    pub fn insert<F>(&mut self, index: usize, block: T, write_callback: F) -> io::Result<()>
+    where
+        F: FnOnce(usize, T) -> io::Result<()>,
+    {
+        if self.map.len() == self.capacity {
+            // TODO(dgreid) - smarter eviction strategy.
+            let to_evict = *self.map.iter().nth(0).unwrap().0;
+            if let Some(evicted) = self.map.remove(&to_evict) {
+                if evicted.dirty() {
+                    write_callback(to_evict, evicted)?;
+                }
+            }
+        }
+        self.map.insert(index, block);
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    struct NumCache(pub u64);
+    impl Cacheable for NumCache {
+        fn dirty(&self) -> bool {
+            true
+        }
+    }
+
+    #[test]
+    fn evicts_when_full() {
+        let mut cache = CacheMap::<NumCache>::new(3);
+        let mut evicted = None;
+        cache
+            .insert(0, NumCache(5), |index, _| {
+                evicted = Some(index);
+                Ok(())
+            })
+            .unwrap();
+        assert_eq!(evicted, None);
+        cache
+            .insert(1, NumCache(6), |index, _| {
+                evicted = Some(index);
+                Ok(())
+            })
+            .unwrap();
+        assert_eq!(evicted, None);
+        cache
+            .insert(2, NumCache(7), |index, _| {
+                evicted = Some(index);
+                Ok(())
+            })
+            .unwrap();
+        assert_eq!(evicted, None);
+        cache
+            .insert(3, NumCache(8), |index, _| {
+                evicted = Some(index);
+                Ok(())
+            })
+            .unwrap();
+        assert!(evicted.is_some());
+
+        // Check that three of the four items inserted are still there and that the most recently
+        // inserted is one of them.
+        let num_items = (0..=3).filter(|k| cache.contains_key(&k)).count();
+        assert_eq!(num_items, 3);
+        assert!(cache.contains_key(&3));
+    }
+}
diff --git a/qcow_utils/Cargo.toml b/qcow_utils/Cargo.toml
new file mode 100644
index 0000000..67b9d28
--- /dev/null
+++ b/qcow_utils/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "qcow_utils"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[lib]
+path = "src/qcow_utils.rs"
+crate-type = ["cdylib"]
+
+[[bin]]
+name = "qcow_img"
+path = "src/qcow_img.rs"
+
+[dependencies]
+getopts = "*"
+libc = "*"
+qcow = { path = "../qcow" }
+sys_util = { path = "../sys_util" }
diff --git a/qcow_utils/libqcow_utils.pc.in b/qcow_utils/libqcow_utils.pc.in
new file mode 100644
index 0000000..a5f0f5f
--- /dev/null
+++ b/qcow_utils/libqcow_utils.pc.in
@@ -0,0 +1,8 @@
+bslot=@BSLOT@
+include_dir=@INCLUDE_DIR@
+
+Name: libqcow_utils
+Description: QCOW2 shared library.
+Version: ${bslot}
+CFlags: -I${include_dir}
+Libs: -lqcow_utils
diff --git a/qcow_utils/platform2_preinstall.sh b/qcow_utils/platform2_preinstall.sh
new file mode 100755
index 0000000..5029010
--- /dev/null
+++ b/qcow_utils/platform2_preinstall.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+v=$1
+include_dir=$2
+target_dir=$3
+
+sed \
+  -e "s/@BSLOT@/${v}/g" \
+  -e "s:@INCLUDE_DIR@:${include_dir}:g" \
+  "qcow_utils/libqcow_utils.pc.in" > "${target_dir}/libqcow_utils.pc"
diff --git a/qcow_utils/src/qcow_img.rs b/qcow_utils/src/qcow_img.rs
new file mode 100644
index 0000000..66230da
--- /dev/null
+++ b/qcow_utils/src/qcow_img.rs
@@ -0,0 +1,322 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fs::OpenOptions;
+use std::io::{Read, Write};
+
+use getopts::Options;
+
+use qcow::QcowFile;
+use sys_util::WriteZeroes;
+
+fn show_usage(program_name: &str) {
+    println!("Usage: {} [subcommand] <subcommand args>", program_name);
+    println!("\nSubcommands:");
+    println!(
+        "{} header <file name> - Show the qcow2 header for a file.",
+        program_name
+    );
+    println!(
+        "{} l1_table <file name> - Show the L1 table entries for a file.",
+        program_name
+    );
+    println!(
+        "{} l22table <file name> <l1 index> - Show the L2 table pointed to by the nth L1 entry.",
+        program_name
+    );
+    println!(
+        "{} ref_table <file name> - Show the refblock table for the file.",
+        program_name
+    );
+    println!(
+        "{} ref_block <file_name> <table index> - Show the nth reblock in the file.",
+        program_name
+    );
+    println!(
+        "{} dd <file_name> <source_file> - Write bytes from the raw source_file to the file.",
+        program_name
+    );
+    println!(
+        "{} convert <src_file> <dst_file> - Convert from src_file to dst_file.",
+        program_name
+    );
+}
+
+fn main() -> std::result::Result<(), ()> {
+    let args: Vec<String> = std::env::args().collect();
+    let opts = Options::new();
+
+    let matches = match opts.parse(&args[1..]) {
+        Ok(m) => m,
+        Err(f) => panic!(f.to_string()),
+    };
+
+    if matches.free.len() < 2 {
+        println!("Must specify the subcommand and the QCOW file to operate on.");
+        show_usage(&args[0]);
+        return Err(());
+    }
+
+    match matches.free[0].as_ref() {
+        "header" => show_header(&matches.free[1]),
+        "help" => {
+            show_usage(&args[0]);
+            Ok(())
+        }
+        "l1_table" => show_l1_table(&matches.free[1]),
+        "l2_table" => {
+            if matches.free.len() < 2 {
+                println!("Filename and table index are required.");
+                show_usage(&args[0]);
+                return Err(());
+            }
+            show_l2_table(&matches.free[1], matches.free[2].parse().unwrap())
+        }
+        "ref_table" => show_ref_table(&matches.free[1]),
+        "ref_block" => {
+            if matches.free.len() < 2 {
+                println!("Filename and block index are required.");
+                show_usage(&args[0]);
+                return Err(());
+            }
+            show_ref_block(&matches.free[1], matches.free[2].parse().unwrap())
+        }
+        "dd" => {
+            if matches.free.len() < 2 {
+                println!("Qcow and source file are required.");
+                show_usage(&args[0]);
+                return Err(());
+            }
+            let count = if matches.free.len() > 3 {
+                Some(matches.free[3].parse().unwrap())
+            } else {
+                None
+            };
+            dd(&matches.free[1], &matches.free[2], count)
+        }
+        "convert" => {
+            if matches.free.len() < 2 {
+                println!("Source and destination files are required.");
+                show_usage(&args[0]);
+                return Err(());
+            }
+            convert(&matches.free[1], &matches.free[2])
+        }
+        c => {
+            println!("invalid subcommand: {:?}", c);
+            Err(())
+        }
+    }
+}
+
+fn show_header(file_path: &str) -> std::result::Result<(), ()> {
+    let file = match OpenOptions::new().read(true).open(file_path) {
+        Ok(f) => f,
+        Err(_) => {
+            println!("Failed to open {}", file_path);
+            return Err(());
+        }
+    };
+
+    let qcow_file = QcowFile::from(file).map_err(|_| ())?;
+    let header = qcow_file.header();
+
+    println!("magic {:x}", header.magic);
+    println!("version {:x}", header.version);
+    println!("backing_file_offset {:x}", header.backing_file_offset);
+    println!("backing_file_size {:x}", header.backing_file_size);
+    println!("cluster_bits {:x}", header.cluster_bits);
+    println!("size {:x}", header.size);
+    println!("crypt_method {:x}", header.crypt_method);
+    println!("l1_size {:x}", header.l1_size);
+    println!("l1_table_offset {:x}", header.l1_table_offset);
+    println!("refcount_table_offset {:x}", header.refcount_table_offset);
+    println!(
+        "refcount_table_clusters {:x}",
+        header.refcount_table_clusters
+    );
+    println!("nb_snapshots {:x}", header.nb_snapshots);
+    println!("snapshots_offset {:x}", header.snapshots_offset);
+    println!("incompatible_features {:x}", header.incompatible_features);
+    println!("compatible_features {:x}", header.compatible_features);
+    println!("autoclear_features {:x}", header.autoclear_features);
+    println!("refcount_order {:x}", header.refcount_order);
+    println!("header_size {:x}", header.header_size);
+    Ok(())
+}
+
+fn show_l1_table(file_path: &str) -> std::result::Result<(), ()> {
+    let file = match OpenOptions::new().read(true).open(file_path) {
+        Ok(f) => f,
+        Err(_) => {
+            println!("Failed to open {}", file_path);
+            return Err(());
+        }
+    };
+
+    let qcow_file = QcowFile::from(file).map_err(|_| ())?;
+    let l1_table = qcow_file.l1_table();
+
+    for (i, l2_offset) in l1_table.iter().enumerate() {
+        println!("{}: {:x}", i, l2_offset);
+    }
+
+    Ok(())
+}
+
+fn show_l2_table(file_path: &str, index: usize) -> std::result::Result<(), ()> {
+    let file = match OpenOptions::new().read(true).open(file_path) {
+        Ok(f) => f,
+        Err(_) => {
+            println!("Failed to open {}", file_path);
+            return Err(());
+        }
+    };
+
+    let mut qcow_file = QcowFile::from(file).map_err(|_| ())?;
+    let l2_table = qcow_file.l2_table(index).unwrap();
+
+    if let Some(cluster_addrs) = l2_table {
+        for (i, addr) in cluster_addrs.iter().enumerate() {
+            if i % 16 == 0 {
+                print!("\n{:x}:", i);
+            }
+            print!(" {:x}", addr);
+        }
+    }
+
+    Ok(())
+}
+
+fn show_ref_table(file_path: &str) -> std::result::Result<(), ()> {
+    let file = match OpenOptions::new().read(true).open(file_path) {
+        Ok(f) => f,
+        Err(_) => {
+            println!("Failed to open {}", file_path);
+            return Err(());
+        }
+    };
+
+    let qcow_file = QcowFile::from(file).map_err(|_| ())?;
+    let ref_table = qcow_file.ref_table();
+
+    for (i, block_offset) in ref_table.iter().enumerate() {
+        println!("{}: {:x}", i, block_offset);
+    }
+
+    Ok(())
+}
+
+fn show_ref_block(file_path: &str, index: usize) -> std::result::Result<(), ()> {
+    let file = match OpenOptions::new().read(true).open(file_path) {
+        Ok(f) => f,
+        Err(_) => {
+            println!("Failed to open {}", file_path);
+            return Err(());
+        }
+    };
+
+    let mut qcow_file = QcowFile::from(file).map_err(|_| ())?;
+    let ref_table = qcow_file.refcount_block(index).unwrap();
+
+    if let Some(counts) = ref_table {
+        for (i, count) in counts.iter().enumerate() {
+            if i % 16 == 0 {
+                print!("\n{:x}:", i);
+            }
+            print!(" {:x}", count);
+        }
+    }
+
+    Ok(())
+}
+
+// Transfers from a raw file specifiec in `source_path` to the qcow file specified in `file_path`.
+fn dd(file_path: &str, source_path: &str, count: Option<usize>) -> std::result::Result<(), ()> {
+    let file = match OpenOptions::new().read(true).write(true).open(file_path) {
+        Ok(f) => f,
+        Err(_) => {
+            println!("Failed to open {}", file_path);
+            return Err(());
+        }
+    };
+
+    let mut qcow_file = QcowFile::from(file).map_err(|_| ())?;
+
+    let mut src_file = match OpenOptions::new().read(true).open(source_path) {
+        Ok(f) => f,
+        Err(_) => {
+            println!("Failed to open {}", file_path);
+            return Err(());
+        }
+    };
+
+    let mut read_count = 0;
+    const CHUNK_SIZE: usize = 65536;
+    let mut buf = [0; CHUNK_SIZE];
+    loop {
+        let this_count = if let Some(count) = count {
+            std::cmp::min(CHUNK_SIZE, count - read_count)
+        } else {
+            CHUNK_SIZE
+        };
+        let nread = src_file.read(&mut buf[..this_count]).map_err(|_| ())?;
+        // If this block is all zeros, then use write_zeros so the output file is sparse.
+        if buf.iter().all(|b| *b == 0) {
+            qcow_file.write_zeroes(CHUNK_SIZE).map_err(|_| ())?;
+        } else {
+            qcow_file.write(&buf).map_err(|_| ())?;
+        }
+        read_count = read_count + nread;
+        if nread == 0 || Some(read_count) == count {
+            break;
+        }
+    }
+
+    println!("wrote {} bytes", read_count);
+
+    Ok(())
+}
+
+// Reads the file at `src_path` and writes it to `dst_path`.
+// The output format is detected based on the `dst_path` file extension.
+fn convert(src_path: &str, dst_path: &str) -> std::result::Result<(), ()> {
+    let src_file = match OpenOptions::new().read(true).open(src_path) {
+        Ok(f) => f,
+        Err(_) => {
+            println!("Failed to open source file {}", src_path);
+            return Err(());
+        }
+    };
+
+    let dst_file = match OpenOptions::new()
+        .read(true)
+        .write(true)
+        .create(true)
+        .open(dst_path)
+    {
+        Ok(f) => f,
+        Err(_) => {
+            println!("Failed to open destination file {}", dst_path);
+            return Err(());
+        }
+    };
+
+    let dst_type = if dst_path.ends_with("qcow2") {
+        qcow::ImageType::Qcow2
+    } else {
+        qcow::ImageType::Raw
+    };
+
+    match qcow::convert(src_file, dst_file, dst_type) {
+        Ok(_) => {
+            println!("Converted {} to {}", src_path, dst_path);
+            Ok(())
+        }
+        Err(_) => {
+            println!("Failed to copy from {} to {}", src_path, dst_path);
+            Err(())
+        }
+    }
+}
diff --git a/qcow_utils/src/qcow_utils.h b/qcow_utils/src/qcow_utils.h
new file mode 100644
index 0000000..90aa23b
--- /dev/null
+++ b/qcow_utils/src/qcow_utils.h
@@ -0,0 +1,30 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+
+// Exported interface to basic qcow functionality to be used from C.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Create a basic, empty qcow2 file that can grow to `virtual_size` at `path`.
+int create_qcow_with_size(const char *path, uint64_t virtual_size);
+
+// Attempt to resize the disk image at `path` to `virtual_size` bytes if
+// the disk image is currently smaller than the requested size.
+int expand_disk_image(const char *path, uint64_t virtual_size);
+
+// Copy the source disk image from `src_fd` into `dst_fd` as a qcow2 image file.
+// Returns 0 on success or a negated errno value on failure.
+int convert_to_qcow2(int src_fd, int dst_fd);
+
+// Copy the source disk image from `src_fd` into `dst_fd` as a raw image file.
+// Returns 0 on success or a negated errno value on failure.
+int convert_to_raw(int src_fd, int dst_fd);
+
+#ifdef __cplusplus
+};
+#endif
diff --git a/qcow_utils/src/qcow_utils.rs b/qcow_utils/src/qcow_utils.rs
new file mode 100644
index 0000000..6c8b86f
--- /dev/null
+++ b/qcow_utils/src/qcow_utils.rs
@@ -0,0 +1,156 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Exported interface to basic qcow functionality to be used from C.
+
+use libc::{EBADFD, EINVAL, EIO, ENOSYS};
+use std::ffi::CStr;
+use std::fs::{File, OpenOptions};
+use std::io::{Seek, SeekFrom};
+use std::mem::forget;
+use std::os::raw::{c_char, c_int};
+use std::os::unix::io::FromRawFd;
+use std::panic::catch_unwind;
+
+use qcow::{ImageType, QcowFile};
+use sys_util::{flock, FileSetLen, FlockOperation};
+
+trait DiskFile: FileSetLen + Seek {}
+impl<D: FileSetLen + Seek> DiskFile for D {}
+
+#[no_mangle]
+pub unsafe extern "C" fn create_qcow_with_size(path: *const c_char, virtual_size: u64) -> c_int {
+    // NULL pointers are checked, but this will access any other invalid pointer passed from C
+    // code. It's the caller's responsibility to pass a valid pointer.
+    if path.is_null() {
+        return -EINVAL;
+    }
+    let c_str = CStr::from_ptr(path);
+    let file_path = match c_str.to_str() {
+        Ok(s) => s,
+        Err(_) => return -EINVAL,
+    };
+
+    let file = match OpenOptions::new()
+        .create(true)
+        .read(true)
+        .write(true)
+        .open(file_path)
+    {
+        Ok(f) => f,
+        Err(_) => return -1,
+    };
+
+    match QcowFile::new(file, virtual_size) {
+        Ok(_) => 0,
+        Err(_) => -1,
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn expand_disk_image(path: *const c_char, virtual_size: u64) -> c_int {
+    // NULL pointers are checked, but this will access any other invalid pointer passed from C
+    // code. It's the caller's responsibility to pass a valid pointer.
+    if path.is_null() {
+        return -EINVAL;
+    }
+    let c_str = CStr::from_ptr(path);
+    let file_path = match c_str.to_str() {
+        Ok(s) => s,
+        Err(_) => return -EINVAL,
+    };
+
+    let raw_image = match OpenOptions::new().read(true).write(true).open(file_path) {
+        Ok(f) => f,
+        Err(_) => return -EIO,
+    };
+
+    // Lock the disk image to prevent other processes from using it.
+    if let Err(_) = flock(&raw_image, FlockOperation::LockExclusive, true) {
+        return -EIO;
+    }
+
+    let image_type = match qcow::detect_image_type(&raw_image) {
+        Ok(t) => t,
+        Err(_) => return -EINVAL,
+    };
+
+    let mut disk_image: Box<DiskFile> = match image_type {
+        ImageType::Raw => Box::new(raw_image),
+        ImageType::Qcow2 => match QcowFile::from(raw_image) {
+            Ok(f) => Box::new(f),
+            Err(_) => return -EINVAL,
+        },
+    };
+
+    // For safety against accidentally shrinking the disk image due to a
+    // programming error elsewhere, verify that the new size is larger than
+    // the current size.  This is safe against races due to the exclusive
+    // flock() taken above - this is only an advisory lock, but it is also
+    // acquired by other instances of this function as well as crosvm
+    // itself when running a VM, so this should be safe in all cases that
+    // can access a disk image in normal operation.
+    let current_size = match disk_image.seek(SeekFrom::End(0)) {
+        Ok(len) => len,
+        Err(_) => return -EIO,
+    };
+    if current_size >= virtual_size {
+        return 0;
+    }
+
+    match disk_image.set_len(virtual_size) {
+        Ok(_) => 0,
+        Err(_) => -ENOSYS,
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn convert_to_qcow2(src_fd: c_int, dst_fd: c_int) -> c_int {
+    // The caller is responsible for passing valid file descriptors.
+    // The caller retains ownership of the file descriptors.
+    let src_file = File::from_raw_fd(src_fd);
+    let src_file_owned = src_file.try_clone();
+    forget(src_file);
+
+    let dst_file = File::from_raw_fd(dst_fd);
+    let dst_file_owned = dst_file.try_clone();
+    forget(dst_file);
+
+    match (src_file_owned, dst_file_owned) {
+        (Ok(src_file), Ok(dst_file)) => {
+            catch_unwind(
+                || match qcow::convert(src_file, dst_file, ImageType::Qcow2) {
+                    Ok(_) => 0,
+                    Err(_) => -EIO,
+                },
+            )
+            .unwrap_or(-EIO)
+        }
+        _ => -EBADFD,
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn convert_to_raw(src_fd: c_int, dst_fd: c_int) -> c_int {
+    // The caller is responsible for passing valid file descriptors.
+    // The caller retains ownership of the file descriptors.
+    let src_file = File::from_raw_fd(src_fd);
+    let src_file_owned = src_file.try_clone();
+    forget(src_file);
+
+    let dst_file = File::from_raw_fd(dst_fd);
+    let dst_file_owned = dst_file.try_clone();
+    forget(dst_file);
+
+    match (src_file_owned, dst_file_owned) {
+        (Ok(src_file), Ok(dst_file)) => {
+            catch_unwind(|| match qcow::convert(src_file, dst_file, ImageType::Raw) {
+                Ok(_) => 0,
+                Err(_) => -EIO,
+            })
+            .unwrap_or(-EIO)
+        }
+        _ => -EBADFD,
+    }
+}
diff --git a/rand_ish/Cargo.toml b/rand_ish/Cargo.toml
new file mode 100644
index 0000000..63bb001
--- /dev/null
+++ b/rand_ish/Cargo.toml
@@ -0,0 +1,5 @@
+[package]
+name = "rand_ish"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
diff --git a/rand_ish/src/lib.rs b/rand_ish/src/lib.rs
new file mode 100644
index 0000000..84d1a16
--- /dev/null
+++ b/rand_ish/src/lib.rs
@@ -0,0 +1,75 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fs::File;
+use std::io::{self, Read};
+
+/// A simple prng based on a Linear congruential generator
+/// https://en.wikipedia.org/wiki/Linear_congruential_generator
+pub struct SimpleRng {
+    seed: u64,
+}
+
+impl SimpleRng {
+    /// Create a new SimpleRng
+    pub fn new(seed: u64) -> SimpleRng {
+        SimpleRng { seed }
+    }
+
+    /// Generate random u64
+    pub fn rng(&mut self) -> u64 {
+        // a simple Linear congruential generator
+        let a: u64 = 6364136223846793005;
+        let c: u64 = 1442695040888963407;
+        self.seed = a.wrapping_mul(self.seed).wrapping_add(c);
+        self.seed
+    }
+}
+
+// Uniformly samples the ASCII alphanumeric characters given a random variable. If an `Err` is
+// passed in, the error is returned as `Some(Err(...))`. If the the random variable can not be used
+// to uniformly sample, `None` is returned.
+fn uniform_sample_ascii_alphanumeric(
+    b: Result<u8, std::io::Error>,
+) -> Option<Result<char, std::io::Error>> {
+    const ASCII_CHARS: &[u8] = b"\
+          ABCDEFGHIJKLMNOPQRSTUVWXYZ\
+          abcdefghijklmnopqrstuvwxyz\
+          0123456789";
+    let char_index = match b {
+        Ok(c) => c as usize,
+        Err(e) => return Some(Err(e)),
+    };
+    // Throw away numbers that would cause sampling bias.
+    if char_index >= ASCII_CHARS.len() * 4 {
+        None
+    } else {
+        Some(Ok(ASCII_CHARS[char_index % ASCII_CHARS.len()] as char))
+    }
+}
+
+/// Samples `/dev/urandom` and generates a random ASCII string of length `len`
+pub fn urandom_str(len: usize) -> io::Result<String> {
+    File::open("/dev/urandom")?
+        .bytes()
+        .filter_map(uniform_sample_ascii_alphanumeric)
+        .take(len)
+        .collect::<io::Result<String>>()
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn check_100() {
+        for i in 0..100 {
+            let s = urandom_str(i).unwrap();
+            assert_eq!(s.len(), i);
+            assert!(s.is_ascii());
+            assert!(!s.contains(' '));
+            assert!(!s.contains(|c: char| !c.is_ascii_alphanumeric()));
+        }
+    }
+}
diff --git a/render_node_forward/Cargo.toml b/render_node_forward/Cargo.toml
new file mode 100644
index 0000000..d23b46a
--- /dev/null
+++ b/render_node_forward/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "render_node_forward"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[lib]
+path = "lib.rs"
+
+[dependencies]
+sys_util = { path = "../sys_util" }
diff --git a/render_node_forward/lib.rs b/render_node_forward/lib.rs
new file mode 100644
index 0000000..f96fdd1
--- /dev/null
+++ b/render_node_forward/lib.rs
@@ -0,0 +1,60 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use sys_util::{GuestAddress, GuestMemory, MemoryMapping};
+
+#[link(name = "rendernodehost")]
+extern "C" {
+    fn start_render_node_host(
+        gpu_host_mem: *mut u8,
+        gpu_guest_mem_start: u64,
+        gpu_guest_mem_size: u64,
+        host_start: *const u8,
+        host_4g_start: *const u8,
+    );
+}
+
+/// The number of bytes in 4 GiB.
+pub const FOUR_GB: u64 = (1 << 32);
+/// The size required for the render node host in host and guest address space.
+pub const RENDER_NODE_HOST_SIZE: u64 = FOUR_GB;
+
+/// A render node host device that interfaces with the guest render node forwarder.
+pub struct RenderNodeHost {
+    #[allow(dead_code)]
+    guest_mem: GuestMemory,
+}
+
+impl RenderNodeHost {
+    /// Starts the render node host forwarding service over the given guest and host address ranges.
+    pub fn start(
+        mmap: &MemoryMapping,
+        gpu_guest_address: u64,
+        guest_mem: GuestMemory,
+    ) -> RenderNodeHost {
+        // Render node forward library need to do address translation between host user space
+        // address and guest physical address. We could call Rust function from C library. But
+        // since it's actually a linear mapping now, we just pass the host start address to
+        // render node forward library. We need two start address here since there would be a
+        // hole below 4G if guest memory size is bigger than 4G.
+
+        let host_start_addr = guest_mem.get_host_address(GuestAddress(0)).unwrap();
+        let host_4g_addr = if guest_mem.memory_size() > FOUR_GB {
+            guest_mem.get_host_address(GuestAddress(FOUR_GB)).unwrap()
+        } else {
+            host_start_addr
+        };
+        // Safe because only valid addresses are given.
+        unsafe {
+            start_render_node_host(
+                mmap.as_ptr(),
+                gpu_guest_address,
+                mmap.size() as u64,
+                host_start_addr,
+                host_4g_addr,
+            )
+        }
+        RenderNodeHost { guest_mem }
+    }
+}
diff --git a/resources/Cargo.toml b/resources/Cargo.toml
new file mode 100644
index 0000000..d7458b9
--- /dev/null
+++ b/resources/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "resources"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[features]
+wl-dmabuf = ["gpu_buffer"]
+
+[dependencies]
+gpu_buffer = { path = "../gpu_buffer", optional = true }
+libc = "*"
+msg_socket = { path = "../msg_socket" }
+sys_util = { path = "../sys_util" }
diff --git a/resources/src/address_allocator.rs b/resources/src/address_allocator.rs
new file mode 100644
index 0000000..11978ee
--- /dev/null
+++ b/resources/src/address_allocator.rs
@@ -0,0 +1,246 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::cmp;
+use std::collections::HashMap;
+
+use crate::{Alloc, Error, Result};
+
+/// Manages allocating address ranges.
+/// Use `AddressAllocator` whenever an address range needs to be allocated to different users.
+/// Allocations must be uniquely tagged with an Alloc enum, which can be used for lookup.
+/// An human-readable tag String must also be provided for debugging / reference.
+///
+/// # Examples
+///
+/// ```
+/// // Anon is used for brevity. Don't manually instantiate Anon allocs!
+/// # use resources::{Alloc, AddressAllocator};
+///   AddressAllocator::new(0x1000, 0x10000, Some(0x100)).map(|mut pool| {
+///       assert_eq!(pool.allocate(0x110, Alloc::Anon(0), "caps".to_string()), Ok(0x1000));
+///       assert_eq!(pool.allocate(0x100, Alloc::Anon(1), "cache".to_string()), Ok(0x1200));
+///       assert_eq!(pool.allocate(0x100, Alloc::Anon(2), "etc".to_string()), Ok(0x1300));
+///       assert_eq!(pool.get(&Alloc::Anon(1)), Some(&(0x1200, 0x100, "cache".to_string())));
+///   });
+/// ```
+#[derive(Debug, Eq, PartialEq)]
+pub struct AddressAllocator {
+    pool_base: u64,
+    pool_end: u64,
+    alignment: u64,
+    next_addr: u64,
+    allocs: HashMap<Alloc, (u64, u64, String)>,
+}
+
+impl AddressAllocator {
+    /// Creates a new `AddressAllocator` for managing a range of addresses.
+    /// Can return `None` if `pool_base` + `pool_size` overflows a u64 or if alignment isn't a power
+    /// of two.
+    ///
+    /// * `pool_base` - The starting address of the range to manage.
+    /// * `pool_size` - The size of the address range in bytes.
+    /// * `align_size` - The minimum size of an address region to align to, defaults to four.
+    pub fn new(pool_base: u64, pool_size: u64, align_size: Option<u64>) -> Result<Self> {
+        if pool_size == 0 {
+            return Err(Error::PoolSizeZero);
+        }
+        let pool_end = pool_base
+            .checked_add(pool_size - 1)
+            .ok_or(Error::PoolOverflow {
+                base: pool_base,
+                size: pool_size,
+            })?;
+        let alignment = align_size.unwrap_or(4);
+        if !alignment.is_power_of_two() || alignment == 0 {
+            return Err(Error::BadAlignment);
+        }
+        Ok(AddressAllocator {
+            pool_base,
+            pool_end,
+            alignment,
+            next_addr: pool_base,
+            allocs: HashMap::new(),
+        })
+    }
+
+    /// Allocates a range of addresses from the managed region with an optional tag
+    /// and minimal alignment. Returns allocated_address. (allocated_address, size, tag)
+    /// can be retrieved through the `get` method.
+    pub fn allocate_with_align(
+        &mut self,
+        size: u64,
+        alloc: Alloc,
+        tag: String,
+        alignment: u64,
+    ) -> Result<u64> {
+        let alignment = cmp::max(self.alignment, alignment);
+
+        if self.allocs.contains_key(&alloc) {
+            return Err(Error::ExistingAlloc(alloc));
+        }
+        if size == 0 {
+            return Err(Error::AllocSizeZero);
+        }
+        if !alignment.is_power_of_two() {
+            return Err(Error::BadAlignment);
+        }
+        let align_adjust = if self.next_addr % alignment != 0 {
+            alignment - (self.next_addr % alignment)
+        } else {
+            0
+        };
+        let addr = self
+            .next_addr
+            .checked_add(align_adjust)
+            .ok_or(Error::OutOfSpace)?;
+        let end_addr = addr.checked_add(size - 1).ok_or(Error::OutOfSpace)?;
+        if end_addr > self.pool_end {
+            return Err(Error::OutOfSpace);
+        }
+
+        // TODO(dgreid): Use a smarter allocation strategy. The current strategy is just
+        // bumping this pointer, meaning it will eventually exhaust available addresses.
+        self.next_addr = end_addr.saturating_add(1);
+
+        self.allocs.insert(alloc, (addr, size, tag));
+        Ok(addr)
+    }
+
+    pub fn allocate(&mut self, size: u64, alloc: Alloc, tag: String) -> Result<u64> {
+        self.allocate_with_align(size, alloc, tag, self.alignment)
+    }
+
+    /// Returns allocation associated with `alloc`, or None if no such allocation exists.
+    pub fn get(&self, alloc: &Alloc) -> Option<&(u64, u64, String)> {
+        self.allocs.get(alloc)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn new_fails_overflow() {
+        assert!(AddressAllocator::new(u64::max_value(), 0x100, None).is_err());
+    }
+
+    #[test]
+    fn new_fails_size_zero() {
+        assert!(AddressAllocator::new(0x1000, 0, None).is_err());
+    }
+
+    #[test]
+    fn new_fails_alignment_zero() {
+        assert!(AddressAllocator::new(0x1000, 0x10000, Some(0)).is_err());
+    }
+
+    #[test]
+    fn new_fails_alignment_non_power_of_two() {
+        assert!(AddressAllocator::new(0x1000, 0x10000, Some(200)).is_err());
+    }
+
+    #[test]
+    fn allocate_fails_exising_alloc() {
+        let mut pool = AddressAllocator::new(0x1000, 0x1000, Some(0x100)).unwrap();
+        assert_eq!(
+            pool.allocate(0x800, Alloc::Anon(0), String::from("bar0")),
+            Ok(0x1000)
+        );
+        assert_eq!(
+            pool.allocate(0x800, Alloc::Anon(0), String::from("bar0")),
+            Err(Error::ExistingAlloc(Alloc::Anon(0)))
+        );
+    }
+
+    #[test]
+    fn allocate_fails_not_enough_space() {
+        let mut pool = AddressAllocator::new(0x1000, 0x1000, Some(0x100)).unwrap();
+        assert_eq!(
+            pool.allocate(0x800, Alloc::Anon(0), String::from("bar0")),
+            Ok(0x1000)
+        );
+        assert_eq!(
+            pool.allocate(0x900, Alloc::Anon(1), String::from("bar1")),
+            Err(Error::OutOfSpace)
+        );
+        assert_eq!(
+            pool.allocate(0x800, Alloc::Anon(2), String::from("bar2")),
+            Ok(0x1800)
+        );
+    }
+
+    #[test]
+    fn allocate_alignment() {
+        let mut pool = AddressAllocator::new(0x1000, 0x10000, Some(0x100)).unwrap();
+        assert_eq!(
+            pool.allocate(0x110, Alloc::Anon(0), String::from("bar0")),
+            Ok(0x1000)
+        );
+        assert_eq!(
+            pool.allocate(0x100, Alloc::Anon(1), String::from("bar1")),
+            Ok(0x1200)
+        );
+    }
+
+    #[test]
+    fn allocate_retrieve_alloc() {
+        let mut pool = AddressAllocator::new(0x1000, 0x10000, Some(0x100)).unwrap();
+        assert_eq!(
+            pool.allocate(0x110, Alloc::Anon(0), String::from("bar0")),
+            Ok(0x1000)
+        );
+        assert_eq!(
+            pool.get(&Alloc::Anon(0)),
+            Some(&(0x1000, 0x110, String::from("bar0")))
+        );
+    }
+
+    #[test]
+    fn allocate_with_alignment_allocator_alignment() {
+        let mut pool = AddressAllocator::new(0x1000, 0x10000, Some(0x100)).unwrap();
+        assert_eq!(
+            pool.allocate_with_align(0x110, Alloc::Anon(0), String::from("bar0"), 0x1),
+            Ok(0x1000)
+        );
+        assert_eq!(
+            pool.allocate_with_align(0x100, Alloc::Anon(1), String::from("bar1"), 0x1),
+            Ok(0x1200)
+        );
+    }
+
+    #[test]
+    fn allocate_with_alignment_custom_alignment() {
+        let mut pool = AddressAllocator::new(0x1000, 0x10000, Some(0x4)).unwrap();
+        assert_eq!(
+            pool.allocate_with_align(0x110, Alloc::Anon(0), String::from("bar0"), 0x100),
+            Ok(0x1000)
+        );
+        assert_eq!(
+            pool.allocate_with_align(0x100, Alloc::Anon(1), String::from("bar1"), 0x100),
+            Ok(0x1200)
+        );
+    }
+
+    #[test]
+    fn allocate_with_alignment_no_allocator_alignment() {
+        let mut pool = AddressAllocator::new(0x1000, 0x10000, None).unwrap();
+        assert_eq!(
+            pool.allocate_with_align(0x110, Alloc::Anon(0), String::from("bar0"), 0x100),
+            Ok(0x1000)
+        );
+        assert_eq!(
+            pool.allocate_with_align(0x100, Alloc::Anon(1), String::from("bar1"), 0x100),
+            Ok(0x1200)
+        );
+    }
+
+    #[test]
+    fn allocate_with_alignment_alignment_non_power_of_two() {
+        let mut pool = AddressAllocator::new(0x1000, 0x10000, None).unwrap();
+        assert!(pool
+            .allocate_with_align(0x110, Alloc::Anon(0), String::from("bar0"), 200)
+            .is_err());
+    }
+}
diff --git a/resources/src/gpu_allocator.rs b/resources/src/gpu_allocator.rs
new file mode 100644
index 0000000..a44d3c8
--- /dev/null
+++ b/resources/src/gpu_allocator.rs
@@ -0,0 +1,127 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fmt::Debug;
+use std::fs::File;
+
+#[cfg(feature = "wl-dmabuf")]
+use libc::EINVAL;
+
+#[cfg(feature = "wl-dmabuf")]
+use gpu_buffer;
+use msg_socket::MsgOnSocket;
+use sys_util;
+
+#[allow(dead_code)]
+#[derive(Debug, Eq, PartialEq)]
+pub enum GpuAllocatorError {
+    OpenGpuBufferDevice,
+    CreateGpuBufferDevice,
+}
+
+/// Struct that describes the offset and stride of a plane located in GPU memory.
+#[derive(Clone, Copy, Debug, PartialEq, Default, MsgOnSocket)]
+pub struct GpuMemoryPlaneDesc {
+    pub stride: u32,
+    pub offset: u32,
+}
+
+/// Struct that describes a GPU memory allocation that consists of up to 3 planes.
+#[derive(Clone, Copy, Debug, Default, MsgOnSocket)]
+pub struct GpuMemoryDesc {
+    pub planes: [GpuMemoryPlaneDesc; 3],
+}
+
+/// Trait that needs to be implemented in order to service GPU memory allocation
+/// requests. Implementations are expected to support some set of buffer sizes and
+/// formats but every possible combination is not required.
+pub trait GpuMemoryAllocator: Debug {
+    /// Allocates GPU memory for a buffer of a specific size and format. The memory
+    /// layout for the returned buffer must be linear. A file handle and the
+    /// description of the planes for the buffer are returned on success.
+    ///
+    /// # Arguments
+    /// * `width` - Width of buffer.
+    /// * `height` - Height of buffer.
+    /// * `format` - Fourcc format of buffer.
+    fn allocate(
+        &self,
+        width: u32,
+        height: u32,
+        format: u32,
+    ) -> sys_util::Result<(File, GpuMemoryDesc)>;
+}
+
+#[cfg(feature = "wl-dmabuf")]
+pub struct GpuBufferDevice {
+    device: gpu_buffer::Device,
+}
+
+#[cfg(feature = "wl-dmabuf")]
+impl std::fmt::Debug for GpuBufferDevice {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        write!(f, "GpuBufferDevice {{opaque}}")
+    }
+}
+
+#[cfg(feature = "wl-dmabuf")]
+impl GpuMemoryAllocator for GpuBufferDevice {
+    fn allocate(
+        &self,
+        width: u32,
+        height: u32,
+        format: u32,
+    ) -> sys_util::Result<(File, GpuMemoryDesc)> {
+        let buffer = match self.device.create_buffer(
+            width,
+            height,
+            gpu_buffer::Format::from(format),
+            // Linear layout is a requirement as virtio wayland guest expects
+            // this for CPU access to the buffer. Scanout and texturing are
+            // optional as the consumer (wayland compositor) is expected to
+            // fall-back to a less efficient meachnisms for presentation if
+            // neccesary. In practice, linear buffers for commonly used formats
+            // will also support scanout and texturing.
+            gpu_buffer::Flags::empty().use_linear(true),
+        ) {
+            Ok(v) => v,
+            Err(_) => return Err(sys_util::Error::new(EINVAL)),
+        };
+        // We only support one FD. Buffers with multiple planes are supported
+        // as long as each plane is associated with the same handle.
+        let fd = match buffer.export_plane_fd(0) {
+            Ok(v) => v,
+            Err(e) => return Err(sys_util::Error::new(e)),
+        };
+
+        let mut desc = GpuMemoryDesc::default();
+        for i in 0..buffer.num_planes() {
+            // Use stride and offset for plane if handle matches first plane.
+            if buffer.plane_handle(i) == buffer.plane_handle(0) {
+                desc.planes[i] = GpuMemoryPlaneDesc {
+                    stride: buffer.plane_stride(i),
+                    offset: buffer.plane_offset(i),
+                }
+            }
+        }
+
+        Ok((fd, desc))
+    }
+}
+
+#[cfg(feature = "wl-dmabuf")]
+pub fn create_gpu_memory_allocator() -> Result<Option<Box<GpuMemoryAllocator>>, GpuAllocatorError> {
+    let undesired: &[&str] = &["vgem", "pvr"];
+    let fd = gpu_buffer::rendernode::open_device(undesired)
+        .map_err(|_| GpuAllocatorError::OpenGpuBufferDevice)?;
+    let device =
+        gpu_buffer::Device::new(fd).map_err(|_| GpuAllocatorError::CreateGpuBufferDevice)?;
+    Ok(Some(Box::new(GpuBufferDevice { device })))
+}
+
+#[cfg(not(feature = "wl-dmabuf"))]
+pub fn create_gpu_memory_allocator(
+) -> Result<Option<Box<dyn GpuMemoryAllocator>>, GpuAllocatorError> {
+    Ok(None)
+}
diff --git a/resources/src/lib.rs b/resources/src/lib.rs
new file mode 100644
index 0000000..c10608e
--- /dev/null
+++ b/resources/src/lib.rs
@@ -0,0 +1,72 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Manages system resources that can be allocated to VMs and their devices.
+
+#[cfg(feature = "wl-dmabuf")]
+extern crate gpu_buffer;
+extern crate libc;
+extern crate msg_socket;
+extern crate sys_util;
+
+use std::fmt::Display;
+
+pub use crate::address_allocator::AddressAllocator;
+pub use crate::gpu_allocator::{
+    GpuAllocatorError, GpuMemoryAllocator, GpuMemoryDesc, GpuMemoryPlaneDesc,
+};
+pub use crate::system_allocator::SystemAllocator;
+
+mod address_allocator;
+mod gpu_allocator;
+mod system_allocator;
+
+/// Used to tag SystemAllocator allocations.
+#[derive(Debug, Eq, PartialEq, Hash)]
+pub enum Alloc {
+    /// An anonymous resource allocation.
+    /// Should only be instantiated through `SystemAllocator::get_anon_alloc()`.
+    /// Avoid using these. Instead, use / create a more descriptive Alloc variant.
+    Anon(usize),
+    /// A PCI BAR region with associated bus, device, and bar numbers.
+    PciBar { bus: u8, dev: u8, bar: u8 },
+    /// GPU render node region.
+    GpuRenderNode,
+    /// Pmem device region with associated device index.
+    PmemDevice(usize),
+}
+
+#[derive(Debug, Eq, PartialEq)]
+pub enum Error {
+    AllocSizeZero,
+    BadAlignment,
+    CreateGpuAllocator(GpuAllocatorError),
+    ExistingAlloc(Alloc),
+    MissingDeviceAddresses,
+    MissingMMIOAddresses,
+    NoIoAllocator,
+    OutOfSpace,
+    PoolOverflow { base: u64, size: u64 },
+    PoolSizeZero,
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        use self::Error::*;
+        match self {
+            AllocSizeZero => write!(f, "Allocation cannot have size of 0"),
+            BadAlignment => write!(f, "Pool alignment must be a power of 2"),
+            CreateGpuAllocator(e) => write!(f, "Failed to create GPU allocator: {:?}", e),
+            ExistingAlloc(tag) => write!(f, "Alloc already exists: {:?}", tag),
+            MissingDeviceAddresses => write!(f, "Device address range not specified"),
+            MissingMMIOAddresses => write!(f, "MMIO address range not specified"),
+            NoIoAllocator => write!(f, "No IO address range specified"),
+            OutOfSpace => write!(f, "Out of space"),
+            PoolOverflow { base, size } => write!(f, "base={} + size={} overflows", base, size),
+            PoolSizeZero => write!(f, "Pool cannot have size of 0"),
+        }
+    }
+}
diff --git a/resources/src/system_allocator.rs b/resources/src/system_allocator.rs
new file mode 100644
index 0000000..6cdb70e
--- /dev/null
+++ b/resources/src/system_allocator.rs
@@ -0,0 +1,189 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use sys_util::pagesize;
+
+use crate::address_allocator::AddressAllocator;
+use crate::gpu_allocator::{self, GpuMemoryAllocator};
+use crate::{Alloc, Error, Result};
+
+/// Manages allocating system resources such as address space and interrupt numbers.
+///
+/// # Example - Use the `SystemAddress` builder.
+///
+/// ```
+/// # use resources::{Alloc, SystemAllocator};
+///   if let Ok(mut a) = SystemAllocator::builder()
+///           .add_io_addresses(0x1000, 0x10000)
+///           .add_device_addresses(0x10000000, 0x10000000)
+///           .add_mmio_addresses(0x30000000, 0x10000)
+///           .create_allocator(5, false) {
+///       assert_eq!(a.allocate_irq(), Some(5));
+///       assert_eq!(a.allocate_irq(), Some(6));
+///       assert_eq!(
+///           a.device_allocator()
+///              .allocate(
+///                  0x100,
+///                  Alloc::PciBar { bus: 0, dev: 0, bar: 0 },
+///                  "bar0".to_string()
+///              ),
+///           Ok(0x10000000)
+///       );
+///       assert_eq!(
+///           a.device_allocator().get(&Alloc::PciBar { bus: 0, dev: 0, bar: 0 }),
+///           Some(&(0x10000000, 0x100, "bar0".to_string()))
+///       );
+///   }
+/// ```
+#[derive(Debug)]
+pub struct SystemAllocator {
+    io_address_space: Option<AddressAllocator>,
+    device_address_space: AddressAllocator,
+    mmio_address_space: AddressAllocator,
+    gpu_allocator: Option<Box<dyn GpuMemoryAllocator>>,
+    next_irq: u32,
+    next_anon_id: usize,
+}
+
+impl SystemAllocator {
+    /// Creates a new `SystemAllocator` for managing addresses and irq numvers.
+    /// Can return `None` if `base` + `size` overflows a u64 or if alignment isn't a power
+    /// of two.
+    ///
+    /// * `io_base` - The starting address of IO memory.
+    /// * `io_size` - The size of IO memory.
+    /// * `dev_base` - The starting address of device memory.
+    /// * `dev_size` - The size of device memory.
+    /// * `mmio_base` - The starting address of MMIO space.
+    /// * `mmio_size` - The size of MMIO space.
+    /// * `create_gpu_allocator` - If true, enable gpu memory allocation.
+    /// * `first_irq` - The first irq number to give out.
+    fn new(
+        io_base: Option<u64>,
+        io_size: Option<u64>,
+        dev_base: u64,
+        dev_size: u64,
+        mmio_base: u64,
+        mmio_size: u64,
+        create_gpu_allocator: bool,
+        first_irq: u32,
+    ) -> Result<Self> {
+        let page_size = pagesize() as u64;
+        Ok(SystemAllocator {
+            io_address_space: if let (Some(b), Some(s)) = (io_base, io_size) {
+                Some(AddressAllocator::new(b, s, Some(0x400))?)
+            } else {
+                None
+            },
+            device_address_space: AddressAllocator::new(dev_base, dev_size, Some(page_size))?,
+            mmio_address_space: AddressAllocator::new(mmio_base, mmio_size, Some(page_size))?,
+            gpu_allocator: if create_gpu_allocator {
+                gpu_allocator::create_gpu_memory_allocator().map_err(Error::CreateGpuAllocator)?
+            } else {
+                None
+            },
+            next_irq: first_irq,
+            next_anon_id: 0,
+        })
+    }
+
+    /// Returns a `SystemAllocatorBuilder` that can create a new `SystemAllocator`.
+    pub fn builder() -> SystemAllocatorBuilder {
+        SystemAllocatorBuilder::new()
+    }
+
+    /// Reserves the next available system irq number.
+    pub fn allocate_irq(&mut self) -> Option<u32> {
+        if let Some(irq_num) = self.next_irq.checked_add(1) {
+            self.next_irq = irq_num;
+            Some(irq_num - 1)
+        } else {
+            None
+        }
+    }
+
+    /// Gets an allocator to be used for IO memory.
+    pub fn io_allocator(&mut self) -> Option<&mut AddressAllocator> {
+        self.io_address_space.as_mut()
+    }
+
+    /// Gets an allocator to be used for device memory.
+    pub fn device_allocator(&mut self) -> &mut AddressAllocator {
+        &mut self.device_address_space
+    }
+
+    /// Gets an allocator to be used for MMIO memory.
+    pub fn mmio_allocator(&mut self) -> &mut AddressAllocator {
+        &mut self.mmio_address_space
+    }
+
+    /// Gets an allocator to be used for GPU memory.
+    pub fn gpu_memory_allocator(&self) -> Option<&dyn GpuMemoryAllocator> {
+        self.gpu_allocator.as_ref().map(|v| v.as_ref())
+    }
+
+    /// Gets a unique anonymous allocation
+    pub fn get_anon_alloc(&mut self) -> Alloc {
+        self.next_anon_id += 1;
+        Alloc::Anon(self.next_anon_id)
+    }
+}
+
+/// Used to build a system address map for use in creating a `SystemAllocator`.
+pub struct SystemAllocatorBuilder {
+    io_base: Option<u64>,
+    io_size: Option<u64>,
+    mmio_base: Option<u64>,
+    mmio_size: Option<u64>,
+    device_base: Option<u64>,
+    device_size: Option<u64>,
+}
+
+impl SystemAllocatorBuilder {
+    pub fn new() -> Self {
+        SystemAllocatorBuilder {
+            io_base: None,
+            io_size: None,
+            mmio_base: None,
+            mmio_size: None,
+            device_base: None,
+            device_size: None,
+        }
+    }
+
+    pub fn add_io_addresses(mut self, base: u64, size: u64) -> Self {
+        self.io_base = Some(base);
+        self.io_size = Some(size);
+        self
+    }
+
+    pub fn add_mmio_addresses(mut self, base: u64, size: u64) -> Self {
+        self.mmio_base = Some(base);
+        self.mmio_size = Some(size);
+        self
+    }
+
+    pub fn add_device_addresses(mut self, base: u64, size: u64) -> Self {
+        self.device_base = Some(base);
+        self.device_size = Some(size);
+        self
+    }
+
+    pub fn create_allocator(
+        &self,
+        first_irq: u32,
+        gpu_allocation: bool,
+    ) -> Result<SystemAllocator> {
+        SystemAllocator::new(
+            self.io_base,
+            self.io_size,
+            self.device_base.ok_or(Error::MissingDeviceAddresses)?,
+            self.device_size.ok_or(Error::MissingDeviceAddresses)?,
+            self.mmio_base.ok_or(Error::MissingMMIOAddresses)?,
+            self.mmio_size.ok_or(Error::MissingMMIOAddresses)?,
+            gpu_allocation,
+            first_irq,
+        )
+    }
+}
diff --git a/rust-toolchain b/rust-toolchain
new file mode 100644
index 0000000..2aeaa11
--- /dev/null
+++ b/rust-toolchain
@@ -0,0 +1 @@
+1.35.0
diff --git a/seccomp/arm/9p_device.policy b/seccomp/arm/9p_device.policy
new file mode 100644
index 0000000..b3167b9
--- /dev/null
+++ b/seccomp/arm/9p_device.policy
@@ -0,0 +1,29 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+pread64: 1
+pwrite64: 1
+lstat64: 1
+stat64: 1
+open: 1
+openat: 1
+fstat64: 1
+ioctl: arg1 == FIOCLEX
+getdents64: 1
+fdatasync: 1
+fsync: 1
+mkdir: 1
+rmdir: 1
+rename: 1
+writev: 1
+link: 1
+unlink: 1
+socket: arg0 == AF_UNIX
+utimensat: 1
+ftruncate64: 1
+fchown: arg1 == 0xffffffff && arg2 == 0xffffffff
+statfs64: 1
+fstatat64: 1
diff --git a/seccomp/arm/balloon_device.policy b/seccomp/arm/balloon_device.policy
new file mode 100644
index 0000000..4f7aafd
--- /dev/null
+++ b/seccomp/arm/balloon_device.policy
@@ -0,0 +1,5 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
diff --git a/seccomp/arm/block_device.policy b/seccomp/arm/block_device.policy
new file mode 100644
index 0000000..62f4ee7
--- /dev/null
+++ b/seccomp/arm/block_device.policy
@@ -0,0 +1,15 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+fallocate: 1
+fdatasync: 1
+fstat64: 1
+fsync: 1
+ftruncate64: 1
+_llseek: 1
+timerfd_create: 1
+timerfd_gettime: 1
+timerfd_settime: 1
diff --git a/seccomp/arm/common_device.policy b/seccomp/arm/common_device.policy
new file mode 100644
index 0000000..d2b5a6b
--- /dev/null
+++ b/seccomp/arm/common_device.policy
@@ -0,0 +1,44 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+brk: 1
+clone: arg0 & CLONE_THREAD
+close: 1
+dup2: 1
+dup: 1
+epoll_create1: 1
+epoll_ctl: 1
+epoll_wait: 1
+eventfd2: 1
+exit: 1
+exit_group: 1
+futex: 1
+getpid: 1
+gettimeofday: 1
+kill: 1
+madvise: arg2 == MADV_DONTNEED || arg2 == MADV_DONTDUMP || arg2 == MADV_REMOVE
+mmap2: arg2 in ~PROT_EXEC
+mprotect: arg2 in ~PROT_EXEC
+mremap: 1
+munmap: 1
+nanosleep: 1
+open: return ENOENT
+openat: return ENOENT
+pipe2: 1
+poll: 1
+ppoll: 1
+prctl: arg0 == PR_SET_NAME
+read: 1
+recv: 1
+recvfrom: 1
+recvmsg: 1
+restart_syscall: 1
+rt_sigaction: 1
+rt_sigprocmask: 1
+rt_sigreturn: 1
+sched_getaffinity: 1
+sendmsg: 1
+set_robust_list: 1
+sigaltstack: 1
+write: 1
diff --git a/seccomp/arm/cras_audio_device.policy b/seccomp/arm/cras_audio_device.policy
new file mode 100644
index 0000000..06d63d1
--- /dev/null
+++ b/seccomp/arm/cras_audio_device.policy
@@ -0,0 +1,13 @@
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+madvise: 1
+prlimit64: 1
+setrlimit: 1
+recvmsg: 1
+sendmsg: 1
+socketpair: arg0 == AF_UNIX
+clock_gettime: 1
diff --git a/seccomp/arm/input_device.policy b/seccomp/arm/input_device.policy
new file mode 100644
index 0000000..f26998e
--- /dev/null
+++ b/seccomp/arm/input_device.policy
@@ -0,0 +1,9 @@
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+ioctl: 1
+fcntl: 1
+getsockname: 1
diff --git a/seccomp/arm/net_device.policy b/seccomp/arm/net_device.policy
new file mode 100644
index 0000000..4f7aafd
--- /dev/null
+++ b/seccomp/arm/net_device.policy
@@ -0,0 +1,5 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
diff --git a/seccomp/arm/null_audio_device.policy b/seccomp/arm/null_audio_device.policy
new file mode 100644
index 0000000..089d1bd
--- /dev/null
+++ b/seccomp/arm/null_audio_device.policy
@@ -0,0 +1,10 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+madvise: 1
+prlimit64: 1
+setrlimit: 1
+clock_gettime: 1
diff --git a/seccomp/arm/rng_device.policy b/seccomp/arm/rng_device.policy
new file mode 100644
index 0000000..4f7aafd
--- /dev/null
+++ b/seccomp/arm/rng_device.policy
@@ -0,0 +1,5 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
diff --git a/seccomp/arm/tpm_device.policy b/seccomp/arm/tpm_device.policy
new file mode 100644
index 0000000..72b78fb
--- /dev/null
+++ b/seccomp/arm/tpm_device.policy
@@ -0,0 +1,57 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# common policy
+brk: 1
+clone: arg0 & CLONE_THREAD
+close: 1
+dup2: 1
+dup: 1
+epoll_create1: 1
+epoll_ctl: 1
+epoll_wait: 1
+eventfd2: 1
+exit: 1
+exit_group: 1
+futex: 1
+getpid: 1
+gettimeofday: 1
+kill: 1
+madvise: arg2 == MADV_DONTNEED || arg2 == MADV_DONTDUMP || arg2 == MADV_REMOVE
+mmap2: arg2 in ~PROT_EXEC
+mprotect: arg2 in ~PROT_EXEC
+mremap: 1
+munmap: 1
+nanosleep: 1
+#open: return ENOENT
+#openat: return ENOENT
+pipe2: 1
+poll: 1
+ppoll: 1
+prctl: arg0 == PR_SET_NAME
+read: 1
+recv: 1
+recvfrom: 1
+recvmsg: 1
+restart_syscall: 1
+rt_sigaction: 1
+rt_sigprocmask: 1
+rt_sigreturn: 1
+sched_getaffinity: 1
+sendmsg: 1
+set_robust_list: 1
+sigaltstack: 1
+write: 1
+
+# tpm-specific policy
+chdir: 1
+fstat: 1
+fsync: 1
+ftruncate: 1
+getuid: 1
+lseek: 1
+mkdir: 1
+open: 1
+openat: 1
+stat: 1
diff --git a/seccomp/arm/vhost_net_device.policy b/seccomp/arm/vhost_net_device.policy
new file mode 100644
index 0000000..58fc7ef
--- /dev/null
+++ b/seccomp/arm/vhost_net_device.policy
@@ -0,0 +1,23 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+# Whitelist vhost_net ioctls only.
+# arg1 == VHOST_GET_FEATURES ||
+# arg1 == VHOST_SET_FEATURES ||
+# arg1 == VHOST_SET_OWNER ||
+# arg1 == VHOST_RESET_OWNER ||
+# arg1 == VHOST_SET_MEM_TABLE ||
+# arg1 == VHOST_SET_LOG_BASE ||
+# arg1 == VHOST_SET_LOG_FD ||
+# arg1 == VHOST_SET_VRING_NUM ||
+# arg1 == VHOST_SET_VRING_ADDR ||
+# arg1 == VHOST_SET_VRING_BASE ||
+# arg1 == VHOST_GET_VRING_BASE ||
+# arg1 == VHOST_SET_VRING_KICK ||
+# arg1 == VHOST_SET_VRING_CALL ||
+# arg1 == VHOST_SET_VRING_ERR ||
+# arg1 == VHOST_NET_SET_BACKEND
+ioctl: arg1 == 0x8008af00 || arg1 == 0x4008af00 || arg1 == 0x0000af01 || arg1 == 0x0000af02 || arg1 == 0x4008af03 || arg1 == 0x4008af04 || arg1 == 0x4004af07 || arg1 == 0x4008af10 || arg1 == 0x4028af11 || arg1 == 0x4008af12 || arg1 == 0xc008af12 || arg1 == 0x4008af20 || arg1 == 0x4008af21 || arg1 == 0x4008af22 || arg1 == 0x4008af30
diff --git a/seccomp/arm/vhost_vsock_device.policy b/seccomp/arm/vhost_vsock_device.policy
new file mode 100644
index 0000000..9d9ca59
--- /dev/null
+++ b/seccomp/arm/vhost_vsock_device.policy
@@ -0,0 +1,24 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+# Whitelist vhost_vsock ioctls only.
+# arg1 == VHOST_GET_FEATURES ||
+# arg1 == VHOST_SET_FEATURES ||
+# arg1 == VHOST_SET_OWNER ||
+# arg1 == VHOST_RESET_OWNER ||
+# arg1 == VHOST_SET_MEM_TABLE ||
+# arg1 == VHOST_SET_LOG_BASE ||
+# arg1 == VHOST_SET_LOG_FD ||
+# arg1 == VHOST_SET_VRING_NUM ||
+# arg1 == VHOST_SET_VRING_ADDR ||
+# arg1 == VHOST_SET_VRING_BASE ||
+# arg1 == VHOST_GET_VRING_BASE ||
+# arg1 == VHOST_SET_VRING_KICK ||
+# arg1 == VHOST_SET_VRING_CALL ||
+# arg1 == VHOST_SET_VRING_ERR ||
+# arg1 == VHOST_VSOCK_SET_GUEST_CID ||
+# arg1 == VHOST_VSOCK_SET_RUNNING
+ioctl: arg1 == 0x8008af00 || arg1 == 0x4008af00 || arg1 == 0x0000af01 || arg1 == 0x0000af02 || arg1 == 0x4008af03 || arg1 == 0x4008af04 || arg1 == 0x4004af07 || arg1 == 0x4008af10 || arg1 == 0x4028af11 || arg1 == 0x4008af12 || arg1 == 0xc008af12 || arg1 == 0x4008af20 || arg1 == 0x4008af21 || arg1 == 0x4008af22 || arg1 == 0x4008af60 || arg1 == 0x4004af61
diff --git a/seccomp/arm/wl_device.policy b/seccomp/arm/wl_device.policy
new file mode 100644
index 0000000..1104fba
--- /dev/null
+++ b/seccomp/arm/wl_device.policy
@@ -0,0 +1,22 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+# Used to connect to wayland. arg0 == AF_UNIX && arg1 == SOCK_STREAM|SOCK_CLOEXEC
+socket: arg0 == 1 && arg1 == 0x80001 && arg2 == 0
+# arg1 == FIONBIO || arg1 == DMA_BUF_IOCTL_SYNC
+ioctl: arg1 == 0x5421 || arg1 == 0x40086200
+connect: 1
+# Used to communicate with wayland
+recvmsg: 1
+sendmsg: 1
+# Used for sharing memory with wayland. arg1 == MFD_CLOEXEC|MFD_ALLOW_SEALING
+memfd_create: arg1 == 3
+# Used to set of size new memfd
+ftruncate64: 1
+# Used to determine shm size after recvmsg with fd
+_llseek: 1
+# Allow F_GETFL only
+fcntl64: arg1 == 3
diff --git a/seccomp/arm/xhci.policy b/seccomp/arm/xhci.policy
new file mode 100644
index 0000000..4fca144
--- /dev/null
+++ b/seccomp/arm/xhci.policy
@@ -0,0 +1,47 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+openat: 1
+@include /usr/share/policy/crosvm/common_device.policy
+
+stat64: 1
+fcntl64: 1
+lstat64: 1
+readlink: 1
+readlinkat: 1
+getdents64: 1
+getrandom: 1
+name_to_handle_at: 1
+access: 1
+gettid: 1
+clock_gettime: 1
+timerfd_create: 1
+getsockname: 1
+pipe: 1
+setsockopt: 1
+bind: 1
+fcntl: 1
+socket: arg0 == AF_NETLINK
+stat: 1
+uname: 1
+# The following ioctls are:
+# 0x4004550d == USBDEVFS_REAPURBNDELAY32
+# 0x550b     == USBDEVFS_DISCARDURB
+# 0x8004550f == USBDEVFS_CLAIMINTERFACE
+# 0x80045510 == USBDEVFS_RELEASEINTERFACE
+# 0x8004551a == USBDEVFS_GET_CAPABILITIES
+# 0x802c550a == USBDEVFS_SUBMITURB
+# 0xc0105500 == USBDEVFS_CONTROL
+# 0x5514 == USBDEVFS_RESET
+# 0x80045505 == USBDEVFS_SETCONFIGURATION
+# 0x8108551b == USBDEVFS_DISCONNECT_CLAIM
+# 0x40085511 == USBDEVFS_CONNECTINFO
+# 0x80185520 == USBDEVFS_CONNINFO_EX
+ioctl: arg1 == 0xc0105500 || arg1 == 0x802c550a || arg1 == 0x8004551a || arg1 == 0x4004550d || arg1 == 0x8004550f || arg1 == 0x80045510 || arg1 == 0x550b || arg1 == 0x5514 || arg1 == 0x80045505 || arg1 == 0x8108551b || arg1 == 0x40085511 || arg1 == 0x80185520
+fstat: 1
+sigaltstack: 1
+recvmsg: 1
+getrandom: 1
+getdents: 1
+lseek: 1
diff --git a/seccomp/x86_64/9p_device.policy b/seccomp/x86_64/9p_device.policy
new file mode 100644
index 0000000..ddd7417
--- /dev/null
+++ b/seccomp/x86_64/9p_device.policy
@@ -0,0 +1,28 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+writev: 1
+pwrite64: 1
+stat: 1
+lstat: 1
+open: 1
+openat: 1
+fstat: 1
+ioctl: arg1 == FIOCLEX
+link: 1
+unlink: 1
+rename: 1
+pread64: 1
+getdents: 1
+mkdir: 1
+rmdir: 1
+fsync: 1
+fdatasync: 1
+utimensat: 1
+ftruncate: 1
+fchown: arg1 == 0xffffffff && arg2 == 0xffffffff
+statfs: 1
+newfstatat: 1
diff --git a/seccomp/x86_64/balloon_device.policy b/seccomp/x86_64/balloon_device.policy
new file mode 100644
index 0000000..72ecd5a
--- /dev/null
+++ b/seccomp/x86_64/balloon_device.policy
@@ -0,0 +1,5 @@
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
diff --git a/seccomp/x86_64/block_device.policy b/seccomp/x86_64/block_device.policy
new file mode 100644
index 0000000..20eca1a
--- /dev/null
+++ b/seccomp/x86_64/block_device.policy
@@ -0,0 +1,15 @@
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+fallocate: 1
+fdatasync: 1
+fstat: 1
+fsync: 1
+ftruncate: 1
+lseek: 1
+timerfd_create: 1
+timerfd_gettime: 1
+timerfd_settime: 1
diff --git a/seccomp/x86_64/common_device.policy b/seccomp/x86_64/common_device.policy
new file mode 100644
index 0000000..2379b95
--- /dev/null
+++ b/seccomp/x86_64/common_device.policy
@@ -0,0 +1,43 @@
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+brk: 1
+clone: arg0 & CLONE_THREAD
+close: 1
+dup2: 1
+dup: 1
+epoll_create1: 1
+epoll_ctl: 1
+epoll_wait: 1
+eventfd2: 1
+exit: 1
+exit_group: 1
+futex: 1
+getpid: 1
+gettimeofday: 1
+kill: 1
+madvise: arg2 == MADV_DONTNEED || arg2 == MADV_DONTDUMP || arg2 == MADV_REMOVE
+mmap: arg2 in ~PROT_EXEC
+mprotect: arg2 in ~PROT_EXEC
+mremap: 1
+munmap: 1
+nanosleep: 1
+open: return ENOENT
+openat: return ENOENT
+pipe2: 1
+poll: 1
+ppoll: 1
+prctl: arg0 == PR_SET_NAME
+read: 1
+recvfrom: 1
+recvmsg: 1
+restart_syscall: 1
+rt_sigaction: 1
+rt_sigprocmask: 1
+rt_sigreturn: 1
+sched_getaffinity: 1
+sendmsg: 1
+set_robust_list: 1
+sigaltstack: 1
+write: 1
diff --git a/seccomp/x86_64/cras_audio_device.policy b/seccomp/x86_64/cras_audio_device.policy
new file mode 100644
index 0000000..e5a074e
--- /dev/null
+++ b/seccomp/x86_64/cras_audio_device.policy
@@ -0,0 +1,12 @@
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+madvise: 1
+prlimit64: 1
+setrlimit: 1
+recvmsg: 1
+sendmsg: 1
+socketpair: arg0 == AF_UNIX
diff --git a/seccomp/x86_64/gpu_device.policy b/seccomp/x86_64/gpu_device.policy
new file mode 100644
index 0000000..233f00f
--- /dev/null
+++ b/seccomp/x86_64/gpu_device.policy
@@ -0,0 +1,71 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Rules from common_device.policy with some rules removed because they block certain flags needed
+# for gpu.
+brk: 1
+clone: arg0 & CLONE_THREAD
+close: 1
+dup2: 1
+dup: 1
+epoll_create1: 1
+epoll_ctl: 1
+epoll_wait: 1
+eventfd2: 1
+exit: 1
+exit_group: 1
+futex: 1
+getpid: 1
+gettimeofday: 1
+kill: 1
+madvise: arg2 == MADV_DONTNEED || arg2 == MADV_DONTDUMP || arg2 == MADV_REMOVE
+mremap: 1
+munmap: 1
+nanosleep: 1
+pipe2: 1
+poll: 1
+ppoll: 1
+prctl: arg0 == PR_SET_NAME
+read: 1
+recvfrom: 1
+recvmsg: 1
+restart_syscall: 1
+rt_sigaction: 1
+rt_sigprocmask: 1
+rt_sigreturn: 1
+sched_getaffinity: 1
+sendmsg: 1
+set_robust_list: 1
+sigaltstack: 1
+write: 1
+
+# Rules specific to gpu
+connect: 1
+fcntl: arg1 == F_DUPFD_CLOEXEC
+fstat: 1
+# Used to set of size new memfd.
+ftruncate: 1
+getdents: 1
+geteuid: 1
+getrandom: 1
+getuid: 1
+ioctl: arg1 == FIONBIO || arg1 == FIOCLEX || arg1 == 0x40086200 || arg1 & 0x6400
+lseek: 1
+lstat: 1
+# Used for sharing memory with wayland. arg1 == MFD_CLOEXEC|MFD_ALLOW_SEALING
+memfd_create: arg1 == 3
+# mmap/mprotect/open/openat differ from the common_device.policy
+mmap: arg2 == PROT_READ|PROT_WRITE || arg2 == PROT_NONE || arg2 == PROT_READ|PROT_EXEC
+mprotect: arg2 == PROT_READ|PROT_WRITE || arg2 == PROT_NONE || arg2 == PROT_READ
+open: 1
+openat: 1
+readlink: 1
+socket: arg0 == 1 && arg1 == 0x80001 && arg2 == 0
+stat: 1
+sysinfo: 1
+
+# Rules specific to AMD gpus.
+uname: 1
+sched_setscheduler: 1
+sched_setaffinity: 1
diff --git a/seccomp/x86_64/input_device.policy b/seccomp/x86_64/input_device.policy
new file mode 100644
index 0000000..f26998e
--- /dev/null
+++ b/seccomp/x86_64/input_device.policy
@@ -0,0 +1,9 @@
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+ioctl: 1
+fcntl: 1
+getsockname: 1
diff --git a/seccomp/x86_64/net_device.policy b/seccomp/x86_64/net_device.policy
new file mode 100644
index 0000000..72ecd5a
--- /dev/null
+++ b/seccomp/x86_64/net_device.policy
@@ -0,0 +1,5 @@
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
diff --git a/seccomp/x86_64/null_audio_device.policy b/seccomp/x86_64/null_audio_device.policy
new file mode 100644
index 0000000..9ea7015
--- /dev/null
+++ b/seccomp/x86_64/null_audio_device.policy
@@ -0,0 +1,9 @@
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+madvise: 1
+prlimit64: 1
+setrlimit: 1
diff --git a/seccomp/x86_64/rng_device.policy b/seccomp/x86_64/rng_device.policy
new file mode 100644
index 0000000..72ecd5a
--- /dev/null
+++ b/seccomp/x86_64/rng_device.policy
@@ -0,0 +1,5 @@
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
diff --git a/seccomp/x86_64/tpm_device.policy b/seccomp/x86_64/tpm_device.policy
new file mode 100644
index 0000000..5c21480
--- /dev/null
+++ b/seccomp/x86_64/tpm_device.policy
@@ -0,0 +1,56 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# common policy
+brk: 1
+clone: arg0 & CLONE_THREAD
+close: 1
+dup2: 1
+dup: 1
+epoll_create1: 1
+epoll_ctl: 1
+epoll_wait: 1
+eventfd2: 1
+exit: 1
+exit_group: 1
+futex: 1
+getpid: 1
+gettimeofday: 1
+kill: 1
+madvise: arg2 == MADV_DONTNEED || arg2 == MADV_DONTDUMP || arg2 == MADV_REMOVE
+mmap: arg2 in ~PROT_EXEC
+mprotect: arg2 in ~PROT_EXEC
+mremap: 1
+munmap: 1
+nanosleep: 1
+#open: return ENOENT
+#openat: return ENOENT
+pipe2: 1
+poll: 1
+ppoll: 1
+prctl: arg0 == PR_SET_NAME
+read: 1
+recvfrom: 1
+recvmsg: 1
+restart_syscall: 1
+rt_sigaction: 1
+rt_sigprocmask: 1
+rt_sigreturn: 1
+sched_getaffinity: 1
+sendmsg: 1
+set_robust_list: 1
+sigaltstack: 1
+write: 1
+
+# tpm-specific policy
+chdir: 1
+fstat: 1
+fsync: 1
+ftruncate: 1
+getuid: 1
+lseek: 1
+mkdir: 1
+open: 1
+openat: 1
+stat: 1
diff --git a/seccomp/x86_64/vhost_net_device.policy b/seccomp/x86_64/vhost_net_device.policy
new file mode 100644
index 0000000..306328b
--- /dev/null
+++ b/seccomp/x86_64/vhost_net_device.policy
@@ -0,0 +1,23 @@
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+# Whitelist vhost_net ioctls only.
+# arg1 == VHOST_GET_FEATURES ||
+# arg1 == VHOST_SET_FEATURES ||
+# arg1 == VHOST_SET_OWNER ||
+# arg1 == VHOST_RESET_OWNER ||
+# arg1 == VHOST_SET_MEM_TABLE ||
+# arg1 == VHOST_SET_LOG_BASE ||
+# arg1 == VHOST_SET_LOG_FD ||
+# arg1 == VHOST_SET_VRING_NUM ||
+# arg1 == VHOST_SET_VRING_ADDR ||
+# arg1 == VHOST_SET_VRING_BASE ||
+# arg1 == VHOST_GET_VRING_BASE ||
+# arg1 == VHOST_SET_VRING_KICK ||
+# arg1 == VHOST_SET_VRING_CALL ||
+# arg1 == VHOST_SET_VRING_ERR ||
+# arg1 == VHOST_NET_SET_BACKEND
+ioctl: arg1 == 0x8008af00 || arg1 == 0x4008af00 || arg1 == 0x0000af01 || arg1 == 0x0000af02 || arg1 == 0x4008af03 || arg1 == 0x4008af04 || arg1 == 0x4004af07 || arg1 == 0x4008af10 || arg1 == 0x4028af11 || arg1 == 0x4008af12 || arg1 == 0xc008af12 || arg1 == 0x4008af20 || arg1 == 0x4008af21 || arg1 == 0x4008af22 || arg1 == 0x4008af30
diff --git a/seccomp/x86_64/vhost_vsock_device.policy b/seccomp/x86_64/vhost_vsock_device.policy
new file mode 100644
index 0000000..9c2274c
--- /dev/null
+++ b/seccomp/x86_64/vhost_vsock_device.policy
@@ -0,0 +1,26 @@
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+# Whitelist vhost_vsock ioctls only.
+# arg1 == VHOST_GET_FEATURES ||
+# arg1 == VHOST_SET_FEATURES ||
+# arg1 == VHOST_SET_OWNER ||
+# arg1 == VHOST_RESET_OWNER ||
+# arg1 == VHOST_SET_MEM_TABLE ||
+# arg1 == VHOST_SET_LOG_BASE ||
+# arg1 == VHOST_SET_LOG_FD ||
+# arg1 == VHOST_SET_VRING_NUM ||
+# arg1 == VHOST_SET_VRING_ADDR ||
+# arg1 == VHOST_SET_VRING_BASE ||
+# arg1 == VHOST_GET_VRING_BASE ||
+# arg1 == VHOST_SET_VRING_KICK ||
+# arg1 == VHOST_SET_VRING_CALL ||
+# arg1 == VHOST_SET_VRING_ERR ||
+# arg1 == VHOST_VSOCK_SET_GUEST_CID ||
+# arg1 == VHOST_VSOCK_SET_RUNNING
+ioctl: arg1 == 0x8008af00 || arg1 == 0x4008af00 || arg1 == 0x0000af01 || arg1 == 0x0000af02 || arg1 == 0x4008af03 || arg1 == 0x4008af04 || arg1 == 0x4004af07 || arg1 == 0x4008af10 || arg1 == 0x4028af11 || arg1 == 0x4008af12 || arg1 == 0xc008af12 || arg1 == 0x4008af20 || arg1 == 0x4008af21 || arg1 == 0x4008af22 || arg1 == 0x4008af60 || arg1 == 0x4004af61
+connect: 1
+sendto: 1
diff --git a/seccomp/x86_64/wl_device.policy b/seccomp/x86_64/wl_device.policy
new file mode 100644
index 0000000..2ca7ed9
--- /dev/null
+++ b/seccomp/x86_64/wl_device.policy
@@ -0,0 +1,22 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+@include /usr/share/policy/crosvm/common_device.policy
+
+# Used to connect to wayland. arg0 == AF_UNIX && arg1 == SOCK_STREAM|SOCK_CLOEXEC
+socket: arg0 == 1 && arg1 == 0x80001 && arg2 == 0
+# arg1 == FIONBIO || arg1 == DMA_BUF_IOCTL_SYNC
+ioctl: arg1 == 0x5421 || arg1 == 0x40086200
+connect: 1
+# Used to communicate with wayland
+recvmsg: 1
+sendmsg: 1
+# Used for sharing memory with wayland. arg1 == MFD_CLOEXEC|MFD_ALLOW_SEALING
+memfd_create: arg1 == 3
+# Used to set of size new memfd
+ftruncate: 1
+# Used to determine shm size after recvmsg with fd
+lseek: 1
+# Allow F_GETFL only
+fcntl: arg1 == 3
diff --git a/seccomp/x86_64/xhci.policy b/seccomp/x86_64/xhci.policy
new file mode 100644
index 0000000..98e3335
--- /dev/null
+++ b/seccomp/x86_64/xhci.policy
@@ -0,0 +1,45 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# xhci need "openat" to enumerate device. "openat" is disabled in comman_device policy.
+openat: 1
+@include /usr/share/policy/crosvm/common_device.policy
+
+lstat: 1
+gettid: 1
+readlink: 1
+readlinkat: 1
+timerfd_create: 1
+name_to_handle_at: 1
+access: 1
+timerfd_create: 1
+getsockname: 1
+pipe: 1
+setsockopt: 1
+bind: 1
+fcntl: 1
+socket: arg0 == AF_NETLINK
+stat: 1
+uname: 1
+# The following ioctls are:
+# 0x4008550d == USBDEVFS_REAPURBNDELAY
+# 0x41045508 == USBDEVFS_GETDRIVER
+# 0x550b     == USBDEVFS_DISCARDURB
+# 0x8004550f == USBDEVFS_CLAIMINTERFACE
+# 0x80045510 == USBDEVFS_RELEASEINTERFACE
+# 0x8004551a == USBDEVFS_GET_CAPABILITIES
+# 0x8038550a == USBDEVFS_SUBMITURB
+# 0xc0185500 == USBDEVFS_CONTROL
+# 0x5514 == USBDEVFS_RESET
+# 0x80045505 == USBDEVFS_SETCONFIGURATION
+# 0x8108551b == USBDEVFS_DISCONNECT_CLAIM
+# 0x40085511 == USBDEVFS_CONNECTINFO
+# 0x80185520 == USBDEVFS_CONNINFO_EX
+ioctl: arg1 == 0xc0185500 || arg1 == 0x41045508 || arg1 == 0x8004550f || arg1 == 0x4008550d || arg1 == 0x8004551a || arg1 == 0x550b || arg1 == 0x80045510 || arg1 == 0x8038550a || arg1 == 0x5514 || arg1 == 0x80045505 || arg1 == 0x8108551b || arg1 == 0x40085511 || arg1 == 0x80185520
+fstat: 1
+sigaltstack: 1
+recvmsg: 1
+getrandom: 1
+getdents: 1
+lseek: 1
diff --git a/src/argument.rs b/src/argument.rs
new file mode 100644
index 0000000..7cb56d6
--- /dev/null
+++ b/src/argument.rs
@@ -0,0 +1,425 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Handles argument parsing.
+//!
+//! # Example
+//!
+//! ```
+//! const ARGUMENTS: &'static [Argument] = &[
+//!     Argument::positional("FILES", "files to operate on"),
+//!     Argument::short_value('p', "program", "PROGRAM", "Program to apply to each file"),
+//!     Argument::short_value('c', "cpus", "N", "Number of CPUs to use. (default: 1)"),
+//!     Argument::flag("unmount", "Unmount the root"),
+//!     Argument::short_flag('h', "help", "Print help message."),
+//! ];
+//!
+//! let match_res = set_arguments(args, ARGUMENTS, |name, value| {
+//!     match name {
+//!         "" => println!("positional arg! {}", value.unwrap()),
+//!         "program" => println!("gonna use program {}", value.unwrap()),
+//!         "cpus" => {
+//!             let v: u32 = value.unwrap().parse().map_err(|_| {
+//!                 Error::InvalidValue {
+//!                     value: value.unwrap().to_owned(),
+//!                     expected: "this value for `cpus` needs to be integer",
+//!                 }
+//!             })?;
+//!         }
+//!         "unmount" => println!("gonna unmount"),
+//!         "help" => return Err(Error::PrintHelp),
+//!         _ => unreachable!(),
+//!     }
+//! }
+//!
+//! match match_res {
+//!     Ok(_) => println!("running with settings"),
+//!     Err(Error::PrintHelp) => print_help("best_program", "FILES", ARGUMENTS),
+//!     Err(e) => println!("{}", e),
+//! }
+//! ```
+
+use std::fmt::{self, Display};
+use std::result;
+
+/// An error with argument parsing.
+#[derive(Debug)]
+pub enum Error {
+    /// There was a syntax error with the argument.
+    Syntax(String),
+    /// The argumen's name is unused.
+    UnknownArgument(String),
+    /// The argument was required.
+    ExpectedArgument(String),
+    /// The argument's given value is invalid.
+    InvalidValue {
+        value: String,
+        expected: &'static str,
+    },
+    /// The argument was already given and none more are expected.
+    TooManyArguments(String),
+    /// The argument expects a value.
+    ExpectedValue(String),
+    /// The help information was requested
+    PrintHelp,
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            Syntax(s) => write!(f, "syntax error: {}", s),
+            UnknownArgument(s) => write!(f, "unknown argument: {}", s),
+            ExpectedArgument(s) => write!(f, "expected argument: {}", s),
+            InvalidValue { value, expected } => {
+                write!(f, "invalid value {:?}: {}", value, expected)
+            }
+            TooManyArguments(s) => write!(f, "too many arguments: {}", s),
+            ExpectedValue(s) => write!(f, "expected parameter value: {}", s),
+            PrintHelp => write!(f, "help was requested"),
+        }
+    }
+}
+
+/// Result of a argument parsing.
+pub type Result<T> = result::Result<T, Error>;
+
+/// Information about an argument expected from the command line.
+///
+/// # Examples
+///
+/// To indicate a flag style argument:
+///
+/// ```
+/// Argument::short_flag('f', "flag", "enable awesome mode")
+/// ```
+///
+/// To indicate a parameter style argument that expects a value:
+///
+/// ```
+/// // "VALUE" and "NETMASK" are placeholder values displayed in the help message for these
+/// // arguments.
+/// Argument::short_value('v', "val", "VALUE", "how much do you value this usage information")
+/// Argument::value("netmask", "NETMASK", "hides your netface")
+/// ```
+///
+/// To indicate an argument with no short version:
+///
+/// ```
+/// Argument::flag("verbose", "this option is hard to type quickly")
+/// ```
+///
+/// To indicate a positional argument:
+///
+/// ```
+/// Argument::positional("VALUES", "these are positional arguments")
+/// ```
+#[derive(Default)]
+pub struct Argument {
+    /// The name of the value to display in the usage information. Use None to indicate that there
+    /// is no value expected for this argument.
+    pub value: Option<&'static str>,
+    /// Optional single character shortened argument name.
+    pub short: Option<char>,
+    /// The long name of this argument.
+    pub long: &'static str,
+    /// Helpfuly usage information for this argument to display to the user.
+    pub help: &'static str,
+}
+
+impl Argument {
+    pub fn positional(value: &'static str, help: &'static str) -> Argument {
+        Argument {
+            value: Some(value),
+            long: "",
+            help,
+            ..Default::default()
+        }
+    }
+
+    pub fn value(long: &'static str, value: &'static str, help: &'static str) -> Argument {
+        Argument {
+            value: Some(value),
+            long,
+            help,
+            ..Default::default()
+        }
+    }
+
+    pub fn short_value(
+        short: char,
+        long: &'static str,
+        value: &'static str,
+        help: &'static str,
+    ) -> Argument {
+        Argument {
+            value: Some(value),
+            short: Some(short),
+            long,
+            help,
+        }
+    }
+
+    pub fn flag(long: &'static str, help: &'static str) -> Argument {
+        Argument {
+            long,
+            help,
+            ..Default::default()
+        }
+    }
+
+    pub fn short_flag(short: char, long: &'static str, help: &'static str) -> Argument {
+        Argument {
+            short: Some(short),
+            long,
+            help,
+            ..Default::default()
+        }
+    }
+}
+
+fn parse_arguments<I, R, F>(args: I, mut f: F) -> Result<()>
+where
+    I: Iterator<Item = R>,
+    R: AsRef<str>,
+    F: FnMut(&str, Option<&str>) -> Result<()>,
+{
+    enum State {
+        // Initial state at the start and after finishing a single argument/value.
+        Top,
+        // The remaining arguments are all positional.
+        Positional,
+        // The next string is the value for the argument `name`.
+        Value { name: String },
+    }
+    let mut s = State::Top;
+    for arg in args {
+        let arg = arg.as_ref();
+        s = match s {
+            State::Top => {
+                if arg == "--" {
+                    State::Positional
+                } else if arg.starts_with("--") {
+                    let param = arg.trim_start_matches('-');
+                    if param.contains('=') {
+                        let mut iter = param.splitn(2, '=');
+                        let name = iter.next().unwrap();
+                        let value = iter.next().unwrap();
+                        if name.is_empty() {
+                            return Err(Error::Syntax(
+                                "expected parameter name before `=`".to_owned(),
+                            ));
+                        }
+                        if value.is_empty() {
+                            return Err(Error::Syntax(
+                                "expected parameter value after `=`".to_owned(),
+                            ));
+                        }
+                        f(name, Some(value))?;
+                        State::Top
+                    } else if let Err(e) = f(param, None) {
+                        if let Error::ExpectedValue(_) = e {
+                            State::Value {
+                                name: param.to_owned(),
+                            }
+                        } else {
+                            return Err(e);
+                        }
+                    } else {
+                        State::Top
+                    }
+                } else if arg.starts_with('-') {
+                    if arg.len() == 1 {
+                        return Err(Error::Syntax(
+                            "expected argument short name after `-`".to_owned(),
+                        ));
+                    }
+                    let name = &arg[1..2];
+                    let value = if arg.len() > 2 { Some(&arg[2..]) } else { None };
+                    if let Err(e) = f(name, value) {
+                        if let Error::ExpectedValue(_) = e {
+                            State::Value {
+                                name: name.to_owned(),
+                            }
+                        } else {
+                            return Err(e);
+                        }
+                    } else {
+                        State::Top
+                    }
+                } else {
+                    f("", Some(&arg))?;
+                    State::Positional
+                }
+            }
+            State::Positional => {
+                f("", Some(&arg))?;
+                State::Positional
+            }
+            State::Value { name } => {
+                f(&name, Some(&arg))?;
+                State::Top
+            }
+        };
+    }
+    Ok(())
+}
+
+/// Parses the given `args` against the list of know arguments `arg_list` and calls `f` with each
+/// present argument and value if required.
+///
+/// This function guarantees that only valid long argument names from `arg_list` are sent to the
+/// callback `f`. It is also guaranteed that if an arg requires a value (i.e.
+/// `arg.value.is_some()`), the value will be `Some` in the callbacks arguments. If the callback
+/// returns `Err`, this function will end parsing and return that `Err`.
+///
+/// See the [module level](index.html) example for a usage example.
+pub fn set_arguments<I, R, F>(args: I, arg_list: &[Argument], mut f: F) -> Result<()>
+where
+    I: Iterator<Item = R>,
+    R: AsRef<str>,
+    F: FnMut(&str, Option<&str>) -> Result<()>,
+{
+    parse_arguments(args, |name, value| {
+        let mut matches = None;
+        for arg in arg_list {
+            if let Some(short) = arg.short {
+                if name.len() == 1 && name.starts_with(short) {
+                    if value.is_some() != arg.value.is_some() {
+                        return Err(Error::ExpectedValue(short.to_string()));
+                    }
+                    matches = Some(arg.long);
+                }
+            }
+            if matches.is_none() && arg.long == name {
+                if value.is_some() != arg.value.is_some() {
+                    return Err(Error::ExpectedValue(arg.long.to_owned()));
+                }
+                matches = Some(arg.long);
+            }
+        }
+        match matches {
+            Some(long) => f(long, value),
+            None => Err(Error::UnknownArgument(name.to_owned())),
+        }
+    })
+}
+
+/// Prints command line usage information to stdout.
+///
+/// Usage information is printed according to the help fields in `args` with a leading usage line.
+/// The usage line is of the format "`program_name` [ARGUMENTS] `required_arg`".
+pub fn print_help(program_name: &str, required_arg: &str, args: &[Argument]) {
+    println!(
+        "Usage: {} {}{}\n",
+        program_name,
+        if args.is_empty() { "" } else { "[ARGUMENTS] " },
+        required_arg
+    );
+    if args.is_empty() {
+        return;
+    }
+    println!("Argument{}:", if args.len() > 1 { "s" } else { "" });
+    for arg in args {
+        match arg.short {
+            Some(s) => print!(" -{}, ", s),
+            None => print!("     "),
+        }
+        if arg.long.is_empty() {
+            print!("  ");
+        } else {
+            print!("--");
+        }
+        print!("{:<12}", arg.long);
+        if let Some(v) = arg.value {
+            if arg.long.is_empty() {
+                print!(" ");
+            } else {
+                print!("=");
+            }
+            print!("{:<10}", v);
+        } else {
+            print!("{:<11}", "");
+        }
+        println!("{}", arg.help);
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn request_help() {
+        let arguments = [Argument::short_flag('h', "help", "Print help message.")];
+
+        let match_res = set_arguments(["-h"].iter(), &arguments[..], |name, _| {
+            match name {
+                "help" => return Err(Error::PrintHelp),
+                _ => unreachable!(),
+            };
+        });
+        match match_res {
+            Err(Error::PrintHelp) => {}
+            _ => unreachable!(),
+        }
+    }
+
+    #[test]
+    fn mixed_args() {
+        let arguments = [
+            Argument::positional("FILES", "files to operate on"),
+            Argument::short_value('p', "program", "PROGRAM", "Program to apply to each file"),
+            Argument::short_value('c', "cpus", "N", "Number of CPUs to use. (default: 1)"),
+            Argument::flag("unmount", "Unmount the root"),
+            Argument::short_flag('h', "help", "Print help message."),
+        ];
+
+        let mut unmount = false;
+        let match_res = set_arguments(
+            ["--cpus", "3", "--program", "hello", "--unmount", "file"].iter(),
+            &arguments[..],
+            |name, value| {
+                match name {
+                    "" => assert_eq!(value.unwrap(), "file"),
+                    "program" => assert_eq!(value.unwrap(), "hello"),
+                    "cpus" => {
+                        let c: u32 = value.unwrap().parse().map_err(|_| Error::InvalidValue {
+                            value: value.unwrap().to_owned(),
+                            expected: "this value for `cpus` needs to be integer",
+                        })?;
+                        assert_eq!(c, 3);
+                    }
+                    "unmount" => unmount = true,
+                    "help" => return Err(Error::PrintHelp),
+                    _ => unreachable!(),
+                };
+                Ok(())
+            },
+        );
+        assert!(match_res.is_ok());
+        assert!(unmount);
+    }
+
+    #[test]
+    fn name_value_pair() {
+        let arguments = [Argument::short_value(
+            'c',
+            "cpus",
+            "N",
+            "Number of CPUs to use. (default: 1)",
+        )];
+        let match_res = set_arguments(
+            ["-c", "5", "--cpus", "5", "-c5", "--cpus=5"].iter(),
+            &arguments[..],
+            |name, value| {
+                assert_eq!(name, "cpus");
+                assert_eq!(value, Some("5"));
+                Ok(())
+            },
+        );
+        assert!(match_res.is_ok());
+    }
+}
diff --git a/src/linux.rs b/src/linux.rs
new file mode 100644
index 0000000..9de014a
--- /dev/null
+++ b/src/linux.rs
@@ -0,0 +1,1772 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std;
+use std::cmp::min;
+use std::convert::TryFrom;
+use std::error::Error as StdError;
+use std::ffi::CStr;
+use std::fmt::{self, Display};
+use std::fs::{File, OpenOptions};
+use std::io::{self, stdin, Read};
+use std::net::Ipv4Addr;
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::os::unix::net::UnixStream;
+use std::path::{Path, PathBuf};
+use std::str;
+use std::sync::{Arc, Barrier};
+use std::thread;
+use std::thread::JoinHandle;
+use std::time::{Duration, SystemTime, UNIX_EPOCH};
+
+use libc::{self, c_int, gid_t, uid_t};
+
+use audio_streams::DummyStreamSource;
+use devices::virtio::{self, VirtioDevice};
+use devices::{self, HostBackendDeviceProvider, PciDevice, VirtioPciDevice, XhciController};
+use io_jail::{self, Minijail};
+use kvm::*;
+use libcras::CrasClient;
+use msg_socket::{MsgError, MsgReceiver, MsgSender, MsgSocket};
+use net_util::{Error as NetError, MacAddress, Tap};
+use qcow::{self, ImageType, QcowFile};
+use rand_ish::SimpleRng;
+use remain::sorted;
+use resources::{Alloc, SystemAllocator};
+use sync::{Condvar, Mutex};
+use sys_util::net::{UnixSeqpacket, UnixSeqpacketListener, UnlinkUnixSeqpacketListener};
+
+use sys_util::{
+    self, block_signal, clear_signal, drop_capabilities, error, flock, get_blocked_signals,
+    get_group_id, get_user_id, getegid, geteuid, info, register_signal_handler, set_cpu_affinity,
+    validate_raw_fd, warn, EventFd, FlockOperation, GuestAddress, GuestMemory, Killable,
+    MemoryMapping, PollContext, PollToken, Protection, SignalFd, Terminal, TimerFd, WatchingEvents,
+    SIGRTMIN,
+};
+use vhost;
+use vm_control::{
+    BalloonControlCommand, BalloonControlRequestSocket, BalloonControlResponseSocket,
+    DiskControlCommand, DiskControlRequestSocket, DiskControlResponseSocket, DiskControlResult,
+    UsbControlSocket, VmControlResponseSocket, VmMemoryControlRequestSocket,
+    VmMemoryControlResponseSocket, VmMemoryRequest, VmMemoryResponse, VmRunMode,
+};
+
+use crate::{Config, DiskOption, Executable, TouchDeviceOption};
+
+use arch::{self, LinuxArch, RunnableLinuxVm, VirtioDeviceStub, VmComponents, VmImage};
+
+#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+use aarch64::AArch64 as Arch;
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+use x86_64::X8664arch as Arch;
+
+#[cfg(feature = "gpu-forward")]
+use render_node_forward::*;
+#[cfg(not(feature = "gpu-forward"))]
+type RenderNodeHost = ();
+
+#[sorted]
+#[derive(Debug)]
+pub enum Error {
+    AddGpuDeviceMemory(sys_util::Error),
+    AddPmemDeviceMemory(sys_util::Error),
+    AllocateGpuDeviceAddress,
+    AllocatePmemDeviceAddress(resources::Error),
+    BalloonDeviceNew(virtio::BalloonError),
+    BlockDeviceNew(sys_util::Error),
+    BlockSignal(sys_util::signal::Error),
+    BuildVm(<Arch as LinuxArch>::Error),
+    ChownTpmStorage(sys_util::Error),
+    CloneEventFd(sys_util::Error),
+    CreateCrasClient(libcras::Error),
+    CreateEventFd(sys_util::Error),
+    CreatePollContext(sys_util::Error),
+    CreateSignalFd(sys_util::SignalFdError),
+    CreateSocket(io::Error),
+    CreateTapDevice(NetError),
+    CreateTimerFd(sys_util::Error),
+    CreateTpmStorage(PathBuf, io::Error),
+    CreateUsbProvider(devices::usb::host_backend::error::Error),
+    DetectImageType(qcow::Error),
+    DeviceJail(io_jail::Error),
+    DevicePivotRoot(io_jail::Error),
+    Disk(io::Error),
+    DiskImageLock(sys_util::Error),
+    DropCapabilities(sys_util::Error),
+    InputDeviceNew(virtio::InputError),
+    InputEventsOpen(std::io::Error),
+    InvalidFdPath,
+    InvalidWaylandPath,
+    IoJail(io_jail::Error),
+    LoadKernel(Box<dyn StdError>),
+    NetDeviceNew(virtio::NetError),
+    OpenAndroidFstab(PathBuf, io::Error),
+    OpenBios(PathBuf, io::Error),
+    OpenInitrd(PathBuf, io::Error),
+    OpenKernel(PathBuf, io::Error),
+    OpenVinput(PathBuf, io::Error),
+    P9DeviceNew(virtio::P9Error),
+    PivotRootDoesntExist(&'static str),
+    PmemDeviceImageTooBig,
+    PmemDeviceNew(sys_util::Error),
+    PollContextAdd(sys_util::Error),
+    PollContextDelete(sys_util::Error),
+    QcowDeviceCreate(qcow::Error),
+    ReadLowmemAvailable(io::Error),
+    ReadLowmemMargin(io::Error),
+    RegisterBalloon(arch::DeviceRegistrationError),
+    RegisterBlock(arch::DeviceRegistrationError),
+    RegisterGpu(arch::DeviceRegistrationError),
+    RegisterNet(arch::DeviceRegistrationError),
+    RegisterP9(arch::DeviceRegistrationError),
+    RegisterRng(arch::DeviceRegistrationError),
+    RegisterSignalHandler(sys_util::Error),
+    RegisterWayland(arch::DeviceRegistrationError),
+    ReserveGpuMemory(sys_util::MmapError),
+    ReserveMemory(sys_util::Error),
+    ReservePmemMemory(sys_util::MmapError),
+    ResetTimerFd(sys_util::Error),
+    RngDeviceNew(virtio::RngError),
+    SettingGidMap(io_jail::Error),
+    SettingUidMap(io_jail::Error),
+    SignalFd(sys_util::SignalFdError),
+    SpawnVcpu(io::Error),
+    TimerFd(sys_util::Error),
+    ValidateRawFd(sys_util::Error),
+    VhostNetDeviceNew(virtio::vhost::Error),
+    VhostVsockDeviceNew(virtio::vhost::Error),
+    VirtioPciDev(sys_util::Error),
+    WaylandDeviceNew(sys_util::Error),
+}
+
+impl Display for Error {
+    #[remain::check]
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        #[sorted]
+        match self {
+            AddGpuDeviceMemory(e) => write!(f, "failed to add gpu device memory: {}", e),
+            AddPmemDeviceMemory(e) => write!(f, "failed to add pmem device memory: {}", e),
+            AllocateGpuDeviceAddress => write!(f, "failed to allocate gpu device guest address"),
+            AllocatePmemDeviceAddress(e) => {
+                write!(f, "failed to allocate memory for pmem device: {}", e)
+            }
+            BalloonDeviceNew(e) => write!(f, "failed to create balloon: {}", e),
+            BlockDeviceNew(e) => write!(f, "failed to create block device: {}", e),
+            BlockSignal(e) => write!(f, "failed to block signal: {}", e),
+            BuildVm(e) => write!(f, "The architecture failed to build the vm: {}", e),
+            ChownTpmStorage(e) => write!(f, "failed to chown tpm storage: {}", e),
+            CloneEventFd(e) => write!(f, "failed to clone eventfd: {}", e),
+            CreateCrasClient(e) => write!(f, "failed to create cras client: {}", e),
+            CreateEventFd(e) => write!(f, "failed to create eventfd: {}", e),
+            CreatePollContext(e) => write!(f, "failed to create poll context: {}", e),
+            CreateSignalFd(e) => write!(f, "failed to create signalfd: {}", e),
+            CreateSocket(e) => write!(f, "failed to create socket: {}", e),
+            CreateTapDevice(e) => write!(f, "failed to create tap device: {}", e),
+            CreateTimerFd(e) => write!(f, "failed to create timerfd: {}", e),
+            CreateTpmStorage(p, e) => {
+                write!(f, "failed to create tpm storage dir {}: {}", p.display(), e)
+            }
+            CreateUsbProvider(e) => write!(f, "failed to create usb provider: {}", e),
+            DetectImageType(e) => write!(f, "failed to detect disk image type: {}", e),
+            DeviceJail(e) => write!(f, "failed to jail device: {}", e),
+            DevicePivotRoot(e) => write!(f, "failed to pivot root device: {}", e),
+            Disk(e) => write!(f, "failed to load disk image: {}", e),
+            DiskImageLock(e) => write!(f, "failed to lock disk image: {}", e),
+            DropCapabilities(e) => write!(f, "failed to drop process capabilities: {}", e),
+            InputDeviceNew(e) => write!(f, "failed to set up input device: {}", e),
+            InputEventsOpen(e) => write!(f, "failed to open event device: {}", e),
+            InvalidFdPath => write!(f, "failed parsing a /proc/self/fd/*"),
+            InvalidWaylandPath => write!(f, "wayland socket path has no parent or file name"),
+            IoJail(e) => write!(f, "{}", e),
+            LoadKernel(e) => write!(f, "failed to load kernel: {}", e),
+            NetDeviceNew(e) => write!(f, "failed to set up virtio networking: {}", e),
+            OpenAndroidFstab(p, e) => write!(
+                f,
+                "failed to open android fstab file {}: {}",
+                p.display(),
+                e
+            ),
+            OpenBios(p, e) => write!(f, "failed to open bios {}: {}", p.display(), e),
+            OpenInitrd(p, e) => write!(f, "failed to open initrd {}: {}", p.display(), e),
+            OpenKernel(p, e) => write!(f, "failed to open kernel image {}: {}", p.display(), e),
+            OpenVinput(p, e) => write!(f, "failed to open vinput device {}: {}", p.display(), e),
+            P9DeviceNew(e) => write!(f, "failed to create 9p device: {}", e),
+            PivotRootDoesntExist(p) => write!(f, "{} doesn't exist, can't jail devices.", p),
+            PmemDeviceImageTooBig => {
+                write!(f, "failed to create pmem device: pmem device image too big")
+            }
+            PmemDeviceNew(e) => write!(f, "failed to create pmem device: {}", e),
+            PollContextAdd(e) => write!(f, "failed to add fd to poll context: {}", e),
+            PollContextDelete(e) => write!(f, "failed to remove fd from poll context: {}", e),
+            QcowDeviceCreate(e) => write!(f, "failed to read qcow formatted file {}", e),
+            ReadLowmemAvailable(e) => write!(
+                f,
+                "failed to read /sys/kernel/mm/chromeos-low_mem/available: {}",
+                e
+            ),
+            ReadLowmemMargin(e) => write!(
+                f,
+                "failed to read /sys/kernel/mm/chromeos-low_mem/margin: {}",
+                e
+            ),
+            RegisterBalloon(e) => write!(f, "error registering balloon device: {}", e),
+            RegisterBlock(e) => write!(f, "error registering block device: {}", e),
+            RegisterGpu(e) => write!(f, "error registering gpu device: {}", e),
+            RegisterNet(e) => write!(f, "error registering net device: {}", e),
+            RegisterP9(e) => write!(f, "error registering 9p device: {}", e),
+            RegisterRng(e) => write!(f, "error registering rng device: {}", e),
+            RegisterSignalHandler(e) => write!(f, "error registering signal handler: {}", e),
+            RegisterWayland(e) => write!(f, "error registering wayland device: {}", e),
+            ReserveGpuMemory(e) => write!(f, "failed to reserve gpu memory: {}", e),
+            ReserveMemory(e) => write!(f, "failed to reserve memory: {}", e),
+            ReservePmemMemory(e) => write!(f, "failed to reserve pmem memory: {}", e),
+            ResetTimerFd(e) => write!(f, "failed to reset timerfd: {}", e),
+            RngDeviceNew(e) => write!(f, "failed to set up rng: {}", e),
+            SettingGidMap(e) => write!(f, "error setting GID map: {}", e),
+            SettingUidMap(e) => write!(f, "error setting UID map: {}", e),
+            SignalFd(e) => write!(f, "failed to read signal fd: {}", e),
+            SpawnVcpu(e) => write!(f, "failed to spawn VCPU thread: {}", e),
+            TimerFd(e) => write!(f, "failed to read timer fd: {}", e),
+            ValidateRawFd(e) => write!(f, "failed to validate raw fd: {}", e),
+            VhostNetDeviceNew(e) => write!(f, "failed to set up vhost networking: {}", e),
+            VhostVsockDeviceNew(e) => write!(f, "failed to set up virtual socket device: {}", e),
+            VirtioPciDev(e) => write!(f, "failed to create virtio pci dev: {}", e),
+            WaylandDeviceNew(e) => write!(f, "failed to create wayland device: {}", e),
+        }
+    }
+}
+
+impl From<io_jail::Error> for Error {
+    fn from(err: io_jail::Error) -> Self {
+        Error::IoJail(err)
+    }
+}
+
+impl std::error::Error for Error {}
+
+type Result<T> = std::result::Result<T, Error>;
+
+enum TaggedControlSocket {
+    Vm(VmControlResponseSocket),
+    VmMemory(VmMemoryControlResponseSocket),
+}
+
+impl AsRef<UnixSeqpacket> for TaggedControlSocket {
+    fn as_ref(&self) -> &UnixSeqpacket {
+        use self::TaggedControlSocket::*;
+        match &self {
+            Vm(ref socket) => socket,
+            VmMemory(ref socket) => socket,
+        }
+    }
+}
+
+impl AsRawFd for TaggedControlSocket {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_ref().as_raw_fd()
+    }
+}
+
+fn create_base_minijail(root: &Path, seccomp_policy: &Path) -> Result<Minijail> {
+    // All child jails run in a new user namespace without any users mapped,
+    // they run as nobody unless otherwise configured.
+    let mut j = Minijail::new().map_err(Error::DeviceJail)?;
+    j.namespace_pids();
+    j.namespace_user();
+    j.namespace_user_disable_setgroups();
+    // Don't need any capabilities.
+    j.use_caps(0);
+    // Create a new mount namespace with an empty root FS.
+    j.namespace_vfs();
+    j.enter_pivot_root(root).map_err(Error::DevicePivotRoot)?;
+    // Run in an empty network namespace.
+    j.namespace_net();
+    // Apply the block device seccomp policy.
+    j.no_new_privs();
+    // Use TSYNC only for the side effect of it using SECCOMP_RET_TRAP, which will correctly kill
+    // the entire device process if a worker thread commits a seccomp violation.
+    j.set_seccomp_filter_tsync();
+    #[cfg(debug_assertions)]
+    j.log_seccomp_filter_failures();
+    j.parse_seccomp_filters(seccomp_policy)
+        .map_err(Error::DeviceJail)?;
+    j.use_seccomp_filter();
+    // Don't do init setup.
+    j.run_as_init();
+    Ok(j)
+}
+
+fn simple_jail(cfg: &Config, policy: &str) -> Result<Option<Minijail>> {
+    if cfg.sandbox {
+        let pivot_root: &str = option_env!("DEFAULT_PIVOT_ROOT").unwrap_or("/var/empty");
+        // A directory for a jailed device's pivot root.
+        let root_path = Path::new(pivot_root);
+        if !root_path.exists() {
+            return Err(Error::PivotRootDoesntExist(pivot_root));
+        }
+        let policy_path: PathBuf = cfg.seccomp_policy_dir.join(policy);
+        Ok(Some(create_base_minijail(root_path, &policy_path)?))
+    } else {
+        Ok(None)
+    }
+}
+
+type DeviceResult<T = VirtioDeviceStub> = std::result::Result<T, Error>;
+
+fn create_block_device(
+    cfg: &Config,
+    disk: &DiskOption,
+    disk_device_socket: DiskControlResponseSocket,
+) -> DeviceResult {
+    // Special case '/proc/self/fd/*' paths. The FD is already open, just use it.
+    let raw_image: File = if disk.path.parent() == Some(Path::new("/proc/self/fd")) {
+        // Safe because we will validate |raw_fd|.
+        unsafe { File::from_raw_fd(raw_fd_from_path(&disk.path)?) }
+    } else {
+        OpenOptions::new()
+            .read(true)
+            .write(!disk.read_only)
+            .open(&disk.path)
+            .map_err(Error::Disk)?
+    };
+    // Lock the disk image to prevent other crosvm instances from using it.
+    let lock_op = if disk.read_only {
+        FlockOperation::LockShared
+    } else {
+        FlockOperation::LockExclusive
+    };
+    flock(&raw_image, lock_op, true).map_err(Error::DiskImageLock)?;
+
+    let image_type = qcow::detect_image_type(&raw_image).map_err(Error::DetectImageType)?;
+    let dev = match image_type {
+        ImageType::Raw => {
+            // Access as a raw block device.
+            let dev = virtio::Block::new(raw_image, disk.read_only, Some(disk_device_socket))
+                .map_err(Error::BlockDeviceNew)?;
+            Box::new(dev) as Box<dyn VirtioDevice>
+        }
+        ImageType::Qcow2 => {
+            // Valid qcow header present
+            let qcow_image = QcowFile::from(raw_image).map_err(Error::QcowDeviceCreate)?;
+            let dev = virtio::Block::new(qcow_image, disk.read_only, Some(disk_device_socket))
+                .map_err(Error::BlockDeviceNew)?;
+            Box::new(dev) as Box<dyn VirtioDevice>
+        }
+    };
+
+    Ok(VirtioDeviceStub {
+        dev,
+        jail: simple_jail(&cfg, "block_device.policy")?,
+    })
+}
+
+fn create_rng_device(cfg: &Config) -> DeviceResult {
+    let dev = virtio::Rng::new().map_err(Error::RngDeviceNew)?;
+
+    Ok(VirtioDeviceStub {
+        dev: Box::new(dev),
+        jail: simple_jail(&cfg, "rng_device.policy")?,
+    })
+}
+
+#[cfg(feature = "tpm")]
+fn create_tpm_device(cfg: &Config) -> DeviceResult {
+    use std::ffi::CString;
+    use std::fs;
+    use std::process;
+    use sys_util::chown;
+
+    let tpm_storage: PathBuf;
+    let mut tpm_jail = simple_jail(&cfg, "tpm_device.policy")?;
+
+    match &mut tpm_jail {
+        Some(jail) => {
+            // Create a tmpfs in the device's root directory for tpm
+            // simulator storage. The size is 20*1024, or 20 KB.
+            jail.mount_with_data(
+                Path::new("none"),
+                Path::new("/"),
+                "tmpfs",
+                (libc::MS_NOSUID | libc::MS_NODEV | libc::MS_NOEXEC) as usize,
+                "size=20480",
+            )?;
+
+            let crosvm_ids = add_crosvm_user_to_jail(jail, "tpm")?;
+
+            let pid = process::id();
+            let tpm_pid_dir = format!("/run/vm/tpm.{}", pid);
+            tpm_storage = Path::new(&tpm_pid_dir).to_owned();
+            fs::create_dir_all(&tpm_storage)
+                .map_err(|e| Error::CreateTpmStorage(tpm_storage.to_owned(), e))?;
+            let tpm_pid_dir_c = CString::new(tpm_pid_dir).expect("no nul bytes");
+            chown(&tpm_pid_dir_c, crosvm_ids.uid, crosvm_ids.gid)
+                .map_err(Error::ChownTpmStorage)?;
+
+            jail.mount_bind(&tpm_storage, &tpm_storage, true)?;
+        }
+        None => {
+            // Path used inside cros_sdk which does not have /run/vm.
+            tpm_storage = Path::new("/tmp/tpm-simulator").to_owned();
+        }
+    }
+
+    let dev = virtio::Tpm::new(tpm_storage);
+
+    Ok(VirtioDeviceStub {
+        dev: Box::new(dev),
+        jail: tpm_jail,
+    })
+}
+
+fn create_single_touch_device(cfg: &Config, single_touch_spec: &TouchDeviceOption) -> DeviceResult {
+    let socket = create_input_socket(&single_touch_spec.path).map_err(|e| {
+        error!("failed configuring virtio single touch: {:?}", e);
+        e
+    })?;
+
+    let dev = virtio::new_single_touch(socket, single_touch_spec.width, single_touch_spec.height)
+        .map_err(Error::InputDeviceNew)?;
+    Ok(VirtioDeviceStub {
+        dev: Box::new(dev),
+        jail: simple_jail(&cfg, "input_device.policy")?,
+    })
+}
+
+fn create_trackpad_device(cfg: &Config, trackpad_spec: &TouchDeviceOption) -> DeviceResult {
+    let socket = create_input_socket(&trackpad_spec.path).map_err(|e| {
+        error!("failed configuring virtio trackpad: {}", e);
+        e
+    })?;
+
+    let dev = virtio::new_trackpad(socket, trackpad_spec.width, trackpad_spec.height)
+        .map_err(Error::InputDeviceNew)?;
+
+    Ok(VirtioDeviceStub {
+        dev: Box::new(dev),
+        jail: simple_jail(&cfg, "input_device.policy")?,
+    })
+}
+
+fn create_mouse_device(cfg: &Config, mouse_socket: &Path) -> DeviceResult {
+    let socket = create_input_socket(&mouse_socket).map_err(|e| {
+        error!("failed configuring virtio mouse: {}", e);
+        e
+    })?;
+
+    let dev = virtio::new_mouse(socket).map_err(Error::InputDeviceNew)?;
+
+    Ok(VirtioDeviceStub {
+        dev: Box::new(dev),
+        jail: simple_jail(&cfg, "input_device.policy")?,
+    })
+}
+
+fn create_keyboard_device(cfg: &Config, keyboard_socket: &Path) -> DeviceResult {
+    let socket = create_input_socket(&keyboard_socket).map_err(|e| {
+        error!("failed configuring virtio keyboard: {}", e);
+        e
+    })?;
+
+    let dev = virtio::new_keyboard(socket).map_err(Error::InputDeviceNew)?;
+
+    Ok(VirtioDeviceStub {
+        dev: Box::new(dev),
+        jail: simple_jail(&cfg, "input_device.policy")?,
+    })
+}
+
+fn create_vinput_device(cfg: &Config, dev_path: &Path) -> DeviceResult {
+    let dev_file = OpenOptions::new()
+        .read(true)
+        .write(true)
+        .open(dev_path)
+        .map_err(|e| Error::OpenVinput(dev_path.to_owned(), e))?;
+
+    let dev = virtio::new_evdev(dev_file).map_err(Error::InputDeviceNew)?;
+
+    Ok(VirtioDeviceStub {
+        dev: Box::new(dev),
+        jail: simple_jail(&cfg, "input_device.policy")?,
+    })
+}
+
+fn create_balloon_device(cfg: &Config, socket: BalloonControlResponseSocket) -> DeviceResult {
+    let dev = virtio::Balloon::new(socket).map_err(Error::BalloonDeviceNew)?;
+
+    Ok(VirtioDeviceStub {
+        dev: Box::new(dev),
+        jail: simple_jail(&cfg, "balloon_device.policy")?,
+    })
+}
+
+fn create_tap_net_device(cfg: &Config, tap_fd: RawFd) -> DeviceResult {
+    // Safe because we ensure that we get a unique handle to the fd.
+    let tap = unsafe {
+        Tap::from_raw_fd(validate_raw_fd(tap_fd).map_err(Error::ValidateRawFd)?)
+            .map_err(Error::CreateTapDevice)?
+    };
+
+    let dev = virtio::Net::from(tap).map_err(Error::NetDeviceNew)?;
+
+    Ok(VirtioDeviceStub {
+        dev: Box::new(dev),
+        jail: simple_jail(&cfg, "net_device.policy")?,
+    })
+}
+
+fn create_net_device(
+    cfg: &Config,
+    host_ip: Ipv4Addr,
+    netmask: Ipv4Addr,
+    mac_address: MacAddress,
+    mem: &GuestMemory,
+) -> DeviceResult {
+    let dev = if cfg.vhost_net {
+        let dev =
+            virtio::vhost::Net::<Tap, vhost::Net<Tap>>::new(host_ip, netmask, mac_address, mem)
+                .map_err(Error::VhostNetDeviceNew)?;
+        Box::new(dev) as Box<dyn VirtioDevice>
+    } else {
+        let dev =
+            virtio::Net::<Tap>::new(host_ip, netmask, mac_address).map_err(Error::NetDeviceNew)?;
+        Box::new(dev) as Box<dyn VirtioDevice>
+    };
+
+    let policy = if cfg.vhost_net {
+        "vhost_net_device.policy"
+    } else {
+        "net_device.policy"
+    };
+
+    Ok(VirtioDeviceStub {
+        dev,
+        jail: simple_jail(&cfg, policy)?,
+    })
+}
+
+#[cfg(feature = "gpu")]
+fn create_gpu_device(
+    cfg: &Config,
+    exit_evt: &EventFd,
+    gpu_device_socket: VmMemoryControlRequestSocket,
+    gpu_socket: virtio::resource_bridge::ResourceResponseSocket,
+    wayland_socket_path: &Path,
+) -> DeviceResult {
+    let jailed_wayland_path = Path::new("/wayland-0");
+
+    let dev = virtio::Gpu::new(
+        exit_evt.try_clone().map_err(Error::CloneEventFd)?,
+        Some(gpu_device_socket),
+        Some(gpu_socket),
+        if cfg.sandbox {
+            &jailed_wayland_path
+        } else {
+            wayland_socket_path
+        },
+    );
+
+    let jail = match simple_jail(&cfg, "gpu_device.policy")? {
+        Some(mut jail) => {
+            // Create a tmpfs in the device's root directory so that we can bind mount the
+            // dri directory into it.  The size=67108864 is size=64*1024*1024 or size=64MB.
+            jail.mount_with_data(
+                Path::new("none"),
+                Path::new("/"),
+                "tmpfs",
+                (libc::MS_NOSUID | libc::MS_NODEV | libc::MS_NOEXEC) as usize,
+                "size=67108864",
+            )?;
+
+            // Device nodes required for DRM.
+            let sys_dev_char_path = Path::new("/sys/dev/char");
+            jail.mount_bind(sys_dev_char_path, sys_dev_char_path, false)?;
+            let sys_devices_path = Path::new("/sys/devices");
+            jail.mount_bind(sys_devices_path, sys_devices_path, false)?;
+            let drm_dri_path = Path::new("/dev/dri");
+            jail.mount_bind(drm_dri_path, drm_dri_path, false)?;
+
+            // Libraries that are required when mesa drivers are dynamically loaded.
+            let lib_path = Path::new("/lib64");
+            jail.mount_bind(lib_path, lib_path, false)?;
+            let usr_lib_path = Path::new("/usr/lib64");
+            jail.mount_bind(usr_lib_path, usr_lib_path, false)?;
+
+            // Bind mount the wayland socket into jail's root. This is necessary since each
+            // new wayland context must open() the socket.
+            jail.mount_bind(wayland_socket_path, jailed_wayland_path, true)?;
+
+            add_crosvm_user_to_jail(&mut jail, "gpu")?;
+
+            Some(jail)
+        }
+        None => None,
+    };
+
+    Ok(VirtioDeviceStub {
+        dev: Box::new(dev),
+        jail,
+    })
+}
+
+fn create_wayland_device(
+    cfg: &Config,
+    socket_path: &Path,
+    socket: VmMemoryControlRequestSocket,
+    resource_bridge: Option<virtio::resource_bridge::ResourceRequestSocket>,
+) -> DeviceResult {
+    let wayland_socket_dir = socket_path.parent().ok_or(Error::InvalidWaylandPath)?;
+    let wayland_socket_name = socket_path.file_name().ok_or(Error::InvalidWaylandPath)?;
+    let jailed_wayland_dir = Path::new("/wayland");
+    let jailed_wayland_path = jailed_wayland_dir.join(wayland_socket_name);
+
+    let dev = virtio::Wl::new(
+        if cfg.sandbox {
+            &jailed_wayland_path
+        } else {
+            socket_path
+        },
+        socket,
+        resource_bridge,
+    )
+    .map_err(Error::WaylandDeviceNew)?;
+
+    let jail = match simple_jail(&cfg, "wl_device.policy")? {
+        Some(mut jail) => {
+            // Create a tmpfs in the device's root directory so that we can bind mount the wayland
+            // socket directory into it. The size=67108864 is size=64*1024*1024 or size=64MB.
+            jail.mount_with_data(
+                Path::new("none"),
+                Path::new("/"),
+                "tmpfs",
+                (libc::MS_NOSUID | libc::MS_NODEV | libc::MS_NOEXEC) as usize,
+                "size=67108864",
+            )?;
+
+            // Bind mount the wayland socket's directory into jail's root. This is necessary since
+            // each new wayland context must open() the socket. If the wayland socket is ever
+            // destroyed and remade in the same host directory, new connections will be possible
+            // without restarting the wayland device.
+            jail.mount_bind(wayland_socket_dir, jailed_wayland_dir, true)?;
+
+            add_crosvm_user_to_jail(&mut jail, "Wayland")?;
+
+            Some(jail)
+        }
+        None => None,
+    };
+
+    Ok(VirtioDeviceStub {
+        dev: Box::new(dev),
+        jail,
+    })
+}
+
+fn create_vhost_vsock_device(cfg: &Config, cid: u64, mem: &GuestMemory) -> DeviceResult {
+    let dev = virtio::vhost::Vsock::new(cid, mem).map_err(Error::VhostVsockDeviceNew)?;
+
+    Ok(VirtioDeviceStub {
+        dev: Box::new(dev),
+        jail: simple_jail(&cfg, "vhost_vsock_device.policy")?,
+    })
+}
+
+fn create_9p_device(cfg: &Config, chronos: Ids, src: &Path, tag: &str) -> DeviceResult {
+    let (jail, root) = match simple_jail(&cfg, "9p_device.policy")? {
+        Some(mut jail) => {
+            //  The shared directory becomes the root of the device's file system.
+            let root = Path::new("/");
+            jail.mount_bind(src, root, true)?;
+
+            // Set the uid/gid for the jailed process, and give a basic id map. This
+            // is required for the above bind mount to work.
+            jail.change_uid(chronos.uid);
+            jail.change_gid(chronos.gid);
+            jail.uidmap(&format!("{0} {0} 1", chronos.uid))
+                .map_err(Error::SettingUidMap)?;
+            jail.gidmap(&format!("{0} {0} 1", chronos.gid))
+                .map_err(Error::SettingGidMap)?;
+
+            (Some(jail), root)
+        }
+        None => {
+            // There's no bind mount so we tell the server to treat the source directory as the
+            // root.
+            (None, src)
+        }
+    };
+
+    let dev = virtio::P9::new(root, tag).map_err(Error::P9DeviceNew)?;
+
+    Ok(VirtioDeviceStub {
+        dev: Box::new(dev),
+        jail,
+    })
+}
+
+fn create_pmem_device(
+    cfg: &Config,
+    vm: &mut Vm,
+    resources: &mut SystemAllocator,
+    disk: &DiskOption,
+    index: usize,
+) -> DeviceResult {
+    let fd = OpenOptions::new()
+        .read(true)
+        .write(!disk.read_only)
+        .open(&disk.path)
+        .map_err(Error::Disk)?;
+
+    let image_size = {
+        let metadata = std::fs::metadata(&disk.path).map_err(Error::Disk)?;
+        metadata.len()
+    };
+
+    let protection = {
+        if disk.read_only {
+            Protection::read()
+        } else {
+            Protection::read_write()
+        }
+    };
+
+    let memory_mapping = {
+        // Conversion from u64 to usize may fail on 32bit system.
+        let image_size = usize::try_from(image_size).map_err(|_| Error::PmemDeviceImageTooBig)?;
+
+        MemoryMapping::from_fd_offset_protection(&fd, image_size, 0, protection)
+            .map_err(Error::ReservePmemMemory)?
+    };
+
+    let mapping_address = resources
+        .device_allocator()
+        .allocate_with_align(
+            image_size,
+            Alloc::PmemDevice(index),
+            format!("pmem_disk_image_{}", index),
+            // Linux kernel requires pmem namespaces to be 128 MiB aligned.
+            128 * 1024 * 1024, /* 128 MiB */
+        )
+        .map_err(Error::AllocatePmemDeviceAddress)?;
+
+    vm.add_device_memory(
+        GuestAddress(mapping_address),
+        memory_mapping,
+        /* read_only = */ disk.read_only,
+        /* log_dirty_pages = */ false,
+    )
+    .map_err(Error::AddPmemDeviceMemory)?;
+
+    let dev = virtio::Pmem::new(fd, GuestAddress(mapping_address), image_size)
+        .map_err(Error::PmemDeviceNew)?;
+
+    Ok(VirtioDeviceStub {
+        dev: Box::new(dev) as Box<dyn VirtioDevice>,
+        /// TODO(jstaron) Create separate device policy for pmem_device.
+        jail: simple_jail(&cfg, "block_device.policy")?,
+    })
+}
+
+// gpu_device_socket is not used when GPU support is disabled.
+#[cfg_attr(not(feature = "gpu"), allow(unused_variables))]
+fn create_virtio_devices(
+    cfg: &Config,
+    mem: &GuestMemory,
+    vm: &mut Vm,
+    resources: &mut SystemAllocator,
+    _exit_evt: &EventFd,
+    wayland_device_socket: VmMemoryControlRequestSocket,
+    gpu_device_socket: VmMemoryControlRequestSocket,
+    balloon_device_socket: BalloonControlResponseSocket,
+    disk_device_sockets: &mut Vec<DiskControlResponseSocket>,
+) -> DeviceResult<Vec<VirtioDeviceStub>> {
+    let mut devs = Vec::new();
+
+    for disk in &cfg.disks {
+        let disk_device_socket = disk_device_sockets.remove(0);
+        devs.push(create_block_device(cfg, disk, disk_device_socket)?);
+    }
+
+    for (index, pmem_disk) in cfg.pmem_devices.iter().enumerate() {
+        devs.push(create_pmem_device(cfg, vm, resources, pmem_disk, index)?);
+    }
+
+    devs.push(create_rng_device(cfg)?);
+
+    #[cfg(feature = "tpm")]
+    {
+        if cfg.software_tpm {
+            devs.push(create_tpm_device(cfg)?);
+        }
+    }
+
+    if let Some(single_touch_spec) = &cfg.virtio_single_touch {
+        devs.push(create_single_touch_device(cfg, single_touch_spec)?);
+    }
+
+    if let Some(trackpad_spec) = &cfg.virtio_trackpad {
+        devs.push(create_trackpad_device(cfg, trackpad_spec)?);
+    }
+
+    if let Some(mouse_socket) = &cfg.virtio_mouse {
+        devs.push(create_mouse_device(cfg, mouse_socket)?);
+    }
+
+    if let Some(keyboard_socket) = &cfg.virtio_keyboard {
+        devs.push(create_keyboard_device(cfg, keyboard_socket)?);
+    }
+
+    for dev_path in &cfg.virtio_input_evdevs {
+        devs.push(create_vinput_device(cfg, dev_path)?);
+    }
+
+    devs.push(create_balloon_device(cfg, balloon_device_socket)?);
+
+    // We checked above that if the IP is defined, then the netmask is, too.
+    for tap_fd in &cfg.tap_fd {
+        devs.push(create_tap_net_device(cfg, *tap_fd)?);
+    }
+
+    if let (Some(host_ip), Some(netmask), Some(mac_address)) =
+        (cfg.host_ip, cfg.netmask, cfg.mac_address)
+    {
+        devs.push(create_net_device(cfg, host_ip, netmask, mac_address, mem)?);
+    }
+
+    #[cfg_attr(not(feature = "gpu"), allow(unused_mut))]
+    let mut resource_bridge_wl_socket = None::<virtio::resource_bridge::ResourceRequestSocket>;
+
+    #[cfg(feature = "gpu")]
+    {
+        if cfg.gpu {
+            if let Some(wayland_socket_path) = &cfg.wayland_socket_path {
+                let (wl_socket, gpu_socket) =
+                    virtio::resource_bridge::pair().map_err(Error::CreateSocket)?;
+                resource_bridge_wl_socket = Some(wl_socket);
+
+                devs.push(create_gpu_device(
+                    cfg,
+                    _exit_evt,
+                    gpu_device_socket,
+                    gpu_socket,
+                    wayland_socket_path,
+                )?);
+            }
+        }
+    }
+
+    if let Some(wayland_socket_path) = cfg.wayland_socket_path.as_ref() {
+        devs.push(create_wayland_device(
+            cfg,
+            wayland_socket_path,
+            wayland_device_socket,
+            resource_bridge_wl_socket,
+        )?);
+    }
+
+    if let Some(cid) = cfg.cid {
+        devs.push(create_vhost_vsock_device(cfg, cid, mem)?);
+    }
+
+    let chronos = get_chronos_ids();
+
+    for (src, tag) in &cfg.shared_dirs {
+        devs.push(create_9p_device(cfg, chronos, src, tag)?);
+    }
+
+    Ok(devs)
+}
+
+fn create_devices(
+    cfg: &Config,
+    mem: &GuestMemory,
+    vm: &mut Vm,
+    resources: &mut SystemAllocator,
+    exit_evt: &EventFd,
+    wayland_device_socket: VmMemoryControlRequestSocket,
+    gpu_device_socket: VmMemoryControlRequestSocket,
+    balloon_device_socket: BalloonControlResponseSocket,
+    disk_device_sockets: &mut Vec<DiskControlResponseSocket>,
+    usb_provider: HostBackendDeviceProvider,
+) -> DeviceResult<Vec<(Box<dyn PciDevice>, Option<Minijail>)>> {
+    let stubs = create_virtio_devices(
+        &cfg,
+        mem,
+        vm,
+        resources,
+        exit_evt,
+        wayland_device_socket,
+        gpu_device_socket,
+        balloon_device_socket,
+        disk_device_sockets,
+    )?;
+
+    let mut pci_devices = Vec::new();
+
+    for stub in stubs {
+        let dev = VirtioPciDevice::new(mem.clone(), stub.dev).map_err(Error::VirtioPciDev)?;
+        let dev = Box::new(dev) as Box<dyn PciDevice>;
+        pci_devices.push((dev, stub.jail));
+    }
+
+    if cfg.cras_audio {
+        let mut server = Box::new(CrasClient::new().map_err(Error::CreateCrasClient)?);
+        if cfg.cras_capture {
+            server.enable_cras_capture();
+        }
+        let cras_audio = devices::Ac97Dev::new(mem.clone(), server);
+
+        pci_devices.push((
+            Box::new(cras_audio),
+            simple_jail(&cfg, "cras_audio_device.policy")?,
+        ));
+    }
+
+    if cfg.null_audio {
+        let server = Box::new(DummyStreamSource::new());
+        let null_audio = devices::Ac97Dev::new(mem.clone(), server);
+
+        pci_devices.push((
+            Box::new(null_audio),
+            simple_jail(&cfg, "null_audio_device.policy")?,
+        ));
+    }
+    // Create xhci controller.
+    let usb_controller = Box::new(XhciController::new(mem.clone(), usb_provider));
+    pci_devices.push((usb_controller, simple_jail(&cfg, "xhci.policy")?));
+
+    Ok(pci_devices)
+}
+
+#[derive(Copy, Clone)]
+struct Ids {
+    uid: uid_t,
+    gid: gid_t,
+}
+
+fn get_chronos_ids() -> Ids {
+    let chronos_user_group = CStr::from_bytes_with_nul(b"chronos\0").unwrap();
+
+    let chronos_uid = match get_user_id(&chronos_user_group) {
+        Ok(u) => u,
+        Err(e) => {
+            warn!("falling back to current user id for 9p: {}", e);
+            geteuid()
+        }
+    };
+
+    let chronos_gid = match get_group_id(&chronos_user_group) {
+        Ok(u) => u,
+        Err(e) => {
+            warn!("falling back to current group id for 9p: {}", e);
+            getegid()
+        }
+    };
+
+    Ids {
+        uid: chronos_uid,
+        gid: chronos_gid,
+    }
+}
+
+// Set the uid/gid for the jailed process and give a basic id map. This is
+// required for bind mounts to work.
+fn add_crosvm_user_to_jail(jail: &mut Minijail, feature: &str) -> Result<Ids> {
+    let crosvm_user_group = CStr::from_bytes_with_nul(b"crosvm\0").unwrap();
+
+    let crosvm_uid = match get_user_id(&crosvm_user_group) {
+        Ok(u) => u,
+        Err(e) => {
+            warn!("falling back to current user id for {}: {}", feature, e);
+            geteuid()
+        }
+    };
+
+    let crosvm_gid = match get_group_id(&crosvm_user_group) {
+        Ok(u) => u,
+        Err(e) => {
+            warn!("falling back to current group id for {}: {}", feature, e);
+            getegid()
+        }
+    };
+
+    jail.change_uid(crosvm_uid);
+    jail.change_gid(crosvm_gid);
+    jail.uidmap(&format!("{0} {0} 1", crosvm_uid))
+        .map_err(Error::SettingUidMap)?;
+    jail.gidmap(&format!("{0} {0} 1", crosvm_gid))
+        .map_err(Error::SettingGidMap)?;
+
+    Ok(Ids {
+        uid: crosvm_uid,
+        gid: crosvm_gid,
+    })
+}
+
+fn raw_fd_from_path(path: &Path) -> Result<RawFd> {
+    if !path.is_file() {
+        return Err(Error::InvalidFdPath);
+    }
+    let raw_fd = path
+        .file_name()
+        .and_then(|fd_osstr| fd_osstr.to_str())
+        .and_then(|fd_str| fd_str.parse::<c_int>().ok())
+        .ok_or(Error::InvalidFdPath)?;
+    validate_raw_fd(raw_fd).map_err(Error::ValidateRawFd)
+}
+
+fn create_input_socket(path: &Path) -> Result<UnixStream> {
+    if path.parent() == Some(Path::new("/proc/self/fd")) {
+        // Safe because we will validate |raw_fd|.
+        unsafe { Ok(UnixStream::from_raw_fd(raw_fd_from_path(path)?)) }
+    } else {
+        UnixStream::connect(path).map_err(Error::InputEventsOpen)
+    }
+}
+
+fn setup_vcpu_signal_handler() -> Result<()> {
+    unsafe {
+        extern "C" fn handle_signal() {}
+        // Our signal handler does nothing and is trivially async signal safe.
+        register_signal_handler(SIGRTMIN() + 0, handle_signal)
+            .map_err(Error::RegisterSignalHandler)?;
+    }
+    block_signal(SIGRTMIN() + 0).map_err(Error::BlockSignal)?;
+    Ok(())
+}
+
+#[derive(Default)]
+struct VcpuRunMode {
+    mtx: Mutex<VmRunMode>,
+    cvar: Condvar,
+}
+
+impl VcpuRunMode {
+    fn set_and_notify(&self, new_mode: VmRunMode) {
+        *self.mtx.lock() = new_mode;
+        self.cvar.notify_all();
+    }
+}
+
+fn run_vcpu(
+    vcpu: Vcpu,
+    cpu_id: u32,
+    vcpu_affinity: Vec<usize>,
+    start_barrier: Arc<Barrier>,
+    io_bus: devices::Bus,
+    mmio_bus: devices::Bus,
+    exit_evt: EventFd,
+    requires_kvmclock_ctrl: bool,
+    run_mode_arc: Arc<VcpuRunMode>,
+) -> Result<JoinHandle<()>> {
+    thread::Builder::new()
+        .name(format!("crosvm_vcpu{}", cpu_id))
+        .spawn(move || {
+            if vcpu_affinity.len() != 0 {
+                if let Err(e) = set_cpu_affinity(vcpu_affinity) {
+                    error!("Failed to set CPU affinity: {}", e);
+                }
+            }
+
+            let mut sig_ok = true;
+            match get_blocked_signals() {
+                Ok(mut v) => {
+                    v.retain(|&x| x != SIGRTMIN() + 0);
+                    if let Err(e) = vcpu.set_signal_mask(&v) {
+                        error!(
+                            "Failed to set the KVM_SIGNAL_MASK for vcpu {} : {}",
+                            cpu_id, e
+                        );
+                        sig_ok = false;
+                    }
+                }
+                Err(e) => {
+                    error!(
+                        "Failed to retrieve signal mask for vcpu {} : {}",
+                        cpu_id, e
+                    );
+                    sig_ok = false;
+                }
+            };
+
+            start_barrier.wait();
+
+            if sig_ok {
+                'vcpu_loop: loop {
+                    let mut interrupted_by_signal = false;
+                    match vcpu.run() {
+                        Ok(VcpuExit::IoIn { port, mut size }) => {
+                            let mut data = [0; 8];
+                            if size > data.len() {
+                                error!("unsupported IoIn size of {} bytes", size);
+                                size = data.len();
+                            }
+                            io_bus.read(port as u64, &mut data[..size]);
+                            if let Err(e) = vcpu.set_data(&data[..size]) {
+                                error!("failed to set return data for IoIn: {}", e);
+                            }
+                        }
+                        Ok(VcpuExit::IoOut {
+                            port,
+                            mut size,
+                            data,
+                        }) => {
+                            if size > data.len() {
+                                error!("unsupported IoOut size of {} bytes", size);
+                                size = data.len();
+                            }
+                            io_bus.write(port as u64, &data[..size]);
+                        }
+                        Ok(VcpuExit::MmioRead { address, size }) => {
+                            let mut data = [0; 8];
+                            mmio_bus.read(address, &mut data[..size]);
+                            // Setting data for mmio can not fail.
+                            let _ = vcpu.set_data(&data[..size]);
+                        }
+                        Ok(VcpuExit::MmioWrite {
+                            address,
+                            size,
+                            data,
+                        }) => {
+                            mmio_bus.write(address, &data[..size]);
+                        }
+                        Ok(VcpuExit::Hlt) => break,
+                        Ok(VcpuExit::Shutdown) => break,
+                        Ok(VcpuExit::SystemEvent(_, _)) => break,
+                        Ok(r) => warn!("unexpected vcpu exit: {:?}", r),
+                        Err(e) => match e.errno() {
+                            libc::EINTR => interrupted_by_signal = true,
+                            libc::EAGAIN => {}
+                            _ => {
+                                error!("vcpu hit unknown error: {}", e);
+                                break;
+                            }
+                        },
+                    }
+
+                    if interrupted_by_signal {
+                        // Try to clear the signal that we use to kick VCPU if it is pending before
+                        // attempting to handle pause requests.
+                        if let Err(e) = clear_signal(SIGRTMIN() + 0) {
+                            error!("failed to clear pending signal: {}", e);
+                            break;
+                        }
+                        let mut run_mode_lock = run_mode_arc.mtx.lock();
+                        loop {
+                            match *run_mode_lock {
+                                VmRunMode::Running => break,
+                                VmRunMode::Suspending => {
+                                    // On KVM implementations that use a paravirtualized clock (e.g.
+                                    // x86), a flag must be set to indicate to the guest kernel that
+                                    // a VCPU was suspended. The guest kernel will use this flag to
+                                    // prevent the soft lockup detection from triggering when this
+                                    // VCPU resumes, which could happen days later in realtime.
+                                    if requires_kvmclock_ctrl {
+                                        if let Err(e) = vcpu.kvmclock_ctrl() {
+                                            error!("failed to signal to kvm that vcpu {} is being suspended: {}", cpu_id, e);
+                                        }
+                                    }
+                                }
+                                VmRunMode::Exiting => break 'vcpu_loop,
+                            }
+                            // Give ownership of our exclusive lock to the condition variable that
+                            // will block. When the condition variable is notified, `wait` will
+                            // unblock and return a new exclusive lock.
+                            run_mode_lock = run_mode_arc.cvar.wait(run_mode_lock);
+                        }
+                    }
+                }
+            }
+            exit_evt
+                .write(1)
+                .expect("failed to signal vcpu exit eventfd");
+        })
+        .map_err(Error::SpawnVcpu)
+}
+
+// Reads the contents of a file and converts the space-separated fields into a Vec of u64s.
+// Returns an error if any of the fields fail to parse.
+fn file_fields_to_u64<P: AsRef<Path>>(path: P) -> io::Result<Vec<u64>> {
+    let mut file = File::open(path)?;
+
+    let mut buf = [0u8; 32];
+    let count = file.read(&mut buf)?;
+
+    let content =
+        str::from_utf8(&buf[..count]).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
+    content
+        .trim()
+        .split_whitespace()
+        .map(|x| {
+            x.parse::<u64>()
+                .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
+        })
+        .collect()
+}
+
+// Reads the contents of a file and converts them into a u64, and if there
+// are multiple fields it only returns the first one.
+fn file_to_u64<P: AsRef<Path>>(path: P) -> io::Result<u64> {
+    file_fields_to_u64(path)?
+        .into_iter()
+        .next()
+        .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "empty file"))
+}
+
+pub fn run_config(cfg: Config) -> Result<()> {
+    if cfg.sandbox {
+        // Printing something to the syslog before entering minijail so that libc's syslogger has a
+        // chance to open files necessary for its operation, like `/etc/localtime`. After jailing,
+        // access to those files will not be possible.
+        info!("crosvm entering multiprocess mode");
+    }
+
+    let (usb_control_socket, usb_provider) =
+        HostBackendDeviceProvider::new().map_err(Error::CreateUsbProvider)?;
+    // Masking signals is inherently dangerous, since this can persist across clones/execs. Do this
+    // before any jailed devices have been spawned, so that we can catch any of them that fail very
+    // quickly.
+    let sigchld_fd = SignalFd::new(libc::SIGCHLD).map_err(Error::CreateSignalFd)?;
+
+    let initrd_image = if let Some(initrd_path) = &cfg.initrd_path {
+        Some(File::open(initrd_path).map_err(|e| Error::OpenInitrd(initrd_path.clone(), e))?)
+    } else {
+        None
+    };
+
+    let vm_image = match cfg.executable_path {
+        Some(Executable::Kernel(ref kernel_path)) => VmImage::Kernel(
+            File::open(kernel_path).map_err(|e| Error::OpenKernel(kernel_path.to_path_buf(), e))?,
+        ),
+        Some(Executable::Bios(ref bios_path)) => VmImage::Bios(
+            File::open(bios_path).map_err(|e| Error::OpenBios(bios_path.to_path_buf(), e))?,
+        ),
+        _ => panic!("Did not receive a bios or kernel, should be impossible."),
+    };
+
+    let components = VmComponents {
+        memory_size: (cfg.memory.unwrap_or(256) << 20) as u64,
+        vcpu_count: cfg.vcpu_count.unwrap_or(1),
+        vcpu_affinity: cfg.vcpu_affinity.clone(),
+        vm_image,
+        android_fstab: cfg
+            .android_fstab
+            .as_ref()
+            .map(|x| File::open(x).map_err(|e| Error::OpenAndroidFstab(x.to_path_buf(), e)))
+            .map_or(Ok(None), |v| v.map(Some))?,
+        initrd_image,
+        extra_kernel_params: cfg.params.clone(),
+        wayland_dmabuf: cfg.wayland_dmabuf,
+    };
+
+    let control_server_socket = match &cfg.socket_path {
+        Some(path) => Some(UnlinkUnixSeqpacketListener(
+            UnixSeqpacketListener::bind(path).map_err(Error::CreateSocket)?,
+        )),
+        None => None,
+    };
+
+    let mut control_sockets = Vec::new();
+    let (wayland_host_socket, wayland_device_socket) =
+        msg_socket::pair::<VmMemoryResponse, VmMemoryRequest>().map_err(Error::CreateSocket)?;
+    control_sockets.push(TaggedControlSocket::VmMemory(wayland_host_socket));
+    // Balloon gets a special socket so balloon requests can be forwarded from the main process.
+    let (balloon_host_socket, balloon_device_socket) =
+        msg_socket::pair::<BalloonControlCommand, ()>().map_err(Error::CreateSocket)?;
+
+    // Create one control socket per disk.
+    let mut disk_device_sockets = Vec::new();
+    let mut disk_host_sockets = Vec::new();
+    let disk_count = cfg.disks.len();
+    for _ in 0..disk_count {
+        let (disk_host_socket, disk_device_socket) =
+            msg_socket::pair::<DiskControlCommand, DiskControlResult>()
+                .map_err(Error::CreateSocket)?;
+        disk_host_sockets.push(disk_host_socket);
+        disk_device_sockets.push(disk_device_socket);
+    }
+
+    let (gpu_host_socket, gpu_device_socket) =
+        msg_socket::pair::<VmMemoryResponse, VmMemoryRequest>().map_err(Error::CreateSocket)?;
+    control_sockets.push(TaggedControlSocket::VmMemory(gpu_host_socket));
+
+    let sandbox = cfg.sandbox;
+    let linux = Arch::build_vm(
+        components,
+        cfg.split_irqchip,
+        &cfg.serial_parameters,
+        |mem, vm, sys_allocator, exit_evt| {
+            create_devices(
+                &cfg,
+                mem,
+                vm,
+                sys_allocator,
+                exit_evt,
+                wayland_device_socket,
+                gpu_device_socket,
+                balloon_device_socket,
+                &mut disk_device_sockets,
+                usb_provider,
+            )
+        },
+    )
+    .map_err(Error::BuildVm)?;
+
+    let _render_node_host = ();
+    #[cfg(feature = "gpu-forward")]
+    let (_render_node_host, linux) = {
+        // Rebinds linux as mutable.
+        let mut linux = linux;
+
+        // Reserve memory range for GPU buffer allocation in advance to bypass region count
+        // limitation. We use mremap/MAP_FIXED later to make sure GPU buffers fall into this range.
+        let gpu_mmap =
+            MemoryMapping::new_protection(RENDER_NODE_HOST_SIZE as usize, Protection::none())
+                .map_err(Error::ReserveGpuMemory)?;
+
+        // Put the non-accessible memory map into device memory so that no other devices use that
+        // guest address space.
+        let gpu_addr = linux
+            .resources
+            .device_allocator()
+            .allocate(
+                RENDER_NODE_HOST_SIZE,
+                Alloc::GpuRenderNode,
+                "gpu_render_node".to_string(),
+            )
+            .map_err(|_| Error::AllocateGpuDeviceAddress)?;
+
+        let host = RenderNodeHost::start(&gpu_mmap, gpu_addr, linux.vm.get_memory().clone());
+
+        // Makes the gpu memory accessible at allocated address.
+        linux
+            .vm
+            .add_device_memory(
+                GuestAddress(gpu_addr),
+                gpu_mmap,
+                /* read_only = */ false,
+                /* log_dirty_pages = */ false,
+            )
+            .map_err(Error::AddGpuDeviceMemory)?;
+        (host, linux)
+    };
+
+    run_control(
+        linux,
+        control_server_socket,
+        control_sockets,
+        balloon_host_socket,
+        &disk_host_sockets,
+        usb_control_socket,
+        sigchld_fd,
+        _render_node_host,
+        sandbox,
+    )
+}
+
+fn run_control(
+    mut linux: RunnableLinuxVm,
+    control_server_socket: Option<UnlinkUnixSeqpacketListener>,
+    mut control_sockets: Vec<TaggedControlSocket>,
+    balloon_host_socket: BalloonControlRequestSocket,
+    disk_host_sockets: &[DiskControlRequestSocket],
+    usb_control_socket: UsbControlSocket,
+    sigchld_fd: SignalFd,
+    _render_node_host: RenderNodeHost,
+    sandbox: bool,
+) -> Result<()> {
+    // Paths to get the currently available memory and the low memory threshold.
+    const LOWMEM_MARGIN: &str = "/sys/kernel/mm/chromeos-low_mem/margin";
+    const LOWMEM_AVAILABLE: &str = "/sys/kernel/mm/chromeos-low_mem/available";
+
+    // The amount of additional memory to claim back from the VM whenever the system is
+    // low on memory.
+    const ONE_GB: u64 = (1 << 30);
+
+    let max_balloon_memory = match linux.vm.get_memory().memory_size() {
+        // If the VM has at least 1.5 GB, the balloon driver can consume all but the last 1 GB.
+        n if n >= (ONE_GB / 2) * 3 => n - ONE_GB,
+        // Otherwise, if the VM has at least 500MB the balloon driver will consume at most
+        // half of it.
+        n if n >= (ONE_GB / 2) => n / 2,
+        // Otherwise, the VM is too small for us to take memory away from it.
+        _ => 0,
+    };
+    let mut current_balloon_memory: u64 = 0;
+    let balloon_memory_increment: u64 = max_balloon_memory / 16;
+
+    #[derive(PollToken)]
+    enum Token {
+        Exit,
+        Stdin,
+        ChildSignal,
+        CheckAvailableMemory,
+        LowMemory,
+        LowmemTimer,
+        VmControlServer,
+        VmControl { index: usize },
+    }
+
+    let stdin_handle = stdin();
+    let stdin_lock = stdin_handle.lock();
+    stdin_lock
+        .set_raw_mode()
+        .expect("failed to set terminal raw mode");
+
+    let poll_ctx = PollContext::new().map_err(Error::CreatePollContext)?;
+    poll_ctx
+        .add(&linux.exit_evt, Token::Exit)
+        .map_err(Error::PollContextAdd)?;
+    if let Err(e) = poll_ctx.add(&stdin_handle, Token::Stdin) {
+        warn!("failed to add stdin to poll context: {}", e);
+    }
+    poll_ctx
+        .add(&sigchld_fd, Token::ChildSignal)
+        .map_err(Error::PollContextAdd)?;
+
+    if let Some(socket_server) = &control_server_socket {
+        poll_ctx
+            .add(socket_server, Token::VmControlServer)
+            .map_err(Error::PollContextAdd)?;
+    }
+    for (index, socket) in control_sockets.iter().enumerate() {
+        poll_ctx
+            .add(socket.as_ref(), Token::VmControl { index })
+            .map_err(Error::PollContextAdd)?;
+    }
+
+    // Watch for low memory notifications and take memory back from the VM.
+    let low_mem = File::open("/dev/chromeos-low-mem").ok();
+    if let Some(low_mem) = &low_mem {
+        poll_ctx
+            .add(low_mem, Token::LowMemory)
+            .map_err(Error::PollContextAdd)?;
+    } else {
+        warn!("Unable to open low mem indicator, maybe not a chrome os kernel");
+    }
+
+    // Used to rate limit balloon requests.
+    let mut lowmem_timer = TimerFd::new().map_err(Error::CreateTimerFd)?;
+    poll_ctx
+        .add(&lowmem_timer, Token::LowmemTimer)
+        .map_err(Error::PollContextAdd)?;
+
+    // Used to check whether it's ok to start giving memory back to the VM.
+    let mut freemem_timer = TimerFd::new().map_err(Error::CreateTimerFd)?;
+    poll_ctx
+        .add(&freemem_timer, Token::CheckAvailableMemory)
+        .map_err(Error::PollContextAdd)?;
+
+    // Used to add jitter to timer values so that we don't have a thundering herd problem when
+    // multiple VMs are running.
+    let mut simple_rng = SimpleRng::new(
+        SystemTime::now()
+            .duration_since(UNIX_EPOCH)
+            .expect("time went backwards")
+            .subsec_nanos() as u64,
+    );
+
+    if sandbox {
+        // Before starting VCPUs, in case we started with some capabilities, drop them all.
+        drop_capabilities().map_err(Error::DropCapabilities)?;
+    }
+
+    let mut vcpu_handles = Vec::with_capacity(linux.vcpus.len());
+    let vcpu_thread_barrier = Arc::new(Barrier::new(linux.vcpus.len() + 1));
+    let run_mode_arc = Arc::new(VcpuRunMode::default());
+    setup_vcpu_signal_handler()?;
+    for (cpu_id, vcpu) in linux.vcpus.into_iter().enumerate() {
+        let handle = run_vcpu(
+            vcpu,
+            cpu_id as u32,
+            linux.vcpu_affinity.clone(),
+            vcpu_thread_barrier.clone(),
+            linux.io_bus.clone(),
+            linux.mmio_bus.clone(),
+            linux.exit_evt.try_clone().map_err(Error::CloneEventFd)?,
+            linux.vm.check_extension(Cap::KvmclockCtrl),
+            run_mode_arc.clone(),
+        )?;
+        vcpu_handles.push(handle);
+    }
+    vcpu_thread_barrier.wait();
+
+    'poll: loop {
+        let events = {
+            match poll_ctx.wait() {
+                Ok(v) => v,
+                Err(e) => {
+                    error!("failed to poll: {}", e);
+                    break;
+                }
+            }
+        };
+
+        let mut vm_control_indices_to_remove = Vec::new();
+        for event in events.iter_readable() {
+            match event.token() {
+                Token::Exit => {
+                    info!("vcpu requested shutdown");
+                    break 'poll;
+                }
+                Token::Stdin => {
+                    let mut out = [0u8; 64];
+                    match stdin_lock.read_raw(&mut out[..]) {
+                        Ok(0) => {
+                            // Zero-length read indicates EOF. Remove from pollables.
+                            let _ = poll_ctx.delete(&stdin_handle);
+                        }
+                        Err(e) => {
+                            warn!("error while reading stdin: {}", e);
+                            let _ = poll_ctx.delete(&stdin_handle);
+                        }
+                        Ok(count) => {
+                            if let Some(ref stdio_serial) = linux.stdio_serial {
+                                stdio_serial
+                                    .lock()
+                                    .queue_input_bytes(&out[..count])
+                                    .expect("failed to queue bytes into serial port");
+                            }
+                        }
+                    }
+                }
+                Token::ChildSignal => {
+                    // Print all available siginfo structs, then exit the loop.
+                    while let Some(siginfo) = sigchld_fd.read().map_err(Error::SignalFd)? {
+                        let pid = siginfo.ssi_pid;
+                        let pid_label = match linux.pid_debug_label_map.get(&pid) {
+                            Some(label) => format!("{} (pid {})", label, pid),
+                            None => format!("pid {}", pid),
+                        };
+                        error!(
+                            "child {} died: signo {}, status {}, code {}",
+                            pid_label, siginfo.ssi_signo, siginfo.ssi_status, siginfo.ssi_code
+                        );
+                    }
+                    break 'poll;
+                }
+                Token::CheckAvailableMemory => {
+                    // Acknowledge the timer.
+                    freemem_timer.wait().map_err(Error::TimerFd)?;
+                    if current_balloon_memory == 0 {
+                        // Nothing to see here.
+                        if let Err(e) = freemem_timer.clear() {
+                            warn!("unable to clear available memory check timer: {}", e);
+                        }
+                        continue;
+                    }
+
+                    // Otherwise see if we can free up some memory.
+                    let margin = file_to_u64(LOWMEM_MARGIN).map_err(Error::ReadLowmemMargin)?;
+                    let available =
+                        file_to_u64(LOWMEM_AVAILABLE).map_err(Error::ReadLowmemAvailable)?;
+
+                    // `available` and `margin` are specified in MB while `balloon_memory_increment` is in
+                    // bytes.  So to correctly compare them we need to turn the increment value into MB.
+                    if available >= margin + 2 * (balloon_memory_increment >> 20) {
+                        current_balloon_memory =
+                            if current_balloon_memory >= balloon_memory_increment {
+                                current_balloon_memory - balloon_memory_increment
+                            } else {
+                                0
+                            };
+                        let command = BalloonControlCommand::Adjust {
+                            num_bytes: current_balloon_memory,
+                        };
+                        if let Err(e) = balloon_host_socket.send(&command) {
+                            warn!("failed to send memory value to balloon device: {}", e);
+                        }
+                    }
+                }
+                Token::LowMemory => {
+                    if let Some(low_mem) = &low_mem {
+                        let old_balloon_memory = current_balloon_memory;
+                        current_balloon_memory = min(
+                            current_balloon_memory + balloon_memory_increment,
+                            max_balloon_memory,
+                        );
+                        if current_balloon_memory != old_balloon_memory {
+                            let command = BalloonControlCommand::Adjust {
+                                num_bytes: current_balloon_memory,
+                            };
+                            if let Err(e) = balloon_host_socket.send(&command) {
+                                warn!("failed to send memory value to balloon device: {}", e);
+                            }
+                        }
+
+                        // Stop polling the lowmem device until the timer fires.
+                        poll_ctx.delete(low_mem).map_err(Error::PollContextDelete)?;
+
+                        // Add some jitter to the timer so that if there are multiple VMs running
+                        // they don't all start ballooning at exactly the same time.
+                        let lowmem_dur = Duration::from_millis(1000 + simple_rng.rng() % 200);
+                        lowmem_timer
+                            .reset(lowmem_dur, None)
+                            .map_err(Error::ResetTimerFd)?;
+
+                        // Also start a timer to check when we can start giving memory back.  Do the
+                        // first check after a minute (with jitter) and subsequent checks after
+                        // every 30 seconds (with jitter).
+                        let freemem_dur = Duration::from_secs(60 + simple_rng.rng() % 12);
+                        let freemem_int = Duration::from_secs(30 + simple_rng.rng() % 6);
+                        freemem_timer
+                            .reset(freemem_dur, Some(freemem_int))
+                            .map_err(Error::ResetTimerFd)?;
+                    }
+                }
+                Token::LowmemTimer => {
+                    // Acknowledge the timer.
+                    lowmem_timer.wait().map_err(Error::TimerFd)?;
+
+                    if let Some(low_mem) = &low_mem {
+                        // Start polling the lowmem device again.
+                        poll_ctx
+                            .add(low_mem, Token::LowMemory)
+                            .map_err(Error::PollContextAdd)?;
+                    }
+                }
+                Token::VmControlServer => {
+                    if let Some(socket_server) = &control_server_socket {
+                        match socket_server.accept() {
+                            Ok(socket) => {
+                                poll_ctx
+                                    .add(
+                                        &socket,
+                                        Token::VmControl {
+                                            index: control_sockets.len(),
+                                        },
+                                    )
+                                    .map_err(Error::PollContextAdd)?;
+                                control_sockets
+                                    .push(TaggedControlSocket::Vm(MsgSocket::new(socket)));
+                            }
+                            Err(e) => error!("failed to accept socket: {}", e),
+                        }
+                    }
+                }
+                Token::VmControl { index } => {
+                    if let Some(socket) = control_sockets.get(index) {
+                        match socket {
+                            TaggedControlSocket::Vm(socket) => match socket.recv() {
+                                Ok(request) => {
+                                    let mut run_mode_opt = None;
+                                    let response = request.execute(
+                                        &mut run_mode_opt,
+                                        &balloon_host_socket,
+                                        disk_host_sockets,
+                                        &usb_control_socket,
+                                    );
+                                    if let Err(e) = socket.send(&response) {
+                                        error!("failed to send VmResponse: {}", e);
+                                    }
+                                    if let Some(run_mode) = run_mode_opt {
+                                        info!("control socket changed run mode to {}", run_mode);
+                                        match run_mode {
+                                            VmRunMode::Exiting => {
+                                                break 'poll;
+                                            }
+                                            other => {
+                                                run_mode_arc.set_and_notify(other);
+                                                for handle in &vcpu_handles {
+                                                    let _ = handle.kill(SIGRTMIN() + 0);
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                                Err(e) => {
+                                    if let MsgError::BadRecvSize { actual: 0, .. } = e {
+                                        vm_control_indices_to_remove.push(index);
+                                    } else {
+                                        error!("failed to recv VmRequest: {}", e);
+                                    }
+                                }
+                            },
+                            TaggedControlSocket::VmMemory(socket) => match socket.recv() {
+                                Ok(request) => {
+                                    let response =
+                                        request.execute(&mut linux.vm, &mut linux.resources);
+                                    if let Err(e) = socket.send(&response) {
+                                        error!("failed to send VmMemoryControlResponse: {}", e);
+                                    }
+                                }
+                                Err(e) => {
+                                    if let MsgError::BadRecvSize { actual: 0, .. } = e {
+                                        vm_control_indices_to_remove.push(index);
+                                    } else {
+                                        error!("failed to recv VmMemoryControlRequest: {}", e);
+                                    }
+                                }
+                            },
+                        }
+                    }
+                }
+            }
+        }
+
+        for event in events.iter_hungup() {
+            match event.token() {
+                Token::Exit => {}
+                Token::Stdin => {
+                    let _ = poll_ctx.delete(&stdin_handle);
+                }
+                Token::ChildSignal => {}
+                Token::CheckAvailableMemory => {}
+                Token::LowMemory => {}
+                Token::LowmemTimer => {}
+                Token::VmControlServer => {}
+                Token::VmControl { index } => {
+                    // It's possible more data is readable and buffered while the socket is hungup,
+                    // so don't delete the socket from the poll context until we're sure all the
+                    // data is read.
+                    match control_sockets
+                        .get(index)
+                        .map(|s| s.as_ref().get_readable_bytes())
+                    {
+                        Some(Ok(0)) | Some(Err(_)) => vm_control_indices_to_remove.push(index),
+                        Some(Ok(x)) => info!("control index {} has {} bytes readable", index, x),
+                        _ => {}
+                    }
+                }
+            }
+        }
+
+        // Sort in reverse so the highest indexes are removed first. This removal algorithm
+        // preserved correct indexes as each element is removed.
+        vm_control_indices_to_remove.sort_unstable_by(|a, b| b.cmp(a));
+        vm_control_indices_to_remove.dedup();
+        for index in vm_control_indices_to_remove {
+            control_sockets.swap_remove(index);
+            if let Some(socket) = control_sockets.get(index) {
+                poll_ctx
+                    .modify(
+                        socket,
+                        WatchingEvents::empty().set_read(),
+                        Token::VmControl { index },
+                    )
+                    .map_err(Error::PollContextAdd)?;
+            }
+        }
+    }
+
+    // VCPU threads MUST see the VmRunMode flag, otherwise they may re-enter the VM.
+    run_mode_arc.set_and_notify(VmRunMode::Exiting);
+    for handle in vcpu_handles {
+        match handle.kill(SIGRTMIN() + 0) {
+            Ok(_) => {
+                if let Err(e) = handle.join() {
+                    error!("failed to join vcpu thread: {:?}", e);
+                }
+            }
+            Err(e) => error!("failed to kill vcpu thread: {}", e),
+        }
+    }
+
+    stdin_lock
+        .set_canon_mode()
+        .expect("failed to restore canonical mode for terminal");
+
+    Ok(())
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..64001a4
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,1449 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Runs a virtual machine under KVM
+
+pub mod argument;
+pub mod linux;
+pub mod panic_hook;
+#[cfg(feature = "plugin")]
+pub mod plugin;
+
+use std::collections::BTreeMap;
+use std::fmt;
+use std::fs::{File, OpenOptions};
+use std::net;
+use std::num::ParseIntError;
+use std::os::unix::io::{FromRawFd, RawFd};
+use std::path::{Path, PathBuf};
+use std::string::String;
+use std::thread::sleep;
+use std::time::Duration;
+
+use devices::{SerialParameters, SerialType};
+use msg_socket::{MsgReceiver, MsgSender, MsgSocket};
+use qcow::QcowFile;
+use sys_util::{
+    debug, error, getpid, info, kill_process_group, net::UnixSeqpacket, reap_child, syslog,
+    validate_raw_fd, warn,
+};
+use vm_control::{
+    BalloonControlCommand, DiskControlCommand, MaybeOwnedFd, UsbControlCommand, UsbControlResult,
+    VmControlRequestSocket, VmRequest, VmResponse, USB_CONTROL_MAX_PORTS,
+};
+
+use crate::argument::{print_help, set_arguments, Argument};
+
+static SECCOMP_POLICY_DIR: &'static str = "/usr/share/policy/crosvm";
+
+struct DiskOption {
+    path: PathBuf,
+    read_only: bool,
+}
+
+#[allow(dead_code)]
+struct BindMount {
+    src: PathBuf,
+    dst: PathBuf,
+    writable: bool,
+}
+
+#[allow(dead_code)]
+struct GidMap {
+    inner: libc::gid_t,
+    outer: libc::gid_t,
+    count: u32,
+}
+
+const DEFAULT_TOUCH_DEVICE_WIDTH: u32 = 800;
+const DEFAULT_TOUCH_DEVICE_HEIGHT: u32 = 1280;
+
+struct TouchDeviceOption {
+    path: PathBuf,
+    width: u32,
+    height: u32,
+}
+
+impl TouchDeviceOption {
+    fn new(path: PathBuf) -> TouchDeviceOption {
+        TouchDeviceOption {
+            path,
+            width: DEFAULT_TOUCH_DEVICE_WIDTH,
+            height: DEFAULT_TOUCH_DEVICE_HEIGHT,
+        }
+    }
+}
+
+#[derive(Debug)]
+pub enum Executable {
+    Bios(PathBuf),
+    Kernel(PathBuf),
+    Plugin(PathBuf),
+}
+
+fn executable_is_plugin(executable: &Option<Executable>) -> bool {
+    match executable {
+        Some(Executable::Plugin(_)) => true,
+        _ => false,
+    }
+}
+
+pub struct Config {
+    vcpu_count: Option<u32>,
+    vcpu_affinity: Vec<usize>,
+    memory: Option<usize>,
+    executable_path: Option<Executable>,
+    android_fstab: Option<PathBuf>,
+    initrd_path: Option<PathBuf>,
+    params: Vec<String>,
+    socket_path: Option<PathBuf>,
+    plugin_root: Option<PathBuf>,
+    plugin_mounts: Vec<BindMount>,
+    plugin_gid_maps: Vec<GidMap>,
+    disks: Vec<DiskOption>,
+    pmem_devices: Vec<DiskOption>,
+    host_ip: Option<net::Ipv4Addr>,
+    netmask: Option<net::Ipv4Addr>,
+    mac_address: Option<net_util::MacAddress>,
+    vhost_net: bool,
+    tap_fd: Vec<RawFd>,
+    cid: Option<u64>,
+    wayland_socket_path: Option<PathBuf>,
+    wayland_dmabuf: bool,
+    shared_dirs: Vec<(PathBuf, String)>,
+    sandbox: bool,
+    seccomp_policy_dir: PathBuf,
+    gpu: bool,
+    software_tpm: bool,
+    cras_audio: bool,
+    cras_capture: bool,
+    null_audio: bool,
+    serial_parameters: BTreeMap<u8, SerialParameters>,
+    syslog_tag: Option<String>,
+    virtio_single_touch: Option<TouchDeviceOption>,
+    virtio_trackpad: Option<TouchDeviceOption>,
+    virtio_mouse: Option<PathBuf>,
+    virtio_keyboard: Option<PathBuf>,
+    virtio_input_evdevs: Vec<PathBuf>,
+    split_irqchip: bool,
+}
+
+impl Default for Config {
+    fn default() -> Config {
+        Config {
+            vcpu_count: None,
+            vcpu_affinity: Vec::new(),
+            memory: None,
+            executable_path: None,
+            android_fstab: None,
+            initrd_path: None,
+            params: Vec::new(),
+            socket_path: None,
+            plugin_root: None,
+            plugin_mounts: Vec::new(),
+            plugin_gid_maps: Vec::new(),
+            disks: Vec::new(),
+            pmem_devices: Vec::new(),
+            host_ip: None,
+            netmask: None,
+            mac_address: None,
+            vhost_net: false,
+            tap_fd: Vec::new(),
+            cid: None,
+            gpu: false,
+            software_tpm: false,
+            wayland_socket_path: None,
+            wayland_dmabuf: false,
+            shared_dirs: Vec::new(),
+            sandbox: !cfg!(feature = "default-no-sandbox"),
+            seccomp_policy_dir: PathBuf::from(SECCOMP_POLICY_DIR),
+            cras_audio: false,
+            cras_capture: false,
+            null_audio: false,
+            serial_parameters: BTreeMap::new(),
+            syslog_tag: None,
+            virtio_single_touch: None,
+            virtio_trackpad: None,
+            virtio_mouse: None,
+            virtio_keyboard: None,
+            virtio_input_evdevs: Vec::new(),
+            split_irqchip: false,
+        }
+    }
+}
+
+// Wait for all children to exit. Return true if they have all exited, false
+// otherwise.
+fn wait_all_children() -> bool {
+    const CHILD_WAIT_MAX_ITER: isize = 100;
+    const CHILD_WAIT_MS: u64 = 10;
+    for _ in 0..CHILD_WAIT_MAX_ITER {
+        loop {
+            match reap_child() {
+                Ok(0) => break,
+                // We expect ECHILD which indicates that there were no children left.
+                Err(e) if e.errno() == libc::ECHILD => return true,
+                Err(e) => {
+                    warn!("error while waiting for children: {}", e);
+                    return false;
+                }
+                // We reaped one child, so continue reaping.
+                _ => {}
+            }
+        }
+        // There's no timeout option for waitpid which reap_child calls internally, so our only
+        // recourse is to sleep while waiting for the children to exit.
+        sleep(Duration::from_millis(CHILD_WAIT_MS));
+    }
+
+    // If we've made it to this point, not all of the children have exited.
+    false
+}
+
+/// Parse a comma-separated list of CPU numbers and ranges and convert it to a Vec of CPU numbers.
+fn parse_cpu_set(s: &str) -> argument::Result<Vec<usize>> {
+    let mut cpuset = Vec::new();
+    for part in s.split(',') {
+        let range: Vec<&str> = part.split('-').collect();
+        if range.len() == 0 || range.len() > 2 {
+            return Err(argument::Error::InvalidValue {
+                value: part.to_owned(),
+                expected: "invalid list syntax",
+            });
+        }
+        let first_cpu: usize = range[0]
+            .parse()
+            .map_err(|_| argument::Error::InvalidValue {
+                value: part.to_owned(),
+                expected: "CPU index must be a non-negative integer",
+            })?;
+        let last_cpu: usize = if range.len() == 2 {
+            range[1]
+                .parse()
+                .map_err(|_| argument::Error::InvalidValue {
+                    value: part.to_owned(),
+                    expected: "CPU index must be a non-negative integer",
+                })?
+        } else {
+            first_cpu
+        };
+
+        if last_cpu < first_cpu {
+            return Err(argument::Error::InvalidValue {
+                value: part.to_owned(),
+                expected: "CPU ranges must be from low to high",
+            });
+        }
+
+        for cpu in first_cpu..=last_cpu {
+            cpuset.push(cpu);
+        }
+    }
+    Ok(cpuset)
+}
+
+fn parse_serial_options(s: &str) -> argument::Result<SerialParameters> {
+    let mut serial_setting = SerialParameters {
+        type_: SerialType::Sink,
+        path: None,
+        num: 1,
+        console: false,
+    };
+
+    let opts = s
+        .split(",")
+        .map(|frag| frag.split("="))
+        .map(|mut kv| (kv.next().unwrap_or(""), kv.next().unwrap_or("")));
+
+    for (k, v) in opts {
+        match k {
+            "type" => {
+                serial_setting.type_ = v
+                    .parse::<SerialType>()
+                    .map_err(|e| argument::Error::UnknownArgument(format!("{}", e)))?
+            }
+            "num" => {
+                let num = v.parse::<u8>().map_err(|e| {
+                    argument::Error::Syntax(format!("serial device number is not parsable: {}", e))
+                })?;
+                if num < 1 || num > 4 {
+                    return Err(argument::Error::InvalidValue {
+                        value: num.to_string(),
+                        expected: "Serial port num must be between 1 - 4",
+                    });
+                }
+                serial_setting.num = num;
+            }
+            "console" => {
+                serial_setting.console = v.parse::<bool>().map_err(|e| {
+                    argument::Error::Syntax(format!(
+                        "serial device console is not parseable: {}",
+                        e
+                    ))
+                })?
+            }
+            "path" => serial_setting.path = Some(PathBuf::from(v)),
+            _ => {
+                return Err(argument::Error::UnknownArgument(format!(
+                    "serial parameter {}",
+                    k
+                )));
+            }
+        }
+    }
+
+    Ok(serial_setting)
+}
+
+fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::Result<()> {
+    match name {
+        "" => {
+            if cfg.executable_path.is_some() {
+                return Err(argument::Error::TooManyArguments(format!(
+                    "A VM executable was already specified: {:?}",
+                    cfg.executable_path
+                )));
+            }
+            let kernel_path = PathBuf::from(value.unwrap());
+            if !kernel_path.exists() {
+                return Err(argument::Error::InvalidValue {
+                    value: value.unwrap().to_owned(),
+                    expected: "this kernel path does not exist",
+                });
+            }
+            cfg.executable_path = Some(Executable::Kernel(kernel_path));
+        }
+        "android-fstab" => {
+            if cfg.android_fstab.is_some()
+                && !cfg.android_fstab.as_ref().unwrap().as_os_str().is_empty()
+            {
+                return Err(argument::Error::TooManyArguments(
+                    "expected exactly one android fstab path".to_owned(),
+                ));
+            } else {
+                let android_fstab = PathBuf::from(value.unwrap());
+                if !android_fstab.exists() {
+                    return Err(argument::Error::InvalidValue {
+                        value: value.unwrap().to_owned(),
+                        expected: "this android fstab path does not exist",
+                    });
+                }
+                cfg.android_fstab = Some(android_fstab);
+            }
+        }
+        "params" => {
+            cfg.params.push(value.unwrap().to_owned());
+        }
+        "cpus" => {
+            if cfg.vcpu_count.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`cpus` already given".to_owned(),
+                ));
+            }
+            cfg.vcpu_count =
+                Some(
+                    value
+                        .unwrap()
+                        .parse()
+                        .map_err(|_| argument::Error::InvalidValue {
+                            value: value.unwrap().to_owned(),
+                            expected: "this value for `cpus` needs to be integer",
+                        })?,
+                )
+        }
+        "cpu-affinity" => {
+            if cfg.vcpu_affinity.len() != 0 {
+                return Err(argument::Error::TooManyArguments(
+                    "`cpu-affinity` already given".to_owned(),
+                ));
+            }
+            cfg.vcpu_affinity = parse_cpu_set(value.unwrap())?;
+        }
+        "mem" => {
+            if cfg.memory.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`mem` already given".to_owned(),
+                ));
+            }
+            cfg.memory =
+                Some(
+                    value
+                        .unwrap()
+                        .parse()
+                        .map_err(|_| argument::Error::InvalidValue {
+                            value: value.unwrap().to_owned(),
+                            expected: "this value for `mem` needs to be integer",
+                        })?,
+                )
+        }
+        "cras-audio" => {
+            cfg.cras_audio = true;
+        }
+        "cras-capture" => {
+            cfg.cras_capture = true;
+        }
+        "null-audio" => {
+            cfg.null_audio = true;
+        }
+        "serial" => {
+            let serial_params = parse_serial_options(value.unwrap())?;
+            let num = serial_params.num;
+            if cfg.serial_parameters.contains_key(&num) {
+                return Err(argument::Error::TooManyArguments(format!(
+                    "serial num {}",
+                    num
+                )));
+            }
+
+            if serial_params.console {
+                for params in cfg.serial_parameters.values() {
+                    if params.console {
+                        return Err(argument::Error::TooManyArguments(format!(
+                            "serial device {} already set as console",
+                            params.num
+                        )));
+                    }
+                }
+            }
+
+            cfg.serial_parameters.insert(num, serial_params);
+        }
+        "syslog-tag" => {
+            if cfg.syslog_tag.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`syslog-tag` already given".to_owned(),
+                ));
+            }
+            syslog::set_proc_name(value.unwrap());
+            cfg.syslog_tag = Some(value.unwrap().to_owned());
+        }
+        "root" | "disk" | "rwdisk" | "qcow" | "rwqcow" => {
+            let disk_path = PathBuf::from(value.unwrap());
+            if !disk_path.exists() {
+                return Err(argument::Error::InvalidValue {
+                    value: value.unwrap().to_owned(),
+                    expected: "this disk path does not exist",
+                });
+            }
+            if name == "root" {
+                if cfg.disks.len() >= 26 {
+                    return Err(argument::Error::TooManyArguments(
+                        "ran out of letters for to assign to root disk".to_owned(),
+                    ));
+                }
+                cfg.params.push(format!(
+                    "root=/dev/vd{} ro",
+                    char::from(b'a' + cfg.disks.len() as u8)
+                ));
+            }
+            cfg.disks.push(DiskOption {
+                path: disk_path,
+                read_only: !name.starts_with("rw"),
+            });
+        }
+        "pmem-device" | "rw-pmem-device" => {
+            let disk_path = PathBuf::from(value.unwrap());
+            if !disk_path.exists() {
+                return Err(argument::Error::InvalidValue {
+                    value: value.unwrap().to_owned(),
+                    expected: "this disk path does not exist",
+                });
+            }
+
+            cfg.pmem_devices.push(DiskOption {
+                path: disk_path,
+                read_only: !name.starts_with("rw"),
+            });
+        }
+        "host_ip" => {
+            if cfg.host_ip.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`host_ip` already given".to_owned(),
+                ));
+            }
+            cfg.host_ip =
+                Some(
+                    value
+                        .unwrap()
+                        .parse()
+                        .map_err(|_| argument::Error::InvalidValue {
+                            value: value.unwrap().to_owned(),
+                            expected: "`host_ip` needs to be in the form \"x.x.x.x\"",
+                        })?,
+                )
+        }
+        "netmask" => {
+            if cfg.netmask.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`netmask` already given".to_owned(),
+                ));
+            }
+            cfg.netmask =
+                Some(
+                    value
+                        .unwrap()
+                        .parse()
+                        .map_err(|_| argument::Error::InvalidValue {
+                            value: value.unwrap().to_owned(),
+                            expected: "`netmask` needs to be in the form \"x.x.x.x\"",
+                        })?,
+                )
+        }
+        "mac" => {
+            if cfg.mac_address.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`mac` already given".to_owned(),
+                ));
+            }
+            cfg.mac_address =
+                Some(
+                    value
+                        .unwrap()
+                        .parse()
+                        .map_err(|_| argument::Error::InvalidValue {
+                            value: value.unwrap().to_owned(),
+                            expected: "`mac` needs to be in the form \"XX:XX:XX:XX:XX:XX\"",
+                        })?,
+                )
+        }
+        "wayland-sock" => {
+            if cfg.wayland_socket_path.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`wayland-sock` already given".to_owned(),
+                ));
+            }
+            let wayland_socket_path = PathBuf::from(value.unwrap());
+            if !wayland_socket_path.exists() {
+                return Err(argument::Error::InvalidValue {
+                    value: value.unwrap().to_string(),
+                    expected: "Wayland socket does not exist",
+                });
+            }
+            cfg.wayland_socket_path = Some(wayland_socket_path);
+        }
+        #[cfg(feature = "wl-dmabuf")]
+        "wayland-dmabuf" => cfg.wayland_dmabuf = true,
+        "socket" => {
+            if cfg.socket_path.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`socket` already given".to_owned(),
+                ));
+            }
+            let mut socket_path = PathBuf::from(value.unwrap());
+            if socket_path.is_dir() {
+                socket_path.push(format!("crosvm-{}.sock", getpid()));
+            }
+            if socket_path.exists() {
+                return Err(argument::Error::InvalidValue {
+                    value: socket_path.to_string_lossy().into_owned(),
+                    expected: "this socket path already exists",
+                });
+            }
+            cfg.socket_path = Some(socket_path);
+        }
+        "disable-sandbox" => {
+            cfg.sandbox = false;
+        }
+        "cid" => {
+            if cfg.cid.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`cid` alread given".to_owned(),
+                ));
+            }
+            cfg.cid = Some(
+                value
+                    .unwrap()
+                    .parse()
+                    .map_err(|_| argument::Error::InvalidValue {
+                        value: value.unwrap().to_owned(),
+                        expected: "this value for `cid` must be an unsigned integer",
+                    })?,
+            );
+        }
+        "shared-dir" => {
+            // Formatted as <src:tag>.
+            let param = value.unwrap();
+            let mut components = param.splitn(2, ':');
+            let src =
+                PathBuf::from(
+                    components
+                        .next()
+                        .ok_or_else(|| argument::Error::InvalidValue {
+                            value: param.to_owned(),
+                            expected: "missing source path for `shared-dir`",
+                        })?,
+                );
+            let tag = components
+                .next()
+                .ok_or_else(|| argument::Error::InvalidValue {
+                    value: param.to_owned(),
+                    expected: "missing tag for `shared-dir`",
+                })?
+                .to_owned();
+
+            if !src.is_dir() {
+                return Err(argument::Error::InvalidValue {
+                    value: param.to_owned(),
+                    expected: "source path for `shared-dir` must be a directory",
+                });
+            }
+
+            cfg.shared_dirs.push((src, tag));
+        }
+        "seccomp-policy-dir" => {
+            // `value` is Some because we are in this match so it's safe to unwrap.
+            cfg.seccomp_policy_dir = PathBuf::from(value.unwrap());
+        }
+        "plugin" => {
+            if cfg.executable_path.is_some() {
+                return Err(argument::Error::TooManyArguments(format!(
+                    "A VM executable was already specified: {:?}",
+                    cfg.executable_path
+                )));
+            }
+            let plugin = PathBuf::from(value.unwrap().to_owned());
+            if plugin.is_relative() {
+                return Err(argument::Error::InvalidValue {
+                    value: plugin.to_string_lossy().into_owned(),
+                    expected: "the plugin path must be an absolute path",
+                });
+            }
+            cfg.executable_path = Some(Executable::Plugin(plugin));
+        }
+        "plugin-root" => {
+            cfg.plugin_root = Some(PathBuf::from(value.unwrap().to_owned()));
+        }
+        "plugin-mount" => {
+            let components: Vec<&str> = value.unwrap().split(":").collect();
+            if components.len() != 3 {
+                return Err(argument::Error::InvalidValue {
+                    value: value.unwrap().to_owned(),
+                    expected:
+                        "`plugin-mount` must have exactly 3 components: <src>:<dst>:<writable>",
+                });
+            }
+
+            let src = PathBuf::from(components[0]);
+            if src.is_relative() {
+                return Err(argument::Error::InvalidValue {
+                    value: components[0].to_owned(),
+                    expected: "the source path for `plugin-mount` must be absolute",
+                });
+            }
+            if !src.exists() {
+                return Err(argument::Error::InvalidValue {
+                    value: components[0].to_owned(),
+                    expected: "the source path for `plugin-mount` does not exist",
+                });
+            }
+
+            let dst = PathBuf::from(components[1]);
+            if dst.is_relative() {
+                return Err(argument::Error::InvalidValue {
+                    value: components[1].to_owned(),
+                    expected: "the destination path for `plugin-mount` must be absolute",
+                });
+            }
+
+            let writable: bool =
+                components[2]
+                    .parse()
+                    .map_err(|_| argument::Error::InvalidValue {
+                        value: components[2].to_owned(),
+                        expected: "the <writable> component for `plugin-mount` is not valid bool",
+                    })?;
+
+            cfg.plugin_mounts.push(BindMount { src, dst, writable });
+        }
+        "plugin-gid-map" => {
+            let components: Vec<&str> = value.unwrap().split(":").collect();
+            if components.len() != 3 {
+                return Err(argument::Error::InvalidValue {
+                    value: value.unwrap().to_owned(),
+                    expected:
+                        "`plugin-gid-map` must have exactly 3 components: <inner>:<outer>:<count>",
+                });
+            }
+
+            let inner: libc::gid_t =
+                components[0]
+                    .parse()
+                    .map_err(|_| argument::Error::InvalidValue {
+                        value: components[0].to_owned(),
+                        expected: "the <inner> component for `plugin-gid-map` is not valid gid",
+                    })?;
+
+            let outer: libc::gid_t =
+                components[1]
+                    .parse()
+                    .map_err(|_| argument::Error::InvalidValue {
+                        value: components[1].to_owned(),
+                        expected: "the <outer> component for `plugin-gid-map` is not valid gid",
+                    })?;
+
+            let count: u32 = components[2]
+                .parse()
+                .map_err(|_| argument::Error::InvalidValue {
+                    value: components[2].to_owned(),
+                    expected: "the <count> component for `plugin-gid-map` is not valid number",
+                })?;
+
+            cfg.plugin_gid_maps.push(GidMap {
+                inner,
+                outer,
+                count,
+            });
+        }
+        "vhost-net" => cfg.vhost_net = true,
+        "tap-fd" => {
+            cfg.tap_fd.push(
+                value
+                    .unwrap()
+                    .parse()
+                    .map_err(|_| argument::Error::InvalidValue {
+                        value: value.unwrap().to_owned(),
+                        expected: "this value for `tap-fd` must be an unsigned integer",
+                    })?,
+            );
+        }
+        "gpu" => {
+            cfg.gpu = true;
+        }
+        "software-tpm" => {
+            cfg.software_tpm = true;
+        }
+        "single-touch" => {
+            if cfg.virtio_single_touch.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`single-touch` already given".to_owned(),
+                ));
+            }
+            let mut it = value.unwrap().split(":");
+
+            let mut single_touch_spec =
+                TouchDeviceOption::new(PathBuf::from(it.next().unwrap().to_owned()));
+            if let Some(width) = it.next() {
+                single_touch_spec.width = width.trim().parse().unwrap();
+            }
+            if let Some(height) = it.next() {
+                single_touch_spec.height = height.trim().parse().unwrap();
+            }
+
+            cfg.virtio_single_touch = Some(single_touch_spec);
+        }
+        "trackpad" => {
+            if cfg.virtio_trackpad.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`trackpad` already given".to_owned(),
+                ));
+            }
+            let mut it = value.unwrap().split(":");
+
+            let mut trackpad_spec =
+                TouchDeviceOption::new(PathBuf::from(it.next().unwrap().to_owned()));
+            if let Some(width) = it.next() {
+                trackpad_spec.width = width.trim().parse().unwrap();
+            }
+            if let Some(height) = it.next() {
+                trackpad_spec.height = height.trim().parse().unwrap();
+            }
+
+            cfg.virtio_trackpad = Some(trackpad_spec);
+        }
+        "mouse" => {
+            if cfg.virtio_mouse.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`mouse` already given".to_owned(),
+                ));
+            }
+            cfg.virtio_mouse = Some(PathBuf::from(value.unwrap().to_owned()));
+        }
+        "keyboard" => {
+            if cfg.virtio_keyboard.is_some() {
+                return Err(argument::Error::TooManyArguments(
+                    "`keyboard` already given".to_owned(),
+                ));
+            }
+            cfg.virtio_keyboard = Some(PathBuf::from(value.unwrap().to_owned()));
+        }
+        "evdev" => {
+            let dev_path = PathBuf::from(value.unwrap());
+            if !dev_path.exists() {
+                return Err(argument::Error::InvalidValue {
+                    value: value.unwrap().to_owned(),
+                    expected: "this input device path does not exist",
+                });
+            }
+            cfg.virtio_input_evdevs.push(dev_path);
+        }
+        "split-irqchip" => {
+            cfg.split_irqchip = true;
+        }
+        "initrd" => {
+            cfg.initrd_path = Some(PathBuf::from(value.unwrap().to_owned()));
+        }
+        "bios" => {
+            if cfg.executable_path.is_some() {
+                return Err(argument::Error::TooManyArguments(format!(
+                    "A VM executable was already specified: {:?}",
+                    cfg.executable_path
+                )));
+            }
+            cfg.executable_path = Some(Executable::Bios(PathBuf::from(value.unwrap().to_owned())));
+        }
+        "help" => return Err(argument::Error::PrintHelp),
+        _ => unreachable!(),
+    }
+    Ok(())
+}
+
+fn run_vm(args: std::env::Args) -> std::result::Result<(), ()> {
+    let arguments =
+        &[Argument::positional("KERNEL", "bzImage of kernel to run"),
+          Argument::value("android-fstab", "PATH", "Path to Android fstab"),
+          Argument::short_value('i', "initrd", "PATH", "Initial ramdisk to load."),
+          Argument::short_value('p',
+                                "params",
+                                "PARAMS",
+                                "Extra kernel or plugin command line arguments. Can be given more than once."),
+          Argument::short_value('c', "cpus", "N", "Number of VCPUs. (default: 1)"),
+          Argument::value("cpu-affinity", "CPUSET", "Comma-separated list of CPUs or CPU ranges to run VCPUs on. (e.g. 0,1-3,5) (default: no mask)"),
+          Argument::short_value('m',
+                                "mem",
+                                "N",
+                                "Amount of guest memory in MiB. (default: 256)"),
+          Argument::short_value('r',
+                                "root",
+                                "PATH",
+                                "Path to a root disk image. Like `--disk` but adds appropriate kernel command line option."),
+          Argument::short_value('d', "disk", "PATH", "Path to a disk image."),
+          Argument::value("qcow", "PATH", "Path to a qcow2 disk image. (Deprecated; use --disk instead.)"),
+          Argument::value("rwdisk", "PATH", "Path to a writable disk image."),
+          Argument::value("rwqcow", "PATH", "Path to a writable qcow2 disk image. (Deprecated; use --rwdisk instead.)"),
+          Argument::value("rw-pmem-device", "PATH", "Path to a writable disk image."),
+          Argument::value("pmem-device", "PATH", "Path to a disk image."),
+          Argument::value("host_ip",
+                          "IP",
+                          "IP address to assign to host tap interface."),
+          Argument::value("netmask", "NETMASK", "Netmask for VM subnet."),
+          Argument::value("mac", "MAC", "MAC address for VM."),
+          Argument::flag("cras-audio", "Add an audio device to the VM that plays samples through CRAS server"),
+          Argument::flag("cras-capture", "Enable capturing audio from CRAS server to the cras-audio device"),
+          Argument::flag("null-audio", "Add an audio device to the VM that plays samples to /dev/null"),
+          Argument::value("serial",
+                          "type=TYPE,[num=NUM,path=PATH,console]",
+                          "Comma seperated key=value pairs for setting up serial devices. Can be given more than once.
+                          Possible key values:
+                          type=(stdout,syslog,sink,file) - Where to route the serial device
+                          num=(1,2,3,4) - Serial Device Number. If not provided, num will default to 1.
+                          path=PATH - The path to the file to write to when type=file
+                          console - Use this serial device as the guest console. Can only be given once. Will default to first serial port if not provided.
+                          "),
+          Argument::value("syslog-tag", "TAG", "When logging to syslog, use the provided tag."),
+          Argument::value("wayland-sock", "PATH", "Path to the Wayland socket to use."),
+          #[cfg(feature = "wl-dmabuf")]
+          Argument::flag("wayland-dmabuf", "Enable support for DMABufs in Wayland device."),
+          Argument::short_value('s',
+                                "socket",
+                                "PATH",
+                                "Path to put the control socket. If PATH is a directory, a name will be generated."),
+          Argument::flag("disable-sandbox", "Run all devices in one, non-sandboxed process."),
+          Argument::value("cid", "CID", "Context ID for virtual sockets."),
+          Argument::value("shared-dir", "PATH:TAG",
+                          "Directory to be shared with a VM as a source:tag pair. Can be given more than once."),
+          Argument::value("seccomp-policy-dir", "PATH", "Path to seccomp .policy files."),
+          #[cfg(feature = "plugin")]
+          Argument::value("plugin", "PATH", "Absolute path to plugin process to run under crosvm."),
+          #[cfg(feature = "plugin")]
+          Argument::value("plugin-root", "PATH", "Absolute path to a directory that will become root filesystem for the plugin process."),
+          #[cfg(feature = "plugin")]
+          Argument::value("plugin-mount", "PATH:PATH:BOOL", "Path to be mounted into the plugin's root filesystem.  Can be given more than once."),
+          #[cfg(feature = "plugin")]
+          Argument::value("plugin-gid-map", "GID:GID:INT", "Supplemental GIDs that should be mapped in plugin jail.  Can be given more than once."),
+          Argument::flag("vhost-net", "Use vhost for networking."),
+          Argument::value("tap-fd",
+                          "fd",
+                          "File descriptor for configured tap device. A different virtual network card will be added each time this argument is given."),
+          #[cfg(feature = "gpu")]
+          Argument::flag("gpu", "(EXPERIMENTAL) enable virtio-gpu device"),
+          #[cfg(feature = "tpm")]
+          Argument::flag("software-tpm", "enable a software emulated trusted platform module device"),
+          Argument::value("evdev", "PATH", "Path to an event device node. The device will be grabbed (unusable from the host) and made available to the guest with the same configuration it shows on the host"),
+          Argument::value("single-touch", "PATH:WIDTH:HEIGHT", "Path to a socket from where to read single touch input events (such as those from a touchscreen) and write status updates to, optionally followed by width and height (defaults to 800x1280)."),
+          Argument::value("trackpad", "PATH:WIDTH:HEIGHT", "Path to a socket from where to read trackpad input events and write status updates to, optionally followed by screen width and height (defaults to 800x1280)."),
+          Argument::value("mouse", "PATH", "Path to a socket from where to read mouse input events and write status updates to."),
+          Argument::value("keyboard", "PATH", "Path to a socket from where to read keyboard input events and write status updates to."),
+          #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+          Argument::flag("split-irqchip", "(EXPERIMENTAL) enable split-irqchip support"),
+          Argument::value("bios", "PATH", "Path to BIOS/firmware ROM"),
+          Argument::short_flag('h', "help", "Print help message.")];
+
+    let mut cfg = Config::default();
+    let match_res = set_arguments(args, &arguments[..], |name, value| {
+        set_argument(&mut cfg, name, value)
+    })
+    .and_then(|_| {
+        if cfg.executable_path.is_none() {
+            return Err(argument::Error::ExpectedArgument("`KERNEL`".to_owned()));
+        }
+        if cfg.host_ip.is_some() || cfg.netmask.is_some() || cfg.mac_address.is_some() {
+            if cfg.host_ip.is_none() {
+                return Err(argument::Error::ExpectedArgument(
+                    "`host_ip` missing from network config".to_owned(),
+                ));
+            }
+            if cfg.netmask.is_none() {
+                return Err(argument::Error::ExpectedArgument(
+                    "`netmask` missing from network config".to_owned(),
+                ));
+            }
+            if cfg.mac_address.is_none() {
+                return Err(argument::Error::ExpectedArgument(
+                    "`mac` missing from network config".to_owned(),
+                ));
+            }
+        }
+        if cfg.plugin_root.is_some() && !executable_is_plugin(&cfg.executable_path) {
+            return Err(argument::Error::ExpectedArgument(
+                "`plugin-root` requires `plugin`".to_owned(),
+            ));
+        }
+        Ok(())
+    });
+
+    match match_res {
+        #[cfg(feature = "plugin")]
+        Ok(()) if executable_is_plugin(&cfg.executable_path) => match plugin::run_config(cfg) {
+            Ok(_) => {
+                info!("crosvm and plugin have exited normally");
+                Ok(())
+            }
+            Err(e) => {
+                error!("{}", e);
+                Err(())
+            }
+        },
+        Ok(()) => match linux::run_config(cfg) {
+            Ok(_) => {
+                info!("crosvm has exited normally");
+                Ok(())
+            }
+            Err(e) => {
+                error!("{}", e);
+                Err(())
+            }
+        },
+        Err(argument::Error::PrintHelp) => {
+            print_help("crosvm run", "KERNEL", &arguments[..]);
+            Ok(())
+        }
+        Err(e) => {
+            println!("{}", e);
+            Err(())
+        }
+    }
+}
+
+fn handle_request(
+    request: &VmRequest,
+    args: std::env::Args,
+) -> std::result::Result<VmResponse, ()> {
+    let mut return_result = Err(());
+    for socket_path in args {
+        match UnixSeqpacket::connect(&socket_path) {
+            Ok(s) => {
+                let socket: VmControlRequestSocket = MsgSocket::new(s);
+                if let Err(e) = socket.send(request) {
+                    error!(
+                        "failed to send request to socket at '{}': {}",
+                        socket_path, e
+                    );
+                    return_result = Err(());
+                    continue;
+                }
+                match socket.recv() {
+                    Ok(response) => return_result = Ok(response),
+                    Err(e) => {
+                        error!(
+                            "failed to send request to socket at2 '{}': {}",
+                            socket_path, e
+                        );
+                        return_result = Err(());
+                        continue;
+                    }
+                }
+            }
+            Err(e) => {
+                error!("failed to connect to socket at '{}': {}", socket_path, e);
+                return_result = Err(());
+            }
+        }
+    }
+
+    return_result
+}
+
+fn vms_request(request: &VmRequest, args: std::env::Args) -> std::result::Result<(), ()> {
+    let response = handle_request(request, args)?;
+    info!("request response was {}", response);
+    Ok(())
+}
+
+fn stop_vms(args: std::env::Args) -> std::result::Result<(), ()> {
+    if args.len() == 0 {
+        print_help("crosvm stop", "VM_SOCKET...", &[]);
+        println!("Stops the crosvm instance listening on each `VM_SOCKET` given.");
+        return Err(());
+    }
+    vms_request(&VmRequest::Exit, args)
+}
+
+fn suspend_vms(args: std::env::Args) -> std::result::Result<(), ()> {
+    if args.len() == 0 {
+        print_help("crosvm suspend", "VM_SOCKET...", &[]);
+        println!("Suspends the crosvm instance listening on each `VM_SOCKET` given.");
+        return Err(());
+    }
+    vms_request(&VmRequest::Suspend, args)
+}
+
+fn resume_vms(args: std::env::Args) -> std::result::Result<(), ()> {
+    if args.len() == 0 {
+        print_help("crosvm resume", "VM_SOCKET...", &[]);
+        println!("Resumes the crosvm instance listening on each `VM_SOCKET` given.");
+        return Err(());
+    }
+    vms_request(&VmRequest::Resume, args)
+}
+
+fn balloon_vms(mut args: std::env::Args) -> std::result::Result<(), ()> {
+    if args.len() < 2 {
+        print_help("crosvm balloon", "SIZE VM_SOCKET...", &[]);
+        println!("Set the ballon size of the crosvm instance to `SIZE` bytes.");
+        return Err(());
+    }
+    let num_bytes = match args.nth(0).unwrap().parse::<u64>() {
+        Ok(n) => n,
+        Err(_) => {
+            error!("Failed to parse number of bytes");
+            return Err(());
+        }
+    };
+
+    let command = BalloonControlCommand::Adjust { num_bytes };
+    vms_request(&VmRequest::BalloonCommand(command), args)
+}
+
+fn create_qcow2(mut args: std::env::Args) -> std::result::Result<(), ()> {
+    if args.len() != 2 {
+        print_help("crosvm create_qcow2", "PATH SIZE", &[]);
+        println!("Create a new QCOW2 image at `PATH` of the specified `SIZE` in bytes.");
+        return Err(());
+    }
+    let file_path = args.nth(0).unwrap();
+    let size: u64 = match args.nth(0).unwrap().parse::<u64>() {
+        Ok(n) => n,
+        Err(_) => {
+            error!("Failed to parse size of the disk.");
+            return Err(());
+        }
+    };
+
+    let file = OpenOptions::new()
+        .create(true)
+        .read(true)
+        .write(true)
+        .open(&file_path)
+        .map_err(|e| {
+            error!("Failed opening qcow file at '{}': {}", file_path, e);
+        })?;
+
+    QcowFile::new(file, size).map_err(|e| {
+        error!("Failed to create qcow file at '{}': {}", file_path, e);
+    })?;
+
+    Ok(())
+}
+
+fn disk_cmd(mut args: std::env::Args) -> std::result::Result<(), ()> {
+    if args.len() < 2 {
+        print_help("crosvm disk", "SUBCOMMAND VM_SOCKET...", &[]);
+        println!("Manage attached virtual disk devices.");
+        println!("Subcommands:");
+        println!("  resize DISK_INDEX NEW_SIZE VM_SOCKET");
+        return Err(());
+    }
+    let subcommand: &str = &args.nth(0).unwrap();
+
+    let request = match subcommand {
+        "resize" => {
+            let disk_index = match args.nth(0).unwrap().parse::<usize>() {
+                Ok(n) => n,
+                Err(_) => {
+                    error!("Failed to parse disk index");
+                    return Err(());
+                }
+            };
+
+            let new_size = match args.nth(0).unwrap().parse::<u64>() {
+                Ok(n) => n,
+                Err(_) => {
+                    error!("Failed to parse disk size");
+                    return Err(());
+                }
+            };
+
+            VmRequest::DiskCommand {
+                disk_index,
+                command: DiskControlCommand::Resize { new_size },
+            }
+        }
+        _ => {
+            error!("Unknown disk subcommand '{}'", subcommand);
+            return Err(());
+        }
+    };
+
+    vms_request(&request, args)
+}
+
+enum ModifyUsbError {
+    ArgMissing(&'static str),
+    ArgParse(&'static str, String),
+    ArgParseInt(&'static str, String, ParseIntError),
+    FailedFdValidate(sys_util::Error),
+    PathDoesNotExist(PathBuf),
+    SocketFailed,
+    UnexpectedResponse(VmResponse),
+    UnknownCommand(String),
+    UsbControl(UsbControlResult),
+}
+
+impl fmt::Display for ModifyUsbError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::ModifyUsbError::*;
+
+        match self {
+            ArgMissing(a) => write!(f, "argument missing: {}", a),
+            ArgParse(name, value) => {
+                write!(f, "failed to parse argument {} value `{}`", name, value)
+            }
+            ArgParseInt(name, value, e) => write!(
+                f,
+                "failed to parse integer argument {} value `{}`: {}",
+                name, value, e
+            ),
+            FailedFdValidate(e) => write!(f, "failed to validate file descriptor: {}", e),
+            PathDoesNotExist(p) => write!(f, "path `{}` does not exist", p.display()),
+            SocketFailed => write!(f, "socket failed"),
+            UnexpectedResponse(r) => write!(f, "unexpected response: {}", r),
+            UnknownCommand(c) => write!(f, "unknown command: `{}`", c),
+            UsbControl(e) => write!(f, "{}", e),
+        }
+    }
+}
+
+type ModifyUsbResult<T> = std::result::Result<T, ModifyUsbError>;
+
+fn parse_bus_id_addr(v: &str) -> ModifyUsbResult<(u8, u8, u16, u16)> {
+    debug!("parse_bus_id_addr: {}", v);
+    let mut ids = v.split(":");
+    match (ids.next(), ids.next(), ids.next(), ids.next()) {
+        (Some(bus_id), Some(addr), Some(vid), Some(pid)) => {
+            let bus_id = bus_id
+                .parse::<u8>()
+                .map_err(|e| ModifyUsbError::ArgParseInt("bus_id", bus_id.to_owned(), e))?;
+            let addr = addr
+                .parse::<u8>()
+                .map_err(|e| ModifyUsbError::ArgParseInt("addr", addr.to_owned(), e))?;
+            let vid = u16::from_str_radix(&vid, 16)
+                .map_err(|e| ModifyUsbError::ArgParseInt("vid", vid.to_owned(), e))?;
+            let pid = u16::from_str_radix(&pid, 16)
+                .map_err(|e| ModifyUsbError::ArgParseInt("pid", pid.to_owned(), e))?;
+            Ok((bus_id, addr, vid, pid))
+        }
+        _ => Err(ModifyUsbError::ArgParse(
+            "BUS_ID_ADDR_BUS_NUM_DEV_NUM",
+            v.to_owned(),
+        )),
+    }
+}
+
+fn raw_fd_from_path(path: &Path) -> ModifyUsbResult<RawFd> {
+    if !path.exists() {
+        return Err(ModifyUsbError::PathDoesNotExist(path.to_owned()));
+    }
+    let raw_fd = path
+        .file_name()
+        .and_then(|fd_osstr| fd_osstr.to_str())
+        .map_or(
+            Err(ModifyUsbError::ArgParse(
+                "USB_DEVICE_PATH",
+                path.to_string_lossy().into_owned(),
+            )),
+            |fd_str| {
+                fd_str.parse::<libc::c_int>().map_err(|e| {
+                    ModifyUsbError::ArgParseInt("USB_DEVICE_PATH", fd_str.to_owned(), e)
+                })
+            },
+        )?;
+    validate_raw_fd(raw_fd).map_err(ModifyUsbError::FailedFdValidate)
+}
+
+fn usb_attach(mut args: std::env::Args) -> ModifyUsbResult<UsbControlResult> {
+    let val = args
+        .next()
+        .ok_or(ModifyUsbError::ArgMissing("BUS_ID_ADDR_BUS_NUM_DEV_NUM"))?;
+    let (bus, addr, vid, pid) = parse_bus_id_addr(&val)?;
+    let dev_path = PathBuf::from(
+        args.next()
+            .ok_or(ModifyUsbError::ArgMissing("usb device path"))?,
+    );
+    let usb_file: Option<File> = if dev_path == Path::new("-") {
+        None
+    } else if dev_path.parent() == Some(Path::new("/proc/self/fd")) {
+        // Special case '/proc/self/fd/*' paths. The FD is already open, just use it.
+        // Safe because we will validate |raw_fd|.
+        Some(unsafe { File::from_raw_fd(raw_fd_from_path(&dev_path)?) })
+    } else {
+        Some(
+            OpenOptions::new()
+                .read(true)
+                .write(true)
+                .open(&dev_path)
+                .map_err(|_| ModifyUsbError::UsbControl(UsbControlResult::FailedToOpenDevice))?,
+        )
+    };
+
+    let request = VmRequest::UsbCommand(UsbControlCommand::AttachDevice {
+        bus,
+        addr,
+        vid,
+        pid,
+        fd: usb_file.map(MaybeOwnedFd::Owned),
+    });
+    let response = handle_request(&request, args).map_err(|_| ModifyUsbError::SocketFailed)?;
+    match response {
+        VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
+        r => Err(ModifyUsbError::UnexpectedResponse(r)),
+    }
+}
+
+fn usb_detach(mut args: std::env::Args) -> ModifyUsbResult<UsbControlResult> {
+    let port: u8 = args
+        .next()
+        .map_or(Err(ModifyUsbError::ArgMissing("PORT")), |p| {
+            p.parse::<u8>()
+                .map_err(|e| ModifyUsbError::ArgParseInt("PORT", p.to_owned(), e))
+        })?;
+    let request = VmRequest::UsbCommand(UsbControlCommand::DetachDevice { port });
+    let response = handle_request(&request, args).map_err(|_| ModifyUsbError::SocketFailed)?;
+    match response {
+        VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
+        r => Err(ModifyUsbError::UnexpectedResponse(r)),
+    }
+}
+
+fn usb_list(args: std::env::Args) -> ModifyUsbResult<UsbControlResult> {
+    let mut ports: [u8; USB_CONTROL_MAX_PORTS] = Default::default();
+    for (index, port) in ports.iter_mut().enumerate() {
+        *port = index as u8
+    }
+    let request = VmRequest::UsbCommand(UsbControlCommand::ListDevice { ports });
+    let response = handle_request(&request, args).map_err(|_| ModifyUsbError::SocketFailed)?;
+    match response {
+        VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
+        r => Err(ModifyUsbError::UnexpectedResponse(r)),
+    }
+}
+
+fn modify_usb(mut args: std::env::Args) -> std::result::Result<(), ()> {
+    if args.len() < 2 {
+        print_help("crosvm usb",
+                   "[attach BUS_ID:ADDR:VENDOR_ID:PRODUCT_ID [USB_DEVICE_PATH|-] | detach PORT | list] VM_SOCKET...", &[]);
+        return Err(());
+    }
+
+    // This unwrap will not panic because of the above length check.
+    let command = args.next().unwrap();
+    let result = match command.as_ref() {
+        "attach" => usb_attach(args),
+        "detach" => usb_detach(args),
+        "list" => usb_list(args),
+        other => Err(ModifyUsbError::UnknownCommand(other.to_owned())),
+    };
+    match result {
+        Ok(response) => {
+            println!("{}", response);
+            Ok(())
+        }
+        Err(e) => {
+            println!("error {}", e);
+            Err(())
+        }
+    }
+}
+
+fn print_usage() {
+    print_help("crosvm", "[stop|run]", &[]);
+    println!("Commands:");
+    println!("    stop - Stops crosvm instances via their control sockets.");
+    println!("    run  - Start a new crosvm instance.");
+    println!("    create_qcow2  - Create a new qcow2 disk image file.");
+    println!("    disk - Manage attached virtual disk devices.");
+    println!("    usb - Manage attached virtual USB devices.");
+}
+
+fn crosvm_main() -> std::result::Result<(), ()> {
+    if let Err(e) = syslog::init() {
+        println!("failed to initialize syslog: {}", e);
+        return Err(());
+    }
+
+    panic_hook::set_panic_hook();
+
+    let mut args = std::env::args();
+    if args.next().is_none() {
+        error!("expected executable name");
+        return Err(());
+    }
+
+    // Past this point, usage of exit is in danger of leaking zombie processes.
+    let ret = match args.next().as_ref().map(|a| a.as_ref()) {
+        None => {
+            print_usage();
+            Ok(())
+        }
+        Some("stop") => stop_vms(args),
+        Some("suspend") => suspend_vms(args),
+        Some("resume") => resume_vms(args),
+        Some("run") => run_vm(args),
+        Some("balloon") => balloon_vms(args),
+        Some("create_qcow2") => create_qcow2(args),
+        Some("disk") => disk_cmd(args),
+        Some("usb") => modify_usb(args),
+        Some(c) => {
+            println!("invalid subcommand: {:?}", c);
+            print_usage();
+            Err(())
+        }
+    };
+
+    // Reap exit status from any child device processes. At this point, all devices should have been
+    // dropped in the main process and told to shutdown. Try over a period of 100ms, since it may
+    // take some time for the processes to shut down.
+    if !wait_all_children() {
+        // We gave them a chance, and it's too late.
+        warn!("not all child processes have exited; sending SIGKILL");
+        if let Err(e) = kill_process_group() {
+            // We're now at the mercy of the OS to clean up after us.
+            warn!("unable to kill all child processes: {}", e);
+        }
+    }
+
+    // WARNING: Any code added after this point is not guaranteed to run
+    // since we may forcibly kill this process (and its children) above.
+    ret
+}
+
+fn main() {
+    std::process::exit(if crosvm_main().is_ok() { 0 } else { 1 });
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn parse_cpu_set_single() {
+        assert_eq!(parse_cpu_set("123").expect("parse failed"), vec![123]);
+    }
+
+    #[test]
+    fn parse_cpu_set_list() {
+        assert_eq!(
+            parse_cpu_set("0,1,2,3").expect("parse failed"),
+            vec![0, 1, 2, 3]
+        );
+    }
+
+    #[test]
+    fn parse_cpu_set_range() {
+        assert_eq!(
+            parse_cpu_set("0-3").expect("parse failed"),
+            vec![0, 1, 2, 3]
+        );
+    }
+
+    #[test]
+    fn parse_cpu_set_list_of_ranges() {
+        assert_eq!(
+            parse_cpu_set("3-4,7-9,18").expect("parse failed"),
+            vec![3, 4, 7, 8, 9, 18]
+        );
+    }
+
+    #[test]
+    fn parse_cpu_set_repeated() {
+        // For now, allow duplicates - they will be handled gracefully by the vec to cpu_set_t conversion.
+        assert_eq!(parse_cpu_set("1,1,1").expect("parse failed"), vec![1, 1, 1]);
+    }
+
+    #[test]
+    fn parse_cpu_set_negative() {
+        // Negative CPU numbers are not allowed.
+        parse_cpu_set("-3").expect_err("parse should have failed");
+    }
+
+    #[test]
+    fn parse_cpu_set_reverse_range() {
+        // Ranges must be from low to high.
+        parse_cpu_set("5-2").expect_err("parse should have failed");
+    }
+
+    #[test]
+    fn parse_cpu_set_open_range() {
+        parse_cpu_set("3-").expect_err("parse should have failed");
+    }
+
+    #[test]
+    fn parse_cpu_set_extra_comma() {
+        parse_cpu_set("0,1,2,").expect_err("parse should have failed");
+    }
+
+    #[test]
+    fn parse_serial_vaild() {
+        parse_serial_options("type=syslog,num=1,console=true").expect("parse should have succeded");
+    }
+
+    #[test]
+    fn parse_serial_valid_no_num() {
+        parse_serial_options("type=syslog").expect("parse should have succeded");
+    }
+
+    #[test]
+    fn parse_serial_invalid_type() {
+        parse_serial_options("type=wormhole,num=1").expect_err("parse should have failed");
+    }
+
+    #[test]
+    fn parse_serial_invalid_num_upper() {
+        parse_serial_options("type=syslog,num=5").expect_err("parse should have failed");
+    }
+
+    #[test]
+    fn parse_serial_invalid_num_lower() {
+        parse_serial_options("type=syslog,num=0").expect_err("parse should have failed");
+    }
+
+    #[test]
+    fn parse_serial_invalid_num_string() {
+        parse_serial_options("type=syslog,num=number3").expect_err("parse should have failed");
+    }
+
+    #[test]
+    fn parse_serial_invalid_option() {
+        parse_serial_options("type=syslog,speed=lightspeed").expect_err("parse should have failed");
+    }
+}
diff --git a/src/panic_hook.rs b/src/panic_hook.rs
new file mode 100644
index 0000000..48cf0c5
--- /dev/null
+++ b/src/panic_hook.rs
@@ -0,0 +1,103 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::env;
+use std::fs::File;
+use std::io::{stderr, Read};
+use std::os::unix::io::{FromRawFd, IntoRawFd};
+use std::panic::{self, PanicInfo};
+use std::process::abort;
+use std::string::String;
+
+use libc::{close, dup, dup2, pipe2, O_NONBLOCK, STDERR_FILENO};
+use sys_util::error;
+
+// Opens a pipe and puts the write end into the stderr FD slot. On success, returns the read end of
+// the pipe and the old stderr as a pair of files.
+fn redirect_stderr() -> Option<(File, File)> {
+    let mut fds = [-1, -1];
+    unsafe {
+        // Trivially safe because the return value is checked.
+        let old_stderr = dup(STDERR_FILENO);
+        if old_stderr == -1 {
+            return None;
+        }
+        // Safe because pipe2 will only ever write two integers to our array and we check output.
+        let mut ret = pipe2(fds.as_mut_ptr(), O_NONBLOCK);
+        if ret != 0 {
+            // Leaks FDs, but not important right before abort.
+            return None;
+        }
+        // Safe because the FD we are duplicating is owned by us.
+        ret = dup2(fds[1], STDERR_FILENO);
+        if ret == -1 {
+            // Leaks FDs, but not important right before abort.
+            return None;
+        }
+        // The write end is no longer needed.
+        close(fds[1]);
+        // Safe because each of the fds was the result of a successful FD creation syscall.
+        Some((File::from_raw_fd(fds[0]), File::from_raw_fd(old_stderr)))
+    }
+}
+
+// Sets stderr to the given file. Returns true on success.
+fn restore_stderr(stderr: File) -> bool {
+    let fd = stderr.into_raw_fd();
+
+    // Safe because fd is guaranteed to be valid and replacing stderr should be an atomic operation.
+    unsafe { dup2(fd, STDERR_FILENO) != -1 }
+}
+
+// Sends as much information about the panic as possible to syslog.
+fn log_panic_info(default_panic: &(dyn Fn(&PanicInfo) + Sync + Send + 'static), info: &PanicInfo) {
+    // Grab a lock of stderr to prevent concurrent threads from trampling on our stderr capturing
+    // procedure. The default_panic procedure likely uses stderr.lock as well, but the mutex inside
+    // stderr is reentrant, so it will not dead-lock on this thread.
+    let stderr = stderr();
+    let _stderr_lock = stderr.lock();
+
+    // Redirect stderr to a pipe we can read from later.
+    let (mut read_file, old_stderr) = match redirect_stderr() {
+        Some(f) => f,
+        None => {
+            error!("failed to capture stderr during panic");
+            return;
+        }
+    };
+    // Only through the default panic handler can we get a stacktrace. It only ever prints to
+    // stderr, hence all the previous code to redirect it to a pipe we can read.
+    env::set_var("RUST_BACKTRACE", "1");
+    default_panic(info);
+
+    // Closes the write end of the pipe so that we can reach EOF in read_to_string. Also allows
+    // others to write to stderr without failure.
+    if !restore_stderr(old_stderr) {
+        error!("failed to restore stderr during panic");
+        return;
+    }
+    drop(_stderr_lock);
+
+    let mut panic_output = String::new();
+    // Ignore errors and print what we got.
+    let _ = read_file.read_to_string(&mut panic_output);
+    // Split by line because the logging facilities do not handle embedded new lines well.
+    for line in panic_output.lines() {
+        error!("{}", line);
+    }
+}
+
+/// The intent of our panic hook is to get panic info and a stacktrace into the syslog, even for
+/// jailed subprocesses. It will always abort on panic to ensure a minidump is generated.
+///
+/// Note that jailed processes will usually have a stacktrace of <unknown> because the backtrace
+/// routines attempt to open this binary and are unable to do so in a jail.
+pub fn set_panic_hook() {
+    let default_panic = panic::take_hook();
+    panic::set_hook(Box::new(move |info| {
+        log_panic_info(default_panic.as_ref(), info);
+        // Abort to trigger the crash reporter so that a minidump is generated.
+        abort();
+    }));
+}
diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs
new file mode 100644
index 0000000..1cb3e57
--- /dev/null
+++ b/src/plugin/mod.rs
@@ -0,0 +1,801 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+mod process;
+mod vcpu;
+
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::io;
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
+use std::os::unix::net::UnixDatagram;
+use std::path::Path;
+use std::result;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::{Arc, Barrier};
+use std::thread;
+use std::time::{Duration, Instant};
+
+use libc::{
+    c_int, c_ulong, fcntl, ioctl, socketpair, AF_UNIX, EAGAIN, EBADF, EDEADLK, EEXIST, EINTR,
+    EINVAL, ENOENT, EOVERFLOW, EPERM, FIOCLEX, F_SETPIPE_SZ, MS_NODEV, MS_NOEXEC, MS_NOSUID,
+    SIGCHLD, SOCK_SEQPACKET,
+};
+
+use protobuf::ProtobufError;
+use remain::sorted;
+
+use io_jail::{self, Minijail};
+use kvm::{Datamatch, IoeventAddress, Kvm, Vcpu, VcpuExit, Vm};
+use net_util::{Error as TapError, Tap, TapT};
+use sys_util::{
+    block_signal, clear_signal, drop_capabilities, error, getegid, geteuid, info, pipe,
+    register_signal_handler, validate_raw_fd, warn, Error as SysError, EventFd, GuestMemory,
+    Killable, MmapError, PollContext, PollToken, Result as SysResult, SignalFd, SignalFdError,
+    SIGRTMIN,
+};
+
+use self::process::*;
+use self::vcpu::*;
+use crate::{Config, Executable};
+
+const MAX_DATAGRAM_SIZE: usize = 4096;
+const MAX_VCPU_DATAGRAM_SIZE: usize = 0x40000;
+
+/// An error that occurs during the lifetime of a plugin process.
+#[sorted]
+pub enum Error {
+    CloneEventFd(SysError),
+    CloneVcpuPipe(io::Error),
+    CreateEventFd(SysError),
+    CreateIrqChip(SysError),
+    CreateJail(io_jail::Error),
+    CreateKvm(SysError),
+    CreateMainSocket(SysError),
+    CreatePIT(SysError),
+    CreatePollContext(SysError),
+    CreateSignalFd(SignalFdError),
+    CreateSocketPair(io::Error),
+    CreateTapFd(TapError),
+    CreateVcpu(SysError),
+    CreateVcpuSocket(SysError),
+    CreateVm(SysError),
+    DecodeRequest(ProtobufError),
+    DropCapabilities(SysError),
+    EncodeResponse(ProtobufError),
+    Mount(io_jail::Error),
+    MountDev(io_jail::Error),
+    MountLib(io_jail::Error),
+    MountLib64(io_jail::Error),
+    MountPlugin(io_jail::Error),
+    MountPluginLib(io_jail::Error),
+    MountRoot(io_jail::Error),
+    NoRootDir,
+    ParsePivotRoot(io_jail::Error),
+    ParseSeccomp(io_jail::Error),
+    PluginFailed(i32),
+    PluginKill(SysError),
+    PluginKilled(i32),
+    PluginRunJail(io_jail::Error),
+    PluginSocketHup,
+    PluginSocketPoll(SysError),
+    PluginSocketRecv(SysError),
+    PluginSocketSend(SysError),
+    PluginSpawn(io::Error),
+    PluginTimeout,
+    PluginWait(SysError),
+    Poll(SysError),
+    PollContextAdd(SysError),
+    RootNotAbsolute,
+    RootNotDir,
+    SetGidMap(io_jail::Error),
+    SetUidMap(io_jail::Error),
+    SigChild {
+        pid: u32,
+        signo: u32,
+        status: i32,
+        code: i32,
+    },
+    SignalFd(SignalFdError),
+    SpawnVcpu(io::Error),
+    TapEnable(TapError),
+    TapOpen(TapError),
+    TapSetIp(TapError),
+    TapSetMacAddress(TapError),
+    TapSetNetmask(TapError),
+    ValidateTapFd(SysError),
+}
+
+impl Display for Error {
+    #[remain::check]
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        #[sorted]
+        match self {
+            CloneEventFd(e) => write!(f, "failed to clone eventfd: {}", e),
+            CloneVcpuPipe(e) => write!(f, "failed to clone vcpu pipe: {}", e),
+            CreateEventFd(e) => write!(f, "failed to create eventfd: {}", e),
+            CreateIrqChip(e) => write!(f, "failed to create kvm irqchip: {}", e),
+            CreateJail(e) => write!(f, "failed to create jail: {}", e),
+            CreateKvm(e) => write!(f, "error creating Kvm: {}", e),
+            CreateMainSocket(e) => write!(f, "error creating main request socket: {}", e),
+            CreatePIT(e) => write!(f, "failed to create kvm PIT: {}", e),
+            CreatePollContext(e) => write!(f, "failed to create poll context: {}", e),
+            CreateSignalFd(e) => write!(f, "failed to create signalfd: {}", e),
+            CreateSocketPair(e) => write!(f, "failed to create socket pair: {}", e),
+            CreateTapFd(e) => write!(f, "failed to create tap device from raw fd: {}", e),
+            CreateVcpu(e) => write!(f, "error creating vcpu: {}", e),
+            CreateVcpuSocket(e) => write!(f, "error creating vcpu request socket: {}", e),
+            CreateVm(e) => write!(f, "error creating vm: {}", e),
+            DecodeRequest(e) => write!(f, "failed to decode plugin request: {}", e),
+            DropCapabilities(e) => write!(f, "failed to drop process capabilities: {}", e),
+            EncodeResponse(e) => write!(f, "failed to encode plugin response: {}", e),
+            Mount(e) | MountDev(e) | MountLib(e) | MountLib64(e) | MountPlugin(e)
+            | MountPluginLib(e) | MountRoot(e) => write!(f, "failed to mount: {}", e),
+            NoRootDir => write!(f, "no root directory for jailed process to pivot root into"),
+            ParsePivotRoot(e) => write!(f, "failed to set jail pivot root: {}", e),
+            ParseSeccomp(e) => write!(f, "failed to parse jail seccomp filter: {}", e),
+            PluginFailed(e) => write!(f, "plugin exited with error: {}", e),
+            PluginKill(e) => write!(f, "error sending kill signal to plugin: {}", e),
+            PluginKilled(e) => write!(f, "plugin exited with signal {}", e),
+            PluginRunJail(e) => write!(f, "failed to run jail: {}", e),
+            PluginSocketHup => write!(f, "plugin request socket has been hung up"),
+            PluginSocketPoll(e) => write!(f, "failed to poll plugin request sockets: {}", e),
+            PluginSocketRecv(e) => write!(f, "failed to recv from plugin request socket: {}", e),
+            PluginSocketSend(e) => write!(f, "failed to send to plugin request socket: {}", e),
+            PluginSpawn(e) => write!(f, "failed to spawn plugin: {}", e),
+            PluginTimeout => write!(f, "plugin did not exit within timeout"),
+            PluginWait(e) => write!(f, "error waiting for plugin to exit: {}", e),
+            Poll(e) => write!(f, "failed to poll all FDs: {}", e),
+            PollContextAdd(e) => write!(f, "failed to add fd to poll context: {}", e),
+            RootNotAbsolute => write!(f, "path to the root directory must be absolute"),
+            RootNotDir => write!(f, "specified root directory is not a directory"),
+            SetGidMap(e) => write!(f, "failed to set gidmap for jail: {}", e),
+            SetUidMap(e) => write!(f, "failed to set uidmap for jail: {}", e),
+            SigChild {
+                pid,
+                signo,
+                status,
+                code,
+            } => write!(
+                f,
+                "process {} died with signal {}, status {}, and code {}",
+                pid, signo, status, code
+            ),
+            SignalFd(e) => write!(f, "failed to read signal fd: {}", e),
+            SpawnVcpu(e) => write!(f, "error spawning vcpu thread: {}", e),
+            TapEnable(e) => write!(f, "error enabling tap device: {}", e),
+            TapOpen(e) => write!(f, "error opening tap device: {}", e),
+            TapSetIp(e) => write!(f, "error setting tap ip: {}", e),
+            TapSetMacAddress(e) => write!(f, "error setting tap mac address: {}", e),
+            TapSetNetmask(e) => write!(f, "error setting tap netmask: {}", e),
+            ValidateTapFd(e) => write!(f, "failed to validate raw tap fd: {}", e),
+        }
+    }
+}
+
+type Result<T> = result::Result<T, Error>;
+
+fn downcast_file<F: IntoRawFd>(f: F) -> File {
+    unsafe { File::from_raw_fd(f.into_raw_fd()) }
+}
+
+fn new_seqpacket_pair() -> SysResult<(UnixDatagram, UnixDatagram)> {
+    let mut fds = [0, 0];
+    unsafe {
+        let ret = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds.as_mut_ptr());
+        if ret == 0 {
+            ioctl(fds[0], FIOCLEX);
+            Ok((
+                UnixDatagram::from_raw_fd(fds[0]),
+                UnixDatagram::from_raw_fd(fds[1]),
+            ))
+        } else {
+            Err(SysError::last())
+        }
+    }
+}
+
+struct VcpuPipe {
+    crosvm_read: File,
+    plugin_write: File,
+    plugin_read: File,
+    crosvm_write: File,
+}
+
+fn new_pipe_pair() -> SysResult<VcpuPipe> {
+    let to_crosvm = pipe(true)?;
+    let to_plugin = pipe(true)?;
+    // Increasing the pipe size can be a nice-to-have to make sure that
+    // messages get across atomically (and made sure that writes don't block),
+    // though it's not necessary a hard requirement for things to work.
+    let flags = unsafe {
+        fcntl(
+            to_crosvm.0.as_raw_fd(),
+            F_SETPIPE_SZ,
+            MAX_VCPU_DATAGRAM_SIZE as c_int,
+        )
+    };
+    if flags < 0 || flags != MAX_VCPU_DATAGRAM_SIZE as i32 {
+        warn!(
+            "Failed to adjust size of crosvm pipe (result {}): {}",
+            flags,
+            SysError::last()
+        );
+    }
+    let flags = unsafe {
+        fcntl(
+            to_plugin.0.as_raw_fd(),
+            F_SETPIPE_SZ,
+            MAX_VCPU_DATAGRAM_SIZE as c_int,
+        )
+    };
+    if flags < 0 || flags != MAX_VCPU_DATAGRAM_SIZE as i32 {
+        warn!(
+            "Failed to adjust size of plugin pipe (result {}): {}",
+            flags,
+            SysError::last()
+        );
+    }
+    Ok(VcpuPipe {
+        crosvm_read: to_crosvm.0,
+        plugin_write: to_crosvm.1,
+        plugin_read: to_plugin.0,
+        crosvm_write: to_plugin.1,
+    })
+}
+
+fn proto_to_sys_err(e: ProtobufError) -> SysError {
+    match e {
+        ProtobufError::IoError(e) => SysError::new(e.raw_os_error().unwrap_or(EINVAL)),
+        _ => SysError::new(EINVAL),
+    }
+}
+
+fn io_to_sys_err(e: io::Error) -> SysError {
+    SysError::new(e.raw_os_error().unwrap_or(EINVAL))
+}
+
+fn mmap_to_sys_err(e: MmapError) -> SysError {
+    match e {
+        MmapError::SystemCallFailed(e) => e,
+        _ => SysError::new(EINVAL),
+    }
+}
+
+fn create_plugin_jail(root: &Path, seccomp_policy: &Path) -> Result<Minijail> {
+    // All child jails run in a new user namespace without any users mapped,
+    // they run as nobody unless otherwise configured.
+    let mut j = Minijail::new().map_err(Error::CreateJail)?;
+    j.namespace_pids();
+    j.namespace_user();
+    j.uidmap(&format!("0 {0} 1", geteuid()))
+        .map_err(Error::SetUidMap)?;
+    j.gidmap(&format!("0 {0} 1", getegid()))
+        .map_err(Error::SetGidMap)?;
+    j.namespace_user_disable_setgroups();
+    // Don't need any capabilities.
+    j.use_caps(0);
+    // Create a new mount namespace with an empty root FS.
+    j.namespace_vfs();
+    j.enter_pivot_root(root).map_err(Error::ParsePivotRoot)?;
+    // Run in an empty network namespace.
+    j.namespace_net();
+    j.no_new_privs();
+    // Use TSYNC only for the side effect of it using SECCOMP_RET_TRAP, which will correctly kill
+    // the entire plugin process if a worker thread commits a seccomp violation.
+    j.set_seccomp_filter_tsync();
+    #[cfg(debug_assertions)]
+    j.log_seccomp_filter_failures();
+    j.parse_seccomp_filters(seccomp_policy)
+        .map_err(Error::ParseSeccomp)?;
+    j.use_seccomp_filter();
+    // Don't do init setup.
+    j.run_as_init();
+
+    // Create a tmpfs in the plugin's root directory so that we can bind mount it's executable
+    // file into it.  The size=67108864 is size=64*1024*1024 or size=64MB.
+    j.mount_with_data(
+        Path::new("none"),
+        Path::new("/"),
+        "tmpfs",
+        (MS_NOSUID | MS_NODEV | MS_NOEXEC) as usize,
+        "size=67108864",
+    )
+    .map_err(Error::MountRoot)?;
+
+    Ok(j)
+}
+
+/// Each `PluginObject` represents one object that was instantiated by the guest using the `Create`
+/// request.
+///
+/// Each such object has an ID associated with it that exists in an ID space shared by every variant
+/// of `PluginObject`. This allows all the objects to be indexed in a single map, and allows for a
+/// common destroy method.
+///
+
+/// In addition to the destory method, each object may have methods specific to its variant type.
+/// These variant methods must be done by matching the variant to the expected type for that method.
+/// For example, getting the dirty log from a `Memory` object starting with an ID:
+///
+/// ```
+/// match objects.get(&request_id) {
+///    Some(&PluginObject::Memory { slot, length }) => vm.get_dirty_log(slot, &mut dirty_log[..])
+///    _ => return Err(SysError::new(ENOENT)),
+/// }
+/// ```
+enum PluginObject {
+    IoEvent {
+        evt: EventFd,
+        addr: IoeventAddress,
+        length: u32,
+        datamatch: u64,
+    },
+    Memory {
+        slot: u32,
+        length: usize,
+    },
+    IrqEvent {
+        irq_id: u32,
+        evt: EventFd,
+    },
+}
+
+impl PluginObject {
+    fn destroy(self, vm: &mut Vm) -> SysResult<()> {
+        match self {
+            PluginObject::IoEvent {
+                evt,
+                addr,
+                length,
+                datamatch,
+            } => match length {
+                0 => vm.unregister_ioevent(&evt, addr, Datamatch::AnyLength),
+                1 => vm.unregister_ioevent(&evt, addr, Datamatch::U8(Some(datamatch as u8))),
+                2 => vm.unregister_ioevent(&evt, addr, Datamatch::U16(Some(datamatch as u16))),
+                4 => vm.unregister_ioevent(&evt, addr, Datamatch::U32(Some(datamatch as u32))),
+                8 => vm.unregister_ioevent(&evt, addr, Datamatch::U64(Some(datamatch as u64))),
+                _ => Err(SysError::new(EINVAL)),
+            },
+            PluginObject::Memory { slot, .. } => vm.remove_device_memory(slot).and(Ok(())),
+            PluginObject::IrqEvent { irq_id, evt } => vm.unregister_irqfd(&evt, irq_id),
+        }
+    }
+}
+
+pub fn run_vcpus(
+    kvm: &Kvm,
+    vm: &Vm,
+    plugin: &Process,
+    vcpu_count: u32,
+    kill_signaled: &Arc<AtomicBool>,
+    exit_evt: &EventFd,
+    vcpu_handles: &mut Vec<thread::JoinHandle<()>>,
+) -> Result<()> {
+    let vcpu_thread_barrier = Arc::new(Barrier::new((vcpu_count) as usize));
+    for cpu_id in 0..vcpu_count {
+        let kill_signaled = kill_signaled.clone();
+        let vcpu_thread_barrier = vcpu_thread_barrier.clone();
+        let vcpu_exit_evt = exit_evt.try_clone().map_err(Error::CloneEventFd)?;
+        let vcpu_plugin = plugin.create_vcpu(cpu_id)?;
+        let vcpu = Vcpu::new(cpu_id as c_ulong, kvm, vm).map_err(Error::CreateVcpu)?;
+
+        vcpu_handles.push(
+            thread::Builder::new()
+                .name(format!("crosvm_vcpu{}", cpu_id))
+                .spawn(move || {
+                    unsafe {
+                        extern "C" fn handle_signal() {}
+                        // Our signal handler does nothing and is trivially async signal safe.
+                        // We need to install this signal handler even though we do block
+                        // the signal below, to ensure that this signal will interrupt
+                        // execution of KVM_RUN (this is implementation issue).
+                        register_signal_handler(SIGRTMIN() + 0, handle_signal)
+                            .expect("failed to register vcpu signal handler");
+                    }
+
+                    // We do not really want the signal handler to run...
+                    block_signal(SIGRTMIN() + 0).expect("failed to block signal");
+                    // Tell KVM to not block anything when entering kvm run
+                    // because we will be using first RT signal to kick the VCPU.
+                    vcpu.set_signal_mask(&[])
+                        .expect("failed to set up KVM VCPU signal mask");
+
+                    let res = vcpu_plugin.init(&vcpu);
+                    vcpu_thread_barrier.wait();
+                    if let Err(e) = res {
+                        error!("failed to initialize vcpu {}: {}", cpu_id, e);
+                    } else {
+                        loop {
+                            let mut interrupted_by_signal = false;
+                            let run_res = vcpu.run();
+                            match run_res {
+                                Ok(run) => match run {
+                                    VcpuExit::IoIn { port, mut size } => {
+                                        let mut data = [0; 256];
+                                        if size > data.len() {
+                                            error!("unsupported IoIn size of {} bytes", size);
+                                            size = data.len();
+                                        }
+                                        vcpu_plugin.io_read(port as u64, &mut data[..size], &vcpu);
+                                        if let Err(e) = vcpu.set_data(&data[..size]) {
+                                            error!("failed to set return data for IoIn: {}", e);
+                                        }
+                                    }
+                                    VcpuExit::IoOut {
+                                        port,
+                                        mut size,
+                                        data,
+                                    } => {
+                                        if size > data.len() {
+                                            error!("unsupported IoOut size of {} bytes", size);
+                                            size = data.len();
+                                        }
+                                        vcpu_plugin.io_write(port as u64, &data[..size], &vcpu);
+                                    }
+                                    VcpuExit::MmioRead { address, size } => {
+                                        let mut data = [0; 8];
+                                        vcpu_plugin.mmio_read(
+                                            address as u64,
+                                            &mut data[..size],
+                                            &vcpu,
+                                        );
+                                        // Setting data for mmio can not fail.
+                                        let _ = vcpu.set_data(&data[..size]);
+                                    }
+                                    VcpuExit::MmioWrite {
+                                        address,
+                                        size,
+                                        data,
+                                    } => {
+                                        vcpu_plugin.mmio_write(
+                                            address as u64,
+                                            &data[..size],
+                                            &vcpu,
+                                        );
+                                    }
+                                    VcpuExit::Hlt => break,
+                                    VcpuExit::Shutdown => break,
+                                    VcpuExit::InternalError => {
+                                        error!("vcpu {} has internal error", cpu_id);
+                                        break;
+                                    }
+                                    r => warn!("unexpected vcpu exit: {:?}", r),
+                                },
+                                Err(e) => match e.errno() {
+                                    EINTR => interrupted_by_signal = true,
+                                    EAGAIN => {}
+                                    _ => {
+                                        error!("vcpu hit unknown error: {}", e);
+                                        break;
+                                    }
+                                },
+                            }
+                            if kill_signaled.load(Ordering::SeqCst) {
+                                break;
+                            }
+
+                            // Try to clear the signal that we use to kick VCPU if it is
+                            // pending before attempting to handle pause requests.
+                            if interrupted_by_signal {
+                                clear_signal(SIGRTMIN() + 0)
+                                    .expect("failed to clear pending signal");
+                            }
+
+                            if let Err(e) = vcpu_plugin.pre_run(&vcpu) {
+                                error!("failed to process pause on vcpu {}: {}", cpu_id, e);
+                                break;
+                            }
+                        }
+                    }
+                    vcpu_exit_evt
+                        .write(1)
+                        .expect("failed to signal vcpu exit eventfd");
+                })
+                .map_err(Error::SpawnVcpu)?,
+        );
+    }
+    Ok(())
+}
+
+#[derive(PollToken)]
+enum Token {
+    Exit,
+    ChildSignal,
+    Plugin { index: usize },
+}
+
+/// Run a VM with a plugin process specified by `cfg`.
+///
+/// Not every field of `cfg` will be used. In particular, most field that pertain to a specific
+/// device are ignored because the plugin is responsible for emulating hardware.
+pub fn run_config(cfg: Config) -> Result<()> {
+    info!("crosvm starting plugin process");
+
+    // Masking signals is inherently dangerous, since this can persist across clones/execs. Do this
+    // before any jailed devices have been spawned, so that we can catch any of them that fail very
+    // quickly.
+    let sigchld_fd = SignalFd::new(SIGCHLD).map_err(Error::CreateSignalFd)?;
+
+    let jail = if cfg.sandbox {
+        // An empty directory for jailed plugin pivot root.
+        let root_path = match &cfg.plugin_root {
+            Some(dir) => dir,
+            None => Path::new("/var/empty"),
+        };
+
+        if root_path.is_relative() {
+            return Err(Error::RootNotAbsolute);
+        }
+
+        if !root_path.exists() {
+            return Err(Error::NoRootDir);
+        }
+
+        if !root_path.is_dir() {
+            return Err(Error::RootNotDir);
+        }
+
+        let policy_path = cfg.seccomp_policy_dir.join("plugin.policy");
+        let mut jail = create_plugin_jail(root_path, &policy_path)?;
+
+        // Update gid map of the jail if caller provided supplemental groups.
+        if !cfg.plugin_gid_maps.is_empty() {
+            let map = format!("0 {} 1", getegid())
+                + &cfg
+                    .plugin_gid_maps
+                    .into_iter()
+                    .map(|m| format!(",{} {} {}", m.inner, m.outer, m.count))
+                    .collect::<String>();
+            jail.gidmap(&map).map_err(Error::SetGidMap)?;
+        }
+
+        // Mount minimal set of devices (full, zero, urandom, etc). We can not use
+        // jail.mount_dev() here because crosvm may not be running with CAP_SYS_ADMIN.
+        let device_names = ["full", "null", "urandom", "zero"];
+        for name in &device_names {
+            let device = Path::new("/dev").join(&name);
+            jail.mount_bind(&device, &device, true)
+                .map_err(Error::MountDev)?;
+        }
+
+        for bind_mount in &cfg.plugin_mounts {
+            jail.mount_bind(&bind_mount.src, &bind_mount.dst, bind_mount.writable)
+                .map_err(Error::Mount)?;
+        }
+
+        Some(jail)
+    } else {
+        None
+    };
+
+    let mut tap_interfaces: Vec<Tap> = Vec::new();
+    if let Some(host_ip) = cfg.host_ip {
+        if let Some(netmask) = cfg.netmask {
+            if let Some(mac_address) = cfg.mac_address {
+                let tap = Tap::new(false).map_err(Error::TapOpen)?;
+                tap.set_ip_addr(host_ip).map_err(Error::TapSetIp)?;
+                tap.set_netmask(netmask).map_err(Error::TapSetNetmask)?;
+                tap.set_mac_address(mac_address)
+                    .map_err(Error::TapSetMacAddress)?;
+
+                tap.enable().map_err(Error::TapEnable)?;
+                tap_interfaces.push(tap);
+            }
+        }
+    }
+    for tap_fd in cfg.tap_fd {
+        // Safe because we ensure that we get a unique handle to the fd.
+        let tap = unsafe {
+            Tap::from_raw_fd(validate_raw_fd(tap_fd).map_err(Error::ValidateTapFd)?)
+                .map_err(Error::CreateTapFd)?
+        };
+        tap_interfaces.push(tap);
+    }
+
+    let plugin_args: Vec<&str> = cfg.params.iter().map(|s| &s[..]).collect();
+
+    let plugin_path = match cfg.executable_path {
+        Some(Executable::Plugin(ref plugin_path)) => plugin_path.as_path(),
+        _ => panic!("Executable was not a plugin"),
+    };
+    let vcpu_count = cfg.vcpu_count.unwrap_or(1);
+    let mem = GuestMemory::new(&[]).unwrap();
+    let kvm = Kvm::new().map_err(Error::CreateKvm)?;
+    let mut vm = Vm::new(&kvm, mem).map_err(Error::CreateVm)?;
+    vm.create_irq_chip().map_err(Error::CreateIrqChip)?;
+    vm.create_pit().map_err(Error::CreatePIT)?;
+
+    let mut plugin = Process::new(vcpu_count, plugin_path, &plugin_args, jail)?;
+    // Now that the jail for the plugin has been created and we had a chance to adjust gids there,
+    // we can drop all our capabilities in case we had any.
+    drop_capabilities().map_err(Error::DropCapabilities)?;
+
+    let mut res = Ok(());
+    // If Some, we will exit after enough time is passed to shutdown cleanly.
+    let mut dying_instant: Option<Instant> = None;
+    let duration_to_die = Duration::from_millis(1000);
+
+    let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?;
+    let kill_signaled = Arc::new(AtomicBool::new(false));
+    let mut vcpu_handles = Vec::with_capacity(vcpu_count as usize);
+
+    let poll_ctx = PollContext::new().map_err(Error::CreatePollContext)?;
+    poll_ctx
+        .add(&exit_evt, Token::Exit)
+        .map_err(Error::PollContextAdd)?;
+    poll_ctx
+        .add(&sigchld_fd, Token::ChildSignal)
+        .map_err(Error::PollContextAdd)?;
+
+    let mut sockets_to_drop = Vec::new();
+    let mut redo_poll_ctx_sockets = true;
+    // In this loop, make every attempt to not return early. If an error is encountered, set `res`
+    // to the error, set `dying_instant` to now, and signal the plugin that it will be killed soon.
+    // If the plugin cannot be signaled because it is dead of `signal_kill` failed, simply break
+    // from the poll loop so that the VCPU threads can be cleaned up.
+    'poll: loop {
+        // After we have waited long enough, it's time to give up and exit.
+        if dying_instant
+            .map(|i| i.elapsed() >= duration_to_die)
+            .unwrap_or(false)
+        {
+            break;
+        }
+
+        if redo_poll_ctx_sockets {
+            for (index, socket) in plugin.sockets().iter().enumerate() {
+                poll_ctx
+                    .add(socket, Token::Plugin { index })
+                    .map_err(Error::PollContextAdd)?;
+            }
+        }
+
+        let plugin_socket_count = plugin.sockets().len();
+        let events = {
+            let poll_res = match dying_instant {
+                Some(inst) => poll_ctx.wait_timeout(duration_to_die - inst.elapsed()),
+                None => poll_ctx.wait(),
+            };
+            match poll_res {
+                Ok(v) => v,
+                Err(e) => {
+                    // Polling no longer works, time to break and cleanup,
+                    if res.is_ok() {
+                        res = Err(Error::Poll(e));
+                    }
+                    break;
+                }
+            }
+        };
+        for event in events.iter_readable() {
+            match event.token() {
+                Token::Exit => {
+                    // No need to check the exit event if we are already doing cleanup.
+                    let _ = poll_ctx.delete(&exit_evt);
+                    dying_instant.get_or_insert(Instant::now());
+                    let sig_res = plugin.signal_kill();
+                    if res.is_ok() && sig_res.is_err() {
+                        res = sig_res.map_err(Error::PluginKill);
+                    }
+                }
+                Token::ChildSignal => {
+                    // Print all available siginfo structs, then exit the loop.
+                    loop {
+                        match sigchld_fd.read() {
+                            Ok(Some(siginfo)) => {
+                                // If the plugin process has ended, there is no need to continue
+                                // processing plugin connections, so we break early.
+                                if siginfo.ssi_pid == plugin.pid() as u32 {
+                                    break 'poll;
+                                }
+                                // Because SIGCHLD is not expected from anything other than the
+                                // plugin process, report it as an error.
+                                if res.is_ok() {
+                                    res = Err(Error::SigChild {
+                                        pid: siginfo.ssi_pid,
+                                        signo: siginfo.ssi_signo,
+                                        status: siginfo.ssi_status,
+                                        code: siginfo.ssi_code,
+                                    })
+                                }
+                            }
+                            Ok(None) => break, // No more signals to read.
+                            Err(e) => {
+                                // Something really must be messed up for this to happen, continue
+                                // processing connections for a limited time.
+                                if res.is_ok() {
+                                    res = Err(Error::SignalFd(e));
+                                }
+                                break;
+                            }
+                        }
+                    }
+                    // As we only spawn the plugin process, getting a SIGCHLD can only mean
+                    // something went wrong.
+                    dying_instant.get_or_insert(Instant::now());
+                    let sig_res = plugin.signal_kill();
+                    if res.is_ok() && sig_res.is_err() {
+                        res = sig_res.map_err(Error::PluginKill);
+                    }
+                }
+                Token::Plugin { index } => {
+                    match plugin.handle_socket(index, &kvm, &mut vm, &vcpu_handles, &tap_interfaces)
+                    {
+                        Ok(_) => {}
+                        // A HUP is an expected event for a socket, so don't bother warning about
+                        // it.
+                        Err(Error::PluginSocketHup) => sockets_to_drop.push(index),
+                        // Only one connection out of potentially many is broken. Drop it, but don't
+                        // start cleaning up. Because the error isn't returned, we will warn about
+                        // it here.
+                        Err(e) => {
+                            warn!("error handling plugin socket: {}", e);
+                            sockets_to_drop.push(index);
+                        }
+                    }
+                }
+            }
+        }
+
+        if vcpu_handles.is_empty() && dying_instant.is_none() && plugin.is_started() {
+            let res = run_vcpus(
+                &kvm,
+                &vm,
+                &plugin,
+                vcpu_count,
+                &kill_signaled,
+                &exit_evt,
+                &mut vcpu_handles,
+            );
+            if let Err(e) = res {
+                dying_instant.get_or_insert(Instant::now());
+                error!("failed to start vcpus: {}", e);
+            }
+        }
+
+        redo_poll_ctx_sockets =
+            !sockets_to_drop.is_empty() || plugin.sockets().len() != plugin_socket_count;
+
+        // Cleanup all of the sockets that we have determined were disconnected or suffered some
+        // other error.
+        plugin.drop_sockets(&mut sockets_to_drop);
+        sockets_to_drop.clear();
+
+        if redo_poll_ctx_sockets {
+            for socket in plugin.sockets() {
+                let _ = poll_ctx.delete(socket);
+            }
+        }
+    }
+
+    // vcpu threads MUST see the kill signaled flag, otherwise they may re-enter the VM.
+    kill_signaled.store(true, Ordering::SeqCst);
+    // Depending on how we ended up here, the plugin process, or a VCPU thread waiting for requests
+    // might be stuck. The `signal_kill` call will unstick all the VCPU threads by closing their
+    // blocked connections.
+    plugin.signal_kill().map_err(Error::PluginKill)?;
+    for handle in vcpu_handles {
+        match handle.kill(SIGRTMIN() + 0) {
+            Ok(_) => {
+                if let Err(e) = handle.join() {
+                    error!("failed to join vcpu thread: {:?}", e);
+                }
+            }
+            Err(e) => error!("failed to kill vcpu thread: {}", e),
+        }
+    }
+
+    match plugin.try_wait() {
+        // The plugin has run out of time by now
+        Ok(ProcessStatus::Running) => Err(Error::PluginTimeout),
+        // Return an error discovered earlier in this function.
+        Ok(ProcessStatus::Success) => res,
+        Ok(ProcessStatus::Fail(code)) => Err(Error::PluginFailed(code)),
+        Ok(ProcessStatus::Signal(code)) => Err(Error::PluginKilled(code)),
+        Err(e) => Err(Error::PluginWait(e)),
+    }
+}
diff --git a/src/plugin/process.rs b/src/plugin/process.rs
new file mode 100644
index 0000000..50b4465
--- /dev/null
+++ b/src/plugin/process.rs
@@ -0,0 +1,705 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::collections::hash_map::{Entry, HashMap, VacantEntry};
+use std::env::set_var;
+use std::fs::File;
+use std::io::Write;
+use std::mem::transmute;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::os::unix::net::UnixDatagram;
+use std::path::Path;
+use std::process::Command;
+use std::sync::{Arc, RwLock};
+use std::thread::JoinHandle;
+
+use net_util;
+use net_util::Error as NetError;
+
+use libc::{pid_t, waitpid, EINVAL, ENODATA, ENOTTY, WEXITSTATUS, WIFEXITED, WNOHANG, WTERMSIG};
+
+use protobuf;
+use protobuf::Message;
+
+use io_jail::Minijail;
+use kvm::{dirty_log_bitmap_size, Datamatch, IoeventAddress, IrqRoute, IrqSource, PicId, Vm};
+use kvm_sys::{kvm_clock_data, kvm_ioapic_state, kvm_pic_state, kvm_pit_state2};
+use protos::plugin::*;
+use sync::Mutex;
+use sys_util::{
+    error, Error as SysError, EventFd, GuestAddress, Killable, MemoryMapping, Result as SysResult,
+    ScmSocket, SharedMemory, SIGRTMIN,
+};
+
+use super::*;
+
+// Wrapper types to make the kvm state structs DataInit
+use data_model::DataInit;
+#[derive(Copy, Clone)]
+struct VmPicState(kvm_pic_state);
+unsafe impl DataInit for VmPicState {}
+#[derive(Copy, Clone)]
+struct VmIoapicState(kvm_ioapic_state);
+unsafe impl DataInit for VmIoapicState {}
+#[derive(Copy, Clone)]
+struct VmPitState(kvm_pit_state2);
+unsafe impl DataInit for VmPitState {}
+#[derive(Copy, Clone)]
+struct VmClockState(kvm_clock_data);
+unsafe impl DataInit for VmClockState {}
+
+fn get_vm_state(vm: &Vm, state_set: MainRequest_StateSet) -> SysResult<Vec<u8>> {
+    Ok(match state_set {
+        MainRequest_StateSet::PIC0 => VmPicState(vm.get_pic_state(PicId::Primary)?)
+            .as_slice()
+            .to_vec(),
+        MainRequest_StateSet::PIC1 => VmPicState(vm.get_pic_state(PicId::Secondary)?)
+            .as_slice()
+            .to_vec(),
+        MainRequest_StateSet::IOAPIC => VmIoapicState(vm.get_ioapic_state()?).as_slice().to_vec(),
+        MainRequest_StateSet::PIT => VmPitState(vm.get_pit_state()?).as_slice().to_vec(),
+        MainRequest_StateSet::CLOCK => VmClockState(vm.get_clock()?).as_slice().to_vec(),
+    })
+}
+
+fn set_vm_state(vm: &Vm, state_set: MainRequest_StateSet, state: &[u8]) -> SysResult<()> {
+    match state_set {
+        MainRequest_StateSet::PIC0 => vm.set_pic_state(
+            PicId::Primary,
+            &VmPicState::from_slice(state)
+                .ok_or(SysError::new(EINVAL))?
+                .0,
+        ),
+        MainRequest_StateSet::PIC1 => vm.set_pic_state(
+            PicId::Secondary,
+            &VmPicState::from_slice(state)
+                .ok_or(SysError::new(EINVAL))?
+                .0,
+        ),
+        MainRequest_StateSet::IOAPIC => vm.set_ioapic_state(
+            &VmIoapicState::from_slice(state)
+                .ok_or(SysError::new(EINVAL))?
+                .0,
+        ),
+        MainRequest_StateSet::PIT => vm.set_pit_state(
+            &VmPitState::from_slice(state)
+                .ok_or(SysError::new(EINVAL))?
+                .0,
+        ),
+        MainRequest_StateSet::CLOCK => vm.set_clock(
+            &VmClockState::from_slice(state)
+                .ok_or(SysError::new(EINVAL))?
+                .0,
+        ),
+    }
+}
+
+/// The status of a process, either that it is running, or that it exited under some condition.
+pub enum ProcessStatus {
+    /// The process is running and therefore has no information about its result.
+    Running,
+    /// The process has exited with a successful code.
+    Success,
+    /// The process failed with the given exit code.
+    Fail(i32),
+    /// The process was terminated with the given signal code.
+    Signal(i32),
+}
+
+/// Creates, owns, and handles messages from a plugin process.
+///
+/// A plugin process has control over a single VM and a fixed number of VCPUs via a set of pipes & unix
+/// domain socket connections and a protocol defined in `protos::plugin`. The plugin process is run
+/// in an unprivileged manner as a child process spawned via a path to a arbitrary executable.
+pub struct Process {
+    started: bool,
+    plugin_pid: pid_t,
+    request_sockets: Vec<UnixDatagram>,
+    objects: HashMap<u32, PluginObject>,
+    shared_vcpu_state: Arc<RwLock<SharedVcpuState>>,
+    per_vcpu_states: Vec<Arc<Mutex<PerVcpuState>>>,
+
+    // Resource to sent to plugin
+    kill_evt: EventFd,
+    vcpu_pipes: Vec<VcpuPipe>,
+
+    // Socket Transmission
+    request_buffer: Vec<u8>,
+    response_buffer: Vec<u8>,
+}
+
+impl Process {
+    /// Creates a new plugin process for the given number of vcpus and VM.
+    ///
+    /// This will immediately spawn the plugin process and wait for the child to signal that it is
+    /// ready to start. This call may block indefinitely.
+    ///
+    /// Set the `jail` argument to spawn the plugin process within the preconfigured jail.
+    /// Due to an API limitation in libminijail necessitating that this function set an environment
+    /// variable, this function is not thread-safe.
+    pub fn new(
+        cpu_count: u32,
+        cmd: &Path,
+        args: &[&str],
+        jail: Option<Minijail>,
+    ) -> Result<Process> {
+        let (request_socket, child_socket) =
+            new_seqpacket_pair().map_err(Error::CreateMainSocket)?;
+
+        let mut vcpu_pipes: Vec<VcpuPipe> = Vec::with_capacity(cpu_count as usize);
+        for _ in 0..cpu_count {
+            vcpu_pipes.push(new_pipe_pair().map_err(Error::CreateVcpuSocket)?);
+        }
+        let mut per_vcpu_states: Vec<Arc<Mutex<PerVcpuState>>> =
+            Vec::with_capacity(cpu_count as usize);
+        // TODO(zachr): replace with `resize_default` when that stabilizes. Using a plain `resize`
+        // is incorrect because each element in the `Vec` will contain a shared reference to the
+        // same `PerVcpuState` instance. This happens because `resize` fills new slots using clones
+        // of the instance given to `resize`.
+        for _ in 0..cpu_count {
+            per_vcpu_states.push(Default::default());
+        }
+
+        let plugin_pid = match jail {
+            Some(jail) => {
+                set_var("CROSVM_SOCKET", child_socket.as_raw_fd().to_string());
+                jail.run(cmd, &[0, 1, 2, child_socket.as_raw_fd()], args)
+                    .map_err(Error::PluginRunJail)?
+            }
+            None => Command::new(cmd)
+                .args(args)
+                .env("CROSVM_SOCKET", child_socket.as_raw_fd().to_string())
+                .spawn()
+                .map_err(Error::PluginSpawn)?
+                .id() as pid_t,
+        };
+
+        Ok(Process {
+            started: false,
+            plugin_pid,
+            request_sockets: vec![request_socket],
+            objects: Default::default(),
+            shared_vcpu_state: Default::default(),
+            per_vcpu_states,
+            kill_evt: EventFd::new().map_err(Error::CreateEventFd)?,
+            vcpu_pipes,
+            request_buffer: vec![0; MAX_DATAGRAM_SIZE],
+            response_buffer: Vec::new(),
+        })
+    }
+
+    /// Creates a VCPU plugin connection object, used by a VCPU run loop to communicate with the
+    /// plugin process.
+    ///
+    /// While each invocation of `create_vcpu` with the given `cpu_id` will return a unique
+    /// `PluginVcpu` object, the underlying resources are shared by each `PluginVcpu` resulting from
+    /// the same `cpu_id`.
+    pub fn create_vcpu(&self, cpu_id: u32) -> Result<PluginVcpu> {
+        let vcpu_pipe_read = self.vcpu_pipes[cpu_id as usize]
+            .crosvm_read
+            .try_clone()
+            .map_err(Error::CloneVcpuPipe)?;
+        let vcpu_pipe_write = self.vcpu_pipes[cpu_id as usize]
+            .crosvm_write
+            .try_clone()
+            .map_err(Error::CloneVcpuPipe)?;
+        Ok(PluginVcpu::new(
+            self.shared_vcpu_state.clone(),
+            self.per_vcpu_states[cpu_id as usize].clone(),
+            vcpu_pipe_read,
+            vcpu_pipe_write,
+        ))
+    }
+
+    /// Returns if the plugin process indicated the VM was ready to start.
+    pub fn is_started(&self) -> bool {
+        self.started
+    }
+
+    /// Returns the process ID of the plugin process.
+    pub fn pid(&self) -> pid_t {
+        self.plugin_pid
+    }
+
+    /// Returns a slice of each socket that should be polled.
+    ///
+    /// If any socket in this slice becomes readable, `handle_socket` should be called with the
+    /// index of that socket. If any socket becomes closed, its index should be passed to
+    /// `drop_sockets`.
+    pub fn sockets(&self) -> &[UnixDatagram] {
+        &self.request_sockets
+    }
+
+    /// Drops the each socket identified by its index in the slice returned by `sockets`.
+    ///
+    /// The given `socket_idxs` slice will be modified in an arbitrary way for efficient removal of
+    /// the sockets from internal data structures.
+    pub fn drop_sockets(&mut self, socket_idxs: &mut [usize]) {
+        // Takes a mutable slice so that the indices can be sorted for efficient removal in
+        // request_sockets..
+        socket_idxs.sort_unstable_by(|a, b| b.cmp(a));
+        let old_len = self.request_sockets.len();
+        for &socket_index in socket_idxs.iter() {
+            // swap_remove changes the index of the last element, but we already know that one
+            // doesn't need to be removed because we are removing sockets in descending order thanks
+            // to the above sort.
+            self.request_sockets.swap_remove(socket_index);
+        }
+        assert_eq!(old_len - socket_idxs.len(), self.request_sockets.len());
+    }
+
+    /// Gently requests that the plugin process exit cleanly, and ends handling of all VCPU
+    /// connections.
+    ///
+    /// The plugin process can ignore the given signal, and so some timeout should be used before
+    /// forcefully terminating the process.
+    ///
+    /// Any blocked VCPU connections will get interrupted so that the VCPU threads can exit cleanly.
+    /// Any subsequent attempt to use the VCPU connections will fail.
+    pub fn signal_kill(&mut self) -> SysResult<()> {
+        self.kill_evt.write(1)?;
+        // Normally we'd get any blocked recv() calls in the VCPU threads
+        // to unblock by calling shutdown().  However, we're using pipes
+        // (for improved performance), and pipes don't have shutdown so
+        // instead we'll write a shutdown message to ourselves using the
+        // the writable side of the pipe (normally used by the plugin).
+        for pipe in self.vcpu_pipes.iter_mut() {
+            let mut shutdown_request = VcpuRequest::new();
+            shutdown_request.set_shutdown(VcpuRequest_Shutdown::new());
+            let mut buffer = Vec::new();
+            shutdown_request
+                .write_to_vec(&mut buffer)
+                .map_err(proto_to_sys_err)?;
+            pipe.plugin_write
+                .write(&buffer[..])
+                .map_err(io_to_sys_err)?;
+        }
+        Ok(())
+    }
+
+    /// Waits without blocking for the plugin process to exit and returns the status.
+    pub fn try_wait(&mut self) -> SysResult<ProcessStatus> {
+        let mut status = 0;
+        // Safe because waitpid is given a valid pointer of correct size and mutability, and the
+        // return value is checked.
+        let ret = unsafe { waitpid(self.plugin_pid, &mut status, WNOHANG) };
+        match ret {
+            -1 => Err(SysError::last()),
+            0 => Ok(ProcessStatus::Running),
+            _ => {
+                // Trivially safe
+                if unsafe { WIFEXITED(status) } {
+                    match unsafe { WEXITSTATUS(status) } {
+                        // Trivially safe
+                        0 => Ok(ProcessStatus::Success),
+                        code => Ok(ProcessStatus::Fail(code)),
+                    }
+                } else {
+                    // Plugin terminated but has no exit status, so it must have been signaled.
+                    Ok(ProcessStatus::Signal(unsafe { WTERMSIG(status) })) // Trivially safe
+                }
+            }
+        }
+    }
+
+    fn handle_io_event(
+        entry: VacantEntry<u32, PluginObject>,
+        vm: &mut Vm,
+        io_event: &MainRequest_Create_IoEvent,
+    ) -> SysResult<RawFd> {
+        let evt = EventFd::new()?;
+        let addr = match io_event.space {
+            AddressSpace::IOPORT => IoeventAddress::Pio(io_event.address),
+            AddressSpace::MMIO => IoeventAddress::Mmio(io_event.address),
+        };
+        match io_event.length {
+            0 => vm.register_ioevent(&evt, addr, Datamatch::AnyLength)?,
+            1 => vm.register_ioevent(&evt, addr, Datamatch::U8(Some(io_event.datamatch as u8)))?,
+            2 => {
+                vm.register_ioevent(&evt, addr, Datamatch::U16(Some(io_event.datamatch as u16)))?
+            }
+            4 => {
+                vm.register_ioevent(&evt, addr, Datamatch::U32(Some(io_event.datamatch as u32)))?
+            }
+            8 => {
+                vm.register_ioevent(&evt, addr, Datamatch::U64(Some(io_event.datamatch as u64)))?
+            }
+            _ => return Err(SysError::new(EINVAL)),
+        };
+
+        let fd = evt.as_raw_fd();
+        entry.insert(PluginObject::IoEvent {
+            evt,
+            addr,
+            length: io_event.length,
+            datamatch: io_event.datamatch,
+        });
+        Ok(fd)
+    }
+
+    fn handle_memory(
+        entry: VacantEntry<u32, PluginObject>,
+        vm: &mut Vm,
+        memfd: File,
+        offset: u64,
+        start: u64,
+        length: u64,
+        read_only: bool,
+        dirty_log: bool,
+    ) -> SysResult<()> {
+        let shm = SharedMemory::from_raw_fd(memfd)?;
+        // Checking the seals ensures the plugin process won't shrink the mmapped file, causing us
+        // to SIGBUS in the future.
+        let seals = shm.get_seals()?;
+        if !seals.shrink_seal() {
+            return Err(SysError::new(EPERM));
+        }
+        // Check to make sure we don't mmap areas beyond the end of the memfd.
+        match length.checked_add(offset) {
+            Some(end) if end > shm.size() => return Err(SysError::new(EINVAL)),
+            None => return Err(SysError::new(EOVERFLOW)),
+            _ => {}
+        }
+        let mem = MemoryMapping::from_fd_offset(&shm, length as usize, offset as usize)
+            .map_err(mmap_to_sys_err)?;
+        let slot = vm.add_device_memory(GuestAddress(start), mem, read_only, dirty_log)?;
+        entry.insert(PluginObject::Memory {
+            slot,
+            length: length as usize,
+        });
+        Ok(())
+    }
+
+    fn handle_reserve_range(&mut self, reserve_range: &MainRequest_ReserveRange) -> SysResult<()> {
+        match self.shared_vcpu_state.write() {
+            Ok(mut lock) => {
+                let space = match reserve_range.space {
+                    AddressSpace::IOPORT => IoSpace::Ioport,
+                    AddressSpace::MMIO => IoSpace::Mmio,
+                };
+                match reserve_range.length {
+                    0 => lock.unreserve_range(space, reserve_range.start),
+                    _ => lock.reserve_range(space, reserve_range.start, reserve_range.length),
+                }
+            }
+            Err(_) => Err(SysError::new(EDEADLK)),
+        }
+    }
+
+    fn handle_set_irq_routing(
+        vm: &mut Vm,
+        irq_routing: &MainRequest_SetIrqRouting,
+    ) -> SysResult<()> {
+        let mut routes = Vec::with_capacity(irq_routing.routes.len());
+        for route in &irq_routing.routes {
+            routes.push(IrqRoute {
+                gsi: route.irq_id,
+                source: if route.has_irqchip() {
+                    let irqchip = route.get_irqchip();
+                    IrqSource::Irqchip {
+                        chip: irqchip.irqchip,
+                        pin: irqchip.pin,
+                    }
+                } else if route.has_msi() {
+                    let msi = route.get_msi();
+                    IrqSource::Msi {
+                        address: msi.address,
+                        data: msi.data,
+                    }
+                } else {
+                    // Because route is a oneof field in the proto definition, this should
+                    // only happen if a new variant gets added without updating this chained
+                    // if block.
+                    return Err(SysError::new(EINVAL));
+                },
+            });
+        }
+        vm.set_gsi_routing(&routes[..])
+    }
+
+    fn handle_pause_vcpus(&self, vcpu_handles: &[JoinHandle<()>], cpu_mask: u64, user_data: u64) {
+        for (cpu_id, (handle, per_cpu_state)) in
+            vcpu_handles.iter().zip(&self.per_vcpu_states).enumerate()
+        {
+            if cpu_mask & (1 << cpu_id) != 0 {
+                per_cpu_state.lock().request_pause(user_data);
+                if let Err(e) = handle.kill(SIGRTMIN() + 0) {
+                    error!("failed to interrupt vcpu {}: {}", cpu_id, e);
+                }
+            }
+        }
+    }
+
+    fn handle_get_net_config(
+        tap: &net_util::Tap,
+        config: &mut MainResponse_GetNetConfig,
+    ) -> SysResult<()> {
+        // Log any NetError so that the cause can be found later, but extract and return the
+        // underlying errno for the client as well.
+        fn map_net_error(s: &str, e: NetError) -> SysError {
+            error!("failed to get {}: {}", s, e);
+            e.sys_error()
+        }
+
+        let ip_addr = tap.ip_addr().map_err(|e| map_net_error("IP address", e))?;
+        config.set_host_ipv4_address(u32::from(ip_addr));
+
+        let netmask = tap.netmask().map_err(|e| map_net_error("netmask", e))?;
+        config.set_netmask(u32::from(netmask));
+
+        let result_mac_addr = config.mut_host_mac_address();
+        let mac_addr_octets = tap
+            .mac_address()
+            .map_err(|e| map_net_error("mac address", e))?
+            .octets();
+        result_mac_addr.resize(mac_addr_octets.len(), 0);
+        result_mac_addr.clone_from_slice(&mac_addr_octets);
+
+        Ok(())
+    }
+
+    /// Handles a request on a readable socket identified by its index in the slice returned by
+    /// `sockets`.
+    ///
+    /// The `vm` is used to service request that affect the VM. The `vcpu_handles` slice is used to
+    /// interrupt a VCPU thread currently running in the VM if the socket request it.
+    pub fn handle_socket(
+        &mut self,
+        index: usize,
+        kvm: &Kvm,
+        vm: &mut Vm,
+        vcpu_handles: &[JoinHandle<()>],
+        taps: &[Tap],
+    ) -> Result<()> {
+        let (msg_size, request_file) = self.request_sockets[index]
+            .recv_with_fd(&mut self.request_buffer)
+            .map_err(Error::PluginSocketRecv)?;
+
+        if msg_size == 0 {
+            return Err(Error::PluginSocketHup);
+        }
+
+        let request = protobuf::parse_from_bytes::<MainRequest>(&self.request_buffer[..msg_size])
+            .map_err(Error::DecodeRequest)?;
+
+        let mut response_files = Vec::new();
+        let mut response_fds = Vec::new();
+        let mut response = MainResponse::new();
+        let res = if request.has_create() {
+            response.mut_create();
+            let create = request.get_create();
+            match self.objects.entry(create.id) {
+                Entry::Vacant(entry) => {
+                    if create.has_io_event() {
+                        match Self::handle_io_event(entry, vm, create.get_io_event()) {
+                            Ok(fd) => {
+                                response_fds.push(fd);
+                                Ok(())
+                            }
+                            Err(e) => Err(e),
+                        }
+                    } else if create.has_memory() {
+                        let memory = create.get_memory();
+                        match request_file {
+                            Some(memfd) => Self::handle_memory(
+                                entry,
+                                vm,
+                                memfd,
+                                memory.offset,
+                                memory.start,
+                                memory.length,
+                                memory.read_only,
+                                memory.dirty_log,
+                            ),
+                            None => Err(SysError::new(EBADF)),
+                        }
+                    } else if create.has_irq_event() {
+                        let irq_event = create.get_irq_event();
+                        match (EventFd::new(), EventFd::new()) {
+                            (Ok(evt), Ok(resample_evt)) => match vm.register_irqfd_resample(
+                                &evt,
+                                &resample_evt,
+                                irq_event.irq_id,
+                            ) {
+                                Ok(()) => {
+                                    response_fds.push(evt.as_raw_fd());
+                                    response_fds.push(resample_evt.as_raw_fd());
+                                    response_files.push(downcast_file(resample_evt));
+                                    entry.insert(PluginObject::IrqEvent {
+                                        irq_id: irq_event.irq_id,
+                                        evt,
+                                    });
+                                    Ok(())
+                                }
+                                Err(e) => Err(e),
+                            },
+                            (Err(e), _) | (_, Err(e)) => Err(e),
+                        }
+                    } else {
+                        Err(SysError::new(ENOTTY))
+                    }
+                }
+                Entry::Occupied(_) => Err(SysError::new(EEXIST)),
+            }
+        } else if request.has_destroy() {
+            response.mut_destroy();
+            match self.objects.entry(request.get_destroy().id) {
+                Entry::Occupied(entry) => entry.remove().destroy(vm),
+                Entry::Vacant(_) => Err(SysError::new(ENOENT)),
+            }
+        } else if request.has_new_connection() {
+            response.mut_new_connection();
+            match new_seqpacket_pair() {
+                Ok((request_socket, child_socket)) => {
+                    self.request_sockets.push(request_socket);
+                    response_fds.push(child_socket.as_raw_fd());
+                    response_files.push(downcast_file(child_socket));
+                    Ok(())
+                }
+                Err(e) => Err(e),
+            }
+        } else if request.has_get_shutdown_eventfd() {
+            response.mut_get_shutdown_eventfd();
+            response_fds.push(self.kill_evt.as_raw_fd());
+            Ok(())
+        } else if request.has_check_extension() {
+            // Safe because the Cap enum is not read by the check_extension method. In that method,
+            // cap is cast back to an integer and fed to an ioctl. If the extension name is actually
+            // invalid, the kernel will safely reject the extension under the assumption that the
+            // capability is legitimately unsupported.
+            let cap = unsafe { transmute(request.get_check_extension().extension) };
+            response.mut_check_extension().has_extension = vm.check_extension(cap);
+            Ok(())
+        } else if request.has_reserve_range() {
+            response.mut_reserve_range();
+            self.handle_reserve_range(request.get_reserve_range())
+        } else if request.has_set_irq() {
+            response.mut_set_irq();
+            let irq = request.get_set_irq();
+            vm.set_irq_line(irq.irq_id, irq.active)
+        } else if request.has_set_irq_routing() {
+            response.mut_set_irq_routing();
+            Self::handle_set_irq_routing(vm, request.get_set_irq_routing())
+        } else if request.has_get_state() {
+            let response_state = response.mut_get_state();
+            match get_vm_state(vm, request.get_get_state().set) {
+                Ok(state) => {
+                    response_state.state = state;
+                    Ok(())
+                }
+                Err(e) => Err(e),
+            }
+        } else if request.has_set_state() {
+            response.mut_set_state();
+            let set_state = request.get_set_state();
+            set_vm_state(vm, set_state.set, set_state.get_state())
+        } else if request.has_set_identity_map_addr() {
+            response.mut_set_identity_map_addr();
+            let addr = request.get_set_identity_map_addr().address;
+            vm.set_identity_map_addr(GuestAddress(addr as u64))
+        } else if request.has_pause_vcpus() {
+            response.mut_pause_vcpus();
+            let pause_vcpus = request.get_pause_vcpus();
+            self.handle_pause_vcpus(vcpu_handles, pause_vcpus.cpu_mask, pause_vcpus.user);
+            Ok(())
+        } else if request.has_get_vcpus() {
+            response.mut_get_vcpus();
+            for pipe in self.vcpu_pipes.iter() {
+                response_fds.push(pipe.plugin_write.as_raw_fd());
+                response_fds.push(pipe.plugin_read.as_raw_fd());
+            }
+            Ok(())
+        } else if request.has_start() {
+            response.mut_start();
+            if self.started {
+                Err(SysError::new(EINVAL))
+            } else {
+                self.started = true;
+                Ok(())
+            }
+        } else if request.has_get_net_config() {
+            match taps.first() {
+                Some(tap) => {
+                    match Self::handle_get_net_config(tap, response.mut_get_net_config()) {
+                        Ok(_) => {
+                            response_fds.push(tap.as_raw_fd());
+                            Ok(())
+                        }
+                        Err(e) => Err(e),
+                    }
+                }
+                None => Err(SysError::new(ENODATA)),
+            }
+        } else if request.has_dirty_log() {
+            let dirty_log_response = response.mut_dirty_log();
+            match self.objects.get(&request.get_dirty_log().id) {
+                Some(&PluginObject::Memory { slot, length }) => {
+                    let dirty_log = dirty_log_response.mut_bitmap();
+                    dirty_log.resize(dirty_log_bitmap_size(length), 0);
+                    vm.get_dirty_log(slot, &mut dirty_log[..])
+                }
+                _ => Err(SysError::new(ENOENT)),
+            }
+        } else if request.has_get_supported_cpuid() {
+            let cpuid_response = &mut response.mut_get_supported_cpuid().entries;
+            match kvm.get_supported_cpuid() {
+                Ok(mut cpuid) => {
+                    for entry in cpuid.mut_entries_slice() {
+                        cpuid_response.push(cpuid_kvm_to_proto(entry));
+                    }
+                    Ok(())
+                }
+                Err(e) => Err(e),
+            }
+        } else if request.has_get_emulated_cpuid() {
+            let cpuid_response = &mut response.mut_get_emulated_cpuid().entries;
+            match kvm.get_emulated_cpuid() {
+                Ok(mut cpuid) => {
+                    for entry in cpuid.mut_entries_slice() {
+                        cpuid_response.push(cpuid_kvm_to_proto(entry));
+                    }
+                    Ok(())
+                }
+                Err(e) => Err(e),
+            }
+        } else if request.has_get_msr_index_list() {
+            let msr_list_response = &mut response.mut_get_msr_index_list().indices;
+            match kvm.get_msr_index_list() {
+                Ok(indices) => {
+                    for entry in indices {
+                        msr_list_response.push(entry);
+                    }
+                    Ok(())
+                }
+                Err(e) => Err(e),
+            }
+        } else {
+            Err(SysError::new(ENOTTY))
+        };
+
+        if let Err(e) = res {
+            response.errno = e.errno();
+        }
+
+        self.response_buffer.clear();
+        response
+            .write_to_vec(&mut self.response_buffer)
+            .map_err(Error::EncodeResponse)?;
+        assert_ne!(self.response_buffer.len(), 0);
+        self.request_sockets[index]
+            .send_with_fds(&self.response_buffer[..], &response_fds)
+            .map_err(Error::PluginSocketSend)?;
+
+        Ok(())
+    }
+}
+
+impl Drop for Process {
+    fn drop(&mut self) {
+        // Ignore the result because there is nothing we can do about it.
+        if let Err(e) = self.signal_kill() {
+            error!("failed to signal kill event for plugin: {}", e);
+        }
+    }
+}
diff --git a/src/plugin/vcpu.rs b/src/plugin/vcpu.rs
new file mode 100644
index 0000000..c9d811a
--- /dev/null
+++ b/src/plugin/vcpu.rs
@@ -0,0 +1,608 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::alloc::Layout;
+use std::cell::{Cell, RefCell};
+use std::cmp::min;
+use std::cmp::{self, Ord, PartialEq, PartialOrd};
+use std::collections::btree_set::BTreeSet;
+use std::io::{Read, Write};
+use std::mem;
+use std::sync::{Arc, RwLock};
+
+use libc::{EINVAL, ENOENT, ENOTTY, EPERM, EPIPE, EPROTO};
+
+use protobuf;
+use protobuf::Message;
+
+use assertions::const_assert;
+use data_model::DataInit;
+use kvm::{CpuId, Vcpu};
+use kvm_sys::{
+    kvm_debugregs, kvm_fpu, kvm_lapic_state, kvm_mp_state, kvm_msr_entry, kvm_msrs, kvm_regs,
+    kvm_sregs, kvm_vcpu_events, kvm_xcrs, KVM_CPUID_FLAG_SIGNIFCANT_INDEX,
+};
+use protos::plugin::*;
+use sync::Mutex;
+use sys_util::{error, LayoutAllocation};
+
+use super::*;
+
+/// Identifier for an address space in the VM.
+#[derive(Copy, Clone)]
+pub enum IoSpace {
+    Ioport,
+    Mmio,
+}
+
+#[derive(Debug, Copy, Clone)]
+struct Range(u64, u64);
+
+impl Eq for Range {}
+
+impl PartialEq for Range {
+    fn eq(&self, other: &Range) -> bool {
+        self.0 == other.0
+    }
+}
+
+impl Ord for Range {
+    fn cmp(&self, other: &Range) -> cmp::Ordering {
+        self.0.cmp(&other.0)
+    }
+}
+
+impl PartialOrd for Range {
+    fn partial_cmp(&self, other: &Range) -> Option<cmp::Ordering> {
+        self.0.partial_cmp(&other.0)
+    }
+}
+
+// Wrapper types to make the kvm register structs DataInit
+#[derive(Copy, Clone)]
+struct VcpuRegs(kvm_regs);
+unsafe impl DataInit for VcpuRegs {}
+#[derive(Copy, Clone)]
+struct VcpuSregs(kvm_sregs);
+unsafe impl DataInit for VcpuSregs {}
+#[derive(Copy, Clone)]
+struct VcpuFpu(kvm_fpu);
+unsafe impl DataInit for VcpuFpu {}
+#[derive(Copy, Clone)]
+struct VcpuDebugregs(kvm_debugregs);
+unsafe impl DataInit for VcpuDebugregs {}
+#[derive(Copy, Clone)]
+struct VcpuXcregs(kvm_xcrs);
+unsafe impl DataInit for VcpuXcregs {}
+#[derive(Copy, Clone)]
+struct VcpuLapicState(kvm_lapic_state);
+unsafe impl DataInit for VcpuLapicState {}
+#[derive(Copy, Clone)]
+struct VcpuMpState(kvm_mp_state);
+unsafe impl DataInit for VcpuMpState {}
+#[derive(Copy, Clone)]
+struct VcpuEvents(kvm_vcpu_events);
+unsafe impl DataInit for VcpuEvents {}
+
+fn get_vcpu_state(vcpu: &Vcpu, state_set: VcpuRequest_StateSet) -> SysResult<Vec<u8>> {
+    Ok(match state_set {
+        VcpuRequest_StateSet::REGS => VcpuRegs(vcpu.get_regs()?).as_slice().to_vec(),
+        VcpuRequest_StateSet::SREGS => VcpuSregs(vcpu.get_sregs()?).as_slice().to_vec(),
+        VcpuRequest_StateSet::FPU => VcpuFpu(vcpu.get_fpu()?).as_slice().to_vec(),
+        VcpuRequest_StateSet::DEBUGREGS => VcpuDebugregs(vcpu.get_debugregs()?).as_slice().to_vec(),
+        VcpuRequest_StateSet::XCREGS => VcpuXcregs(vcpu.get_xcrs()?).as_slice().to_vec(),
+        VcpuRequest_StateSet::LAPIC => VcpuLapicState(vcpu.get_lapic()?).as_slice().to_vec(),
+        VcpuRequest_StateSet::MP => VcpuMpState(vcpu.get_mp_state()?).as_slice().to_vec(),
+        VcpuRequest_StateSet::EVENTS => VcpuEvents(vcpu.get_vcpu_events()?).as_slice().to_vec(),
+    })
+}
+
+fn set_vcpu_state(vcpu: &Vcpu, state_set: VcpuRequest_StateSet, state: &[u8]) -> SysResult<()> {
+    match state_set {
+        VcpuRequest_StateSet::REGS => {
+            vcpu.set_regs(&VcpuRegs::from_slice(state).ok_or(SysError::new(EINVAL))?.0)
+        }
+        VcpuRequest_StateSet::SREGS => {
+            vcpu.set_sregs(&VcpuSregs::from_slice(state).ok_or(SysError::new(EINVAL))?.0)
+        }
+        VcpuRequest_StateSet::FPU => {
+            vcpu.set_fpu(&VcpuFpu::from_slice(state).ok_or(SysError::new(EINVAL))?.0)
+        }
+        VcpuRequest_StateSet::DEBUGREGS => vcpu.set_debugregs(
+            &VcpuDebugregs::from_slice(state)
+                .ok_or(SysError::new(EINVAL))?
+                .0,
+        ),
+        VcpuRequest_StateSet::XCREGS => vcpu.set_xcrs(
+            &VcpuXcregs::from_slice(state)
+                .ok_or(SysError::new(EINVAL))?
+                .0,
+        ),
+        VcpuRequest_StateSet::LAPIC => vcpu.set_lapic(
+            &VcpuLapicState::from_slice(state)
+                .ok_or(SysError::new(EINVAL))?
+                .0,
+        ),
+        VcpuRequest_StateSet::MP => vcpu.set_mp_state(
+            &VcpuMpState::from_slice(state)
+                .ok_or(SysError::new(EINVAL))?
+                .0,
+        ),
+        VcpuRequest_StateSet::EVENTS => vcpu.set_vcpu_events(
+            &VcpuEvents::from_slice(state)
+                .ok_or(SysError::new(EINVAL))?
+                .0,
+        ),
+    }
+}
+
+/// State shared by every VCPU, grouped together to make edits to the state coherent across VCPUs.
+#[derive(Default)]
+pub struct SharedVcpuState {
+    ioport_regions: BTreeSet<Range>,
+    mmio_regions: BTreeSet<Range>,
+}
+
+impl SharedVcpuState {
+    /// Reserves the given range for handling by the plugin process.
+    ///
+    /// This will reject any reservation that overlaps with an existing reservation.
+    pub fn reserve_range(&mut self, space: IoSpace, start: u64, length: u64) -> SysResult<()> {
+        if length == 0 {
+            return Err(SysError::new(EINVAL));
+        }
+
+        // Reject all cases where this reservation is part of another reservation.
+        if self.is_reserved(space, start) {
+            return Err(SysError::new(EPERM));
+        }
+
+        let last_address = match start.checked_add(length) {
+            Some(end) => end - 1,
+            None => return Err(SysError::new(EINVAL)),
+        };
+
+        let space = match space {
+            IoSpace::Ioport => &mut self.ioport_regions,
+            IoSpace::Mmio => &mut self.mmio_regions,
+        };
+
+        match space.range(..Range(last_address, 0)).next_back().cloned() {
+            Some(Range(existing_start, _)) if existing_start >= start => Err(SysError::new(EPERM)),
+            _ => {
+                space.insert(Range(start, length));
+                Ok(())
+            }
+        }
+    }
+
+    //// Releases a reservation previously made at `start` in the given `space`.
+    pub fn unreserve_range(&mut self, space: IoSpace, start: u64) -> SysResult<()> {
+        let range = Range(start, 0);
+        let space = match space {
+            IoSpace::Ioport => &mut self.ioport_regions,
+            IoSpace::Mmio => &mut self.mmio_regions,
+        };
+        if space.remove(&range) {
+            Ok(())
+        } else {
+            Err(SysError::new(ENOENT))
+        }
+    }
+
+    fn is_reserved(&self, space: IoSpace, addr: u64) -> bool {
+        if let Some(Range(start, len)) = self.first_before(space, addr) {
+            let offset = addr - start;
+            if offset < len {
+                return true;
+            }
+        }
+        false
+    }
+
+    fn first_before(&self, io_space: IoSpace, addr: u64) -> Option<Range> {
+        let space = match io_space {
+            IoSpace::Ioport => &self.ioport_regions,
+            IoSpace::Mmio => &self.mmio_regions,
+        };
+
+        match addr.checked_add(1) {
+            Some(next_addr) => space.range(..Range(next_addr, 0)).next_back().cloned(),
+            None => None,
+        }
+    }
+}
+
+/// State specific to a VCPU, grouped so that each `PluginVcpu` object will share a canonical
+/// version.
+#[derive(Default)]
+pub struct PerVcpuState {
+    pause_request: Option<u64>,
+}
+
+impl PerVcpuState {
+    /// Indicates that a VCPU should wait until the plugin process resumes the VCPU.
+    ///
+    /// This method will not cause a VCPU to pause immediately. Instead, the VCPU thread will
+    /// continue running until a interrupted, at which point it will check for a pending pause. If
+    /// there is another call to `request_pause` for this VCPU before that happens, the last pause
+    /// request's `data` will be overwritten with the most recent `data.
+    ///
+    /// To get an immediate pause after calling `request_pause`, send a signal (with a registered
+    /// handler) to the thread handling the VCPU corresponding to this state. This should interrupt
+    /// the running VCPU, which should check for a pause with `PluginVcpu::pre_run`.
+    pub fn request_pause(&mut self, data: u64) {
+        self.pause_request = Some(data);
+    }
+}
+
+enum VcpuRunData<'a> {
+    Read(&'a mut [u8]),
+    Write(&'a [u8]),
+}
+
+impl<'a> VcpuRunData<'a> {
+    fn is_write(&self) -> bool {
+        match self {
+            VcpuRunData::Write(_) => true,
+            _ => false,
+        }
+    }
+
+    fn as_slice(&self) -> &[u8] {
+        match self {
+            VcpuRunData::Read(s) => s,
+            VcpuRunData::Write(s) => s,
+        }
+    }
+
+    fn copy_from_slice(&mut self, data: &[u8]) {
+        if let VcpuRunData::Read(s) = self {
+            let copy_size = min(s.len(), data.len());
+            s.copy_from_slice(&data[..copy_size]);
+        }
+    }
+}
+
+/// State object for a VCPU's connection with the plugin process.
+///
+/// This is used by a VCPU thread to allow the plugin process to handle vmexits. Each method may
+/// block indefinitely while the plugin process is handling requests. In order to cleanly shutdown
+/// during these blocking calls, the `connection` socket should be shutdown. This will end the
+/// blocking calls,
+pub struct PluginVcpu {
+    shared_vcpu_state: Arc<RwLock<SharedVcpuState>>,
+    per_vcpu_state: Arc<Mutex<PerVcpuState>>,
+    read_pipe: File,
+    write_pipe: File,
+    wait_reason: Cell<Option<VcpuResponse_Wait>>,
+    request_buffer: RefCell<Vec<u8>>,
+    response_buffer: RefCell<Vec<u8>>,
+}
+
+impl PluginVcpu {
+    /// Creates the plugin state and connection container for a VCPU thread.
+    pub fn new(
+        shared_vcpu_state: Arc<RwLock<SharedVcpuState>>,
+        per_vcpu_state: Arc<Mutex<PerVcpuState>>,
+        read_pipe: File,
+        write_pipe: File,
+    ) -> PluginVcpu {
+        PluginVcpu {
+            shared_vcpu_state,
+            per_vcpu_state,
+            read_pipe,
+            write_pipe,
+            wait_reason: Default::default(),
+            request_buffer: Default::default(),
+            response_buffer: Default::default(),
+        }
+    }
+
+    /// Tells the plugin process to initialize this VCPU.
+    ///
+    /// This should be called for each VCPU before the first run of any of the VCPUs in the VM.
+    pub fn init(&self, vcpu: &Vcpu) -> SysResult<()> {
+        let mut wait_reason = VcpuResponse_Wait::new();
+        wait_reason.mut_init();
+        self.wait_reason.set(Some(wait_reason));
+        self.handle_until_resume(vcpu)?;
+        Ok(())
+    }
+
+    /// The VCPU thread should call this before rerunning a VM in order to handle pending requests
+    /// to this VCPU.
+    pub fn pre_run(&self, vcpu: &Vcpu) -> SysResult<()> {
+        let request = {
+            let mut lock = self.per_vcpu_state.lock();
+            lock.pause_request.take()
+        };
+
+        if let Some(user_data) = request {
+            let mut wait_reason = VcpuResponse_Wait::new();
+            wait_reason.mut_user().user = user_data;
+            self.wait_reason.set(Some(wait_reason));
+            self.handle_until_resume(vcpu)?;
+        }
+        Ok(())
+    }
+
+    fn process(&self, io_space: IoSpace, addr: u64, mut data: VcpuRunData, vcpu: &Vcpu) -> bool {
+        let vcpu_state_lock = match self.shared_vcpu_state.read() {
+            Ok(l) => l,
+            Err(e) => {
+                error!("error read locking shared cpu state: {}", e);
+                return false;
+            }
+        };
+
+        let first_before_addr = vcpu_state_lock.first_before(io_space, addr);
+        // Drops the read lock as soon as possible, to prevent holding lock while blocked in
+        // `handle_until_resume`.
+        drop(vcpu_state_lock);
+
+        match first_before_addr {
+            Some(Range(start, len)) => {
+                let offset = addr - start;
+                if offset >= len {
+                    return false;
+                }
+
+                let mut wait_reason = VcpuResponse_Wait::new();
+                let io = wait_reason.mut_io();
+                io.space = match io_space {
+                    IoSpace::Ioport => AddressSpace::IOPORT,
+                    IoSpace::Mmio => AddressSpace::MMIO,
+                };
+                io.address = addr;
+                io.is_write = data.is_write();
+                io.data = data.as_slice().to_vec();
+
+                self.wait_reason.set(Some(wait_reason));
+                match self.handle_until_resume(vcpu) {
+                    Ok(resume_data) => data.copy_from_slice(&resume_data),
+                    Err(e) if e.errno() == EPIPE => {}
+                    Err(e) => error!("failed to process vcpu requests: {}", e),
+                }
+                true
+            }
+            None => false,
+        }
+    }
+
+    /// Has the plugin process handle a IO port read.
+    pub fn io_read(&self, addr: u64, data: &mut [u8], vcpu: &Vcpu) -> bool {
+        self.process(IoSpace::Ioport, addr, VcpuRunData::Read(data), vcpu)
+    }
+
+    /// Has the plugin process handle a IO port write.
+    pub fn io_write(&self, addr: u64, data: &[u8], vcpu: &Vcpu) -> bool {
+        self.process(IoSpace::Ioport, addr, VcpuRunData::Write(data), vcpu)
+    }
+
+    /// Has the plugin process handle a MMIO read.
+    pub fn mmio_read(&self, addr: u64, data: &mut [u8], vcpu: &Vcpu) -> bool {
+        self.process(IoSpace::Mmio, addr, VcpuRunData::Read(data), vcpu)
+    }
+
+    /// Has the plugin process handle a MMIO write.
+    pub fn mmio_write(&self, addr: u64, data: &[u8], vcpu: &Vcpu) -> bool {
+        self.process(IoSpace::Mmio, addr, VcpuRunData::Write(data), vcpu)
+    }
+
+    fn handle_request(&self, vcpu: &Vcpu) -> SysResult<Option<Vec<u8>>> {
+        let mut wait_reason = self.wait_reason.take();
+        let mut do_recv = true;
+        let mut resume_data = None;
+        let mut response = VcpuResponse::new();
+
+        // Typically a response is sent for every request received.  The odd (yet common)
+        // case is when a resume request is received.  This function will skip sending
+        // a resume reply, and instead we'll go run the VM and then later reply with a wait
+        // response message.  This code block handles checking if a wait reason is pending (where
+        // the wait reason isn't the first-time init [first time init needs to first
+        // receive a wait request from the plugin]) to send it as a reply before doing a recv()
+        // for the next request.  Note that if a wait reply is pending then this function
+        // will send the reply and do nothing else--the expectation is that handle_until_resume()
+        // is the only caller of this function, so the function will immediately get called again
+        // and this second call will no longer see a pending wait reason and do a recv() for the
+        // next message.
+        if let Some(reason) = wait_reason {
+            if reason.has_init() {
+                wait_reason = Some(reason);
+            } else {
+                response.set_wait(reason);
+                do_recv = false;
+                wait_reason = None;
+            }
+        }
+
+        if do_recv {
+            let mut request_buffer = self.request_buffer.borrow_mut();
+            request_buffer.resize(MAX_VCPU_DATAGRAM_SIZE, 0);
+
+            let mut read_pipe = &self.read_pipe;
+            let msg_size = read_pipe.read(&mut request_buffer).map_err(io_to_sys_err)?;
+
+            let mut request =
+                protobuf::parse_from_bytes::<VcpuRequest>(&request_buffer[..msg_size])
+                    .map_err(proto_to_sys_err)?;
+
+            let res = if request.has_wait() {
+                match wait_reason {
+                    Some(wait_reason) => {
+                        response.set_wait(wait_reason);
+                        Ok(())
+                    }
+                    None => Err(SysError::new(EPROTO)),
+                }
+            } else if wait_reason.is_some() {
+                // Any request other than getting the wait_reason while there is one pending is invalid.
+                self.wait_reason.set(wait_reason);
+                Err(SysError::new(EPROTO))
+            } else if request.has_resume() {
+                response.mut_resume();
+                resume_data = Some(request.take_resume().take_data());
+                Ok(())
+            } else if request.has_get_state() {
+                let response_state = response.mut_get_state();
+                match get_vcpu_state(vcpu, request.get_get_state().set) {
+                    Ok(state) => {
+                        response_state.state = state;
+                        Ok(())
+                    }
+                    Err(e) => Err(e),
+                }
+            } else if request.has_set_state() {
+                response.mut_set_state();
+                let set_state = request.get_set_state();
+                set_vcpu_state(vcpu, set_state.set, set_state.get_state())
+            } else if request.has_get_msrs() {
+                let entry_data = &mut response.mut_get_msrs().entry_data;
+                let entry_indices = &request.get_get_msrs().entry_indices;
+                let mut msr_entries = Vec::with_capacity(entry_indices.len());
+                for &index in entry_indices {
+                    msr_entries.push(kvm_msr_entry {
+                        index,
+                        ..Default::default()
+                    });
+                }
+                match vcpu.get_msrs(&mut msr_entries) {
+                    Ok(()) => {
+                        for msr_entry in msr_entries {
+                            entry_data.push(msr_entry.data);
+                        }
+                        Ok(())
+                    }
+                    Err(e) => Err(e),
+                }
+            } else if request.has_set_msrs() {
+                const SIZE_OF_MSRS: usize = mem::size_of::<kvm_msrs>();
+                const SIZE_OF_ENTRY: usize = mem::size_of::<kvm_msr_entry>();
+                const ALIGN_OF_MSRS: usize = mem::align_of::<kvm_msrs>();
+                const ALIGN_OF_ENTRY: usize = mem::align_of::<kvm_msr_entry>();
+                const_assert!(ALIGN_OF_MSRS >= ALIGN_OF_ENTRY);
+
+                response.mut_set_msrs();
+                let request_entries = &request.get_set_msrs().entries;
+
+                let size = SIZE_OF_MSRS + request_entries.len() * SIZE_OF_ENTRY;
+                let layout =
+                    Layout::from_size_align(size, ALIGN_OF_MSRS).expect("impossible layout");
+                let mut allocation = LayoutAllocation::zeroed(layout);
+
+                // Safe to obtain an exclusive reference because there are no other
+                // references to the allocation yet and all-zero is a valid bit
+                // pattern.
+                let kvm_msrs = unsafe { allocation.as_mut::<kvm_msrs>() };
+
+                unsafe {
+                    // Mapping the unsized array to a slice is unsafe becase the length isn't known.
+                    // Providing the length used to create the struct guarantees the entire slice is
+                    // valid.
+                    let kvm_msr_entries: &mut [kvm_msr_entry] =
+                        kvm_msrs.entries.as_mut_slice(request_entries.len());
+                    for (msr_entry, entry) in kvm_msr_entries.iter_mut().zip(request_entries) {
+                        msr_entry.index = entry.index;
+                        msr_entry.data = entry.data;
+                    }
+                }
+                kvm_msrs.nmsrs = request_entries.len() as u32;
+                vcpu.set_msrs(&kvm_msrs)
+            } else if request.has_set_cpuid() {
+                response.mut_set_cpuid();
+                let request_entries = &request.get_set_cpuid().entries;
+                let mut cpuid = CpuId::new(request_entries.len());
+                let cpuid_entries = cpuid.mut_entries_slice();
+                for (request_entry, cpuid_entry) in request_entries.iter().zip(cpuid_entries) {
+                    cpuid_entry.function = request_entry.function;
+                    if request_entry.has_index {
+                        cpuid_entry.index = request_entry.index;
+                        cpuid_entry.flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+                    }
+                    cpuid_entry.eax = request_entry.eax;
+                    cpuid_entry.ebx = request_entry.ebx;
+                    cpuid_entry.ecx = request_entry.ecx;
+                    cpuid_entry.edx = request_entry.edx;
+                }
+                vcpu.set_cpuid2(&cpuid)
+            } else if request.has_shutdown() {
+                return Err(SysError::new(EPIPE));
+            } else {
+                Err(SysError::new(ENOTTY))
+            };
+
+            if let Err(e) = res {
+                response.errno = e.errno();
+            }
+        }
+
+        // Send the response, except if it's a resume response (in which case
+        // we'll go run the VM and afterwards send a wait response message).
+        if !response.has_resume() {
+            let mut response_buffer = self.response_buffer.borrow_mut();
+            response_buffer.clear();
+            response
+                .write_to_vec(&mut response_buffer)
+                .map_err(proto_to_sys_err)?;
+            let mut write_pipe = &self.write_pipe;
+            write_pipe
+                .write(&response_buffer[..])
+                .map_err(io_to_sys_err)?;
+        }
+
+        Ok(resume_data)
+    }
+
+    fn handle_until_resume(&self, vcpu: &Vcpu) -> SysResult<Vec<u8>> {
+        loop {
+            if let Some(resume_data) = self.handle_request(vcpu)? {
+                return Ok(resume_data);
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn shared_vcpu_reserve() {
+        let mut shared_vcpu_state = SharedVcpuState::default();
+        shared_vcpu_state
+            .reserve_range(IoSpace::Ioport, 0x10, 0)
+            .unwrap_err();
+        shared_vcpu_state
+            .reserve_range(IoSpace::Ioport, 0x10, 0x10)
+            .unwrap();
+        shared_vcpu_state
+            .reserve_range(IoSpace::Ioport, 0x0f, 0x10)
+            .unwrap_err();
+        shared_vcpu_state
+            .reserve_range(IoSpace::Ioport, 0x10, 0x10)
+            .unwrap_err();
+        shared_vcpu_state
+            .reserve_range(IoSpace::Ioport, 0x10, 0x15)
+            .unwrap_err();
+        shared_vcpu_state
+            .reserve_range(IoSpace::Ioport, 0x12, 0x15)
+            .unwrap_err();
+        shared_vcpu_state
+            .reserve_range(IoSpace::Ioport, 0x12, 0x01)
+            .unwrap_err();
+        shared_vcpu_state
+            .reserve_range(IoSpace::Ioport, 0x0, 0x20)
+            .unwrap_err();
+        shared_vcpu_state
+            .reserve_range(IoSpace::Ioport, 0x20, 0x05)
+            .unwrap();
+        shared_vcpu_state
+            .reserve_range(IoSpace::Ioport, 0x25, 0x05)
+            .unwrap();
+        shared_vcpu_state
+            .reserve_range(IoSpace::Ioport, 0x0, 0x10)
+            .unwrap();
+    }
+}
diff --git a/sync/Cargo.toml b/sync/Cargo.toml
new file mode 100644
index 0000000..af38fd1
--- /dev/null
+++ b/sync/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "sync"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+include = ["src/**/*", "Cargo.toml"]
+
+[workspace]
diff --git a/sync/src/condvar.rs b/sync/src/condvar.rs
new file mode 100644
index 0000000..4a6e80d
--- /dev/null
+++ b/sync/src/condvar.rs
@@ -0,0 +1,45 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fmt::{self, Debug};
+use std::sync::{Condvar as StdCondvar, MutexGuard};
+
+/// A Condition Variable.
+#[derive(Default)]
+pub struct Condvar {
+    std: StdCondvar,
+}
+
+impl Condvar {
+    /// Creates a new condvar that is ready to be waited on.
+    pub fn new() -> Condvar {
+        Condvar {
+            std: StdCondvar::new(),
+        }
+    }
+
+    /// Waits on a condvar, blocking the current thread until it is notified.
+    pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
+        match self.std.wait(guard) {
+            Ok(guard) => guard,
+            Err(_) => panic!("condvar is poisoned"),
+        }
+    }
+
+    /// Notifies one thread blocked by this condvar.
+    pub fn notify_one(&self) {
+        self.std.notify_one();
+    }
+
+    /// Notifies all threads blocked by this condvar.
+    pub fn notify_all(&self) {
+        self.std.notify_all();
+    }
+}
+
+impl Debug for Condvar {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        Debug::fmt(&self.std, formatter)
+    }
+}
diff --git a/sync/src/lib.rs b/sync/src/lib.rs
new file mode 100644
index 0000000..5a1e883
--- /dev/null
+++ b/sync/src/lib.rs
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Sync primitive types whose methods panic rather than returning error in case of poison.
+//!
+//! The Mutex/Condvar type in this crates wraps the standard library versions and mirrors the same
+//! methods, except that they panic where the standard library would return an Error. This API
+//! codifies our error handling strategy around poisoned mutexes in crosvm.
+//!
+//! - Crosvm releases are built with panic=abort so poisoning never occurs. A panic while a mutex is
+//!   held (or ever) takes down the entire process. Thus we would like for code not to have to
+//!   consider the possibility of poison.
+//!
+//! - We could ask developers to always write `.lock().unwrap()` on a standard library mutex.
+//!   However, we would like to stigmatize the use of unwrap. It is confusing to permit unwrap but
+//!   only on mutex lock results. During code review it may not always be obvious whether a
+//!   particular unwrap is unwrapping a mutex lock result or a different error that should be
+//!   handled in a more principled way.
+//!
+//! Developers should feel free to use types defined in this crate anywhere in crosvm that they
+//! would otherwise be using the corresponding types in std::sync.
+
+mod condvar;
+mod mutex;
+
+pub use crate::condvar::Condvar;
+pub use crate::mutex::{Mutex, WouldBlock};
diff --git a/sync/src/mutex.rs b/sync/src/mutex.rs
new file mode 100644
index 0000000..c479a2e
--- /dev/null
+++ b/sync/src/mutex.rs
@@ -0,0 +1,121 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Mutex type whose methods panic rather than returning error in case of
+//! poison.
+//!
+//! The Mutex type in this module wraps the standard library Mutex and mirrors
+//! the same methods, except that they panic where the standard library would
+//! return a PoisonError. This API codifies our error handling strategy around
+//! poisoned mutexes in crosvm.
+//!
+//! - Crosvm releases are built with panic=abort so poisoning never occurs. A
+//!   panic while a mutex is held (or ever) takes down the entire process. Thus
+//!   we would like for code not to have to consider the possibility of poison.
+//!
+//! - We could ask developers to always write `.lock().unwrap()` on a standard
+//!   library mutex. However, we would like to stigmatize the use of unwrap. It
+//!   is confusing to permit unwrap but only on mutex lock results. During code
+//!   review it may not always be obvious whether a particular unwrap is
+//!   unwrapping a mutex lock result or a different error that should be handled
+//!   in a more principled way.
+//!
+//! Developers should feel free to use sync::Mutex anywhere in crosvm that they
+//! would otherwise be using std::sync::Mutex.
+
+use std::fmt::{self, Debug, Display};
+use std::sync::{Mutex as StdMutex, MutexGuard, TryLockError};
+
+/// A mutual exclusion primitive useful for protecting shared data.
+#[derive(Default)]
+pub struct Mutex<T: ?Sized> {
+    std: StdMutex<T>,
+}
+
+impl<T> Mutex<T> {
+    /// Creates a new mutex in an unlocked state ready for use.
+    pub fn new(value: T) -> Mutex<T> {
+        Mutex {
+            std: StdMutex::new(value),
+        }
+    }
+
+    /// Consumes this mutex, returning the underlying data.
+    pub fn into_inner(self) -> T {
+        match self.std.into_inner() {
+            Ok(value) => value,
+            Err(_) => panic!("mutex is poisoned"),
+        }
+    }
+}
+
+impl<T: ?Sized> Mutex<T> {
+    /// Acquires a mutex, blocking the current thread until it is able to do so.
+    ///
+    /// This function will block the local thread until it is available to
+    /// acquire the mutex. Upon returning, the thread is the only thread with
+    /// the lock held. An RAII guard is returned to allow scoped unlock of the
+    /// lock. When the guard goes out of scope, the mutex will be unlocked.
+    pub fn lock(&self) -> MutexGuard<T> {
+        match self.std.lock() {
+            Ok(guard) => guard,
+            Err(_) => panic!("mutex is poisoned"),
+        }
+    }
+
+    /// Attempts to acquire this lock.
+    ///
+    /// If the lock could not be acquired at this time, then Err is returned.
+    /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
+    /// guard is dropped.
+    ///
+    /// This function does not block.
+    pub fn try_lock(&self) -> Result<MutexGuard<T>, WouldBlock> {
+        match self.std.try_lock() {
+            Ok(guard) => Ok(guard),
+            Err(TryLockError::Poisoned(_)) => panic!("mutex is poisoned"),
+            Err(TryLockError::WouldBlock) => Err(WouldBlock),
+        }
+    }
+
+    /// Returns a mutable reference to the underlying data.
+    ///
+    /// Since this call borrows the Mutex mutably, no actual locking needs to
+    /// take place -- the mutable borrow statically guarantees no locks exist.
+    pub fn get_mut(&mut self) -> &mut T {
+        match self.std.get_mut() {
+            Ok(value) => value,
+            Err(_) => panic!("mutex is poisoned"),
+        }
+    }
+}
+
+impl<T> From<T> for Mutex<T> {
+    fn from(value: T) -> Self {
+        Mutex {
+            std: StdMutex::from(value),
+        }
+    }
+}
+
+impl<T: ?Sized + Debug> Debug for Mutex<T> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        Debug::fmt(&self.std, formatter)
+    }
+}
+
+/// The lock could not be acquired at this time because the operation would
+/// otherwise block.
+///
+/// Error returned by Mutex::try_lock.
+#[derive(Debug)]
+pub struct WouldBlock;
+
+impl Display for WouldBlock {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        Display::fmt(&TryLockError::WouldBlock::<()>, formatter)
+    }
+}
+
+impl std::error::Error for WouldBlock {}
diff --git a/sys_util/Cargo.toml b/sys_util/Cargo.toml
new file mode 100644
index 0000000..00e39fa
--- /dev/null
+++ b/sys_util/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "sys_util"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+include = ["src/**/*", "Cargo.toml"]
+
+[dependencies]
+data_model = { path = "../data_model" } # provided by ebuild
+libc = "*"
+poll_token_derive = { version = "*", path = "poll_token_derive" }
+sync = { path = "../sync" } # provided by ebuild
+syscall_defines = { path = "../syscall_defines" } # provided by ebuild
+
+[workspace]
diff --git a/sys_util/poll_token_derive/Cargo.toml b/sys_util/poll_token_derive/Cargo.toml
new file mode 100644
index 0000000..45c4552
--- /dev/null
+++ b/sys_util/poll_token_derive/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "poll_token_derive"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+include = ["*.rs", "Cargo.toml"]
+
+[lib]
+proc-macro = true
+path = "poll_token_derive.rs"
+
+[dependencies]
+proc-macro2 = "0.4"
+quote = "0.6"
+syn = "0.15"
diff --git a/sys_util/poll_token_derive/poll_token_derive.rs b/sys_util/poll_token_derive/poll_token_derive.rs
new file mode 100644
index 0000000..7b7baac
--- /dev/null
+++ b/sys_util/poll_token_derive/poll_token_derive.rs
@@ -0,0 +1,172 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![recursion_limit = "128"]
+
+extern crate proc_macro;
+
+use proc_macro2::{Ident, TokenStream};
+use quote::quote;
+use syn::{parse_macro_input, Data, DeriveInput, Field, Fields, Index, Member, Variant};
+
+#[cfg(test)]
+mod tests;
+
+// The method for packing an enum into a u64 is as follows:
+// 1) Reserve the lowest "ceil(log_2(x))" bits where x is the number of enum variants.
+// 2) Store the enum variant's index (0-based index based on order in the enum definition) in
+//    reserved bits.
+// 3) If there is data in the enum variant, store the data in remaining bits.
+// The method for unpacking is as follows
+// 1) Mask the raw token to just the reserved bits
+// 2) Match the reserved bits to the enum variant token.
+// 3) If the indicated enum variant had data, extract it from the unreserved bits.
+
+// Calculates the number of bits needed to store the variant index. Essentially the log base 2
+// of the number of variants, rounded up.
+fn variant_bits(variants: &[Variant]) -> u32 {
+    if variants.is_empty() {
+        // The degenerate case of no variants.
+        0
+    } else {
+        variants.len().next_power_of_two().trailing_zeros()
+    }
+}
+
+// Name of the field if it has one, otherwise 0 assuming this is the zeroth
+// field of a tuple variant.
+fn field_member(field: &Field) -> Member {
+    match &field.ident {
+        Some(name) => Member::Named(name.clone()),
+        None => Member::Unnamed(Index::from(0)),
+    }
+}
+
+// Generates the function body for `as_raw_token`.
+fn generate_as_raw_token(enum_name: &Ident, variants: &[Variant]) -> TokenStream {
+    let variant_bits = variant_bits(variants);
+
+    // Each iteration corresponds to one variant's match arm.
+    let cases = variants.iter().enumerate().map(|(index, variant)| {
+        let variant_name = &variant.ident;
+        let index = index as u64;
+
+        // The capture string is for everything between the variant identifier and the `=>` in
+        // the match arm: the variant's data capture.
+        let capture = variant.fields.iter().next().map(|field| {
+            let member = field_member(&field);
+            quote!({ #member: data })
+        });
+
+        // The modifier string ORs the variant index with extra bits from the variant data
+        // field.
+        let modifier = match variant.fields {
+            Fields::Named(_) | Fields::Unnamed(_) => Some(quote! {
+                | ((data as u64) << #variant_bits)
+            }),
+            Fields::Unit => None,
+        };
+
+        // Assembly of the match arm.
+        quote! {
+            #enum_name::#variant_name #capture => #index #modifier
+        }
+    });
+
+    quote! {
+        match *self {
+            #(
+                #cases,
+            )*
+        }
+    }
+}
+
+// Generates the function body for `from_raw_token`.
+fn generate_from_raw_token(enum_name: &Ident, variants: &[Variant]) -> TokenStream {
+    let variant_bits = variant_bits(variants);
+    let variant_mask = ((1 << variant_bits) - 1) as u64;
+
+    // Each iteration corresponds to one variant's match arm.
+    let cases = variants.iter().enumerate().map(|(index, variant)| {
+        let variant_name = &variant.ident;
+        let index = index as u64;
+
+        // The data string is for extracting the enum variant's data bits out of the raw token
+        // data, which includes both variant index and data bits.
+        let data = variant.fields.iter().next().map(|field| {
+            let member = field_member(&field);
+            let ty = &field.ty;
+            quote!({ #member: (data >> #variant_bits) as #ty })
+        });
+
+        // Assembly of the match arm.
+        quote! {
+            #index => #enum_name::#variant_name #data
+        }
+    });
+
+    quote! {
+        // The match expression only matches the bits for the variant index.
+        match data & #variant_mask {
+            #(
+                #cases,
+            )*
+            _ => unreachable!(),
+        }
+    }
+}
+
+// The proc_macro::TokenStream type can only be constructed from within a
+// procedural macro, meaning that unit tests are not able to invoke `fn
+// poll_token` below as an ordinary Rust function. We factor out the logic into
+// a signature that deals with Syn and proc-macro2 types only which are not
+// restricted to a procedural macro invocation.
+fn poll_token_inner(input: DeriveInput) -> TokenStream {
+    let variants: Vec<Variant> = match input.data {
+        Data::Enum(data) => data.variants.into_iter().collect(),
+        Data::Struct(_) | Data::Union(_) => panic!("input must be an enum"),
+    };
+
+    for variant in &variants {
+        assert!(variant.fields.iter().count() <= 1);
+    }
+
+    // Given our basic model of a user given enum that is suitable as a token, we generate the
+    // implementation. The implementation is NOT always well formed, such as when a variant's data
+    // type is not bit shiftable or castable to u64, but we let Rust generate such errors as it
+    // would be difficult to detect every kind of error. Importantly, every implementation that we
+    // generate here and goes on to compile succesfully is sound.
+
+    let enum_name = input.ident;
+    let as_raw_token = generate_as_raw_token(&enum_name, &variants);
+    let from_raw_token = generate_from_raw_token(&enum_name, &variants);
+
+    quote! {
+        impl PollToken for #enum_name {
+            fn as_raw_token(&self) -> u64 {
+                #as_raw_token
+            }
+
+            fn from_raw_token(data: u64) -> Self {
+                #from_raw_token
+            }
+        }
+    }
+}
+
+/// Implements the PollToken trait for a given `enum`.
+///
+/// There are limitations on what `enum`s this custom derive will work on:
+///
+/// * Each variant must be a unit variant (no data), or have a single (un)named data field.
+/// * If a variant has data, it must be a primitive type castable to and from a `u64`.
+/// * If a variant data has size greater than or equal to a `u64`, its most significant bits must be
+///   zero. The number of bits truncated is equal to the number of bits used to store the variant
+///   index plus the number of bits above 64.
+#[proc_macro_derive(PollToken)]
+pub fn poll_token(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let input = parse_macro_input!(input as DeriveInput);
+    poll_token_inner(input).into()
+}
diff --git a/sys_util/poll_token_derive/tests.rs b/sys_util/poll_token_derive/tests.rs
new file mode 100644
index 0000000..935f91c
--- /dev/null
+++ b/sys_util/poll_token_derive/tests.rs
@@ -0,0 +1,65 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use quote::quote;
+use syn::{parse_quote, DeriveInput};
+
+#[test]
+fn test_variant_bits() {
+    let mut variants = vec![parse_quote!(A)];
+    assert_eq!(crate::variant_bits(&variants), 0);
+
+    variants.push(parse_quote!(B));
+    variants.push(parse_quote!(C));
+    assert_eq!(crate::variant_bits(&variants), 2);
+
+    for _ in 0..1021 {
+        variants.push(parse_quote!(Dynamic));
+    }
+    assert_eq!(crate::variant_bits(&variants), 10);
+
+    variants.push(parse_quote!(OneMore));
+    assert_eq!(crate::variant_bits(&variants), 11);
+}
+
+#[test]
+fn poll_token_e2e() {
+    let input: DeriveInput = parse_quote! {
+        enum Token {
+            A,
+            B,
+            C,
+            D(usize),
+            E { foobaz: u32 },
+        }
+    };
+
+    let actual = crate::poll_token_inner(input);
+    let expected = quote! {
+        impl PollToken for Token {
+            fn as_raw_token(&self) -> u64 {
+                match *self {
+                    Token::A => 0u64,
+                    Token::B => 1u64,
+                    Token::C => 2u64,
+                    Token::D { 0: data } => 3u64 | ((data as u64) << 3u32),
+                    Token::E { foobaz: data } => 4u64 | ((data as u64) << 3u32),
+                }
+            }
+
+            fn from_raw_token(data: u64) -> Self {
+                match data & 7u64 {
+                    0u64 => Token::A,
+                    1u64 => Token::B,
+                    2u64 => Token::C,
+                    3u64 => Token::D { 0: (data >> 3u32) as usize },
+                    4u64 => Token::E { foobaz: (data >> 3u32) as u32 },
+                    _ => unreachable!(),
+                }
+            }
+        }
+    };
+
+    assert_eq!(actual.to_string(), expected.to_string());
+}
diff --git a/sys_util/src/affinity.rs b/sys_util/src/affinity.rs
new file mode 100644
index 0000000..d91d3da
--- /dev/null
+++ b/sys_util/src/affinity.rs
@@ -0,0 +1,64 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Wrappers for CPU affinity functions.
+
+use std::iter::FromIterator;
+use std::mem;
+
+use libc::{cpu_set_t, sched_setaffinity, CPU_SET, CPU_SETSIZE, CPU_ZERO, EINVAL};
+
+use crate::{errno_result, Error, Result};
+
+// This is needed because otherwise the compiler will complain that the
+// impl doesn't reference any types from inside this crate.
+struct CpuSet(cpu_set_t);
+
+impl FromIterator<usize> for CpuSet {
+    fn from_iter<I: IntoIterator<Item = usize>>(cpus: I) -> Self {
+        // cpu_set_t is a C struct and can be safely initialized with zeroed memory.
+        let mut cpuset: cpu_set_t = unsafe { mem::zeroed() };
+        // Safe because we pass a valid cpuset pointer.
+        unsafe { CPU_ZERO(&mut cpuset) };
+        for cpu in cpus {
+            // Safe because we pass a valid cpuset pointer and cpu index.
+            unsafe { CPU_SET(cpu, &mut cpuset) };
+        }
+        CpuSet(cpuset)
+    }
+}
+
+/// Set the CPU affinity of the current thread to a given set of CPUs.
+///
+/// # Examples
+///
+/// Set the calling thread's CPU affinity so it will run on only CPUs
+/// 0, 1, 5, and 6.
+///
+/// ```
+/// # use sys_util::set_cpu_affinity;
+///   set_cpu_affinity(vec![0, 1, 5, 6]).unwrap();
+/// ```
+pub fn set_cpu_affinity<I: IntoIterator<Item = usize>>(cpus: I) -> Result<()> {
+    let CpuSet(cpuset) = cpus
+        .into_iter()
+        .map(|cpu| {
+            if cpu < CPU_SETSIZE as usize {
+                Ok(cpu)
+            } else {
+                Err(Error::new(EINVAL))
+            }
+        })
+        .collect::<Result<CpuSet>>()?;
+
+    // Safe because we pass 0 for the current thread, and cpuset is a valid pointer and only
+    // used for the duration of this call.
+    let res = unsafe { sched_setaffinity(0, mem::size_of_val(&cpuset), &cpuset) };
+
+    if res != 0 {
+        errno_result()
+    } else {
+        Ok(())
+    }
+}
diff --git a/sys_util/src/alloc.rs b/sys_util/src/alloc.rs
new file mode 100644
index 0000000..8ac9100
--- /dev/null
+++ b/sys_util/src/alloc.rs
@@ -0,0 +1,123 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::alloc::{alloc, alloc_zeroed, dealloc, Layout};
+
+/// A contiguous memory allocation with a specified size and alignment, with a
+/// Drop impl to perform the deallocation.
+///
+/// Conceptually this is like a Box<[u8]> but for which we can select a minimum
+/// required alignment at the time of allocation.
+///
+/// # Example
+///
+/// ```
+/// use std::alloc::Layout;
+/// use std::mem;
+/// use sys_util::LayoutAllocation;
+///
+/// #[repr(C)]
+/// struct Header {
+///     q: usize,
+///     entries: [Entry; 0], // flexible array member
+/// }
+///
+/// #[repr(C)]
+/// struct Entry {
+///     e: usize,
+/// }
+///
+/// fn demo(num_entries: usize) {
+///     let size = mem::size_of::<Header>() + num_entries * mem::size_of::<Entry>();
+///     let layout = Layout::from_size_align(size, mem::align_of::<Header>()).unwrap();
+///     let mut allocation = LayoutAllocation::zeroed(layout);
+///
+///     // Safe to obtain an exclusive reference because there are no other
+///     // references to the allocation yet and all-zero is a valid bit pattern for
+///     // our header.
+///     let header = unsafe { allocation.as_mut::<Header>() };
+/// }
+/// ```
+pub struct LayoutAllocation {
+    ptr: *mut u8,
+    layout: Layout,
+}
+
+impl LayoutAllocation {
+    /// Allocates memory with the specified size and alignment. The content is
+    /// not initialized.
+    ///
+    /// Uninitialized data is not safe to read. Further, it is not safe to
+    /// obtain a reference to data potentially holding a bit pattern
+    /// incompatible with its type, for example an uninitialized bool or enum.
+    pub fn uninitialized(layout: Layout) -> Self {
+        let ptr = if layout.size() > 0 {
+            unsafe {
+                // Safe as long as we guarantee layout.size() > 0.
+                alloc(layout)
+            }
+        } else {
+            layout.align() as *mut u8
+        };
+        LayoutAllocation { ptr, layout }
+    }
+
+    /// Allocates memory with the specified size and alignment and initializes
+    /// the content to all zero-bytes.
+    ///
+    /// Note that zeroing the memory does not necessarily make it safe to obtain
+    /// a reference to the allocation. Depending on the intended type T,
+    /// all-zero may or may not be a legal bit pattern for that type. For
+    /// example obtaining a reference would immediately be undefined behavior if
+    /// one of the fields has type NonZeroUsize.
+    pub fn zeroed(layout: Layout) -> Self {
+        let ptr = if layout.size() > 0 {
+            unsafe {
+                // Safe as long as we guarantee layout.size() > 0.
+                alloc_zeroed(layout)
+            }
+        } else {
+            layout.align() as *mut u8
+        };
+        LayoutAllocation { ptr, layout }
+    }
+
+    /// Returns a raw pointer to the allocated data.
+    pub fn as_ptr<T>(&self) -> *mut T {
+        self.ptr as *mut T
+    }
+
+    /// Returns a shared reference to the allocated data.
+    ///
+    /// # Safety
+    ///
+    /// Caller is responsible for ensuring that the data behind this pointer has
+    /// been initialized as much as necessary and that there are no already
+    /// existing mutable references to any part of the data.
+    pub unsafe fn as_ref<T>(&self) -> &T {
+        &*self.as_ptr()
+    }
+
+    /// Returns an exclusive reference to the allocated data.
+    ///
+    /// # Safety
+    ///
+    /// Caller is responsible for ensuring that the data behind this pointer has
+    /// been initialized as much as necessary and that there are no already
+    /// existing references to any part of the data.
+    pub unsafe fn as_mut<T>(&mut self) -> &mut T {
+        &mut *self.as_ptr()
+    }
+}
+
+impl Drop for LayoutAllocation {
+    fn drop(&mut self) {
+        if self.layout.size() > 0 {
+            unsafe {
+                // Safe as long as we guarantee layout.size() > 0.
+                dealloc(self.ptr, self.layout);
+            }
+        }
+    }
+}
diff --git a/sys_util/src/capabilities.rs b/sys_util/src/capabilities.rs
new file mode 100644
index 0000000..90b8784
--- /dev/null
+++ b/sys_util/src/capabilities.rs
@@ -0,0 +1,41 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use libc::{c_int, c_void};
+
+use crate::{errno_result, Result};
+
+#[allow(non_camel_case_types)]
+type cap_t = *mut c_void;
+
+#[link(name = "cap")]
+extern "C" {
+    fn cap_init() -> cap_t;
+    fn cap_free(ptr: *mut c_void) -> c_int;
+    fn cap_set_proc(cap: cap_t) -> c_int;
+}
+
+/// Drops all capabilities (permitted, inheritable, and effective) from the current process.
+pub fn drop_capabilities() -> Result<()> {
+    unsafe {
+        // Safe because we do not actually manipulate any memory handled by libcap
+        // and we check errors.
+        let caps = cap_init();
+        if caps.is_null() {
+            return errno_result();
+        }
+
+        // Freshly initialized capabilities do not have any bits set, so applying them
+        // will drop all capabilities from the process.
+        // Safe because we will check the result and otherwise do not touch the memory.
+        let ret = cap_set_proc(caps);
+        // We need to free capabilities regardless of success of the operation above.
+        cap_free(caps);
+        // Now check if we managed to apply (drop) capabilities.
+        if ret < 0 {
+            return errno_result();
+        }
+    }
+    Ok(())
+}
diff --git a/sys_util/src/clock.rs b/sys_util/src/clock.rs
new file mode 100644
index 0000000..878014d
--- /dev/null
+++ b/sys_util/src/clock.rs
@@ -0,0 +1,96 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Utility file to provide a fake clock object representing current time, and a timerfd driven by
+// that time.
+
+use std::os::unix::io::AsRawFd;
+use std::time::{Duration, Instant};
+
+use crate::EventFd;
+
+#[derive(Debug, Copy, Clone)]
+pub struct Clock(Instant);
+impl Clock {
+    pub fn new() -> Self {
+        Clock(Instant::now())
+    }
+
+    pub fn now(&self) -> Self {
+        Clock(Instant::now())
+    }
+
+    pub fn duration_since(&self, earlier: &Self) -> Duration {
+        self.0.duration_since(earlier.0)
+    }
+}
+
+impl Default for Clock {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+const NS_PER_SEC: u64 = 1_000_000_000;
+/// A fake clock that can be used in tests to give exact control over the time.
+/// For a code example, see the tests in sys_util/src/timerfd.rs.
+#[derive(Debug)]
+pub struct FakeClock {
+    ns_since_epoch: u64,
+    deadlines: Vec<(u64, EventFd)>,
+}
+
+impl FakeClock {
+    pub fn new() -> Self {
+        FakeClock {
+            ns_since_epoch: 1_547_163_599 * NS_PER_SEC,
+            deadlines: Vec::new(),
+        }
+    }
+
+    /// Get the current time, according to this clock.
+    pub fn now(&self) -> Self {
+        FakeClock {
+            ns_since_epoch: self.ns_since_epoch,
+            deadlines: Vec::new(),
+        }
+    }
+
+    ///  Get the current time in ns, according to this clock.
+    pub fn nanos(&self) -> u64 {
+        self.ns_since_epoch
+    }
+
+    /// Get the duration since |earlier|, assuming that earlier < self.
+    pub fn duration_since(&self, earlier: &Self) -> Duration {
+        let ns_diff = self.ns_since_epoch - earlier.ns_since_epoch;
+        Duration::new(ns_diff / NS_PER_SEC, (ns_diff % NS_PER_SEC) as u32)
+    }
+
+    /// Register the event fd for a notification when self's time is |deadline_ns|.
+    /// Drop any existing events registered to the same raw fd.
+    pub fn add_event_fd(&mut self, deadline_ns: u64, fd: EventFd) {
+        self.deadlines
+            .retain(|(_, old_fd)| fd.as_raw_fd() != old_fd.as_raw_fd());
+        self.deadlines.push((deadline_ns, fd));
+    }
+
+    pub fn add_ns(&mut self, ns: u64) {
+        self.ns_since_epoch += ns;
+        let time = self.ns_since_epoch;
+        self.deadlines.retain(|(ns, fd)| {
+            let expired = *ns <= time;
+            if expired {
+                fd.write(1).unwrap();
+            }
+            !expired
+        });
+    }
+}
+
+impl Default for FakeClock {
+    fn default() -> Self {
+        Self::new()
+    }
+}
diff --git a/sys_util/src/errno.rs b/sys_util/src/errno.rs
new file mode 100644
index 0000000..cf54aae
--- /dev/null
+++ b/sys_util/src/errno.rs
@@ -0,0 +1,64 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fmt::{self, Display};
+use std::io;
+use std::result;
+
+use libc::__errno_location;
+
+/// An error number, retrieved from errno (man 3 errno), set by a libc
+/// function that returned an error.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct Error(i32);
+pub type Result<T> = result::Result<T, Error>;
+
+impl Error {
+    /// Constructs a new error with the given errno.
+    pub fn new(e: i32) -> Error {
+        Error(e)
+    }
+
+    /// Constructs an error from the current errno.
+    ///
+    /// The result of this only has any meaning just after a libc call that returned a value
+    /// indicating errno was set.
+    pub fn last() -> Error {
+        Error(unsafe { *__errno_location() })
+    }
+
+    /// Gets the errno for this error
+    pub fn errno(self) -> i32 {
+        self.0
+    }
+}
+
+impl From<io::Error> for Error {
+    fn from(e: io::Error) -> Self {
+        Error::new(e.raw_os_error().unwrap_or_default())
+    }
+}
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        io::Error::from_raw_os_error(self.0).fmt(f)
+    }
+}
+
+/// Returns the last errno as a Result that is always an error.
+pub fn errno_result<T>() -> Result<T> {
+    Err(Error::last())
+}
+
+/// Sets errno to given error code.
+/// Only defined when we compile tests as normal code does not
+/// normally need set errno.
+#[cfg(test)]
+pub fn set_errno(e: i32) {
+    unsafe {
+        *__errno_location() = e;
+    }
+}
diff --git a/sys_util/src/eventfd.rs b/sys_util/src/eventfd.rs
new file mode 100644
index 0000000..fc1ead2
--- /dev/null
+++ b/sys_util/src/eventfd.rs
@@ -0,0 +1,132 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fs::File;
+use std::mem;
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+
+use libc::{c_void, dup, eventfd, read, write};
+
+use crate::{errno_result, Result};
+
+/// A safe wrapper around a Linux eventfd (man 2 eventfd).
+///
+/// An eventfd is useful because it is sendable across processes and can be used for signaling in
+/// and out of the KVM API. They can also be polled like any other file descriptor.
+#[derive(Debug)]
+pub struct EventFd {
+    eventfd: File,
+}
+
+impl EventFd {
+    /// Creates a new blocking EventFd with an initial value of 0.
+    pub fn new() -> Result<EventFd> {
+        // This is safe because eventfd merely allocated an eventfd for our process and we handle
+        // the error case.
+        let ret = unsafe { eventfd(0, 0) };
+        if ret < 0 {
+            return errno_result();
+        }
+        // This is safe because we checked ret for success and know the kernel gave us an fd that we
+        // own.
+        Ok(EventFd {
+            eventfd: unsafe { File::from_raw_fd(ret) },
+        })
+    }
+
+    /// Adds `v` to the eventfd's count, blocking until this won't overflow the count.
+    pub fn write(&self, v: u64) -> Result<()> {
+        // This is safe because we made this fd and the pointer we pass can not overflow because we
+        // give the syscall's size parameter properly.
+        let ret = unsafe {
+            write(
+                self.as_raw_fd(),
+                &v as *const u64 as *const c_void,
+                mem::size_of::<u64>(),
+            )
+        };
+        if ret <= 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// Blocks until the the eventfd's count is non-zero, then resets the count to zero.
+    pub fn read(&self) -> Result<u64> {
+        let mut buf: u64 = 0;
+        let ret = unsafe {
+            // This is safe because we made this fd and the pointer we pass can not overflow because
+            // we give the syscall's size parameter properly.
+            read(
+                self.as_raw_fd(),
+                &mut buf as *mut u64 as *mut c_void,
+                mem::size_of::<u64>(),
+            )
+        };
+        if ret <= 0 {
+            return errno_result();
+        }
+        Ok(buf)
+    }
+
+    /// Clones this EventFd, internally creating a new file descriptor. The new EventFd will share
+    /// the same underlying count within the kernel.
+    pub fn try_clone(&self) -> Result<EventFd> {
+        // This is safe because we made this fd and properly check that it returns without error.
+        let ret = unsafe { dup(self.as_raw_fd()) };
+        if ret < 0 {
+            return errno_result();
+        }
+        // This is safe because we checked ret for success and know the kernel gave us an fd that we
+        // own.
+        Ok(EventFd {
+            eventfd: unsafe { File::from_raw_fd(ret) },
+        })
+    }
+}
+
+impl AsRawFd for EventFd {
+    fn as_raw_fd(&self) -> RawFd {
+        self.eventfd.as_raw_fd()
+    }
+}
+
+impl FromRawFd for EventFd {
+    unsafe fn from_raw_fd(fd: RawFd) -> Self {
+        EventFd {
+            eventfd: File::from_raw_fd(fd),
+        }
+    }
+}
+
+impl IntoRawFd for EventFd {
+    fn into_raw_fd(self) -> RawFd {
+        self.eventfd.into_raw_fd()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn new() {
+        EventFd::new().unwrap();
+    }
+
+    #[test]
+    fn read_write() {
+        let evt = EventFd::new().unwrap();
+        evt.write(55).unwrap();
+        assert_eq!(evt.read(), Ok(55));
+    }
+
+    #[test]
+    fn clone() {
+        let evt = EventFd::new().unwrap();
+        let evt_clone = evt.try_clone().unwrap();
+        evt.write(923).unwrap();
+        assert_eq!(evt_clone.read(), Ok(923));
+    }
+}
diff --git a/sys_util/src/file_flags.rs b/sys_util/src/file_flags.rs
new file mode 100644
index 0000000..7a2ad1b
--- /dev/null
+++ b/sys_util/src/file_flags.rs
@@ -0,0 +1,53 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::os::unix::io::AsRawFd;
+
+use libc::{fcntl, EINVAL, F_GETFL, O_ACCMODE, O_RDONLY, O_RDWR, O_WRONLY};
+
+use crate::{errno_result, Error, Result};
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum FileFlags {
+    Read,
+    Write,
+    ReadWrite,
+}
+
+impl FileFlags {
+    pub fn from_file(file: &dyn AsRawFd) -> Result<FileFlags> {
+        // Trivially safe because fcntl with the F_GETFL command is totally safe and we check for
+        // error.
+        let flags = unsafe { fcntl(file.as_raw_fd(), F_GETFL) };
+        if flags == -1 {
+            errno_result()
+        } else {
+            match flags & O_ACCMODE {
+                O_RDONLY => Ok(FileFlags::Read),
+                O_WRONLY => Ok(FileFlags::Write),
+                O_RDWR => Ok(FileFlags::ReadWrite),
+                _ => Err(Error::new(EINVAL)),
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::{pipe, EventFd};
+
+    #[test]
+    fn pipe_pair() {
+        let (read_pipe, write_pipe) = pipe(true).unwrap();
+        assert_eq!(FileFlags::from_file(&read_pipe).unwrap(), FileFlags::Read);
+        assert_eq!(FileFlags::from_file(&write_pipe).unwrap(), FileFlags::Write);
+    }
+
+    #[test]
+    fn eventfd() {
+        let evt = EventFd::new().unwrap();
+        assert_eq!(FileFlags::from_file(&evt).unwrap(), FileFlags::ReadWrite);
+    }
+}
diff --git a/sys_util/src/file_traits.rs b/sys_util/src/file_traits.rs
new file mode 100644
index 0000000..584ac9a
--- /dev/null
+++ b/sys_util/src/file_traits.rs
@@ -0,0 +1,119 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fs::File;
+use std::io::{Error, ErrorKind, Result};
+use std::os::unix::io::AsRawFd;
+
+use data_model::VolatileSlice;
+
+use libc::{c_void, read, write};
+
+/// A trait for flushing the contents of a file to disk.
+/// This is equivalent to File's `sync_all` method, but
+/// wrapped in a trait so that it can be implemented for
+/// other types.
+pub trait FileSync {
+    // Flush buffers related to this file to disk.
+    fn fsync(&mut self) -> Result<()>;
+}
+
+impl FileSync for File {
+    fn fsync(&mut self) -> Result<()> {
+        self.sync_all()
+    }
+}
+
+/// A trait for setting the size of a file.
+/// This is equivalent to File's `set_len` method, but
+/// wrapped in a trait so that it can be implemented for
+/// other types.
+pub trait FileSetLen {
+    // Set the size of this file.
+    // This is the moral equivalent of `ftruncate()`.
+    fn set_len(&self, _len: u64) -> Result<()>;
+}
+
+impl FileSetLen for File {
+    fn set_len(&self, len: u64) -> Result<()> {
+        File::set_len(self, len)
+    }
+}
+
+/// A trait similar to `Read` and `Write`, but uses volatile memory as buffers.
+pub trait FileReadWriteVolatile {
+    /// Read bytes from this file into the given slice, returning the number of bytes read on
+    /// success.
+    fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>;
+
+    /// Reads bytes from this into the given slice until all bytes in the slice are written, or an
+    /// error is returned.
+    fn read_exact_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> {
+        while slice.size() > 0 {
+            let bytes_read = self.read_volatile(slice)?;
+            if bytes_read == 0 {
+                return Err(Error::from(ErrorKind::UnexpectedEof));
+            }
+            // Will panic if read_volatile read more bytes than we gave it, which would be worthy of
+            // a panic.
+            slice = slice.offset(bytes_read as u64).unwrap();
+        }
+        Ok(())
+    }
+
+    /// Write bytes from the slice to the given file, returning the number of bytes written on
+    /// success.
+    fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>;
+
+    /// Write bytes from the slice to the given file until all the bytes from the slice have been
+    /// written, or an error is returned.
+    fn write_all_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> {
+        while slice.size() > 0 {
+            let bytes_written = self.write_volatile(slice)?;
+            if bytes_written == 0 {
+                return Err(Error::from(ErrorKind::WriteZero));
+            }
+            // Will panic if read_volatile read more bytes than we gave it, which would be worthy of
+            // a panic.
+            slice = slice.offset(bytes_written as u64).unwrap();
+        }
+        Ok(())
+    }
+}
+
+impl FileReadWriteVolatile for File {
+    fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
+        // Safe because only bytes inside the slice are accessed and the kernel is expected to
+        // handle arbitrary memory for I/O.
+        let ret = unsafe {
+            read(
+                self.as_raw_fd(),
+                slice.as_ptr() as *mut c_void,
+                slice.size() as usize,
+            )
+        };
+        if ret >= 0 {
+            Ok(ret as usize)
+        } else {
+            Err(Error::last_os_error())
+        }
+    }
+
+    fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
+        // Safe because only bytes inside the slice are accessed and the kernel is expected to
+        // handle arbitrary memory for I/O.
+        let ret = unsafe {
+            write(
+                self.as_raw_fd(),
+                slice.as_ptr() as *const c_void,
+                slice.size() as usize,
+            )
+        };
+        if ret >= 0 {
+            Ok(ret as usize)
+        } else {
+            Err(Error::last_os_error())
+        }
+    }
+}
diff --git a/sys_util/src/fork.rs b/sys_util/src/fork.rs
new file mode 100644
index 0000000..98a22f0
--- /dev/null
+++ b/sys_util/src/fork.rs
@@ -0,0 +1,148 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fs;
+use std::io;
+use std::path::Path;
+use std::process;
+use std::result;
+
+use libc::{c_long, pid_t, syscall, CLONE_NEWPID, CLONE_NEWUSER, SIGCHLD};
+use syscall_defines::linux::LinuxSyscall::SYS_clone;
+
+use crate::errno_result;
+
+/// Controls what namespace `clone_process` will have. See NAMESPACES(7).
+#[repr(u32)]
+pub enum CloneNamespace {
+    /// The new process will inherit the namespace from the old process.
+    Inherit = 0,
+    /// The new process with be in a new user and PID namespace.
+    NewUserPid = CLONE_NEWUSER as u32 | CLONE_NEWPID as u32,
+}
+
+#[derive(Debug)]
+pub enum CloneError {
+    /// There was an error trying to iterate this process's threads.
+    IterateTasks(io::Error),
+    /// There are multiple threads running. The `usize` indicates how many threads.
+    Multithreaded(usize),
+    /// There was an error while cloning.
+    Sys(crate::Error),
+}
+
+unsafe fn do_clone(flags: i32) -> crate::Result<pid_t> {
+    // Forking is unsafe, this function must be unsafe as there is no way to guarantee safety
+    // without more context about the state of the program.
+    let pid = syscall(SYS_clone as c_long, flags | SIGCHLD as i32, 0);
+    if pid < 0 {
+        errno_result()
+    } else {
+        Ok(pid as pid_t)
+    }
+}
+
+fn count_dir_entries<P: AsRef<Path>>(path: P) -> io::Result<usize> {
+    Ok(fs::read_dir(path)?.count())
+}
+
+/// Clones this process and calls a closure in the new process.
+///
+/// After `post_clone_cb` returns or panics, the new process exits. Similar to how a `fork` syscall
+/// works, the new process is the same as the current process with the exception of the namespace
+/// controlled with the `ns` argument.
+///
+/// # Arguments
+/// * `ns` - What namespace the new process will have (see NAMESPACES(7)).
+/// * `post_clone_cb` - Callback to run in the new process
+pub fn clone_process<F>(ns: CloneNamespace, post_clone_cb: F) -> result::Result<pid_t, CloneError>
+where
+    F: FnOnce(),
+{
+    match count_dir_entries("/proc/self/task") {
+        Ok(1) => {}
+        Ok(thread_count) => {
+            // Test cfg gets a free pass on this because tests generally have multiple independent
+            // test threads going.
+            let _ = thread_count;
+            #[cfg(not(test))]
+            return Err(CloneError::Multithreaded(thread_count));
+        }
+        Err(e) => return Err(CloneError::IterateTasks(e)),
+    }
+    // Forking is considered unsafe in mutlithreaded programs, but we just checked for other threads
+    // in this process. We also only allow valid flags from CloneNamespace and check the return
+    // result for errors. We also never let the cloned process return from this function.
+    let ret = unsafe { do_clone(ns as i32) }.map_err(CloneError::Sys)?;
+    if ret == 0 {
+        struct ExitGuard;
+        impl Drop for ExitGuard {
+            fn drop(&mut self) {
+                process::exit(101);
+            }
+        }
+        // Prevents a panic in post_clone_cb from bypassing the process::exit.
+        #[allow(unused_variables)]
+        let exit_guard = ExitGuard {};
+        post_clone_cb();
+        // ! Never returns
+        process::exit(0);
+    }
+
+    Ok(ret)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::{getpid, EventFd};
+    use libc;
+
+    fn wait_process(pid: libc::pid_t) -> crate::Result<libc::c_int> {
+        let mut status: libc::c_int = 0;
+        unsafe {
+            if libc::waitpid(pid, &mut status as *mut libc::c_int, 0) < 0 {
+                errno_result()
+            } else {
+                Ok(libc::WEXITSTATUS(status))
+            }
+        }
+    }
+
+    #[test]
+    fn pid_diff() {
+        let evt_fd = EventFd::new().expect("failed to create EventFd");
+        let evt_fd_fork = evt_fd.try_clone().expect("failed to clone EventFd");
+        let pid = getpid();
+        clone_process(CloneNamespace::Inherit, || {
+            // checks that this is a genuine fork with a new PID
+            if pid != getpid() {
+                evt_fd_fork.write(1).unwrap()
+            } else {
+                evt_fd_fork.write(2).unwrap()
+            }
+        })
+        .expect("failed to clone");
+        assert_eq!(evt_fd.read(), Ok(1));
+    }
+
+    #[test]
+    fn panic_safe() {
+        let pid = getpid();
+        assert_ne!(pid, 0);
+
+        let clone_pid = clone_process(CloneNamespace::Inherit, || {
+            assert!(false);
+        })
+        .expect("failed to clone");
+
+        // This should never happen;
+        if pid != getpid() {
+            process::exit(2);
+        }
+
+        let status = wait_process(clone_pid).expect("wait_process failed");
+        assert!(status == 101 || status == 0);
+    }
+}
diff --git a/sys_util/src/guest_address.rs b/sys_util/src/guest_address.rs
new file mode 100644
index 0000000..1b78e71
--- /dev/null
+++ b/sys_util/src/guest_address.rs
@@ -0,0 +1,144 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Represents an address in the guest's memory space.
+
+use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
+use std::fmt::{self, Display};
+use std::ops::{BitAnd, BitOr};
+
+/// Represents an Address in the guest's memory.
+#[derive(Clone, Copy, Debug)]
+pub struct GuestAddress(pub u64);
+
+impl GuestAddress {
+    /// Returns the offset from this address to the given base address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use sys_util::GuestAddress;
+    ///   let base = GuestAddress(0x100);
+    ///   let addr = GuestAddress(0x150);
+    ///   assert_eq!(addr.offset_from(base), 0x50u64);
+    /// ```
+    pub fn offset_from(self, base: GuestAddress) -> u64 {
+        self.0 - base.0
+    }
+
+    /// Returns the address as a u64 offset from 0x0.
+    /// Use this when a raw number is needed to pass to the kernel.
+    pub fn offset(self) -> u64 {
+        self.0
+    }
+
+    /// Returns the result of the add or None if there is overflow.
+    pub fn checked_add(self, other: u64) -> Option<GuestAddress> {
+        self.0.checked_add(other).map(GuestAddress)
+    }
+
+    /// Returns the result of the base address + the size.
+    /// Only use this when `offset` is guaranteed not to overflow.
+    pub fn unchecked_add(self, offset: u64) -> GuestAddress {
+        GuestAddress(self.0 + offset)
+    }
+
+    /// Returns the result of the subtraction of None if there is underflow.
+    pub fn checked_sub(self, other: u64) -> Option<GuestAddress> {
+        self.0.checked_sub(other).map(GuestAddress)
+    }
+
+    /// Returns the bitwise and of the address with the given mask.
+    pub fn mask(self, mask: u64) -> GuestAddress {
+        GuestAddress(self.0 & mask as u64)
+    }
+}
+
+impl BitAnd<u64> for GuestAddress {
+    type Output = GuestAddress;
+
+    fn bitand(self, other: u64) -> GuestAddress {
+        GuestAddress(self.0 & other as u64)
+    }
+}
+
+impl BitOr<u64> for GuestAddress {
+    type Output = GuestAddress;
+
+    fn bitor(self, other: u64) -> GuestAddress {
+        GuestAddress(self.0 | other as u64)
+    }
+}
+
+impl PartialEq for GuestAddress {
+    fn eq(&self, other: &GuestAddress) -> bool {
+        self.0 == other.0
+    }
+}
+impl Eq for GuestAddress {}
+
+impl Ord for GuestAddress {
+    fn cmp(&self, other: &GuestAddress) -> Ordering {
+        self.0.cmp(&other.0)
+    }
+}
+
+impl PartialOrd for GuestAddress {
+    fn partial_cmp(&self, other: &GuestAddress) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Display for GuestAddress {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{:#x}", self.0)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn equals() {
+        let a = GuestAddress(0x300);
+        let b = GuestAddress(0x300);
+        let c = GuestAddress(0x301);
+        assert_eq!(a, b);
+        assert_eq!(b, a);
+        assert_ne!(a, c);
+        assert_ne!(c, a);
+    }
+
+    #[test]
+    fn cmp() {
+        let a = GuestAddress(0x300);
+        let b = GuestAddress(0x301);
+        assert!(a < b);
+        assert!(b > a);
+        assert!(!(a < a));
+    }
+
+    #[test]
+    fn mask() {
+        let a = GuestAddress(0x5050);
+        assert_eq!(GuestAddress(0x5000), a & 0xff00u64);
+        assert_eq!(GuestAddress(0x5055), a | 0x0005u64);
+    }
+
+    #[test]
+    fn add_sub() {
+        let a = GuestAddress(0x50);
+        let b = GuestAddress(0x60);
+        assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60));
+        assert_eq!(0x10, b.offset_from(a));
+    }
+
+    #[test]
+    fn checked_add_overflow() {
+        let a = GuestAddress(0xffffffffffffff55);
+        assert_eq!(Some(GuestAddress(0xffffffffffffff57)), a.checked_add(2));
+        assert!(a.checked_add(0xf0).is_none());
+    }
+}
diff --git a/sys_util/src/guest_memory.rs b/sys_util/src/guest_memory.rs
new file mode 100644
index 0000000..40ae925
--- /dev/null
+++ b/sys_util/src/guest_memory.rs
@@ -0,0 +1,719 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Track memory regions that are mapped to the guest VM.
+
+use std::ffi::CStr;
+use std::fmt::{self, Display};
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::result;
+use std::sync::Arc;
+
+use crate::guest_address::GuestAddress;
+use crate::mmap::{self, MemoryMapping};
+use crate::shm::{MemfdSeals, SharedMemory};
+use crate::{errno, pagesize};
+use data_model::volatile_memory::*;
+use data_model::DataInit;
+
+#[derive(Debug)]
+pub enum Error {
+    InvalidGuestAddress(GuestAddress),
+    MemoryAccess(GuestAddress, mmap::Error),
+    MemoryMappingFailed(mmap::Error),
+    MemoryRegionOverlap,
+    MemoryNotAligned,
+    MemoryCreationFailed(errno::Error),
+    MemorySetSizeFailed(errno::Error),
+    MemoryAddSealsFailed(errno::Error),
+    ShortWrite { expected: usize, completed: usize },
+    ShortRead { expected: usize, completed: usize },
+}
+pub type Result<T> = result::Result<T, Error>;
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            InvalidGuestAddress(addr) => write!(f, "invalid guest address {}", addr),
+            MemoryAccess(addr, e) => {
+                write!(f, "invalid guest memory access at addr={}: {}", addr, e)
+            }
+            MemoryMappingFailed(e) => write!(f, "failed to map guest memory: {}", e),
+            MemoryRegionOverlap => write!(f, "memory regions overlap"),
+            MemoryNotAligned => write!(f, "memfd regions must be page aligned"),
+            MemoryCreationFailed(_) => write!(f, "failed to create memfd region"),
+            MemorySetSizeFailed(e) => write!(f, "failed to set memfd region size: {}", e),
+            MemoryAddSealsFailed(e) => write!(f, "failed to set seals on memfd region: {}", e),
+            ShortWrite {
+                expected,
+                completed,
+            } => write!(
+                f,
+                "incomplete write of {} instead of {} bytes",
+                completed, expected,
+            ),
+            ShortRead {
+                expected,
+                completed,
+            } => write!(
+                f,
+                "incomplete read of {} instead of {} bytes",
+                completed, expected,
+            ),
+        }
+    }
+}
+
+struct MemoryRegion {
+    mapping: MemoryMapping,
+    guest_base: GuestAddress,
+    memfd_offset: usize,
+}
+
+fn region_end(region: &MemoryRegion) -> GuestAddress {
+    // unchecked_add is safe as the region bounds were checked when it was created.
+    region
+        .guest_base
+        .unchecked_add(region.mapping.size() as u64)
+}
+
+/// Tracks a memory region and where it is mapped in the guest, along with a shm
+/// fd of the underlying memory regions.
+#[derive(Clone)]
+pub struct GuestMemory {
+    regions: Arc<Vec<MemoryRegion>>,
+    memfd: Option<Arc<SharedMemory>>,
+}
+
+impl AsRawFd for GuestMemory {
+    fn as_raw_fd(&self) -> RawFd {
+        match &self.memfd {
+            Some(memfd) => memfd.as_raw_fd(),
+            None => panic!("GuestMemory is not backed by a memfd"),
+        }
+    }
+}
+
+impl GuestMemory {
+    /// Creates backing memfd for GuestMemory regions
+    fn create_memfd(ranges: &[(GuestAddress, u64)]) -> Result<SharedMemory> {
+        let mut aligned_size = 0;
+        let pg_size = pagesize();
+        for range in ranges {
+            if range.1 % pg_size as u64 != 0 {
+                return Err(Error::MemoryNotAligned);
+            }
+
+            aligned_size += range.1;
+        }
+
+        let mut seals = MemfdSeals::new();
+
+        seals.set_shrink_seal();
+        seals.set_grow_seal();
+        seals.set_seal_seal();
+
+        let mut memfd =
+            SharedMemory::new(Some(CStr::from_bytes_with_nul(b"crosvm_guest\0").unwrap()))
+                .map_err(Error::MemoryCreationFailed)?;
+        memfd
+            .set_size(aligned_size)
+            .map_err(Error::MemorySetSizeFailed)?;
+        memfd
+            .add_seals(seals)
+            .map_err(Error::MemoryAddSealsFailed)?;
+
+        Ok(memfd)
+    }
+
+    /// Creates a container for guest memory regions.
+    /// Valid memory regions are specified as a Vec of (Address, Size) tuples sorted by Address.
+    pub fn new(ranges: &[(GuestAddress, u64)]) -> Result<GuestMemory> {
+        // Create memfd
+
+        // TODO(prilik) remove optional memfd once parallel CQ lands (crbug.com/942183).
+        // Many classic CQ builders run old kernels without memfd support, resulting in test
+        // failures. It's less effort to introduce this temporary optional path than to
+        // manually mark all affected tests as ignore.
+        let memfd = match GuestMemory::create_memfd(ranges) {
+            Err(Error::MemoryCreationFailed { .. }) => {
+                warn!("GuestMemory is not backed by a memfd");
+                None
+            }
+            Err(e) => return Err(e),
+            Ok(memfd) => Some(memfd),
+        };
+
+        // Create memory regions
+        let mut regions = Vec::<MemoryRegion>::new();
+        let mut offset = 0;
+
+        for range in ranges {
+            if let Some(last) = regions.last() {
+                if last
+                    .guest_base
+                    .checked_add(last.mapping.size() as u64)
+                    .map_or(true, |a| a > range.0)
+                {
+                    return Err(Error::MemoryRegionOverlap);
+                }
+            }
+
+            let mapping = match &memfd {
+                Some(memfd) => MemoryMapping::from_fd_offset(memfd, range.1 as usize, offset),
+                None => MemoryMapping::new(range.1 as usize),
+            }
+            .map_err(Error::MemoryMappingFailed)?;
+
+            regions.push(MemoryRegion {
+                mapping,
+                guest_base: range.0,
+                memfd_offset: offset,
+            });
+
+            offset += range.1 as usize;
+        }
+
+        Ok(GuestMemory {
+            regions: Arc::new(regions),
+            memfd: match memfd {
+                Some(memfd) => Some(Arc::new(memfd)),
+                None => None,
+            },
+        })
+    }
+
+    /// Returns the end address of memory.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use sys_util::{GuestAddress, GuestMemory, MemoryMapping};
+    /// # fn test_end_addr() -> Result<(), ()> {
+    ///     let start_addr = GuestAddress(0x1000);
+    ///     let mut gm = GuestMemory::new(&vec![(start_addr, 0x400)]).map_err(|_| ())?;
+    ///     assert_eq!(start_addr.checked_add(0x400), Some(gm.end_addr()));
+    ///     Ok(())
+    /// # }
+    /// ```
+    pub fn end_addr(&self) -> GuestAddress {
+        self.regions
+            .iter()
+            .max_by_key(|region| region.guest_base)
+            .map_or(GuestAddress(0), |region| region_end(region))
+    }
+
+    /// Returns the total size of memory in bytes.
+    pub fn memory_size(&self) -> u64 {
+        self.regions
+            .iter()
+            .map(|region| region.mapping.size() as u64)
+            .sum()
+    }
+
+    /// Returns true if the given address is within the memory range available to the guest.
+    pub fn address_in_range(&self, addr: GuestAddress) -> bool {
+        addr < self.end_addr()
+    }
+
+    /// Returns the address plus the offset if it is in range.
+    pub fn checked_offset(&self, addr: GuestAddress, offset: u64) -> Option<GuestAddress> {
+        addr.checked_add(offset)
+            .and_then(|a| if a < self.end_addr() { Some(a) } else { None })
+    }
+
+    /// Returns the size of the memory region in bytes.
+    pub fn num_regions(&self) -> u64 {
+        self.regions.len() as u64
+    }
+
+    /// Madvise away the address range in the host that is associated with the given guest range.
+    pub fn remove_range(&self, addr: GuestAddress, count: u64) -> Result<()> {
+        self.do_in_region(addr, move |mapping, offset| {
+            mapping
+                .remove_range(offset, count as usize)
+                .map_err(|e| Error::MemoryAccess(addr, e))
+        })
+    }
+
+    /// Perform the specified action on each region's addresses.
+    ///
+    /// Callback is called with arguments:
+    ///  * index: usize
+    ///  * guest_addr : GuestAddress
+    ///  * size: usize
+    ///  * host_addr: usize
+    ///  * memfd_offset: usize
+    pub fn with_regions<F, E>(&self, mut cb: F) -> result::Result<(), E>
+    where
+        F: FnMut(usize, GuestAddress, usize, usize, usize) -> result::Result<(), E>,
+    {
+        for (index, region) in self.regions.iter().enumerate() {
+            cb(
+                index,
+                region.guest_base,
+                region.mapping.size(),
+                region.mapping.as_ptr() as usize,
+                region.memfd_offset,
+            )?;
+        }
+        Ok(())
+    }
+
+    /// Writes a slice to guest memory at the specified guest address.
+    /// Returns the number of bytes written.  The number of bytes written can
+    /// be less than the length of the slice if there isn't enough room in the
+    /// memory region.
+    ///
+    /// # Examples
+    /// * Write a slice at guestaddress 0x200.
+    ///
+    /// ```
+    /// # use sys_util::{GuestAddress, GuestMemory, MemoryMapping};
+    /// # fn test_write_u64() -> Result<(), ()> {
+    /// #   let start_addr = GuestAddress(0x1000);
+    /// #   let mut gm = GuestMemory::new(&vec![(start_addr, 0x400)]).map_err(|_| ())?;
+    ///     let res = gm.write_at_addr(&[1,2,3,4,5], GuestAddress(0x200)).map_err(|_| ())?;
+    ///     assert_eq!(5, res);
+    ///     Ok(())
+    /// # }
+    /// ```
+    pub fn write_at_addr(&self, buf: &[u8], guest_addr: GuestAddress) -> Result<usize> {
+        self.do_in_region(guest_addr, move |mapping, offset| {
+            mapping
+                .write_slice(buf, offset)
+                .map_err(|e| Error::MemoryAccess(guest_addr, e))
+        })
+    }
+
+    /// Writes the entire contents of a slice to guest memory at the specified
+    /// guest address.
+    ///
+    /// Returns an error if there isn't enough room in the memory region to
+    /// complete the entire write. Part of the data may have been written
+    /// nevertheless.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use sys_util::{guest_memory, GuestAddress, GuestMemory};
+    ///
+    /// fn test_write_all() -> guest_memory::Result<()> {
+    ///     let ranges = &[(GuestAddress(0x1000), 0x400)];
+    ///     let gm = GuestMemory::new(ranges)?;
+    ///     gm.write_all_at_addr(b"zyxwvut", GuestAddress(0x1200))
+    /// }
+    /// ```
+    pub fn write_all_at_addr(&self, buf: &[u8], guest_addr: GuestAddress) -> Result<()> {
+        let expected = buf.len();
+        let completed = self.write_at_addr(buf, guest_addr)?;
+        if expected == completed {
+            Ok(())
+        } else {
+            Err(Error::ShortWrite {
+                expected,
+                completed,
+            })
+        }
+    }
+
+    /// Reads to a slice from guest memory at the specified guest address.
+    /// Returns the number of bytes read.  The number of bytes read can
+    /// be less than the length of the slice if there isn't enough room in the
+    /// memory region.
+    ///
+    /// # Examples
+    /// * Read a slice of length 16 at guestaddress 0x200.
+    ///
+    /// ```
+    /// # use sys_util::{GuestAddress, GuestMemory, MemoryMapping};
+    /// # fn test_write_u64() -> Result<(), ()> {
+    /// #   let start_addr = GuestAddress(0x1000);
+    /// #   let mut gm = GuestMemory::new(&vec![(start_addr, 0x400)]).map_err(|_| ())?;
+    ///     let buf = &mut [0u8; 16];
+    ///     let res = gm.read_at_addr(buf, GuestAddress(0x200)).map_err(|_| ())?;
+    ///     assert_eq!(16, res);
+    ///     Ok(())
+    /// # }
+    /// ```
+    pub fn read_at_addr(&self, buf: &mut [u8], guest_addr: GuestAddress) -> Result<usize> {
+        self.do_in_region(guest_addr, move |mapping, offset| {
+            mapping
+                .read_slice(buf, offset)
+                .map_err(|e| Error::MemoryAccess(guest_addr, e))
+        })
+    }
+
+    /// Reads from guest memory at the specified address to fill the entire
+    /// buffer.
+    ///
+    /// Returns an error if there isn't enough room in the memory region to fill
+    /// the entire buffer. Part of the buffer may have been filled nevertheless.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use sys_util::{guest_memory, GuestAddress, GuestMemory, MemoryMapping};
+    ///
+    /// fn test_read_exact() -> guest_memory::Result<()> {
+    ///     let ranges = &[(GuestAddress(0x1000), 0x400)];
+    ///     let gm = GuestMemory::new(ranges)?;
+    ///     let mut buffer = [0u8; 0x200];
+    ///     gm.read_exact_at_addr(&mut buffer, GuestAddress(0x1200))
+    /// }
+    /// ```
+    pub fn read_exact_at_addr(&self, buf: &mut [u8], guest_addr: GuestAddress) -> Result<()> {
+        let expected = buf.len();
+        let completed = self.read_at_addr(buf, guest_addr)?;
+        if expected == completed {
+            Ok(())
+        } else {
+            Err(Error::ShortRead {
+                expected,
+                completed,
+            })
+        }
+    }
+
+    /// Reads an object from guest memory at the given guest address.
+    /// Reading from a volatile area isn't strictly safe as it could change
+    /// mid-read.  However, as long as the type T is plain old data and can
+    /// handle random initialization, everything will be OK.
+    ///
+    /// # Examples
+    /// * Read a u64 from two areas of guest memory backed by separate mappings.
+    ///
+    /// ```
+    /// # use sys_util::{GuestAddress, GuestMemory, MemoryMapping};
+    /// # fn test_read_u64() -> Result<u64, ()> {
+    /// #     let start_addr1 = GuestAddress(0x0);
+    /// #     let start_addr2 = GuestAddress(0x400);
+    /// #     let mut gm = GuestMemory::new(&vec![(start_addr1, 0x400), (start_addr2, 0x400)])
+    /// #         .map_err(|_| ())?;
+    ///       let num1: u64 = gm.read_obj_from_addr(GuestAddress(32)).map_err(|_| ())?;
+    ///       let num2: u64 = gm.read_obj_from_addr(GuestAddress(0x400+32)).map_err(|_| ())?;
+    /// #     Ok(num1 + num2)
+    /// # }
+    /// ```
+    pub fn read_obj_from_addr<T: DataInit>(&self, guest_addr: GuestAddress) -> Result<T> {
+        self.do_in_region(guest_addr, |mapping, offset| {
+            mapping
+                .read_obj(offset)
+                .map_err(|e| Error::MemoryAccess(guest_addr, e))
+        })
+    }
+
+    /// Writes an object to the memory region at the specified guest address.
+    /// Returns Ok(()) if the object fits, or Err if it extends past the end.
+    ///
+    /// # Examples
+    /// * Write a u64 at guest address 0x1100.
+    ///
+    /// ```
+    /// # use sys_util::{GuestAddress, GuestMemory, MemoryMapping};
+    /// # fn test_write_u64() -> Result<(), ()> {
+    /// #   let start_addr = GuestAddress(0x1000);
+    /// #   let mut gm = GuestMemory::new(&vec![(start_addr, 0x400)]).map_err(|_| ())?;
+    ///     gm.write_obj_at_addr(55u64, GuestAddress(0x1100))
+    ///         .map_err(|_| ())
+    /// # }
+    /// ```
+    pub fn write_obj_at_addr<T: DataInit>(&self, val: T, guest_addr: GuestAddress) -> Result<()> {
+        self.do_in_region(guest_addr, move |mapping, offset| {
+            mapping
+                .write_obj(val, offset)
+                .map_err(|e| Error::MemoryAccess(guest_addr, e))
+        })
+    }
+
+    /// Reads data from a file descriptor and writes it to guest memory.
+    ///
+    /// # Arguments
+    /// * `guest_addr` - Begin writing memory at this offset.
+    /// * `src` - Read from `src` to memory.
+    /// * `count` - Read `count` bytes from `src` to memory.
+    ///
+    /// # Examples
+    ///
+    /// * Read bytes from /dev/urandom
+    ///
+    /// ```
+    /// # use sys_util::{GuestAddress, GuestMemory, MemoryMapping};
+    /// # use std::fs::File;
+    /// # use std::path::Path;
+    /// # fn test_read_random() -> Result<u32, ()> {
+    /// #     let start_addr = GuestAddress(0x1000);
+    /// #     let gm = GuestMemory::new(&vec![(start_addr, 0x400)]).map_err(|_| ())?;
+    ///       let mut file = File::open(Path::new("/dev/urandom")).map_err(|_| ())?;
+    ///       let addr = GuestAddress(0x1010);
+    ///       gm.read_to_memory(addr, &mut file, 128).map_err(|_| ())?;
+    ///       let read_addr = addr.checked_add(8).ok_or(())?;
+    ///       let rand_val: u32 = gm.read_obj_from_addr(read_addr).map_err(|_| ())?;
+    /// #     Ok(rand_val)
+    /// # }
+    /// ```
+    pub fn read_to_memory(
+        &self,
+        guest_addr: GuestAddress,
+        src: &AsRawFd,
+        count: usize,
+    ) -> Result<()> {
+        self.do_in_region(guest_addr, move |mapping, offset| {
+            mapping
+                .read_to_memory(offset, src, count)
+                .map_err(|e| Error::MemoryAccess(guest_addr, e))
+        })
+    }
+
+    /// Writes data from memory to a file descriptor.
+    ///
+    /// # Arguments
+    /// * `guest_addr` - Begin reading memory from this offset.
+    /// * `dst` - Write from memory to `dst`.
+    /// * `count` - Read `count` bytes from memory to `src`.
+    ///
+    /// # Examples
+    ///
+    /// * Write 128 bytes to /dev/null
+    ///
+    /// ```
+    /// # use sys_util::{GuestAddress, GuestMemory, MemoryMapping};
+    /// # use std::fs::File;
+    /// # use std::path::Path;
+    /// # fn test_write_null() -> Result<(), ()> {
+    /// #     let start_addr = GuestAddress(0x1000);
+    /// #     let gm = GuestMemory::new(&vec![(start_addr, 0x400)]).map_err(|_| ())?;
+    ///       let mut file = File::open(Path::new("/dev/null")).map_err(|_| ())?;
+    ///       let addr = GuestAddress(0x1010);
+    ///       gm.write_from_memory(addr, &mut file, 128).map_err(|_| ())?;
+    /// #     Ok(())
+    /// # }
+    /// ```
+    pub fn write_from_memory(
+        &self,
+        guest_addr: GuestAddress,
+        dst: &AsRawFd,
+        count: usize,
+    ) -> Result<()> {
+        self.do_in_region(guest_addr, move |mapping, offset| {
+            mapping
+                .write_from_memory(offset, dst, count)
+                .map_err(|e| Error::MemoryAccess(guest_addr, e))
+        })
+    }
+
+    /// Convert a GuestAddress into a pointer in the address space of this
+    /// process. This should only be necessary for giving addresses to the
+    /// kernel, as with vhost ioctls. Normal reads/writes to guest memory should
+    /// be done through `write_from_memory`, `read_obj_from_addr`, etc.
+    ///
+    /// # Arguments
+    /// * `guest_addr` - Guest address to convert.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use sys_util::{GuestAddress, GuestMemory};
+    /// # fn test_host_addr() -> Result<(), ()> {
+    ///     let start_addr = GuestAddress(0x1000);
+    ///     let mut gm = GuestMemory::new(&vec![(start_addr, 0x500)]).map_err(|_| ())?;
+    ///     let addr = gm.get_host_address(GuestAddress(0x1200)).unwrap();
+    ///     println!("Host address is {:p}", addr);
+    ///     Ok(())
+    /// # }
+    /// ```
+    pub fn get_host_address(&self, guest_addr: GuestAddress) -> Result<*const u8> {
+        self.do_in_region(guest_addr, |mapping, offset| {
+            // This is safe; `do_in_region` already checks that offset is in
+            // bounds.
+            Ok(unsafe { mapping.as_ptr().add(offset) } as *const u8)
+        })
+    }
+
+    pub fn do_in_region<F, T>(&self, guest_addr: GuestAddress, cb: F) -> Result<T>
+    where
+        F: FnOnce(&MemoryMapping, usize) -> Result<T>,
+    {
+        for region in self.regions.iter() {
+            if guest_addr >= region.guest_base && guest_addr < region_end(region) {
+                return cb(
+                    &region.mapping,
+                    guest_addr.offset_from(region.guest_base) as usize,
+                );
+            }
+        }
+        Err(Error::InvalidGuestAddress(guest_addr))
+    }
+}
+
+impl VolatileMemory for GuestMemory {
+    fn get_slice(&self, offset: u64, count: u64) -> VolatileMemoryResult<VolatileSlice> {
+        for region in self.regions.iter() {
+            if offset >= region.guest_base.0 && offset < region_end(region).0 {
+                return region
+                    .mapping
+                    .get_slice(offset - region.guest_base.0, count);
+            }
+        }
+        Err(VolatileMemoryError::OutOfBounds { addr: offset })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::kernel_has_memfd;
+
+    #[test]
+    fn test_alignment() {
+        let start_addr1 = GuestAddress(0x0);
+        let start_addr2 = GuestAddress(0x1000);
+
+        assert!(GuestMemory::new(&vec![(start_addr1, 0x100), (start_addr2, 0x400)]).is_err());
+        assert!(GuestMemory::new(&vec![(start_addr1, 0x1000), (start_addr2, 0x1000)]).is_ok());
+    }
+
+    #[test]
+    fn two_regions() {
+        let start_addr1 = GuestAddress(0x0);
+        let start_addr2 = GuestAddress(0x4000);
+        assert!(GuestMemory::new(&vec![(start_addr1, 0x4000), (start_addr2, 0x4000)]).is_ok());
+    }
+
+    #[test]
+    fn overlap_memory() {
+        let start_addr1 = GuestAddress(0x0);
+        let start_addr2 = GuestAddress(0x1000);
+        assert!(GuestMemory::new(&vec![(start_addr1, 0x2000), (start_addr2, 0x2000)]).is_err());
+    }
+
+    #[test]
+    fn test_read_u64() {
+        let start_addr1 = GuestAddress(0x0);
+        let start_addr2 = GuestAddress(0x1000);
+        let gm = GuestMemory::new(&vec![(start_addr1, 0x1000), (start_addr2, 0x1000)]).unwrap();
+
+        let val1: u64 = 0xaa55aa55aa55aa55;
+        let val2: u64 = 0x55aa55aa55aa55aa;
+        gm.write_obj_at_addr(val1, GuestAddress(0x500)).unwrap();
+        gm.write_obj_at_addr(val2, GuestAddress(0x1000 + 32))
+            .unwrap();
+        let num1: u64 = gm.read_obj_from_addr(GuestAddress(0x500)).unwrap();
+        let num2: u64 = gm.read_obj_from_addr(GuestAddress(0x1000 + 32)).unwrap();
+        assert_eq!(val1, num1);
+        assert_eq!(val2, num2);
+    }
+
+    #[test]
+    fn test_ref_load_u64() {
+        let start_addr1 = GuestAddress(0x0);
+        let start_addr2 = GuestAddress(0x1000);
+        let gm = GuestMemory::new(&vec![(start_addr1, 0x1000), (start_addr2, 0x1000)]).unwrap();
+
+        let val1: u64 = 0xaa55aa55aa55aa55;
+        let val2: u64 = 0x55aa55aa55aa55aa;
+        gm.write_obj_at_addr(val1, GuestAddress(0x500)).unwrap();
+        gm.write_obj_at_addr(val2, GuestAddress(0x1000 + 32))
+            .unwrap();
+        let num1: u64 = gm.get_ref(0x500).unwrap().load();
+        let num2: u64 = gm.get_ref(0x1000 + 32).unwrap().load();
+        assert_eq!(val1, num1);
+        assert_eq!(val2, num2);
+    }
+
+    #[test]
+    fn test_ref_store_u64() {
+        let start_addr1 = GuestAddress(0x0);
+        let start_addr2 = GuestAddress(0x1000);
+        let gm = GuestMemory::new(&vec![(start_addr1, 0x1000), (start_addr2, 0x1000)]).unwrap();
+
+        let val1: u64 = 0xaa55aa55aa55aa55;
+        let val2: u64 = 0x55aa55aa55aa55aa;
+        gm.get_ref(0x500).unwrap().store(val1);
+        gm.get_ref(0x1000 + 32).unwrap().store(val2);
+        let num1: u64 = gm.read_obj_from_addr(GuestAddress(0x500)).unwrap();
+        let num2: u64 = gm.read_obj_from_addr(GuestAddress(0x1000 + 32)).unwrap();
+        assert_eq!(val1, num1);
+        assert_eq!(val2, num2);
+    }
+
+    #[test]
+    fn test_memory_size() {
+        let start_region1 = GuestAddress(0x0);
+        let size_region1 = 0x1000;
+        let start_region2 = GuestAddress(0x10000);
+        let size_region2 = 0x2000;
+        let gm = GuestMemory::new(&vec![
+            (start_region1, size_region1),
+            (start_region2, size_region2),
+        ])
+        .unwrap();
+
+        let mem_size = gm.memory_size();
+        assert_eq!(mem_size, size_region1 + size_region2);
+    }
+
+    // Get the base address of the mapping for a GuestAddress.
+    fn get_mapping(mem: &GuestMemory, addr: GuestAddress) -> Result<*const u8> {
+        mem.do_in_region(addr, |mapping, _| Ok(mapping.as_ptr() as *const u8))
+    }
+
+    #[test]
+    fn guest_to_host() {
+        let start_addr1 = GuestAddress(0x0);
+        let start_addr2 = GuestAddress(0x1000);
+        let mem = GuestMemory::new(&vec![(start_addr1, 0x1000), (start_addr2, 0x4000)]).unwrap();
+
+        // Verify the host addresses match what we expect from the mappings.
+        let addr1_base = get_mapping(&mem, start_addr1).unwrap();
+        let addr2_base = get_mapping(&mem, start_addr2).unwrap();
+        let host_addr1 = mem.get_host_address(start_addr1).unwrap();
+        let host_addr2 = mem.get_host_address(start_addr2).unwrap();
+        assert_eq!(host_addr1, addr1_base);
+        assert_eq!(host_addr2, addr2_base);
+
+        // Check that a bad address returns an error.
+        let bad_addr = GuestAddress(0x123456);
+        assert!(mem.get_host_address(bad_addr).is_err());
+    }
+
+    #[test]
+    fn memfd_offset() {
+        if !kernel_has_memfd() {
+            return;
+        }
+
+        let start_region1 = GuestAddress(0x0);
+        let size_region1 = 0x1000;
+        let start_region2 = GuestAddress(0x10000);
+        let size_region2 = 0x2000;
+        let gm = GuestMemory::new(&vec![
+            (start_region1, size_region1),
+            (start_region2, size_region2),
+        ])
+        .unwrap();
+
+        gm.write_obj_at_addr(0x1337u16, GuestAddress(0x0)).unwrap();
+        gm.write_obj_at_addr(0x0420u16, GuestAddress(0x10000))
+            .unwrap();
+
+        let _ = gm.with_regions::<_, ()>(|index, _, size, _, memfd_offset| {
+            let mmap = MemoryMapping::from_fd_offset(&gm, size, memfd_offset).unwrap();
+
+            if index == 0 {
+                assert!(mmap.read_obj::<u16>(0x0).unwrap() == 0x1337u16);
+            }
+
+            if index == 1 {
+                assert!(mmap.read_obj::<u16>(0x0).unwrap() == 0x0420u16);
+            }
+
+            Ok(())
+        });
+    }
+}
diff --git a/sys_util/src/handle_eintr.rs b/sys_util/src/handle_eintr.rs
new file mode 100644
index 0000000..d8cc0b3
--- /dev/null
+++ b/sys_util/src/handle_eintr.rs
@@ -0,0 +1,251 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Macro and helper trait for handling interrupted routines.
+
+use std::io;
+
+use libc::EINTR;
+
+/// Trait for determining if a result indicates the operation was interrupted.
+pub trait InterruptibleResult {
+    /// Returns `true` if this result indicates the operation was interrupted and should be retried,
+    /// and `false` in all other cases.
+    fn is_interrupted(&self) -> bool;
+}
+
+impl<T> InterruptibleResult for crate::Result<T> {
+    fn is_interrupted(&self) -> bool {
+        match self {
+            Err(e) if e.errno() == EINTR => true,
+            _ => false,
+        }
+    }
+}
+
+impl<T> InterruptibleResult for io::Result<T> {
+    fn is_interrupted(&self) -> bool {
+        match self {
+            Err(e) if e.kind() == io::ErrorKind::Interrupted => true,
+            _ => false,
+        }
+    }
+}
+
+/// Macro that retries the given expression every time its result indicates it was interrupted (i.e.
+/// returned `EINTR`). This is useful for operations that are prone to being interrupted by
+/// signals, such as blocking syscalls.
+///
+/// The given expression `$x` can return
+///
+/// * `sys_util::Result` in which case the expression is retried if the `Error::errno()` is `EINTR`.
+/// * `std::io::Result` in which case the expression is retried if the `ErrorKind` is `ErrorKind::Interrupted`.
+///
+/// Note that if expression returns i32 (i.e. either -1 or error code), then handle_eintr_errno()
+/// or handle_eintr_rc() should be used instead.
+///
+/// In all cases where the result does not indicate that the expression was interrupted, the result
+/// is returned verbatim to the caller of this macro.
+///
+/// See the section titled _Interruption of system calls and library functions by signal handlers_
+/// on the man page for `signal(7)` to see more information about interruptible syscalls.
+///
+/// To summarize, routines that use one of these syscalls _might_ need to handle `EINTR`:
+///
+/// * `accept(2)`
+/// * `clock_nanosleep(2)`
+/// * `connect(2)`
+/// * `epoll_pwait(2)`
+/// * `epoll_wait(2)`
+/// * `fcntl(2)`
+/// * `fifo(7)`
+/// * `flock(2)`
+/// * `futex(2)`
+/// * `getrandom(2)`
+/// * `inotify(7)`
+/// * `io_getevents(2)`
+/// * `ioctl(2)`
+/// * `mq_receive(3)`
+/// * `mq_send(3)`
+/// * `mq_timedreceive(3)`
+/// * `mq_timedsend(3)`
+/// * `msgrcv(2)`
+/// * `msgsnd(2)`
+/// * `nanosleep(2)`
+/// * `open(2)`
+/// * `pause(2)`
+/// * `poll(2)`
+/// * `ppoll(2)`
+/// * `pselect(2)`
+/// * `pthread_cond_wait(3)`
+/// * `pthread_mutex_lock(3)`
+/// * `read(2)`
+/// * `readv(2)`
+/// * `recv(2)`
+/// * `recvfrom(2)`
+/// * `recvmmsg(2)`
+/// * `recvmsg(2)`
+/// * `select(2)`
+/// * `sem_timedwait(3)`
+/// * `sem_wait(3)`
+/// * `semop(2)`
+/// * `semtimedop(2)`
+/// * `send(2)`
+/// * `sendmsg(2)`
+/// * `sendto(2)`
+/// * `setsockopt(2)`
+/// * `sigsuspend(2)`
+/// * `sigtimedwait(2)`
+/// * `sigwaitinfo(2)`
+/// * `sleep(3)`
+/// * `usleep(3)`
+/// * `wait(2)`
+/// * `wait3(2)`
+/// * `wait4(2)`
+/// * `waitid(2)`
+/// * `waitpid(2)`
+/// * `write(2)`
+/// * `writev(2)`
+///
+/// # Examples
+///
+/// ```
+/// # use sys_util::handle_eintr;
+/// # use std::io::stdin;
+/// # fn main() {
+/// let mut line = String::new();
+/// let res = handle_eintr!(stdin().read_line(&mut line));
+/// # }
+/// ```
+#[macro_export]
+macro_rules! handle_eintr {
+    ($x:expr) => {{
+        use $crate::handle_eintr::InterruptibleResult;
+        let res;
+        loop {
+            match $x {
+                ref v if v.is_interrupted() => continue,
+                v => {
+                    res = v;
+                    break;
+                }
+            }
+        }
+        res
+    }};
+}
+
+/// Macro that retries the given expression every time its result indicates it was interrupted.
+/// It is intended to use with system functions that return `EINTR` and other error codes
+/// directly as their result.
+/// Most of reentrant functions use this way of signalling errors.
+#[macro_export]
+macro_rules! handle_eintr_rc {
+    ($x:expr) => {{
+        use libc::EINTR;
+        let mut res;
+        loop {
+            res = $x;
+            if res != EINTR {
+                break;
+            }
+        }
+        res
+    }};
+}
+
+/// Macro that retries the given expression every time its result indicates it was interrupted.
+/// It is intended to use with system functions that signal error by returning `-1` and setting
+/// `errno` to appropriate error code (`EINTR`, `EINVAL`, etc.)
+/// Most of standard non-reentrant libc functions use this way of signalling errors.
+#[macro_export]
+macro_rules! handle_eintr_errno {
+    ($x:expr) => {{
+        use libc::EINTR;
+        use $crate::Error;
+        let mut res;
+        loop {
+            res = $x;
+            if res != -1 || Error::last() != Error::new(EINTR) {
+                break;
+            }
+        }
+        res
+    }};
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::errno::set_errno;
+    use crate::Error as SysError;
+
+    #[test]
+    fn i32_eintr_rc() {
+        let mut count = 3;
+        let mut dummy = || {
+            count -= 1;
+            if count > 0 {
+                EINTR
+            } else {
+                0
+            }
+        };
+        let res = handle_eintr_rc!(dummy());
+        assert_eq!(res, 0);
+        assert_eq!(count, 0);
+    }
+
+    #[test]
+    fn i32_eintr_errno() {
+        let mut count = 3;
+        let mut dummy = || {
+            count -= 1;
+            if count > 0 {
+                set_errno(EINTR);
+                -1
+            } else {
+                56
+            }
+        };
+        let res = handle_eintr_errno!(dummy());
+        assert_eq!(res, 56);
+        assert_eq!(count, 0);
+    }
+
+    #[test]
+    fn sys_eintr() {
+        let mut count = 7;
+        let mut dummy = || {
+            count -= 1;
+            if count > 1 {
+                Err(SysError::new(EINTR))
+            } else {
+                Ok(101)
+            }
+        };
+        let res = handle_eintr!(dummy());
+        assert_eq!(res, Ok(101));
+        assert_eq!(count, 1);
+    }
+
+    #[test]
+    fn io_eintr() {
+        let mut count = 108;
+        let mut dummy = || {
+            count -= 1;
+            if count > 99 {
+                Err(io::Error::new(
+                    io::ErrorKind::Interrupted,
+                    "interrupted again :(",
+                ))
+            } else {
+                Ok(32)
+            }
+        };
+        let res = handle_eintr!(dummy());
+        assert_eq!(res.unwrap(), 32);
+        assert_eq!(count, 99);
+    }
+}
diff --git a/sys_util/src/ioctl.rs b/sys_util/src/ioctl.rs
new file mode 100644
index 0000000..a0309ff
--- /dev/null
+++ b/sys_util/src/ioctl.rs
@@ -0,0 +1,198 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Macros and wrapper functions for dealing with ioctls.
+
+use std::os::raw::*;
+use std::os::unix::io::AsRawFd;
+
+use libc;
+
+/// Raw macro to declare the expression that calculates an ioctl number
+#[macro_export]
+macro_rules! ioctl_expr {
+    ($dir:expr, $ty:expr, $nr:expr, $size:expr) => {
+        (($dir << $crate::ioctl::_IOC_DIRSHIFT)
+            | ($ty << $crate::ioctl::_IOC_TYPESHIFT)
+            | ($nr << $crate::ioctl::_IOC_NRSHIFT)
+            | ($size << $crate::ioctl::_IOC_SIZESHIFT)) as ::std::os::raw::c_ulong
+    };
+}
+
+/// Raw macro to declare a function that returns an ioctl number.
+#[macro_export]
+macro_rules! ioctl_ioc_nr {
+    ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr) => {
+        #[allow(non_snake_case)]
+        pub fn $name() -> ::std::os::raw::c_ulong {
+            $crate::ioctl_expr!($dir, $ty, $nr, $size)
+        }
+    };
+    ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr, $($v:ident),+) => {
+        #[allow(non_snake_case)]
+        pub fn $name($($v: ::std::os::raw::c_uint),+) -> ::std::os::raw::c_ulong {
+            $crate::ioctl_expr!($dir, $ty, $nr, $size)
+        }
+    };
+}
+
+/// Declare an ioctl that transfers no data.
+#[macro_export]
+macro_rules! ioctl_io_nr {
+    ($name:ident, $ty:expr, $nr:expr) => {
+        $crate::ioctl_ioc_nr!($name, $crate::ioctl::_IOC_NONE, $ty, $nr, 0);
+    };
+    ($name:ident, $ty:expr, $nr:expr, $($v:ident),+) => {
+        $crate::ioctl_ioc_nr!($name, $crate::ioctl::_IOC_NONE, $ty, $nr, 0, $($v),+);
+    };
+}
+
+/// Declare an ioctl that reads data.
+#[macro_export]
+macro_rules! ioctl_ior_nr {
+    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
+        $crate::ioctl_ioc_nr!(
+            $name,
+            $crate::ioctl::_IOC_READ,
+            $ty,
+            $nr,
+            ::std::mem::size_of::<$size>() as u32
+        );
+    };
+    ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
+        $crate::ioctl_ioc_nr!(
+            $name,
+            $crate::ioctl::_IOC_READ,
+            $ty,
+            $nr,
+            ::std::mem::size_of::<$size>() as u32,
+            $($v),+
+        );
+    };
+}
+
+/// Declare an ioctl that writes data.
+#[macro_export]
+macro_rules! ioctl_iow_nr {
+    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
+        $crate::ioctl_ioc_nr!(
+            $name,
+            $crate::ioctl::_IOC_WRITE,
+            $ty,
+            $nr,
+            ::std::mem::size_of::<$size>() as u32
+        );
+    };
+    ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
+        $crate::ioctl_ioc_nr!(
+            $name,
+            $crate::ioctl::_IOC_WRITE,
+            $ty,
+            $nr,
+            ::std::mem::size_of::<$size>() as u32,
+            $($v),+
+        );
+    };
+}
+
+/// Declare an ioctl that reads and writes data.
+#[macro_export]
+macro_rules! ioctl_iowr_nr {
+    ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
+        $crate::ioctl_ioc_nr!(
+            $name,
+            $crate::ioctl::_IOC_READ | $crate::ioctl::_IOC_WRITE,
+            $ty,
+            $nr,
+            ::std::mem::size_of::<$size>() as u32
+        );
+    };
+    ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
+        $crate::ioctl_ioc_nr!(
+            $name,
+            $crate::ioctl::_IOC_READ | $crate::ioctl::_IOC_WRITE,
+            $ty,
+            $nr,
+            ::std::mem::size_of::<$size>() as u32,
+            $($v),+
+        );
+    };
+}
+
+pub const _IOC_NRBITS: c_uint = 8;
+pub const _IOC_TYPEBITS: c_uint = 8;
+pub const _IOC_SIZEBITS: c_uint = 14;
+pub const _IOC_DIRBITS: c_uint = 2;
+pub const _IOC_NRMASK: c_uint = 255;
+pub const _IOC_TYPEMASK: c_uint = 255;
+pub const _IOC_SIZEMASK: c_uint = 16383;
+pub const _IOC_DIRMASK: c_uint = 3;
+pub const _IOC_NRSHIFT: c_uint = 0;
+pub const _IOC_TYPESHIFT: c_uint = 8;
+pub const _IOC_SIZESHIFT: c_uint = 16;
+pub const _IOC_DIRSHIFT: c_uint = 30;
+pub const _IOC_NONE: c_uint = 0;
+pub const _IOC_WRITE: c_uint = 1;
+pub const _IOC_READ: c_uint = 2;
+pub const IOC_IN: c_uint = 1_073_741_824;
+pub const IOC_OUT: c_uint = 2_147_483_648;
+pub const IOC_INOUT: c_uint = 3_221_225_472;
+pub const IOCSIZE_MASK: c_uint = 1_073_676_288;
+pub const IOCSIZE_SHIFT: c_uint = 16;
+
+/// Run an ioctl with no arguments.
+pub unsafe fn ioctl<F: AsRawFd>(fd: &F, nr: c_ulong) -> c_int {
+    libc::ioctl(fd.as_raw_fd(), nr, 0)
+}
+
+/// Run an ioctl with a single value argument.
+pub unsafe fn ioctl_with_val<F: AsRawFd>(fd: &F, nr: c_ulong, arg: c_ulong) -> c_int {
+    libc::ioctl(fd.as_raw_fd(), nr, arg)
+}
+
+/// Run an ioctl with an immutable reference.
+pub unsafe fn ioctl_with_ref<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: &T) -> c_int {
+    libc::ioctl(fd.as_raw_fd(), nr, arg as *const T as *const c_void)
+}
+
+/// Run an ioctl with a mutable reference.
+pub unsafe fn ioctl_with_mut_ref<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: &mut T) -> c_int {
+    libc::ioctl(fd.as_raw_fd(), nr, arg as *mut T as *mut c_void)
+}
+
+/// Run an ioctl with a raw pointer.
+pub unsafe fn ioctl_with_ptr<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: *const T) -> c_int {
+    libc::ioctl(fd.as_raw_fd(), nr, arg as *const c_void)
+}
+
+/// Run an ioctl with a mutable raw pointer.
+pub unsafe fn ioctl_with_mut_ptr<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: *mut T) -> c_int {
+    libc::ioctl(fd.as_raw_fd(), nr, arg as *mut c_void)
+}
+
+#[cfg(test)]
+mod tests {
+    const TUNTAP: ::std::os::raw::c_uint = 0x54;
+    const VHOST: ::std::os::raw::c_uint = 0xaf;
+    const EVDEV: ::std::os::raw::c_uint = 0x45;
+
+    ioctl_io_nr!(VHOST_SET_OWNER, VHOST, 0x01);
+    ioctl_ior_nr!(TUNGETFEATURES, TUNTAP, 0xcf, ::std::os::raw::c_uint);
+    ioctl_iow_nr!(TUNSETQUEUE, TUNTAP, 0xd9, ::std::os::raw::c_int);
+    ioctl_iowr_nr!(VHOST_GET_VRING_BASE, VHOST, 0x12, ::std::os::raw::c_int);
+
+    ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, [u8; 128], evt);
+    ioctl_io_nr!(FAKE_IOCTL_2_ARG, EVDEV, 0x01 + x + y, x, y);
+
+    #[test]
+    fn ioctl_macros() {
+        assert_eq!(0x0000af01, VHOST_SET_OWNER());
+        assert_eq!(0x800454cf, TUNGETFEATURES());
+        assert_eq!(0x400454d9, TUNSETQUEUE());
+        assert_eq!(0xc004af12, VHOST_GET_VRING_BASE());
+
+        assert_eq!(0x80804522, EVIOCGBIT(2));
+        assert_eq!(0x00004509, FAKE_IOCTL_2_ARG(3, 5));
+    }
+}
diff --git a/sys_util/src/lib.rs b/sys_util/src/lib.rs
new file mode 100644
index 0000000..9e2e623
--- /dev/null
+++ b/sys_util/src/lib.rs
@@ -0,0 +1,323 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Small system utility modules for usage by other modules.
+
+pub mod affinity;
+mod alloc;
+#[macro_use]
+pub mod handle_eintr;
+#[macro_use]
+pub mod ioctl;
+#[macro_use]
+pub mod syslog;
+mod capabilities;
+mod clock;
+mod errno;
+mod eventfd;
+mod file_flags;
+mod file_traits;
+mod fork;
+mod guest_address;
+pub mod guest_memory;
+mod mmap;
+pub mod net;
+mod passwd;
+mod poll;
+mod priority;
+mod raw_fd;
+mod seek_hole;
+mod shm;
+pub mod signal;
+mod signalfd;
+mod sock_ctrl_msg;
+mod struct_util;
+mod tempdir;
+mod terminal;
+mod timerfd;
+mod write_zeroes;
+
+pub use crate::affinity::*;
+pub use crate::alloc::LayoutAllocation;
+pub use crate::capabilities::drop_capabilities;
+pub use crate::clock::{Clock, FakeClock};
+use crate::errno::errno_result;
+pub use crate::errno::{Error, Result};
+pub use crate::eventfd::*;
+pub use crate::file_flags::*;
+pub use crate::fork::*;
+pub use crate::guest_address::*;
+pub use crate::guest_memory::*;
+pub use crate::ioctl::*;
+pub use crate::mmap::*;
+pub use crate::passwd::*;
+pub use crate::poll::*;
+pub use crate::priority::*;
+pub use crate::raw_fd::*;
+pub use crate::shm::*;
+pub use crate::signal::*;
+pub use crate::signalfd::*;
+pub use crate::sock_ctrl_msg::*;
+pub use crate::struct_util::*;
+pub use crate::tempdir::*;
+pub use crate::terminal::*;
+pub use crate::timerfd::*;
+pub use poll_token_derive::*;
+
+pub use crate::file_traits::{FileReadWriteVolatile, FileSetLen, FileSync};
+pub use crate::guest_memory::Error as GuestMemoryError;
+pub use crate::mmap::Error as MmapError;
+pub use crate::seek_hole::SeekHole;
+pub use crate::signalfd::Error as SignalFdError;
+pub use crate::write_zeroes::{PunchHole, WriteZeroes};
+
+use std::ffi::CStr;
+use std::fs::{remove_file, File};
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::os::unix::net::UnixDatagram;
+use std::ptr;
+
+use libc::{
+    c_long, gid_t, kill, pid_t, pipe2, syscall, sysconf, uid_t, waitpid, O_CLOEXEC, SIGKILL,
+    WNOHANG, _SC_PAGESIZE,
+};
+
+use syscall_defines::linux::LinuxSyscall::SYS_getpid;
+
+/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
+#[inline(always)]
+pub fn pagesize() -> usize {
+    // Trivially safe
+    unsafe { sysconf(_SC_PAGESIZE) as usize }
+}
+
+/// Uses the system's page size in bytes to round the given value up to the nearest page boundary.
+#[inline(always)]
+pub fn round_up_to_page_size(v: usize) -> usize {
+    let page_mask = pagesize() - 1;
+    (v + page_mask) & !page_mask
+}
+
+/// This bypasses `libc`'s caching `getpid(2)` wrapper which can be invalid if a raw clone was used
+/// elsewhere.
+#[inline(always)]
+pub fn getpid() -> pid_t {
+    // Safe because this syscall can never fail and we give it a valid syscall number.
+    unsafe { syscall(SYS_getpid as c_long) as pid_t }
+}
+
+/// Safe wrapper for `geteuid(2)`.
+#[inline(always)]
+pub fn geteuid() -> uid_t {
+    // trivially safe
+    unsafe { libc::geteuid() }
+}
+
+/// Safe wrapper for `getegid(2)`.
+#[inline(always)]
+pub fn getegid() -> gid_t {
+    // trivially safe
+    unsafe { libc::getegid() }
+}
+
+/// Safe wrapper for chown(2).
+#[inline(always)]
+pub fn chown(path: &CStr, uid: uid_t, gid: gid_t) -> Result<()> {
+    // Safe since we pass in a valid string pointer and check the return value.
+    let ret = unsafe { libc::chown(path.as_ptr(), uid, gid) };
+
+    if ret < 0 {
+        errno_result()
+    } else {
+        Ok(())
+    }
+}
+
+/// The operation to perform with `flock`.
+pub enum FlockOperation {
+    LockShared,
+    LockExclusive,
+    Unlock,
+}
+
+/// Safe wrapper for flock(2) with the operation `op` and optionally `nonblocking`. The lock will be
+/// dropped automatically when `file` is dropped.
+#[inline(always)]
+pub fn flock(file: &dyn AsRawFd, op: FlockOperation, nonblocking: bool) -> Result<()> {
+    let mut operation = match op {
+        FlockOperation::LockShared => libc::LOCK_SH,
+        FlockOperation::LockExclusive => libc::LOCK_EX,
+        FlockOperation::Unlock => libc::LOCK_UN,
+    };
+
+    if nonblocking {
+        operation |= libc::LOCK_NB;
+    }
+
+    // Safe since we pass in a valid fd and flock operation, and check the return value.
+    let ret = unsafe { libc::flock(file.as_raw_fd(), operation) };
+
+    if ret < 0 {
+        errno_result()
+    } else {
+        Ok(())
+    }
+}
+
+/// The operation to perform with `fallocate`.
+pub enum FallocateMode {
+    PunchHole,
+    ZeroRange,
+}
+
+/// Safe wrapper for `fallocate()`.
+pub fn fallocate(
+    file: &dyn AsRawFd,
+    mode: FallocateMode,
+    keep_size: bool,
+    offset: u64,
+    len: u64,
+) -> Result<()> {
+    let offset = if offset > libc::off64_t::max_value() as u64 {
+        return Err(Error::new(libc::EINVAL));
+    } else {
+        offset as libc::off64_t
+    };
+
+    let len = if len > libc::off64_t::max_value() as u64 {
+        return Err(Error::new(libc::EINVAL));
+    } else {
+        len as libc::off64_t
+    };
+
+    let mut mode = match mode {
+        FallocateMode::PunchHole => libc::FALLOC_FL_PUNCH_HOLE,
+        FallocateMode::ZeroRange => libc::FALLOC_FL_ZERO_RANGE,
+    };
+
+    if keep_size {
+        mode |= libc::FALLOC_FL_KEEP_SIZE;
+    }
+
+    // Safe since we pass in a valid fd and fallocate mode, validate offset and len,
+    // and check the return value.
+    let ret = unsafe { libc::fallocate64(file.as_raw_fd(), mode, offset, len) };
+    if ret < 0 {
+        errno_result()
+    } else {
+        Ok(())
+    }
+}
+
+/// Reaps a child process that has terminated.
+///
+/// Returns `Ok(pid)` where `pid` is the process that was reaped or `Ok(0)` if none of the children
+/// have terminated. An `Error` is with `errno == ECHILD` if there are no children left to reap.
+///
+/// # Examples
+///
+/// Reaps all child processes until there are no terminated children to reap.
+///
+/// ```
+/// fn reap_children() {
+///     loop {
+///         match sys_util::reap_child() {
+///             Ok(0) => println!("no children ready to reap"),
+///             Ok(pid) => {
+///                 println!("reaped {}", pid);
+///                 continue
+///             },
+///             Err(e) if e.errno() == libc::ECHILD => println!("no children left"),
+///             Err(e) => println!("error reaping children: {}", e),
+///         }
+///         break
+///     }
+/// }
+/// ```
+pub fn reap_child() -> Result<pid_t> {
+    // Safe because we pass in no memory, prevent blocking with WNOHANG, and check for error.
+    let ret = unsafe { waitpid(-1, ptr::null_mut(), WNOHANG) };
+    if ret == -1 {
+        errno_result()
+    } else {
+        Ok(ret)
+    }
+}
+
+/// Kill all processes in the current process group.
+///
+/// On success, this kills all processes in the current process group, including the current
+/// process, meaning this will not return. This is equivalent to a call to `kill(0, SIGKILL)`.
+pub fn kill_process_group() -> Result<()> {
+    let ret = unsafe { kill(0, SIGKILL) };
+    if ret == -1 {
+        errno_result()
+    } else {
+        // Kill succeeded, so this process never reaches here.
+        unreachable!();
+    }
+}
+
+/// Spawns a pipe pair where the first pipe is the read end and the second pipe is the write end.
+///
+/// If `close_on_exec` is true, the `O_CLOEXEC` flag will be set during pipe creation.
+pub fn pipe(close_on_exec: bool) -> Result<(File, File)> {
+    let flags = if close_on_exec { O_CLOEXEC } else { 0 };
+    let mut pipe_fds = [-1; 2];
+    // Safe because pipe2 will only write 2 element array of i32 to the given pointer, and we check
+    // for error.
+    let ret = unsafe { pipe2(&mut pipe_fds[0], flags) };
+    if ret == -1 {
+        errno_result()
+    } else {
+        // Safe because both fds must be valid for pipe2 to have returned sucessfully and we have
+        // exclusive ownership of them.
+        Ok(unsafe {
+            (
+                File::from_raw_fd(pipe_fds[0]),
+                File::from_raw_fd(pipe_fds[1]),
+            )
+        })
+    }
+}
+
+/// Used to attempt to clean up a named pipe after it is no longer used.
+pub struct UnlinkUnixDatagram(pub UnixDatagram);
+impl AsRef<UnixDatagram> for UnlinkUnixDatagram {
+    fn as_ref(&self) -> &UnixDatagram {
+        &self.0
+    }
+}
+impl Drop for UnlinkUnixDatagram {
+    fn drop(&mut self) {
+        if let Ok(addr) = self.0.local_addr() {
+            if let Some(path) = addr.as_pathname() {
+                if let Err(e) = remove_file(path) {
+                    warn!("failed to remove control socket file: {}", e);
+                }
+            }
+        }
+    }
+}
+
+/// Verifies that |raw_fd| is actually owned by this process and duplicates it to ensure that
+/// we have a unique handle to it.
+pub fn validate_raw_fd(raw_fd: RawFd) -> Result<RawFd> {
+    // Checking that close-on-exec isn't set helps filter out FDs that were opened by
+    // crosvm as all crosvm FDs are close on exec.
+    // Safe because this doesn't modify any memory and we check the return value.
+    let flags = unsafe { libc::fcntl(raw_fd, libc::F_GETFD) };
+    if flags < 0 || (flags & libc::FD_CLOEXEC) != 0 {
+        return Err(Error::new(libc::EBADF));
+    }
+
+    // Duplicate the fd to ensure that we don't accidentally close an fd previously
+    // opened by another subsystem.  Safe because this doesn't modify any memory and
+    // we check the return value.
+    let dup_fd = unsafe { libc::fcntl(raw_fd, libc::F_DUPFD_CLOEXEC, 0) };
+    if dup_fd < 0 {
+        return Err(Error::last());
+    }
+    Ok(dup_fd as RawFd)
+}
diff --git a/sys_util/src/mmap.rs b/sys_util/src/mmap.rs
new file mode 100644
index 0000000..3d1e577
--- /dev/null
+++ b/sys_util/src/mmap.rs
@@ -0,0 +1,986 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! The mmap module provides a safe interface to mmap memory and ensures unmap is called when the
+//! mmap object leaves scope.
+
+use std::cmp::min;
+use std::collections::BTreeMap;
+use std::fmt::{self, Display};
+use std::io;
+use std::mem::{size_of, ManuallyDrop};
+use std::os::unix::io::AsRawFd;
+use std::ptr::{copy_nonoverlapping, null_mut, read_unaligned, write_unaligned};
+
+use libc::{self, c_int, c_void, read, write};
+
+use data_model::volatile_memory::*;
+use data_model::DataInit;
+
+use crate::{errno, pagesize};
+
+#[derive(Debug)]
+pub enum Error {
+    /// Requested memory out of range.
+    InvalidAddress,
+    /// Requested offset is out of range of `libc::off_t`.
+    InvalidOffset,
+    /// Requested mapping is not page aligned
+    NotPageAligned,
+    /// Overlapping regions
+    Overlapping(usize, usize),
+    /// Requested memory range spans past the end of the region.
+    InvalidRange(usize, usize, usize),
+    /// `mmap` returned the given error.
+    SystemCallFailed(errno::Error),
+    /// Writing to memory failed
+    ReadToMemory(io::Error),
+    /// Reading from memory failed
+    WriteFromMemory(io::Error),
+}
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            InvalidAddress => write!(f, "requested memory out of range"),
+            InvalidOffset => write!(f, "requested offset is out of range of off_t"),
+            NotPageAligned => write!(f, "requested memory is not page aligned"),
+            Overlapping(offset, count) => write!(
+                f,
+                "requested memory range overlaps with existing region: offset={} size={}",
+                offset, count
+            ),
+            InvalidRange(offset, count, region_size) => write!(
+                f,
+                "requested memory range spans past the end of the region: offset={} count={} region_size={}",
+                offset, count, region_size,
+            ),
+            SystemCallFailed(e) => write!(f, "mmap system call failed: {}", e),
+            ReadToMemory(e) => write!(f, "failed to read from file to memory: {}", e),
+            WriteFromMemory(e) => write!(f, "failed to write from memory to file: {}", e),
+        }
+    }
+}
+
+/// Memory access type for anonymous shared memory mapping.
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub struct Protection(c_int);
+impl Protection {
+    /// Returns Protection allowing no access.
+    #[inline(always)]
+    pub fn none() -> Protection {
+        Protection(libc::PROT_NONE)
+    }
+
+    /// Returns Protection allowing read/write access.
+    #[inline(always)]
+    pub fn read_write() -> Protection {
+        Protection(libc::PROT_READ | libc::PROT_WRITE)
+    }
+
+    /// Returns Protection allowing read access.
+    #[inline(always)]
+    pub fn read() -> Protection {
+        Protection(libc::PROT_READ)
+    }
+
+    /// Set read events.
+    #[inline(always)]
+    pub fn set_read(self) -> Protection {
+        Protection(self.0 | libc::PROT_READ)
+    }
+
+    /// Set write events.
+    #[inline(always)]
+    pub fn set_write(self) -> Protection {
+        Protection(self.0 | libc::PROT_WRITE)
+    }
+}
+
+impl From<c_int> for Protection {
+    fn from(f: c_int) -> Self {
+        Protection(f)
+    }
+}
+
+impl Into<c_int> for Protection {
+    fn into(self) -> c_int {
+        self.0
+    }
+}
+
+/// Wraps an anonymous shared memory mapping in the current process.
+#[derive(Debug)]
+pub struct MemoryMapping {
+    addr: *mut u8,
+    size: usize,
+}
+
+// Send and Sync aren't automatically inherited for the raw address pointer.
+// Accessing that pointer is only done through the stateless interface which
+// allows the object to be shared by multiple threads without a decrease in
+// safety.
+unsafe impl Send for MemoryMapping {}
+unsafe impl Sync for MemoryMapping {}
+
+impl MemoryMapping {
+    /// Creates an anonymous shared, read/write mapping of `size` bytes.
+    ///
+    /// # Arguments
+    /// * `size` - Size of memory region in bytes.
+    pub fn new(size: usize) -> Result<MemoryMapping> {
+        MemoryMapping::new_protection(size, Protection::read_write())
+    }
+
+    /// Creates an anonymous shared mapping of `size` bytes with `prot` protection.
+    ///
+    /// # Arguments
+    /// * `size` - Size of memory region in bytes.
+    /// * `prot` - Protection (e.g. readable/writable) of the memory region.
+    pub fn new_protection(size: usize, prot: Protection) -> Result<MemoryMapping> {
+        // This is safe because we are creating an anonymous mapping in a place not already used by
+        // any other area in this process.
+        unsafe {
+            MemoryMapping::try_mmap(
+                None,
+                size,
+                prot.into(),
+                libc::MAP_ANONYMOUS | libc::MAP_SHARED | libc::MAP_NORESERVE,
+                None,
+            )
+        }
+    }
+
+    /// Maps the first `size` bytes of the given `fd` as read/write.
+    ///
+    /// # Arguments
+    /// * `fd` - File descriptor to mmap from.
+    /// * `size` - Size of memory region in bytes.
+    pub fn from_fd(fd: &dyn AsRawFd, size: usize) -> Result<MemoryMapping> {
+        MemoryMapping::from_fd_offset(fd, size, 0)
+    }
+
+    pub fn from_fd_offset(fd: &dyn AsRawFd, size: usize, offset: usize) -> Result<MemoryMapping> {
+        MemoryMapping::from_fd_offset_protection(fd, size, offset, Protection::read_write())
+    }
+
+    /// Maps the `size` bytes starting at `offset` bytes of the given `fd` as read/write.
+    ///
+    /// # Arguments
+    /// * `fd` - File descriptor to mmap from.
+    /// * `size` - Size of memory region in bytes.
+    /// * `offset` - Offset in bytes from the beginning of `fd` to start the mmap.
+    /// * `prot` - Protection (e.g. readable/writable) of the memory region.
+    pub fn from_fd_offset_protection(
+        fd: &dyn AsRawFd,
+        size: usize,
+        offset: usize,
+        prot: Protection,
+    ) -> Result<MemoryMapping> {
+        // This is safe because we are creating an anonymous mapping in a place not already used by
+        // any other area in this process.
+        unsafe {
+            MemoryMapping::try_mmap(
+                None,
+                size,
+                prot.into(),
+                libc::MAP_SHARED,
+                Some((fd, offset)),
+            )
+        }
+    }
+
+    /// Creates an anonymous shared mapping of `size` bytes with `prot` protection.
+    /// Unsafe: unmaps any mmap'd regions already present at (addr..addr+size).
+    ///
+    /// # Arguments
+    /// * `addr` - Memory address to mmap at.
+    /// * `size` - Size of memory region in bytes.
+    /// * `prot` - Protection (e.g. readable/writable) of the memory region.
+    pub unsafe fn new_protection_fixed(
+        addr: *mut u8,
+        size: usize,
+        prot: Protection,
+    ) -> Result<MemoryMapping> {
+        MemoryMapping::try_mmap(
+            Some(addr),
+            size,
+            prot.into(),
+            libc::MAP_ANONYMOUS | libc::MAP_SHARED | libc::MAP_NORESERVE,
+            None,
+        )
+    }
+
+    /// Maps the `size` bytes starting at `offset` bytes of the given `fd` with
+    /// `prot` protections.
+    /// Unsafe: unmaps any mmap'd regions already present at (addr..addr+size).
+    ///
+    /// # Arguments
+    /// * `addr` - Memory address to mmap at.
+    /// * `fd` - File descriptor to mmap from.
+    /// * `size` - Size of memory region in bytes.
+    /// * `offset` - Offset in bytes from the beginning of `fd` to start the mmap.
+    /// * `prot` - Protection (e.g. readable/writable) of the memory region.
+    pub unsafe fn from_fd_offset_protection_fixed(
+        addr: *mut u8,
+        fd: &dyn AsRawFd,
+        size: usize,
+        offset: usize,
+        prot: Protection,
+    ) -> Result<MemoryMapping> {
+        MemoryMapping::try_mmap(
+            Some(addr),
+            size,
+            prot.into(),
+            libc::MAP_SHARED | libc::MAP_NORESERVE,
+            Some((fd, offset)),
+        )
+    }
+
+    /// Helper wrapper around libc::mmap that does some basic validation, and calls
+    /// madvise with MADV_DONTDUMP on the created mmap
+    unsafe fn try_mmap(
+        addr: Option<*mut u8>,
+        size: usize,
+        prot: c_int,
+        flags: c_int,
+        fd: Option<(&AsRawFd, usize)>,
+    ) -> Result<MemoryMapping> {
+        let mut flags = flags;
+        // If addr is provided, set the FIXED flag, and validate addr alignment
+        let addr = match addr {
+            Some(addr) => {
+                if (addr as usize) % pagesize() != 0 {
+                    return Err(Error::NotPageAligned);
+                }
+                flags |= libc::MAP_FIXED;
+                addr as *mut libc::c_void
+            }
+            None => null_mut(),
+        };
+        // If fd is provided, validate fd offset is within bounds
+        let (fd, offset) = match fd {
+            Some((fd, offset)) => {
+                if offset > libc::off_t::max_value() as usize {
+                    return Err(Error::InvalidOffset);
+                }
+                (fd.as_raw_fd(), offset as libc::off_t)
+            }
+            None => (-1, 0),
+        };
+        let addr = libc::mmap(addr, size, prot, flags, fd, offset);
+        if addr == libc::MAP_FAILED {
+            return Err(Error::SystemCallFailed(errno::Error::last()));
+        }
+        // This is safe because we call madvise with a valid address and size, and we check the
+        // return value. We only warn about an error because failure here is not fatal to the mmap.
+        if libc::madvise(addr, size, libc::MADV_DONTDUMP) == -1 {
+            warn!(
+                "failed madvise(MADV_DONTDUMP) on mmap: {}",
+                errno::Error::last()
+            );
+        }
+        Ok(MemoryMapping {
+            addr: addr as *mut u8,
+            size,
+        })
+    }
+
+    /// Returns a pointer to the beginning of the memory region. Should only be
+    /// used for passing this region to ioctls for setting guest memory.
+    pub fn as_ptr(&self) -> *mut u8 {
+        self.addr
+    }
+
+    /// Returns the size of the memory region in bytes.
+    pub fn size(&self) -> usize {
+        self.size
+    }
+
+    /// Calls msync with MS_SYNC on the mapping.
+    pub fn msync(&self) -> Result<()> {
+        // This is safe since we use the exact address and length of a known
+        // good memory mapping.
+        let ret = unsafe {
+            libc::msync(
+                self.as_ptr() as *mut libc::c_void,
+                self.size(),
+                libc::MS_SYNC,
+            )
+        };
+        if ret == -1 {
+            return Err(Error::SystemCallFailed(errno::Error::last()));
+        }
+        Ok(())
+    }
+
+    /// Writes a slice to the memory region at the specified offset.
+    /// Returns the number of bytes written.  The number of bytes written can
+    /// be less than the length of the slice if there isn't enough room in the
+    /// memory region.
+    ///
+    /// # Examples
+    /// * Write a slice at offset 256.
+    ///
+    /// ```
+    /// #   use sys_util::MemoryMapping;
+    /// #   let mut mem_map = MemoryMapping::new(1024).unwrap();
+    ///     let res = mem_map.write_slice(&[1,2,3,4,5], 256);
+    ///     assert!(res.is_ok());
+    ///     assert_eq!(res.unwrap(), 5);
+    /// ```
+    pub fn write_slice(&self, buf: &[u8], offset: usize) -> Result<usize> {
+        match self.size.checked_sub(offset) {
+            Some(size_past_offset) => {
+                let bytes_copied = min(size_past_offset, buf.len());
+                // The bytes_copied equation above ensures we don't copy bytes out of range of
+                // either buf or this slice. We also know that the buffers do not overlap because
+                // slices can never occupy the same memory as a volatile slice.
+                unsafe {
+                    copy_nonoverlapping(buf.as_ptr(), self.as_ptr().add(offset), bytes_copied);
+                }
+                Ok(bytes_copied)
+            }
+            None => Err(Error::InvalidAddress),
+        }
+    }
+
+    /// Reads to a slice from the memory region at the specified offset.
+    /// Returns the number of bytes read.  The number of bytes read can
+    /// be less than the length of the slice if there isn't enough room in the
+    /// memory region.
+    ///
+    /// # Examples
+    /// * Read a slice of size 16 at offset 256.
+    ///
+    /// ```
+    /// #   use sys_util::MemoryMapping;
+    /// #   let mut mem_map = MemoryMapping::new(1024).unwrap();
+    ///     let buf = &mut [0u8; 16];
+    ///     let res = mem_map.read_slice(buf, 256);
+    ///     assert!(res.is_ok());
+    ///     assert_eq!(res.unwrap(), 16);
+    /// ```
+    pub fn read_slice(&self, buf: &mut [u8], offset: usize) -> Result<usize> {
+        match self.size.checked_sub(offset) {
+            Some(size_past_offset) => {
+                let bytes_copied = min(size_past_offset, buf.len());
+                // The bytes_copied equation above ensures we don't copy bytes out of range of
+                // either buf or this slice. We also know that the buffers do not overlap because
+                // slices can never occupy the same memory as a volatile slice.
+                unsafe {
+                    copy_nonoverlapping(
+                        self.as_ptr().add(offset) as *const u8,
+                        buf.as_mut_ptr(),
+                        bytes_copied,
+                    );
+                }
+                Ok(bytes_copied)
+            }
+            None => Err(Error::InvalidAddress),
+        }
+    }
+
+    /// Writes an object to the memory region at the specified offset.
+    /// Returns Ok(()) if the object fits, or Err if it extends past the end.
+    ///
+    /// # Examples
+    /// * Write a u64 at offset 16.
+    ///
+    /// ```
+    /// #   use sys_util::MemoryMapping;
+    /// #   let mut mem_map = MemoryMapping::new(1024).unwrap();
+    ///     let res = mem_map.write_obj(55u64, 16);
+    ///     assert!(res.is_ok());
+    /// ```
+    pub fn write_obj<T: DataInit>(&self, val: T, offset: usize) -> Result<()> {
+        self.range_end(offset, size_of::<T>())?;
+        // This is safe because we checked the bounds above.
+        unsafe {
+            write_unaligned(self.as_ptr().add(offset) as *mut T, val);
+        }
+        Ok(())
+    }
+
+    /// Reads on object from the memory region at the given offset.
+    /// Reading from a volatile area isn't strictly safe as it could change
+    /// mid-read.  However, as long as the type T is plain old data and can
+    /// handle random initialization, everything will be OK.
+    ///
+    /// # Examples
+    /// * Read a u64 written to offset 32.
+    ///
+    /// ```
+    /// #   use sys_util::MemoryMapping;
+    /// #   let mut mem_map = MemoryMapping::new(1024).unwrap();
+    ///     let res = mem_map.write_obj(55u64, 32);
+    ///     assert!(res.is_ok());
+    ///     let num: u64 = mem_map.read_obj(32).unwrap();
+    ///     assert_eq!(55, num);
+    /// ```
+    pub fn read_obj<T: DataInit>(&self, offset: usize) -> Result<T> {
+        self.range_end(offset, size_of::<T>())?;
+        // This is safe because by definition Copy types can have their bits set arbitrarily and
+        // still be valid.
+        unsafe {
+            Ok(read_unaligned(
+                self.as_ptr().add(offset) as *const u8 as *const T
+            ))
+        }
+    }
+
+    /// Reads data from a file descriptor and writes it to guest memory.
+    ///
+    /// # Arguments
+    /// * `mem_offset` - Begin writing memory at this offset.
+    /// * `src` - Read from `src` to memory.
+    /// * `count` - Read `count` bytes from `src` to memory.
+    ///
+    /// # Examples
+    ///
+    /// * Read bytes from /dev/urandom
+    ///
+    /// ```
+    /// # use sys_util::MemoryMapping;
+    /// # use std::fs::File;
+    /// # use std::path::Path;
+    /// # fn test_read_random() -> Result<u32, ()> {
+    /// #     let mut mem_map = MemoryMapping::new(1024).unwrap();
+    ///       let mut file = File::open(Path::new("/dev/urandom")).map_err(|_| ())?;
+    ///       mem_map.read_to_memory(32, &mut file, 128).map_err(|_| ())?;
+    ///       let rand_val: u32 =  mem_map.read_obj(40).map_err(|_| ())?;
+    /// #     Ok(rand_val)
+    /// # }
+    /// ```
+    pub fn read_to_memory(
+        &self,
+        mut mem_offset: usize,
+        src: &AsRawFd,
+        mut count: usize,
+    ) -> Result<()> {
+        self.range_end(mem_offset, count)
+            .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
+        while count > 0 {
+            // The check above ensures that no memory outside this slice will get accessed by this
+            // read call.
+            match unsafe {
+                read(
+                    src.as_raw_fd(),
+                    self.as_ptr().add(mem_offset) as *mut c_void,
+                    count,
+                )
+            } {
+                0 => {
+                    return Err(Error::ReadToMemory(io::Error::from(
+                        io::ErrorKind::UnexpectedEof,
+                    )))
+                }
+                r if r < 0 => return Err(Error::ReadToMemory(io::Error::last_os_error())),
+                ret => {
+                    let bytes_read = ret as usize;
+                    match count.checked_sub(bytes_read) {
+                        Some(count_remaining) => count = count_remaining,
+                        None => break,
+                    }
+                    mem_offset += ret as usize;
+                }
+            }
+        }
+        Ok(())
+    }
+
+    /// Writes data from memory to a file descriptor.
+    ///
+    /// # Arguments
+    /// * `mem_offset` - Begin reading memory from this offset.
+    /// * `dst` - Write from memory to `dst`.
+    /// * `count` - Read `count` bytes from memory to `src`.
+    ///
+    /// # Examples
+    ///
+    /// * Write 128 bytes to /dev/null
+    ///
+    /// ```
+    /// # use sys_util::MemoryMapping;
+    /// # use std::fs::File;
+    /// # use std::path::Path;
+    /// # fn test_write_null() -> Result<(), ()> {
+    /// #     let mut mem_map = MemoryMapping::new(1024).unwrap();
+    ///       let mut file = File::open(Path::new("/dev/null")).map_err(|_| ())?;
+    ///       mem_map.write_from_memory(32, &mut file, 128).map_err(|_| ())?;
+    /// #     Ok(())
+    /// # }
+    /// ```
+    pub fn write_from_memory(
+        &self,
+        mut mem_offset: usize,
+        dst: &AsRawFd,
+        mut count: usize,
+    ) -> Result<()> {
+        self.range_end(mem_offset, count)
+            .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
+        while count > 0 {
+            // The check above ensures that no memory outside this slice will get accessed by this
+            // write call.
+            match unsafe {
+                write(
+                    dst.as_raw_fd(),
+                    self.as_ptr().add(mem_offset) as *const c_void,
+                    count,
+                )
+            } {
+                0 => {
+                    return Err(Error::WriteFromMemory(io::Error::from(
+                        io::ErrorKind::WriteZero,
+                    )))
+                }
+                ret if ret < 0 => return Err(Error::WriteFromMemory(io::Error::last_os_error())),
+                ret => {
+                    let bytes_written = ret as usize;
+                    match count.checked_sub(bytes_written) {
+                        Some(count_remaining) => count = count_remaining,
+                        None => break,
+                    }
+                    mem_offset += ret as usize;
+                }
+            }
+        }
+        Ok(())
+    }
+
+    /// Uses madvise to tell the kernel to remove the specified range.  Subsequent reads
+    /// to the pages in the range will return zero bytes.
+    pub fn remove_range(&self, mem_offset: usize, count: usize) -> Result<()> {
+        self.range_end(mem_offset, count)
+            .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
+        let ret = unsafe {
+            // madvising away the region is the same as the guest changing it.
+            // Next time it is read, it may return zero pages.
+            libc::madvise(
+                (self.addr as usize + mem_offset) as *mut _,
+                count,
+                libc::MADV_REMOVE,
+            )
+        };
+        if ret < 0 {
+            Err(Error::InvalidRange(mem_offset, count, self.size()))
+        } else {
+            Ok(())
+        }
+    }
+
+    // Check that offset+count is valid and return the sum.
+    fn range_end(&self, offset: usize, count: usize) -> Result<usize> {
+        let mem_end = offset.checked_add(count).ok_or(Error::InvalidAddress)?;
+        if mem_end > self.size() {
+            return Err(Error::InvalidAddress);
+        }
+        Ok(mem_end)
+    }
+}
+
+impl VolatileMemory for MemoryMapping {
+    fn get_slice(&self, offset: u64, count: u64) -> VolatileMemoryResult<VolatileSlice> {
+        let mem_end = calc_offset(offset, count)?;
+        if mem_end > self.size as u64 {
+            return Err(VolatileMemoryError::OutOfBounds { addr: mem_end });
+        }
+
+        // Safe because we checked that offset + count was within our range and we only ever hand
+        // out volatile accessors.
+        Ok(unsafe { VolatileSlice::new((self.addr as usize + offset as usize) as *mut _, count) })
+    }
+}
+
+impl Drop for MemoryMapping {
+    fn drop(&mut self) {
+        // This is safe because we mmap the area at addr ourselves, and nobody
+        // else is holding a reference to it.
+        unsafe {
+            libc::munmap(self.addr as *mut libc::c_void, self.size);
+        }
+    }
+}
+
+/// Tracks Fixed Memory Maps within an anonymous memory-mapped fixed-sized arena
+/// in the current process.
+pub struct MemoryMappingArena {
+    addr: *mut u8,
+    size: usize,
+    // When doing in-place swaps of MemoryMappings, the BTreeMap returns a owned
+    // instance of the old MemoryMapping. When the old MemoryMapping falls out
+    // of scope, it calls munmap on the same region as the new MemoryMapping
+    // that was just mapped in. To avoid accidentally munmapping the new,
+    // MemoryMapping, all mappings are wrapped in a ManuallyDrop, and then
+    // "forgotten" when removed from the BTreeMap
+    maps: BTreeMap<usize, ManuallyDrop<MemoryMapping>>,
+}
+
+// Send and Sync aren't automatically inherited for the raw address pointer.
+// Accessing that pointer is only done through the stateless interface which
+// allows the object to be shared by multiple threads without a decrease in
+// safety.
+unsafe impl Send for MemoryMappingArena {}
+unsafe impl Sync for MemoryMappingArena {}
+
+impl MemoryMappingArena {
+    /// Creates an mmap arena of `size` bytes.
+    ///
+    /// # Arguments
+    /// * `size` - Size of memory region in bytes.
+    pub fn new(size: usize) -> Result<MemoryMappingArena> {
+        // Reserve the arena's memory using an anonymous read-only mmap.
+        // The actual MemoryMapping object is forgotten, with
+        // MemoryMappingArena manually calling munmap on drop.
+        let mmap = MemoryMapping::new_protection(size, Protection::none().set_read())?;
+        let addr = mmap.as_ptr();
+        let size = mmap.size();
+        std::mem::forget(mmap);
+        Ok(MemoryMappingArena {
+            addr,
+            size,
+            maps: BTreeMap::new(),
+        })
+    }
+
+    /// Anonymously maps `size` bytes at `offset` bytes from the start of the arena.
+    /// `offset` must be page aligned.
+    ///
+    /// # Arguments
+    /// * `offset` - Page aligned offset into the arena in bytes.
+    /// * `size` - Size of memory region in bytes.
+    /// * `fd` - File descriptor to mmap from.
+    pub fn add_anon(&mut self, offset: usize, size: usize) -> Result<()> {
+        self.try_add(offset, size, Protection::read_write(), None)
+    }
+
+    /// Maps `size` bytes from the start of the given `fd` at `offset` bytes from
+    /// the start of the arena. `offset` must be page aligned.
+    ///
+    /// # Arguments
+    /// * `offset` - Page aligned offset into the arena in bytes.
+    /// * `size` - Size of memory region in bytes.
+    /// * `fd` - File descriptor to mmap from.
+    pub fn add_fd(&mut self, offset: usize, size: usize, fd: &dyn AsRawFd) -> Result<()> {
+        self.add_fd_offset(offset, size, fd, 0)
+    }
+
+    /// Maps `size` bytes starting at `fs_offset` bytes from within the given `fd`
+    /// at `offset` bytes from the start of the arena. `offset` must be page aligned.
+    ///
+    /// # Arguments
+    /// * `offset` - Page aligned offset into the arena in bytes.
+    /// * `size` - Size of memory region in bytes.
+    /// * `fd` - File descriptor to mmap from.
+    /// * `fd_offset` - Offset in bytes from the beginning of `fd` to start the mmap.
+    pub fn add_fd_offset(
+        &mut self,
+        offset: usize,
+        size: usize,
+        fd: &dyn AsRawFd,
+        fd_offset: usize,
+    ) -> Result<()> {
+        self.add_fd_offset_protection(offset, size, fd, fd_offset, Protection::read_write())
+    }
+
+    /// Maps `size` bytes starting at `fs_offset` bytes from within the given `fd`
+    /// at `offset` bytes from the start of the arena with `prot` protections.
+    /// `offset` must be page aligned.
+    ///
+    /// # Arguments
+    /// * `offset` - Page aligned offset into the arena in bytes.
+    /// * `size` - Size of memory region in bytes.
+    /// * `fd` - File descriptor to mmap from.
+    /// * `fd_offset` - Offset in bytes from the beginning of `fd` to start the mmap.
+    /// * `prot` - Protection (e.g. readable/writable) of the memory region.
+    pub fn add_fd_offset_protection(
+        &mut self,
+        offset: usize,
+        size: usize,
+        fd: &dyn AsRawFd,
+        fd_offset: usize,
+        prot: Protection,
+    ) -> Result<()> {
+        self.try_add(offset, size, prot, Some((fd, fd_offset)))
+    }
+
+    /// Helper method that calls appropriate MemoryMapping constructor and adds
+    /// the resulting map into the arena.
+    fn try_add(
+        &mut self,
+        offset: usize,
+        size: usize,
+        prot: Protection,
+        fd: Option<(&AsRawFd, usize)>,
+    ) -> Result<()> {
+        self.validate_range(offset, size)?;
+
+        // This is safe since the range has been validated.
+        let mmap = unsafe {
+            match fd {
+                Some((fd, fd_offset)) => MemoryMapping::from_fd_offset_protection_fixed(
+                    (self.addr as usize + offset) as *mut u8,
+                    fd,
+                    size,
+                    fd_offset,
+                    prot,
+                )?,
+                None => MemoryMapping::new_protection_fixed(
+                    (self.addr as usize + offset) as *mut u8,
+                    size,
+                    prot,
+                )?,
+            }
+        };
+
+        self.maps.insert(offset, ManuallyDrop::new(mmap));
+        Ok(())
+    }
+
+    /// Removes a mapping at `offset` from the start of the arena.
+    /// Returns a boolean indicating if there was a mapping present at `offset`.
+    /// If none was present, this method is a noop.
+    pub fn remove(&mut self, offset: usize) -> Result<bool> {
+        if let Some(mmap) = self.maps.remove(&offset) {
+            // Instead of munmapping the memory map, leaving an unprotected hole
+            // in the arena, swap this mmap with an anonymous protection.
+            // This is safe since the memory mapping perfectly overlaps with an
+            // existing, known good memory mapping.
+            let mmap = unsafe {
+                MemoryMapping::new_protection_fixed(
+                    mmap.as_ptr(),
+                    mmap.size(),
+                    Protection::none().set_read(),
+                )?
+            };
+            self.maps.insert(offset, ManuallyDrop::new(mmap));
+            Ok(true)
+        } else {
+            Ok(false)
+        }
+    }
+
+    /// Calls msync with MS_SYNC on the mapping at `offset` from the start of
+    /// the arena.
+    /// Returns a boolean indicating if there was a mapping present at `offset`.
+    /// If none was present, this method is a noop.
+    pub fn msync(&self, offset: usize) -> Result<bool> {
+        if let Some(mmap) = self.maps.get(&offset) {
+            mmap.msync()?;
+            Ok(true)
+        } else {
+            Ok(false)
+        }
+    }
+
+    /// Returns a pointer to the beginning of the memory region.  Should only be
+    /// used for passing this region to ioctls for setting guest memory.
+    pub fn as_ptr(&self) -> *mut u8 {
+        self.addr
+    }
+
+    /// Returns the size of the memory region in bytes.
+    pub fn size(&self) -> usize {
+        self.size
+    }
+
+    /// Validates `offset` and `size`.
+    /// Checks that offset..offset+size doesn't overlap with existing mappings.
+    /// Also ensures correct alignment, and checks for any overflow.
+    /// Note: offset..offset+size is considered valid if it _perfectly_ overlaps
+    /// with single other region.
+    fn validate_range(&self, offset: usize, size: usize) -> Result<()> {
+        // Ensure offset is page-aligned
+        if offset % pagesize() != 0 {
+            return Err(Error::NotPageAligned);
+        }
+        // Ensure offset + size doesn't overflow
+        let end_offset = offset.checked_add(size).ok_or(Error::InvalidAddress)?;
+        // Ensure offset + size are within the arena bounds
+        if end_offset > self.size {
+            return Err(Error::InvalidAddress);
+        }
+        // Ensure offset..offset+size doesn't overlap with existing regions
+        // Find the offset + size of the first mapping before the desired offset
+        let (prev_offset, prev_size) = match self.maps.range(..offset).rev().next() {
+            Some((offset, mmap)) => (*offset, mmap.size()),
+            None => {
+                // Empty map
+                return Ok(());
+            }
+        };
+        if offset == prev_offset {
+            // Perfectly overlapping regions are allowed
+            if size != prev_size {
+                return Err(Error::Overlapping(offset, size));
+            }
+        } else if offset < (prev_offset + prev_size) {
+            return Err(Error::Overlapping(offset, size));
+        }
+
+        Ok(())
+    }
+}
+
+impl Drop for MemoryMappingArena {
+    fn drop(&mut self) {
+        // This is safe because we mmap the area at addr ourselves, and nobody
+        // else is holding a reference to it.
+        unsafe {
+            libc::munmap(self.addr as *mut libc::c_void, self.size);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use data_model::{VolatileMemory, VolatileMemoryError};
+    use std::os::unix::io::FromRawFd;
+
+    #[test]
+    fn basic_map() {
+        let m = MemoryMapping::new(1024).unwrap();
+        assert_eq!(1024, m.size());
+    }
+
+    #[test]
+    fn map_invalid_size() {
+        let res = MemoryMapping::new(0).unwrap_err();
+        if let Error::SystemCallFailed(e) = res {
+            assert_eq!(e.errno(), libc::EINVAL);
+        } else {
+            panic!("unexpected error: {}", res);
+        }
+    }
+
+    #[test]
+    fn map_invalid_fd() {
+        let fd = unsafe { std::fs::File::from_raw_fd(-1) };
+        let res = MemoryMapping::from_fd(&fd, 1024).unwrap_err();
+        if let Error::SystemCallFailed(e) = res {
+            assert_eq!(e.errno(), libc::EBADF);
+        } else {
+            panic!("unexpected error: {}", res);
+        }
+    }
+
+    #[test]
+    fn test_write_past_end() {
+        let m = MemoryMapping::new(5).unwrap();
+        let res = m.write_slice(&[1, 2, 3, 4, 5, 6], 0);
+        assert!(res.is_ok());
+        assert_eq!(res.unwrap(), 5);
+    }
+
+    #[test]
+    fn slice_size() {
+        let m = MemoryMapping::new(5).unwrap();
+        let s = m.get_slice(2, 3).unwrap();
+        assert_eq!(s.size(), 3);
+    }
+
+    #[test]
+    fn slice_addr() {
+        let m = MemoryMapping::new(5).unwrap();
+        let s = m.get_slice(2, 3).unwrap();
+        assert_eq!(s.as_ptr(), unsafe { m.as_ptr().offset(2) });
+    }
+
+    #[test]
+    fn slice_store() {
+        let m = MemoryMapping::new(5).unwrap();
+        let r = m.get_ref(2).unwrap();
+        r.store(9u16);
+        assert_eq!(m.read_obj::<u16>(2).unwrap(), 9);
+    }
+
+    #[test]
+    fn slice_overflow_error() {
+        let m = MemoryMapping::new(5).unwrap();
+        let res = m.get_slice(std::u64::MAX, 3).unwrap_err();
+        assert_eq!(
+            res,
+            VolatileMemoryError::Overflow {
+                base: std::u64::MAX,
+                offset: 3,
+            }
+        );
+    }
+    #[test]
+    fn slice_oob_error() {
+        let m = MemoryMapping::new(5).unwrap();
+        let res = m.get_slice(3, 3).unwrap_err();
+        assert_eq!(res, VolatileMemoryError::OutOfBounds { addr: 6 });
+    }
+
+    #[test]
+    fn from_fd_offset_invalid() {
+        let fd = unsafe { std::fs::File::from_raw_fd(-1) };
+        let res = MemoryMapping::from_fd_offset(&fd, 4096, (libc::off_t::max_value() as usize) + 1)
+            .unwrap_err();
+        match res {
+            Error::InvalidOffset => {}
+            e => panic!("unexpected error: {}", e),
+        }
+    }
+
+    #[test]
+    fn arena_new() {
+        let m = MemoryMappingArena::new(0x40000).unwrap();
+        assert_eq!(m.size(), 0x40000);
+    }
+
+    #[test]
+    fn arena_add() {
+        let mut m = MemoryMappingArena::new(0x40000).unwrap();
+        assert!(m.add_anon(0, pagesize() * 4).is_ok());
+    }
+
+    #[test]
+    fn arena_remove() {
+        let mut m = MemoryMappingArena::new(0x40000).unwrap();
+        assert!(m.add_anon(0, pagesize() * 4).is_ok());
+        assert!(m.remove(0).unwrap(), true);
+        assert!(m.remove(0).unwrap(), false);
+    }
+
+    #[test]
+    fn arena_add_overlap_error() {
+        let page = pagesize();
+        let mut m = MemoryMappingArena::new(page * 4).unwrap();
+        assert!(m.add_anon(0, page * 4).is_ok());
+        let res = m.add_anon(page, page).unwrap_err();
+        match res {
+            Error::Overlapping(a, o) => {
+                assert_eq!((a, o), (page, page));
+            }
+            e => panic!("unexpected error: {}", e),
+        }
+    }
+
+    #[test]
+    fn arena_add_alignment_error() {
+        let mut m = MemoryMappingArena::new(pagesize() * 2).unwrap();
+        assert!(m.add_anon(0, 0x100).is_ok());
+        let res = m.add_anon(pagesize() + 1, 0x100).unwrap_err();
+        match res {
+            Error::NotPageAligned => {}
+            e => panic!("unexpected error: {}", e),
+        }
+    }
+
+    #[test]
+    fn arena_add_oob_error() {
+        let mut m = MemoryMappingArena::new(pagesize()).unwrap();
+        let res = m.add_anon(0, pagesize() + 1).unwrap_err();
+        match res {
+            Error::InvalidAddress => {}
+            e => panic!("unexpected error: {}", e),
+        }
+    }
+}
diff --git a/sys_util/src/net.rs b/sys_util/src/net.rs
new file mode 100644
index 0000000..70f975b
--- /dev/null
+++ b/sys_util/src/net.rs
@@ -0,0 +1,587 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::ffi::OsString;
+use std::fs::remove_file;
+use std::io;
+use std::mem;
+use std::ops::Deref;
+use std::os::unix::{
+    ffi::{OsStrExt, OsStringExt},
+    io::{AsRawFd, FromRawFd, RawFd},
+};
+use std::path::Path;
+use std::path::PathBuf;
+use std::ptr::null_mut;
+use std::time::Duration;
+
+// Offset of sun_path in structure sockaddr_un.
+fn sun_path_offset() -> usize {
+    // Prefer 0 to null() so that we do not need to subtract from the `sub_path` pointer.
+    #[allow(clippy::zero_ptr)]
+    let addr = 0 as *const libc::sockaddr_un;
+    // Safe because we only use the dereference to create a pointer to the desired field in
+    // calculating the offset.
+    unsafe { &(*addr).sun_path as *const _ as usize }
+}
+
+// Return `sockaddr_un` for a given `path`
+fn sockaddr_un<P: AsRef<Path>>(path: P) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
+    let mut addr = libc::sockaddr_un {
+        sun_family: libc::AF_UNIX as libc::sa_family_t,
+        sun_path: [0; 108],
+    };
+
+    // Check if the input path is valid. Since
+    // * The pathname in sun_path should be null-terminated.
+    // * The length of the pathname, including the terminating null byte,
+    //   should not exceed the size of sun_path.
+    //
+    // and our input is a `Path`, we only need to check
+    // * If the string size of `Path` should less than sizeof(sun_path)
+    // and make sure `sun_path` ends with '\0' by initialized the sun_path with zeros.
+    //
+    // Empty path name is valid since abstract socket address has sun_paht[0] = '\0'
+    let bytes = path.as_ref().as_os_str().as_bytes();
+    if bytes.len() >= addr.sun_path.len() {
+        return Err(io::Error::new(
+            io::ErrorKind::InvalidInput,
+            "Input path size should be less than the length of sun_path.",
+        ));
+    };
+
+    // Copy data from `path` to `addr.sun_path`
+    for (dst, src) in addr.sun_path.iter_mut().zip(bytes) {
+        *dst = *src as libc::c_char;
+    }
+
+    // The addrlen argument that describes the enclosing sockaddr_un structure
+    // should have a value of at least:
+    //
+    //     offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path) + 1
+    //
+    // or, more simply, addrlen can be specified as sizeof(struct sockaddr_un).
+    let len = sun_path_offset() + bytes.len() + 1;
+    Ok((addr, len as libc::socklen_t))
+}
+
+/// A Unix `SOCK_SEQPACKET` socket point to given `path`
+pub struct UnixSeqpacket {
+    fd: RawFd,
+}
+
+impl UnixSeqpacket {
+    /// Open a `SOCK_SEQPACKET` connection to socket named by `path`.
+    ///
+    /// # Arguments
+    /// * `path` - Path to `SOCK_SEQPACKET` socket
+    ///
+    /// # Returns
+    /// A `UnixSeqpacket` structure point to the socket
+    ///
+    /// # Errors
+    /// Return `io::Error` when error occurs.
+    pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<Self> {
+        // Safe socket initialization since we handle the returned error.
+        let fd = unsafe {
+            match libc::socket(libc::AF_UNIX, libc::SOCK_SEQPACKET, 0) {
+                -1 => return Err(io::Error::last_os_error()),
+                fd => fd,
+            }
+        };
+
+        let (addr, len) = sockaddr_un(path.as_ref())?;
+        // Safe connect since we handle the error and use the right length generated from
+        // `sockaddr_un`.
+        unsafe {
+            let ret = libc::connect(fd, &addr as *const _ as *const _, len);
+            if ret < 0 {
+                return Err(io::Error::last_os_error());
+            }
+        }
+        Ok(UnixSeqpacket { fd })
+    }
+
+    /// Creates a pair of connected `SOCK_SEQPACKET` sockets.
+    ///
+    /// Both returned file descriptors have the `CLOEXEC` flag set.s
+    pub fn pair() -> io::Result<(UnixSeqpacket, UnixSeqpacket)> {
+        let mut fds = [0, 0];
+        unsafe {
+            // Safe because we give enough space to store all the fds and we check the return value.
+            let ret = libc::socketpair(
+                libc::AF_UNIX,
+                libc::SOCK_SEQPACKET | libc::SOCK_CLOEXEC,
+                0,
+                &mut fds[0],
+            );
+            if ret == 0 {
+                Ok((
+                    UnixSeqpacket::from_raw_fd(fds[0]),
+                    UnixSeqpacket::from_raw_fd(fds[1]),
+                ))
+            } else {
+                Err(io::Error::last_os_error())
+            }
+        }
+    }
+
+    /// Clone the underlying FD.
+    pub fn try_clone(&self) -> io::Result<Self> {
+        // Calling `dup` is safe as the kernel doesn't touch any user memory it the process.
+        let new_fd = unsafe { libc::dup(self.fd) };
+        if new_fd < 0 {
+            Err(io::Error::last_os_error())
+        } else {
+            Ok(UnixSeqpacket { fd: new_fd })
+        }
+    }
+
+    /// Gets the number of bytes that can be read from this socket without blocking.
+    pub fn get_readable_bytes(&self) -> io::Result<usize> {
+        let mut byte_count = 0 as libc::c_int;
+        let ret = unsafe { libc::ioctl(self.fd, libc::FIONREAD, &mut byte_count) };
+        if ret < 0 {
+            Err(io::Error::last_os_error())
+        } else {
+            Ok(byte_count as usize)
+        }
+    }
+
+    /// Write data from a given buffer to the socket fd
+    ///
+    /// # Arguments
+    /// * `buf` - A reference to the data buffer.
+    ///
+    /// # Returns
+    /// * `usize` - The size of bytes written to the buffer.
+    ///
+    /// # Errors
+    /// Returns error when `libc::write` failed.
+    pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+        // Safe since we make sure the input `count` == `buf.len()` and handle the returned error.
+        unsafe {
+            let ret = libc::write(self.fd, buf.as_ptr() as *const _, buf.len());
+            if ret < 0 {
+                Err(io::Error::last_os_error())
+            } else {
+                Ok(ret as usize)
+            }
+        }
+    }
+
+    /// Read data from the socket fd to a given buffer
+    ///
+    /// # Arguments
+    /// * `buf` - A mut reference to the data buffer.
+    ///
+    /// # Returns
+    /// * `usize` - The size of bytes read to the buffer.
+    ///
+    /// # Errors
+    /// Returns error when `libc::read` failed.
+    pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+        // Safe since we make sure the input `count` == `buf.len()` and handle the returned error.
+        unsafe {
+            let ret = libc::read(self.fd, buf.as_mut_ptr() as *mut _, buf.len());
+            if ret < 0 {
+                Err(io::Error::last_os_error())
+            } else {
+                Ok(ret as usize)
+            }
+        }
+    }
+
+    fn set_timeout(&self, timeout: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
+        let timeval = match timeout {
+            Some(t) => {
+                if t.as_secs() == 0 && t.subsec_micros() == 0 {
+                    return Err(io::Error::new(
+                        io::ErrorKind::InvalidInput,
+                        "zero timeout duration is invalid",
+                    ));
+                }
+                // subsec_micros fits in i32 because it is defined to be less than one million.
+                let nsec = t.subsec_micros() as i32;
+                libc::timeval {
+                    tv_sec: t.as_secs() as libc::time_t,
+                    tv_usec: libc::suseconds_t::from(nsec),
+                }
+            }
+            None => libc::timeval {
+                tv_sec: 0,
+                tv_usec: 0,
+            },
+        };
+        // Safe because we own the fd, and the length of the pointer's data is the same as the
+        // passed in length parameter. The level argument is valid, the kind is assumed to be valid,
+        // and the return value is checked.
+        let ret = unsafe {
+            libc::setsockopt(
+                self.fd,
+                libc::SOL_SOCKET,
+                kind,
+                &timeval as *const libc::timeval as *const libc::c_void,
+                mem::size_of::<libc::timeval>() as libc::socklen_t,
+            )
+        };
+        if ret < 0 {
+            Err(io::Error::last_os_error())
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Sets or removes the timeout for read/recv operations on this socket.
+    pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+        self.set_timeout(timeout, libc::SO_RCVTIMEO)
+    }
+
+    /// Sets or removes the timeout for write/send operations on this socket.
+    pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+        self.set_timeout(timeout, libc::SO_SNDTIMEO)
+    }
+}
+
+impl Drop for UnixSeqpacket {
+    fn drop(&mut self) {
+        // Safe if the UnixSeqpacket is created from Self::connect.
+        unsafe {
+            libc::close(self.fd);
+        }
+    }
+}
+
+impl FromRawFd for UnixSeqpacket {
+    // Unsafe in drop function
+    unsafe fn from_raw_fd(fd: RawFd) -> Self {
+        Self { fd }
+    }
+}
+
+impl AsRawFd for UnixSeqpacket {
+    fn as_raw_fd(&self) -> RawFd {
+        self.fd
+    }
+}
+
+/// Like a `UnixListener` but for accepting `UnixSeqpacket` type sockets.
+pub struct UnixSeqpacketListener {
+    fd: RawFd,
+}
+
+impl UnixSeqpacketListener {
+    /// Creates a new `UnixSeqpacketListener` bound to the given path.
+    pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<Self> {
+        // Safe socket initialization since we handle the returned error.
+        let fd = unsafe {
+            match libc::socket(libc::AF_UNIX, libc::SOCK_SEQPACKET, 0) {
+                -1 => return Err(io::Error::last_os_error()),
+                fd => fd,
+            }
+        };
+
+        let (addr, len) = sockaddr_un(path.as_ref())?;
+        // Safe connect since we handle the error and use the right length generated from
+        // `sockaddr_un`.
+        unsafe {
+            let ret = handle_eintr_errno!(libc::bind(fd, &addr as *const _ as *const _, len));
+            if ret < 0 {
+                return Err(io::Error::last_os_error());
+            }
+            let ret = handle_eintr_errno!(libc::listen(fd, 128));
+            if ret < 0 {
+                return Err(io::Error::last_os_error());
+            }
+        }
+        Ok(UnixSeqpacketListener { fd })
+    }
+
+    /// Blocks for and accepts a new incoming connection and returns the socket associated with that
+    /// connection.
+    ///
+    /// The returned socket has the close-on-exec flag set.
+    pub fn accept(&self) -> io::Result<UnixSeqpacket> {
+        // Safe because we own this fd and the kernel will not write to null pointers.
+        let ret = unsafe { libc::accept4(self.fd, null_mut(), null_mut(), libc::SOCK_CLOEXEC) };
+        if ret < 0 {
+            return Err(io::Error::last_os_error());
+        }
+        // Safe because we checked the return value of accept. Therefore, the return value must be a
+        // valid socket.
+        Ok(unsafe { UnixSeqpacket::from_raw_fd(ret) })
+    }
+
+    /// Gets the path that this listener is bound to.
+    pub fn path(&self) -> io::Result<PathBuf> {
+        let mut addr = libc::sockaddr_un {
+            sun_family: libc::AF_UNIX as libc::sa_family_t,
+            sun_path: [0; 108],
+        };
+        let sun_path_offset = (&addr.sun_path as *const _ as usize
+            - &addr.sun_family as *const _ as usize)
+            as libc::socklen_t;
+        let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
+        // Safe because the length given matches the length of the data of the given pointer, and we
+        // check the return value.
+        let ret = unsafe {
+            handle_eintr_errno!(libc::getsockname(
+                self.fd,
+                &mut addr as *mut libc::sockaddr_un as *mut libc::sockaddr,
+                &mut len
+            ))
+        };
+        if ret < 0 {
+            return Err(io::Error::last_os_error());
+        }
+        if addr.sun_family != libc::AF_UNIX as libc::sa_family_t
+            || addr.sun_path[0] == 0
+            || len < 1 + sun_path_offset
+        {
+            return Err(io::Error::new(
+                io::ErrorKind::InvalidInput,
+                "getsockname on socket returned invalid value",
+            ));
+        }
+
+        let path_os_str = OsString::from_vec(
+            addr.sun_path[..(len - sun_path_offset - 1) as usize]
+                .iter()
+                .map(|&c| c as _)
+                .collect(),
+        );
+        Ok(path_os_str.into())
+    }
+}
+
+impl Drop for UnixSeqpacketListener {
+    fn drop(&mut self) {
+        // Safe if the UnixSeqpacketListener is created from Self::listen.
+        unsafe {
+            libc::close(self.fd);
+        }
+    }
+}
+
+impl FromRawFd for UnixSeqpacketListener {
+    // Unsafe in drop function
+    unsafe fn from_raw_fd(fd: RawFd) -> Self {
+        Self { fd }
+    }
+}
+
+impl AsRawFd for UnixSeqpacketListener {
+    fn as_raw_fd(&self) -> RawFd {
+        self.fd
+    }
+}
+
+/// Used to attempt to clean up a `UnixSeqpacketListener` after it is dropped.
+pub struct UnlinkUnixSeqpacketListener(pub UnixSeqpacketListener);
+impl AsRef<UnixSeqpacketListener> for UnlinkUnixSeqpacketListener {
+    fn as_ref(&self) -> &UnixSeqpacketListener {
+        &self.0
+    }
+}
+
+impl AsRawFd for UnlinkUnixSeqpacketListener {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl Deref for UnlinkUnixSeqpacketListener {
+    type Target = UnixSeqpacketListener;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl Drop for UnlinkUnixSeqpacketListener {
+    fn drop(&mut self) {
+        if let Ok(path) = self.0.path() {
+            if let Err(e) = remove_file(path) {
+                warn!("failed to remove control socket file: {:?}", e);
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::env;
+    use std::path::PathBuf;
+
+    fn tmpdir() -> PathBuf {
+        env::temp_dir()
+    }
+
+    #[test]
+    fn sockaddr_un_zero_length_input() {
+        let _res = sockaddr_un(Path::new("")).expect("sockaddr_un failed");
+    }
+
+    #[test]
+    fn sockaddr_un_long_input_err() {
+        let res = sockaddr_un(Path::new(&"a".repeat(108)));
+        assert!(res.is_err());
+    }
+
+    #[test]
+    fn sockaddr_un_long_input_pass() {
+        let _res = sockaddr_un(Path::new(&"a".repeat(107))).expect("sockaddr_un failed");
+    }
+
+    #[test]
+    fn sockaddr_un_len_check() {
+        let (_addr, len) = sockaddr_un(Path::new(&"a".repeat(50))).expect("sockaddr_un failed");
+        assert_eq!(len, (sun_path_offset() + 50 + 1) as u32);
+    }
+
+    #[test]
+    fn sockaddr_un_pass() {
+        let path_size = 50;
+        let (addr, len) =
+            sockaddr_un(Path::new(&"a".repeat(path_size))).expect("sockaddr_un failed");
+        assert_eq!(len, (sun_path_offset() + path_size + 1) as u32);
+        assert_eq!(addr.sun_family, libc::AF_UNIX as libc::sa_family_t);
+
+        // Check `sun_path` in returned `sockaddr_un`
+        let mut ref_sun_path = [0 as libc::c_char; 108];
+        for i in 0..path_size {
+            ref_sun_path[i] = 'a' as libc::c_char;
+        }
+
+        for (addr_char, ref_char) in addr.sun_path.iter().zip(ref_sun_path.iter()) {
+            assert_eq!(addr_char, ref_char);
+        }
+    }
+
+    #[test]
+    fn unix_seqpacket_path_not_exists() {
+        let res = UnixSeqpacket::connect("/path/not/exists");
+        assert!(res.is_err());
+    }
+
+    #[test]
+    fn unix_seqpacket_listener_path() {
+        let mut socket_path = tmpdir();
+        socket_path.push("unix_seqpacket_listener_path");
+        let listener = UnlinkUnixSeqpacketListener(
+            UnixSeqpacketListener::bind(&socket_path)
+                .expect("failed to create UnixSeqpacketListener"),
+        );
+        let listener_path = listener.path().expect("failed to get socket listener path");
+        assert_eq!(socket_path, listener_path);
+    }
+
+    #[test]
+    fn unix_seqpacket_path_exists_pass() {
+        let mut socket_path = tmpdir();
+        socket_path.push("path_to_socket");
+        let _listener = UnlinkUnixSeqpacketListener(
+            UnixSeqpacketListener::bind(&socket_path)
+                .expect("failed to create UnixSeqpacketListener"),
+        );
+        let _res =
+            UnixSeqpacket::connect(socket_path.as_path()).expect("UnixSeqpacket::connect failed");
+    }
+
+    #[test]
+    fn unix_seqpacket_path_listener_accept() {
+        let mut socket_path = tmpdir();
+        socket_path.push("path_listerner_accept");
+        let listener = UnlinkUnixSeqpacketListener(
+            UnixSeqpacketListener::bind(&socket_path)
+                .expect("failed to create UnixSeqpacketListener"),
+        );
+        let s1 =
+            UnixSeqpacket::connect(socket_path.as_path()).expect("UnixSeqpacket::connect failed");
+
+        let s2 = listener.accept().expect("UnixSeqpacket::accept failed");
+
+        let data1 = &[0, 1, 2, 3, 4];
+        let data2 = &[10, 11, 12, 13, 14];
+        s2.send(data2).expect("failed to send data2");
+        s1.send(data1).expect("failed to send data1");
+        let recv_data = &mut [0; 5];
+        s2.recv(recv_data).expect("failed to recv data");
+        assert_eq!(data1, recv_data);
+        s1.recv(recv_data).expect("failed to recv data");
+        assert_eq!(data2, recv_data);
+    }
+
+    #[test]
+    fn unix_seqpacket_zero_timeout() {
+        let (s1, _s2) = UnixSeqpacket::pair().expect("failed to create socket pair");
+        // Timeouts less than a microsecond are too small and round to zero.
+        s1.set_read_timeout(Some(Duration::from_nanos(10)))
+            .expect_err("successfully set zero timeout");
+    }
+
+    #[test]
+    fn unix_seqpacket_read_timeout() {
+        let (s1, _s2) = UnixSeqpacket::pair().expect("failed to create socket pair");
+        s1.set_read_timeout(Some(Duration::from_millis(1)))
+            .expect("failed to set read timeout for socket");
+        let _ = s1.recv(&mut [0]);
+    }
+
+    #[test]
+    fn unix_seqpacket_write_timeout() {
+        let (s1, _s2) = UnixSeqpacket::pair().expect("failed to create socket pair");
+        s1.set_write_timeout(Some(Duration::from_millis(1)))
+            .expect("failed to set write timeout for socket");
+    }
+
+    #[test]
+    fn unix_seqpacket_send_recv() {
+        let (s1, s2) = UnixSeqpacket::pair().expect("failed to create socket pair");
+        let data1 = &[0, 1, 2, 3, 4];
+        let data2 = &[10, 11, 12, 13, 14];
+        s2.send(data2).expect("failed to send data2");
+        s1.send(data1).expect("failed to send data1");
+        let recv_data = &mut [0; 5];
+        s2.recv(recv_data).expect("failed to recv data");
+        assert_eq!(data1, recv_data);
+        s1.recv(recv_data).expect("failed to recv data");
+        assert_eq!(data2, recv_data);
+    }
+
+    #[test]
+    fn unix_seqpacket_send_fragments() {
+        let (s1, s2) = UnixSeqpacket::pair().expect("failed to create socket pair");
+        let data1 = &[0, 1, 2, 3, 4];
+        let data2 = &[10, 11, 12, 13, 14, 15, 16];
+        s1.send(data1).expect("failed to send data1");
+        s1.send(data2).expect("failed to send data2");
+
+        let recv_data = &mut [0; 32];
+        let size = s2.recv(recv_data).expect("failed to recv data");
+        assert_eq!(size, data1.len());
+        assert_eq!(data1, &recv_data[0..size]);
+
+        let size = s2.recv(recv_data).expect("failed to recv data");
+        assert_eq!(size, data2.len());
+        assert_eq!(data2, &recv_data[0..size]);
+    }
+
+    #[test]
+    fn unix_seqpacket_get_readable_bytes() {
+        let (s1, s2) = UnixSeqpacket::pair().expect("failed to create socket pair");
+        assert_eq!(s1.get_readable_bytes().unwrap(), 0);
+        assert_eq!(s2.get_readable_bytes().unwrap(), 0);
+        let data1 = &[0, 1, 2, 3, 4];
+        s1.send(data1).expect("failed to send data");
+
+        assert_eq!(s1.get_readable_bytes().unwrap(), 0);
+        assert_eq!(s2.get_readable_bytes().unwrap(), data1.len());
+
+        let recv_data = &mut [0; 5];
+        s2.recv(recv_data).expect("failed to recv data");
+        assert_eq!(s1.get_readable_bytes().unwrap(), 0);
+        assert_eq!(s2.get_readable_bytes().unwrap(), 0);
+    }
+}
diff --git a/sys_util/src/passwd.rs b/sys_util/src/passwd.rs
new file mode 100644
index 0000000..19a72cb
--- /dev/null
+++ b/sys_util/src/passwd.rs
@@ -0,0 +1,122 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Wrappers for passwd and group file access.
+
+use std::ffi::CStr;
+use std::mem;
+use std::ptr;
+
+use libc::{self, c_char, getgrnam_r, getpwnam_r, gid_t, uid_t};
+
+use crate::{errno_result, Result};
+
+/// Safe wrapper for getting a uid from a user name with `getpwnam_r(3)`.
+#[inline(always)]
+pub fn get_user_id(user_name: &CStr) -> Result<uid_t> {
+    // libc::passwd is a C struct and can be safely initialized with zeroed memory.
+    let mut passwd: libc::passwd = unsafe { mem::zeroed() };
+    let mut passwd_result: *mut libc::passwd = ptr::null_mut();
+    let mut buf = [0 as c_char; 256];
+
+    // For thread-safety, use the reentrant version of this function. This allows us to give it a
+    // buffer on the stack (instead of a global buffer). Unlike most libc functions, the return
+    // value of this doesn't really need to be checked, since the extra result pointer that is
+    // passed in indicates whether or not the function succeeded.
+    //
+    // This call is safe as long as it behaves as described in the man page. We pass in valid
+    // pointers to stack-allocated buffers, and the length check for the scratch buffer is correct.
+    unsafe {
+        handle_eintr_rc!(getpwnam_r(
+            user_name.as_ptr(),
+            &mut passwd,
+            buf.as_mut_ptr(),
+            buf.len(),
+            &mut passwd_result
+        ))
+    };
+
+    if passwd_result.is_null() {
+        errno_result()
+    } else {
+        Ok(passwd.pw_uid)
+    }
+}
+
+/// Safe wrapper for getting a gid from a group name with `getgrnam_r(3)`.
+#[inline(always)]
+pub fn get_group_id(group_name: &CStr) -> Result<gid_t> {
+    // libc::group is a C struct and can be safely initialized with zeroed memory.
+    let mut group: libc::group = unsafe { mem::zeroed() };
+    let mut group_result: *mut libc::group = ptr::null_mut();
+    let mut buf = [0 as c_char; 256];
+
+    // For thread-safety, use the reentrant version of this function. This allows us to give it a
+    // buffer on the stack (instead of a global buffer). Unlike most libc functions, the return
+    // value of this doesn't really need to be checked, since the extra result pointer that is
+    // passed in indicates whether or not the function succeeded.
+    //
+    // This call is safe as long as it behaves as described in the man page. We pass in valid
+    // pointers to stack-allocated buffers, and the length check for the scratch buffer is correct.
+    unsafe {
+        handle_eintr_rc!(getgrnam_r(
+            group_name.as_ptr(),
+            &mut group,
+            buf.as_mut_ptr(),
+            buf.len(),
+            &mut group_result
+        ))
+    };
+
+    if group_result.is_null() {
+        errno_result()
+    } else {
+        Ok(group.gr_gid)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn get_good_uid() {
+        let root_name = CStr::from_bytes_with_nul(b"root\0").unwrap();
+
+        // root's uid should always exist, and should be 0.
+        let root_uid = get_user_id(root_name).unwrap();
+        assert_eq!(root_uid, 0);
+    }
+
+    #[test]
+    fn get_bad_uid() {
+        let bad_name = CStr::from_bytes_with_nul(b"this better not be a user\0").unwrap();
+
+        // This user should give us an error. As a cruel joke, the getpwnam(3) man page allows
+        // ENOENT, ESRCH, EBADF, EPERM, or even 0 to be set in errno if a user isn't found. So
+        // instead of checking which error we got, just see that we did get one.
+        let bad_uid_result = get_user_id(bad_name);
+        assert!(bad_uid_result.is_err());
+    }
+
+    #[test]
+    fn get_good_gid() {
+        let root_name = CStr::from_bytes_with_nul(b"root\0").unwrap();
+
+        // root's gid should always exist, and should be 0.
+        let root_gid = get_group_id(root_name).unwrap();
+        assert_eq!(root_gid, 0);
+    }
+
+    #[test]
+    fn get_bad_gid() {
+        let bad_name = CStr::from_bytes_with_nul(b"this better not be a group\0").unwrap();
+
+        // This group should give us an error. As a cruel joke, the getgrnam(3) man page allows
+        // ENOENT, ESRCH, EBADF, EPERM, or even 0 to be set in errno if a group isn't found. So
+        // instead of checking which error we got, just see that we did get one.
+        let bad_gid_result = get_group_id(bad_name);
+        assert!(bad_gid_result.is_err());
+    }
+}
diff --git a/sys_util/src/poll.rs b/sys_util/src/poll.rs
new file mode 100644
index 0000000..0da0831
--- /dev/null
+++ b/sys_util/src/poll.rs
@@ -0,0 +1,753 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::cell::{Cell, Ref, RefCell};
+use std::cmp::min;
+use std::fs::File;
+use std::i32;
+use std::i64;
+use std::marker::PhantomData;
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use std::ptr::null_mut;
+use std::slice;
+use std::thread;
+use std::time::Duration;
+
+use libc::{
+    c_int, epoll_create1, epoll_ctl, epoll_event, epoll_wait, EPOLLHUP, EPOLLIN, EPOLLOUT,
+    EPOLL_CLOEXEC, EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD,
+};
+
+use crate::{errno_result, Result};
+
+const POLL_CONTEXT_MAX_EVENTS: usize = 16;
+
+/// EpollEvents wraps raw epoll_events, it should only be used with EpollContext.
+pub struct EpollEvents(RefCell<[epoll_event; POLL_CONTEXT_MAX_EVENTS]>);
+
+impl EpollEvents {
+    pub fn new() -> EpollEvents {
+        EpollEvents(RefCell::new(
+            [epoll_event { events: 0, u64: 0 }; POLL_CONTEXT_MAX_EVENTS],
+        ))
+    }
+}
+
+impl Default for EpollEvents {
+    fn default() -> EpollEvents {
+        Self::new()
+    }
+}
+
+/// Trait for a token that can be associated with an `fd` in a `PollContext`.
+///
+/// Simple enums that have no or primitive variant data data can use the `#[derive(PollToken)]`
+/// custom derive to implement this trait. See
+/// [poll_token_derive::poll_token](../poll_token_derive/fn.poll_token.html) for details.
+pub trait PollToken {
+    /// Converts this token into a u64 that can be turned back into a token via `from_raw_token`.
+    fn as_raw_token(&self) -> u64;
+
+    /// Converts a raw token as returned from `as_raw_token` back into a token.
+    ///
+    /// It is invalid to give a raw token that was not returned via `as_raw_token` from the same
+    /// `Self`. The implementation can expect that this will never happen as a result of its usage
+    /// in `PollContext`.
+    fn from_raw_token(data: u64) -> Self;
+}
+
+impl PollToken for usize {
+    fn as_raw_token(&self) -> u64 {
+        *self as u64
+    }
+
+    fn from_raw_token(data: u64) -> Self {
+        data as Self
+    }
+}
+
+impl PollToken for u64 {
+    fn as_raw_token(&self) -> u64 {
+        *self as u64
+    }
+
+    fn from_raw_token(data: u64) -> Self {
+        data as Self
+    }
+}
+
+impl PollToken for u32 {
+    fn as_raw_token(&self) -> u64 {
+        u64::from(*self)
+    }
+
+    fn from_raw_token(data: u64) -> Self {
+        data as Self
+    }
+}
+
+impl PollToken for u16 {
+    fn as_raw_token(&self) -> u64 {
+        u64::from(*self)
+    }
+
+    fn from_raw_token(data: u64) -> Self {
+        data as Self
+    }
+}
+
+impl PollToken for u8 {
+    fn as_raw_token(&self) -> u64 {
+        u64::from(*self)
+    }
+
+    fn from_raw_token(data: u64) -> Self {
+        data as Self
+    }
+}
+
+impl PollToken for () {
+    fn as_raw_token(&self) -> u64 {
+        0
+    }
+
+    fn from_raw_token(_data: u64) -> Self {}
+}
+
+/// An event returned by `PollContext::wait`.
+pub struct PollEvent<'a, T> {
+    event: &'a epoll_event,
+    token: PhantomData<T>, // Needed to satisfy usage of T
+}
+
+impl<'a, T: PollToken> PollEvent<'a, T> {
+    /// Gets the token associated in `PollContext::add` with this event.
+    pub fn token(&self) -> T {
+        T::from_raw_token(self.event.u64)
+    }
+
+    /// True if the `fd` associated with this token in `PollContext::add` is readable.
+    pub fn readable(&self) -> bool {
+        self.event.events & (EPOLLIN as u32) != 0
+    }
+
+    /// True if the `fd` associated with this token in `PollContext::add` has been hungup on.
+    pub fn hungup(&self) -> bool {
+        self.event.events & (EPOLLHUP as u32) != 0
+    }
+}
+
+/// An iterator over some (sub)set of events returned by `PollContext::wait`.
+pub struct PollEventIter<'a, I, T>
+where
+    I: Iterator<Item = &'a epoll_event>,
+{
+    mask: u32,
+    iter: I,
+    tokens: PhantomData<[T]>, // Needed to satisfy usage of T
+}
+
+impl<'a, I, T> Iterator for PollEventIter<'a, I, T>
+where
+    I: Iterator<Item = &'a epoll_event>,
+    T: PollToken,
+{
+    type Item = PollEvent<'a, T>;
+    fn next(&mut self) -> Option<Self::Item> {
+        let mask = self.mask;
+        self.iter
+            .find(|event| (event.events & mask) != 0)
+            .map(|event| PollEvent {
+                event,
+                token: PhantomData,
+            })
+    }
+}
+
+/// The list of event returned by `PollContext::wait`.
+pub struct PollEvents<'a, T> {
+    count: usize,
+    events: Ref<'a, [epoll_event; POLL_CONTEXT_MAX_EVENTS]>,
+    tokens: PhantomData<[T]>, // Needed to satisfy usage of T
+}
+
+impl<'a, T: PollToken> PollEvents<'a, T> {
+    /// Copies the events to an owned structure so the reference to this (and by extension
+    /// `PollContext`) can be dropped.
+    pub fn to_owned(&self) -> PollEventsOwned<T> {
+        PollEventsOwned {
+            count: self.count,
+            events: RefCell::new(*self.events),
+            tokens: PhantomData,
+        }
+    }
+
+    /// Iterates over each event.
+    pub fn iter(&self) -> PollEventIter<slice::Iter<epoll_event>, T> {
+        PollEventIter {
+            mask: 0xffff_ffff,
+            iter: self.events[..self.count].iter(),
+            tokens: PhantomData,
+        }
+    }
+
+    /// Iterates over each readable event.
+    pub fn iter_readable(&self) -> PollEventIter<slice::Iter<epoll_event>, T> {
+        PollEventIter {
+            mask: EPOLLIN as u32,
+            iter: self.events[..self.count].iter(),
+            tokens: PhantomData,
+        }
+    }
+
+    /// Iterates over each hungup event.
+    pub fn iter_hungup(&self) -> PollEventIter<slice::Iter<epoll_event>, T> {
+        PollEventIter {
+            mask: EPOLLHUP as u32,
+            iter: self.events[..self.count].iter(),
+            tokens: PhantomData,
+        }
+    }
+}
+
+impl<'a, T: PollToken> IntoIterator for &'a PollEvents<'_, T> {
+    type Item = PollEvent<'a, T>;
+    type IntoIter = PollEventIter<'a, slice::Iter<'a, epoll_event>, T>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+/// A deep copy of the event records from `PollEvents`.
+pub struct PollEventsOwned<T> {
+    count: usize,
+    events: RefCell<[epoll_event; POLL_CONTEXT_MAX_EVENTS]>,
+    tokens: PhantomData<T>, // Needed to satisfy usage of T
+}
+
+impl<T: PollToken> PollEventsOwned<T> {
+    /// Takes a reference to the events so that they can be iterated via methods in `PollEvents`.
+    pub fn as_ref(&self) -> PollEvents<T> {
+        PollEvents {
+            count: self.count,
+            events: self.events.borrow(),
+            tokens: PhantomData,
+        }
+    }
+}
+
+/// Watching events taken by PollContext.
+pub struct WatchingEvents(u32);
+
+impl WatchingEvents {
+    /// Returns empty Events.
+    #[inline(always)]
+    pub fn empty() -> WatchingEvents {
+        WatchingEvents(0)
+    }
+
+    /// Build Events from raw epoll events (defined in epoll_ctl(2)).
+    #[inline(always)]
+    pub fn new(raw: u32) -> WatchingEvents {
+        WatchingEvents(raw)
+    }
+
+    /// Set read events.
+    #[inline(always)]
+    pub fn set_read(self) -> WatchingEvents {
+        WatchingEvents(self.0 | EPOLLIN as u32)
+    }
+
+    /// Set write events.
+    #[inline(always)]
+    pub fn set_write(self) -> WatchingEvents {
+        WatchingEvents(self.0 | EPOLLOUT as u32)
+    }
+
+    /// Get the underlying epoll events.
+    pub fn get_raw(&self) -> u32 {
+        self.0
+    }
+}
+
+/// EpollContext wraps linux epoll. It provides similar interface to PollContext.
+/// It is thread safe while PollContext is not. It requires user to pass in a reference of
+/// EpollEvents while PollContext does not. Always use PollContext if you don't need to access the
+/// same epoll from different threads.
+pub struct EpollContext<T> {
+    epoll_ctx: File,
+    // Needed to satisfy usage of T
+    tokens: PhantomData<[T]>,
+}
+
+impl<T: PollToken> EpollContext<T> {
+    /// Creates a new `EpollContext`.
+    pub fn new() -> Result<EpollContext<T>> {
+        // Safe because we check the return value.
+        let epoll_fd = unsafe { epoll_create1(EPOLL_CLOEXEC) };
+        if epoll_fd < 0 {
+            return errno_result();
+        }
+        Ok(EpollContext {
+            epoll_ctx: unsafe { File::from_raw_fd(epoll_fd) },
+            tokens: PhantomData,
+        })
+    }
+
+    /// Adds the given `fd` to this context and associates the given `token` with the `fd`'s
+    /// readable events.
+    ///
+    /// A `fd` can only be added once and does not need to be kept open. If the `fd` is dropped and
+    /// there were no duplicated file descriptors (i.e. adding the same descriptor with a different
+    /// FD number) added to this context, events will not be reported by `wait` anymore.
+    pub fn add(&self, fd: &dyn AsRawFd, token: T) -> Result<()> {
+        self.add_fd_with_events(fd, WatchingEvents::empty().set_read(), token)
+    }
+
+    /// Adds the given `fd` to this context, watching for the specified events and associates the
+    /// given 'token' with those events.
+    ///
+    /// A `fd` can only be added once and does not need to be kept open. If the `fd` is dropped and
+    /// there were no duplicated file descriptors (i.e. adding the same descriptor with a different
+    /// FD number) added to this context, events will not be reported by `wait` anymore.
+    pub fn add_fd_with_events(
+        &self,
+        fd: &dyn AsRawFd,
+        events: WatchingEvents,
+        token: T,
+    ) -> Result<()> {
+        let mut evt = epoll_event {
+            events: events.get_raw(),
+            u64: token.as_raw_token(),
+        };
+        // Safe because we give a valid epoll FD and FD to watch, as well as a valid epoll_event
+        // structure. Then we check the return value.
+        let ret = unsafe {
+            epoll_ctl(
+                self.epoll_ctx.as_raw_fd(),
+                EPOLL_CTL_ADD,
+                fd.as_raw_fd(),
+                &mut evt,
+            )
+        };
+        if ret < 0 {
+            return errno_result();
+        };
+        Ok(())
+    }
+
+    /// If `fd` was previously added to this context, the watched events will be replaced with
+    /// `events` and the token associated with it will be replaced with the given `token`.
+    pub fn modify(&self, fd: &dyn AsRawFd, events: WatchingEvents, token: T) -> Result<()> {
+        let mut evt = epoll_event {
+            events: events.0,
+            u64: token.as_raw_token(),
+        };
+        // Safe because we give a valid epoll FD and FD to modify, as well as a valid epoll_event
+        // structure. Then we check the return value.
+        let ret = unsafe {
+            epoll_ctl(
+                self.epoll_ctx.as_raw_fd(),
+                EPOLL_CTL_MOD,
+                fd.as_raw_fd(),
+                &mut evt,
+            )
+        };
+        if ret < 0 {
+            return errno_result();
+        };
+        Ok(())
+    }
+
+    /// Deletes the given `fd` from this context.
+    ///
+    /// If an `fd`'s token shows up in the list of hangup events, it should be removed using this
+    /// method or by closing/dropping (if and only if the fd was never dup()'d/fork()'d) the `fd`.
+    /// Failure to do so will cause the `wait` method to always return immediately, causing ~100%
+    /// CPU load.
+    pub fn delete(&self, fd: &dyn AsRawFd) -> Result<()> {
+        // Safe because we give a valid epoll FD and FD to stop watching. Then we check the return
+        // value.
+        let ret = unsafe {
+            epoll_ctl(
+                self.epoll_ctx.as_raw_fd(),
+                EPOLL_CTL_DEL,
+                fd.as_raw_fd(),
+                null_mut(),
+            )
+        };
+        if ret < 0 {
+            return errno_result();
+        };
+        Ok(())
+    }
+
+    /// Waits for any events to occur in FDs that were previously added to this context.
+    ///
+    /// The events are level-triggered, meaning that if any events are unhandled (i.e. not reading
+    /// for readable events and not closing for hungup events), subsequent calls to `wait` will
+    /// return immediately. The consequence of not handling an event perpetually while calling
+    /// `wait` is that the callers loop will degenerated to busy loop polling, pinning a CPU to
+    /// ~100% usage.
+    pub fn wait<'a>(&self, events: &'a EpollEvents) -> Result<PollEvents<'a, T>> {
+        self.wait_timeout(events, Duration::new(i64::MAX as u64, 0))
+    }
+
+    /// Like `wait` except will only block for a maximum of the given `timeout`.
+    ///
+    /// This may return earlier than `timeout` with zero events if the duration indicated exceeds
+    /// system limits.
+    pub fn wait_timeout<'a>(
+        &self,
+        events: &'a EpollEvents,
+        timeout: Duration,
+    ) -> Result<PollEvents<'a, T>> {
+        let timeout_millis = if timeout.as_secs() as i64 == i64::max_value() {
+            // We make the convenient assumption that 2^63 seconds is an effectively unbounded time
+            // frame. This is meant to mesh with `wait` calling us with no timeout.
+            -1
+        } else {
+            // In cases where we the number of milliseconds would overflow an i32, we substitute the
+            // maximum timeout which is ~24.8 days.
+            let millis = timeout
+                .as_secs()
+                .checked_mul(1_000)
+                .and_then(|ms| ms.checked_add(u64::from(timeout.subsec_nanos()) / 1_000_000))
+                .unwrap_or(i32::max_value() as u64);
+            min(i32::max_value() as u64, millis) as i32
+        };
+        let ret = {
+            let mut epoll_events = events.0.borrow_mut();
+            let max_events = epoll_events.len() as c_int;
+            // Safe because we give an epoll context and a properly sized epoll_events array
+            // pointer, which we trust the kernel to fill in properly.
+            unsafe {
+                handle_eintr_errno!(epoll_wait(
+                    self.epoll_ctx.as_raw_fd(),
+                    &mut epoll_events[0],
+                    max_events,
+                    timeout_millis
+                ))
+            }
+        };
+        if ret < 0 {
+            return errno_result();
+        }
+        let epoll_events = events.0.borrow();
+        let events = PollEvents {
+            count: ret as usize,
+            events: epoll_events,
+            tokens: PhantomData,
+        };
+        Ok(events)
+    }
+}
+
+impl<T: PollToken> AsRawFd for EpollContext<T> {
+    fn as_raw_fd(&self) -> RawFd {
+        self.epoll_ctx.as_raw_fd()
+    }
+}
+
+impl<T: PollToken> IntoRawFd for EpollContext<T> {
+    fn into_raw_fd(self) -> RawFd {
+        self.epoll_ctx.into_raw_fd()
+    }
+}
+
+/// Used to poll multiple objects that have file descriptors.
+///
+/// # Example
+///
+/// ```
+/// # use sys_util::{Result, EventFd, PollContext, PollEvents};
+/// # fn test() -> Result<()> {
+///     let evt1 = EventFd::new()?;
+///     let evt2 = EventFd::new()?;
+///     evt2.write(1)?;
+///
+///     let ctx: PollContext<u32> = PollContext::new()?;
+///     ctx.add(&evt1, 1)?;
+///     ctx.add(&evt2, 2)?;
+///
+///     let pollevents: PollEvents<u32> = ctx.wait()?;
+///     let tokens: Vec<u32> = pollevents.iter_readable().map(|e| e.token()).collect();
+///     assert_eq!(&tokens[..], &[2]);
+/// #   Ok(())
+/// # }
+/// ```
+pub struct PollContext<T> {
+    epoll_ctx: EpollContext<T>,
+
+    // We use a RefCell here so that the `wait` method only requires an immutable self reference
+    // while returning the events (encapsulated by PollEvents). Without the RefCell, `wait` would
+    // hold a mutable reference that lives as long as its returned reference (i.e. the PollEvents),
+    // even though that reference is immutable. This is terribly inconvenient for the caller because
+    // the borrow checking would prevent them from using `delete` and `add` while the events are in
+    // scope.
+    events: EpollEvents,
+
+    // Hangup busy loop detection variables. See `check_for_hungup_busy_loop`.
+    hangups: Cell<usize>,
+    max_hangups: Cell<usize>,
+}
+
+impl<T: PollToken> PollContext<T> {
+    /// Creates a new `PollContext`.
+    pub fn new() -> Result<PollContext<T>> {
+        Ok(PollContext {
+            epoll_ctx: EpollContext::new()?,
+            events: EpollEvents::new(),
+            hangups: Cell::new(0),
+            max_hangups: Cell::new(0),
+        })
+    }
+
+    /// Adds the given `fd` to this context and associates the given `token` with the `fd`'s
+    /// readable events.
+    ///
+    /// A `fd` can only be added once and does not need to be kept open. If the `fd` is dropped and
+    /// there were no duplicated file descriptors (i.e. adding the same descriptor with a different
+    /// FD number) added to this context, events will not be reported by `wait` anymore.
+    pub fn add(&self, fd: &dyn AsRawFd, token: T) -> Result<()> {
+        self.add_fd_with_events(fd, WatchingEvents::empty().set_read(), token)
+    }
+
+    /// Adds the given `fd` to this context, watching for the specified events and associates the
+    /// given 'token' with those events.
+    ///
+    /// A `fd` can only be added once and does not need to be kept open. If the `fd` is dropped and
+    /// there were no duplicated file descriptors (i.e. adding the same descriptor with a different
+    /// FD number) added to this context, events will not be reported by `wait` anymore.
+    pub fn add_fd_with_events(
+        &self,
+        fd: &dyn AsRawFd,
+        events: WatchingEvents,
+        token: T,
+    ) -> Result<()> {
+        self.epoll_ctx.add_fd_with_events(fd, events, token)?;
+        self.hangups.set(0);
+        self.max_hangups.set(self.max_hangups.get() + 1);
+        Ok(())
+    }
+
+    /// If `fd` was previously added to this context, the watched events will be replaced with
+    /// `events` and the token associated with it will be replaced with the given `token`.
+    pub fn modify(&self, fd: &dyn AsRawFd, events: WatchingEvents, token: T) -> Result<()> {
+        self.epoll_ctx.modify(fd, events, token)
+    }
+
+    /// Deletes the given `fd` from this context.
+    ///
+    /// If an `fd`'s token shows up in the list of hangup events, it should be removed using this
+    /// method or by closing/dropping (if and only if the fd was never dup()'d/fork()'d) the `fd`.
+    /// Failure to do so will cause the `wait` method to always return immediately, causing ~100%
+    /// CPU load.
+    pub fn delete(&self, fd: &dyn AsRawFd) -> Result<()> {
+        self.epoll_ctx.delete(fd)?;
+        self.hangups.set(0);
+        self.max_hangups.set(self.max_hangups.get() - 1);
+        Ok(())
+    }
+
+    // This method determines if the the user of wait is misusing the `PollContext` by leaving FDs
+    // in this `PollContext` that have been shutdown or hungup on. Such an FD will cause `wait` to
+    // return instantly with a hungup event. If that FD is perpetually left in this context, a busy
+    // loop burning ~100% of one CPU will silently occur with no human visible malfunction.
+    //
+    // How do we know if the client of this context is ignoring hangups? A naive implementation
+    // would trigger if consecutive wait calls yield hangup events, but there are legitimate cases
+    // for this, such as two distinct sockets becoming hungup across two consecutive wait calls. A
+    // smarter implementation would only trigger if `delete` wasn't called between waits that
+    // yielded hangups. Sadly `delete` isn't the only way to remove an FD from this context. The
+    // other way is for the client to close the hungup FD, which automatically removes it from this
+    // context. Assuming that the client always uses close, this implementation would too eagerly
+    // trigger.
+    //
+    // The implementation used here keeps an upper bound of FDs in this context using a counter
+    // hooked into add/delete (which is imprecise because close can also remove FDs without us
+    // knowing). The number of consecutive (no add or delete in between) hangups yielded by wait
+    // calls is counted and compared to the upper bound. If the upper bound is exceeded by the
+    // consecutive hangups, the implementation triggers the check and logs.
+    //
+    // This implementation has false negatives because the upper bound can be completely too high,
+    // in the worst case caused by only using close instead of delete. However, this method has the
+    // advantage of always triggering eventually genuine busy loop cases, requires no dynamic
+    // allocations, is fast and constant time to compute, and has no false positives.
+    fn check_for_hungup_busy_loop(&self, new_hangups: usize) {
+        let old_hangups = self.hangups.get();
+        let max_hangups = self.max_hangups.get();
+        if old_hangups <= max_hangups && old_hangups + new_hangups > max_hangups {
+            warn!(
+                "busy poll wait loop with hungup FDs detected on thread {}",
+                thread::current().name().unwrap_or("")
+            );
+            // This panic is helpful for tests of this functionality.
+            #[cfg(test)]
+            panic!("hungup busy loop detected");
+        }
+        self.hangups.set(old_hangups + new_hangups);
+    }
+
+    /// Waits for any events to occur in FDs that were previously added to this context.
+    ///
+    /// The events are level-triggered, meaning that if any events are unhandled (i.e. not reading
+    /// for readable events and not closing for hungup events), subsequent calls to `wait` will
+    /// return immediately. The consequence of not handling an event perpetually while calling
+    /// `wait` is that the callers loop will degenerated to busy loop polling, pinning a CPU to
+    /// ~100% usage.
+    ///
+    /// # Panics
+    /// Panics if the returned `PollEvents` structure is not dropped before subsequent `wait` calls.
+    pub fn wait(&self) -> Result<PollEvents<T>> {
+        self.wait_timeout(Duration::new(i64::MAX as u64, 0))
+    }
+
+    /// Like `wait` except will only block for a maximum of the given `timeout`.
+    ///
+    /// This may return earlier than `timeout` with zero events if the duration indicated exceeds
+    /// system limits.
+    pub fn wait_timeout(&self, timeout: Duration) -> Result<PollEvents<T>> {
+        let events = self.epoll_ctx.wait_timeout(&self.events, timeout)?;
+        let hangups = events.iter_hungup().count();
+        self.check_for_hungup_busy_loop(hangups);
+        Ok(events)
+    }
+}
+
+impl<T: PollToken> AsRawFd for PollContext<T> {
+    fn as_raw_fd(&self) -> RawFd {
+        self.epoll_ctx.as_raw_fd()
+    }
+}
+
+impl<T: PollToken> IntoRawFd for PollContext<T> {
+    fn into_raw_fd(self) -> RawFd {
+        self.epoll_ctx.into_raw_fd()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::EventFd;
+    use poll_token_derive::PollToken;
+    use std::os::unix::net::UnixStream;
+    use std::time::Instant;
+
+    #[test]
+    fn poll_context() {
+        let evt1 = EventFd::new().unwrap();
+        let evt2 = EventFd::new().unwrap();
+        evt1.write(1).unwrap();
+        evt2.write(1).unwrap();
+        let ctx: PollContext<u32> = PollContext::new().unwrap();
+        ctx.add(&evt1, 1).unwrap();
+        ctx.add(&evt2, 2).unwrap();
+
+        let mut evt_count = 0;
+        while evt_count < 2 {
+            for event in ctx.wait().unwrap().iter_readable() {
+                evt_count += 1;
+                match event.token() {
+                    1 => {
+                        evt1.read().unwrap();
+                        ctx.delete(&evt1).unwrap();
+                    }
+                    2 => {
+                        evt2.read().unwrap();
+                        ctx.delete(&evt2).unwrap();
+                    }
+                    _ => panic!("unexpected token"),
+                };
+            }
+        }
+        assert_eq!(evt_count, 2);
+    }
+
+    #[test]
+    fn poll_context_overflow() {
+        const EVT_COUNT: usize = POLL_CONTEXT_MAX_EVENTS * 2 + 1;
+        let ctx: PollContext<usize> = PollContext::new().unwrap();
+        let mut evts = Vec::with_capacity(EVT_COUNT);
+        for i in 0..EVT_COUNT {
+            let evt = EventFd::new().unwrap();
+            evt.write(1).unwrap();
+            ctx.add(&evt, i).unwrap();
+            evts.push(evt);
+        }
+        let mut evt_count = 0;
+        while evt_count < EVT_COUNT {
+            for event in ctx.wait().unwrap().iter_readable() {
+                evts[event.token()].read().unwrap();
+                evt_count += 1;
+            }
+        }
+    }
+
+    #[test]
+    #[should_panic]
+    fn poll_context_hungup() {
+        let (s1, s2) = UnixStream::pair().unwrap();
+        let ctx: PollContext<u32> = PollContext::new().unwrap();
+        ctx.add(&s1, 1).unwrap();
+
+        // Causes s1 to receive hangup events, which we purposefully ignore to trip the detection
+        // logic in `PollContext`.
+        drop(s2);
+
+        // Should easily panic within this many iterations.
+        for _ in 0..1000 {
+            ctx.wait().unwrap();
+        }
+    }
+
+    #[test]
+    fn poll_context_timeout() {
+        let ctx: PollContext<u32> = PollContext::new().unwrap();
+        let dur = Duration::from_millis(10);
+        let start_inst = Instant::now();
+        ctx.wait_timeout(dur).unwrap();
+        assert!(start_inst.elapsed() >= dur);
+    }
+
+    #[test]
+    #[allow(dead_code)]
+    fn poll_token_derive() {
+        #[derive(PollToken)]
+        enum EmptyToken {}
+
+        #[derive(PartialEq, Debug, PollToken)]
+        enum Token {
+            Alpha,
+            Beta,
+            // comments
+            Gamma(u32),
+            Delta { index: usize },
+            Omega,
+        }
+
+        assert_eq!(
+            Token::from_raw_token(Token::Alpha.as_raw_token()),
+            Token::Alpha
+        );
+        assert_eq!(
+            Token::from_raw_token(Token::Beta.as_raw_token()),
+            Token::Beta
+        );
+        assert_eq!(
+            Token::from_raw_token(Token::Gamma(55).as_raw_token()),
+            Token::Gamma(55)
+        );
+        assert_eq!(
+            Token::from_raw_token(Token::Delta { index: 100 }.as_raw_token()),
+            Token::Delta { index: 100 }
+        );
+        assert_eq!(
+            Token::from_raw_token(Token::Omega.as_raw_token()),
+            Token::Omega
+        );
+    }
+}
diff --git a/sys_util/src/priority.rs b/sys_util/src/priority.rs
new file mode 100644
index 0000000..77dfe29
--- /dev/null
+++ b/sys_util/src/priority.rs
@@ -0,0 +1,38 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::{errno_result, Result};
+
+/// Enables real time thread priorities in the current thread up to `limit`.
+pub fn set_rt_prio_limit(limit: u64) -> Result<()> {
+    let rt_limit_arg = libc::rlimit {
+        rlim_cur: limit as libc::rlim_t,
+        rlim_max: limit as libc::rlim_t,
+    };
+    // Safe because the kernel doesn't modify memory that is accessible to the process here.
+    let res = unsafe { libc::setrlimit(libc::RLIMIT_RTPRIO, &rt_limit_arg) };
+
+    if res != 0 {
+        errno_result()
+    } else {
+        Ok(())
+    }
+}
+
+/// Sets the current thread to be scheduled using the round robin real time class with `priority`.
+pub fn set_rt_round_robin(priority: i32) -> Result<()> {
+    let sched_param = libc::sched_param {
+        sched_priority: priority,
+    };
+
+    // Safe because the kernel doesn't modify memory that is accessible to the process here.
+    let res =
+        unsafe { libc::pthread_setschedparam(libc::pthread_self(), libc::SCHED_RR, &sched_param) };
+
+    if res != 0 {
+        errno_result()
+    } else {
+        Ok(())
+    }
+}
diff --git a/sys_util/src/raw_fd.rs b/sys_util/src/raw_fd.rs
new file mode 100644
index 0000000..05a762f
--- /dev/null
+++ b/sys_util/src/raw_fd.rs
@@ -0,0 +1,16 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Utility file to provide a slightly safer Fd type that cannot be confused with c_int.
+// Also useful for situations that require something that is `AsRawFd` but
+// where we don't want to store more than the fd.
+
+use std::os::unix::io::{AsRawFd, RawFd};
+
+pub struct Fd(pub RawFd);
+impl AsRawFd for Fd {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0
+    }
+}
diff --git a/sys_util/src/seek_hole.rs b/sys_util/src/seek_hole.rs
new file mode 100644
index 0000000..8215a8d
--- /dev/null
+++ b/sys_util/src/seek_hole.rs
@@ -0,0 +1,203 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fs::File;
+use std::io::{Error, Result};
+use std::os::unix::io::AsRawFd;
+
+use libc::{lseek64, ENXIO, SEEK_DATA, SEEK_HOLE};
+
+/// A trait for seeking to the next hole or non-hole position in a file.
+pub trait SeekHole {
+    /// Seek to the first hole in a file at a position greater than or equal to `offset`.
+    /// If no holes exist after `offset`, the seek position will be set to the end of the file.
+    /// If `offset` is at or after the end of the file, the seek position is unchanged, and None is returned.
+    /// Returns the current seek position after the seek or an error.
+    fn seek_hole(&mut self, offset: u64) -> Result<Option<u64>>;
+
+    /// Seek to the first data in a file at a position greater than or equal to `offset`.
+    /// If no data exists after `offset`, the seek position is unchanged, and None is returned.
+    /// Returns the current offset after the seek or an error.
+    fn seek_data(&mut self, offset: u64) -> Result<Option<u64>>;
+}
+
+/// Safe wrapper for `libc::lseek64()`
+fn lseek(file: &mut File, offset: i64, whence: i32) -> Result<Option<u64>> {
+    // This is safe because we pass a known-good file descriptor.
+    let res = unsafe { lseek64(file.as_raw_fd(), offset, whence) };
+
+    if res < 0 {
+        // Convert ENXIO into None; pass any other error as-is.
+        let err = Error::last_os_error();
+        if let Some(errno) = Error::raw_os_error(&err) {
+            if errno == ENXIO {
+                return Ok(None);
+            }
+        }
+        Err(err)
+    } else {
+        Ok(Some(res as u64))
+    }
+}
+
+impl SeekHole for File {
+    fn seek_hole(&mut self, offset: u64) -> Result<Option<u64>> {
+        lseek(self, offset as i64, SEEK_HOLE)
+    }
+
+    fn seek_data(&mut self, offset: u64) -> Result<Option<u64>> {
+        lseek(self, offset as i64, SEEK_DATA)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::TempDir;
+    use std::fs::File;
+    use std::io::{Seek, SeekFrom, Write};
+    use std::path::PathBuf;
+
+    fn seek_cur(file: &mut File) -> u64 {
+        file.seek(SeekFrom::Current(0)).unwrap()
+    }
+
+    #[test]
+    fn seek_data() {
+        let tempdir = TempDir::new("/tmp/seek_data_test").unwrap();
+        let mut path = PathBuf::from(tempdir.as_path().unwrap());
+        path.push("test_file");
+        let mut file = File::create(&path).unwrap();
+
+        // Empty file
+        assert_eq!(file.seek_data(0).unwrap(), None);
+        assert_eq!(seek_cur(&mut file), 0);
+
+        // File with non-zero length consisting entirely of a hole
+        file.set_len(0x10000).unwrap();
+        assert_eq!(file.seek_data(0).unwrap(), None);
+        assert_eq!(seek_cur(&mut file), 0);
+
+        // seek_data at or after the end of the file should return None
+        assert_eq!(file.seek_data(0x10000).unwrap(), None);
+        assert_eq!(seek_cur(&mut file), 0);
+        assert_eq!(file.seek_data(0x10001).unwrap(), None);
+        assert_eq!(seek_cur(&mut file), 0);
+
+        // Write some data to [0x10000, 0x20000)
+        let b = [0x55u8; 0x10000];
+        file.seek(SeekFrom::Start(0x10000)).unwrap();
+        file.write_all(&b).unwrap();
+        assert_eq!(file.seek_data(0).unwrap(), Some(0x10000));
+        assert_eq!(seek_cur(&mut file), 0x10000);
+
+        // seek_data within data should return the same offset
+        assert_eq!(file.seek_data(0x10000).unwrap(), Some(0x10000));
+        assert_eq!(seek_cur(&mut file), 0x10000);
+        assert_eq!(file.seek_data(0x10001).unwrap(), Some(0x10001));
+        assert_eq!(seek_cur(&mut file), 0x10001);
+        assert_eq!(file.seek_data(0x1FFFF).unwrap(), Some(0x1FFFF));
+        assert_eq!(seek_cur(&mut file), 0x1FFFF);
+
+        // Extend the file to add another hole after the data
+        file.set_len(0x30000).unwrap();
+        assert_eq!(file.seek_data(0).unwrap(), Some(0x10000));
+        assert_eq!(seek_cur(&mut file), 0x10000);
+        assert_eq!(file.seek_data(0x1FFFF).unwrap(), Some(0x1FFFF));
+        assert_eq!(seek_cur(&mut file), 0x1FFFF);
+        assert_eq!(file.seek_data(0x20000).unwrap(), None);
+        assert_eq!(seek_cur(&mut file), 0x1FFFF);
+    }
+
+    #[test]
+    fn seek_hole() {
+        let tempdir = TempDir::new("/tmp/seek_hole_test").unwrap();
+        let mut path = PathBuf::from(tempdir.as_path().unwrap());
+        path.push("test_file");
+        let mut file = File::create(&path).unwrap();
+
+        // Empty file
+        assert_eq!(file.seek_hole(0).unwrap(), None);
+        assert_eq!(seek_cur(&mut file), 0);
+
+        // File with non-zero length consisting entirely of a hole
+        file.set_len(0x10000).unwrap();
+        assert_eq!(file.seek_hole(0).unwrap(), Some(0));
+        assert_eq!(seek_cur(&mut file), 0);
+        assert_eq!(file.seek_hole(0xFFFF).unwrap(), Some(0xFFFF));
+        assert_eq!(seek_cur(&mut file), 0xFFFF);
+
+        // seek_hole at or after the end of the file should return None
+        file.seek(SeekFrom::Start(0)).unwrap();
+        assert_eq!(file.seek_hole(0x10000).unwrap(), None);
+        assert_eq!(seek_cur(&mut file), 0);
+        assert_eq!(file.seek_hole(0x10001).unwrap(), None);
+        assert_eq!(seek_cur(&mut file), 0);
+
+        // Write some data to [0x10000, 0x20000)
+        let b = [0x55u8; 0x10000];
+        file.seek(SeekFrom::Start(0x10000)).unwrap();
+        file.write_all(&b).unwrap();
+
+        // seek_hole within a hole should return the same offset
+        assert_eq!(file.seek_hole(0).unwrap(), Some(0));
+        assert_eq!(seek_cur(&mut file), 0);
+        assert_eq!(file.seek_hole(0xFFFF).unwrap(), Some(0xFFFF));
+        assert_eq!(seek_cur(&mut file), 0xFFFF);
+
+        // seek_hole within data should return the next hole (EOF)
+        file.seek(SeekFrom::Start(0)).unwrap();
+        assert_eq!(file.seek_hole(0x10000).unwrap(), Some(0x20000));
+        assert_eq!(seek_cur(&mut file), 0x20000);
+        file.seek(SeekFrom::Start(0)).unwrap();
+        assert_eq!(file.seek_hole(0x10001).unwrap(), Some(0x20000));
+        assert_eq!(seek_cur(&mut file), 0x20000);
+        file.seek(SeekFrom::Start(0)).unwrap();
+        assert_eq!(file.seek_hole(0x1FFFF).unwrap(), Some(0x20000));
+        assert_eq!(seek_cur(&mut file), 0x20000);
+
+        // seek_hole at EOF after data should return None
+        file.seek(SeekFrom::Start(0)).unwrap();
+        assert_eq!(file.seek_hole(0x20000).unwrap(), None);
+        assert_eq!(seek_cur(&mut file), 0);
+
+        // Extend the file to add another hole after the data
+        file.set_len(0x30000).unwrap();
+        assert_eq!(file.seek_hole(0).unwrap(), Some(0));
+        assert_eq!(seek_cur(&mut file), 0);
+        assert_eq!(file.seek_hole(0xFFFF).unwrap(), Some(0xFFFF));
+        assert_eq!(seek_cur(&mut file), 0xFFFF);
+        file.seek(SeekFrom::Start(0)).unwrap();
+        assert_eq!(file.seek_hole(0x10000).unwrap(), Some(0x20000));
+        assert_eq!(seek_cur(&mut file), 0x20000);
+        file.seek(SeekFrom::Start(0)).unwrap();
+        assert_eq!(file.seek_hole(0x1FFFF).unwrap(), Some(0x20000));
+        assert_eq!(seek_cur(&mut file), 0x20000);
+        file.seek(SeekFrom::Start(0)).unwrap();
+        assert_eq!(file.seek_hole(0x20000).unwrap(), Some(0x20000));
+        assert_eq!(seek_cur(&mut file), 0x20000);
+        file.seek(SeekFrom::Start(0)).unwrap();
+        assert_eq!(file.seek_hole(0x20001).unwrap(), Some(0x20001));
+        assert_eq!(seek_cur(&mut file), 0x20001);
+
+        // seek_hole at EOF after a hole should return None
+        file.seek(SeekFrom::Start(0)).unwrap();
+        assert_eq!(file.seek_hole(0x30000).unwrap(), None);
+        assert_eq!(seek_cur(&mut file), 0);
+
+        // Write some data to [0x20000, 0x30000)
+        file.seek(SeekFrom::Start(0x20000)).unwrap();
+        file.write_all(&b).unwrap();
+
+        // seek_hole within [0x20000, 0x30000) should now find the hole at EOF
+        assert_eq!(file.seek_hole(0x20000).unwrap(), Some(0x30000));
+        assert_eq!(seek_cur(&mut file), 0x30000);
+        file.seek(SeekFrom::Start(0)).unwrap();
+        assert_eq!(file.seek_hole(0x20001).unwrap(), Some(0x30000));
+        assert_eq!(seek_cur(&mut file), 0x30000);
+        file.seek(SeekFrom::Start(0)).unwrap();
+        assert_eq!(file.seek_hole(0x30000).unwrap(), None);
+        assert_eq!(seek_cur(&mut file), 0);
+    }
+}
diff --git a/sys_util/src/shm.rs b/sys_util/src/shm.rs
new file mode 100644
index 0000000..bb008d9
--- /dev/null
+++ b/sys_util/src/shm.rs
@@ -0,0 +1,397 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::ffi::CStr;
+use std::fs::File;
+use std::io::{self, Read, Seek, SeekFrom, Write};
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+
+use libc::{
+    self, c_char, c_int, c_long, c_uint, close, fcntl, ftruncate64, off64_t, syscall, F_ADD_SEALS,
+    F_GET_SEALS, F_SEAL_GROW, F_SEAL_SEAL, F_SEAL_SHRINK, F_SEAL_WRITE, MFD_ALLOW_SEALING,
+};
+use syscall_defines::linux::LinuxSyscall::SYS_memfd_create;
+
+use crate::{errno, errno_result, Result};
+
+/// A shared memory file descriptor and its size.
+pub struct SharedMemory {
+    fd: File,
+    size: u64,
+}
+
+// from <sys/memfd.h>
+const MFD_CLOEXEC: c_uint = 0x0001;
+
+unsafe fn memfd_create(name: *const c_char, flags: c_uint) -> c_int {
+    syscall(SYS_memfd_create as c_long, name, flags) as c_int
+}
+
+/// A set of memfd seals.
+///
+/// An enumeration of each bit can be found at `fcntl(2)`.
+#[derive(Copy, Clone, Default)]
+pub struct MemfdSeals(i32);
+
+impl MemfdSeals {
+    /// Returns an empty set of memfd seals.
+    #[inline]
+    pub fn new() -> MemfdSeals {
+        MemfdSeals(0)
+    }
+
+    /// Gets the raw bitmask of seals enumerated in `fcntl(2)`.
+    #[inline]
+    pub fn bitmask(self) -> i32 {
+        self.0
+    }
+
+    /// True of the grow seal bit is present.
+    #[inline]
+    pub fn grow_seal(self) -> bool {
+        self.0 & F_SEAL_GROW != 0
+    }
+
+    /// Sets the grow seal bit.
+    #[inline]
+    pub fn set_grow_seal(&mut self) {
+        self.0 |= F_SEAL_GROW;
+    }
+
+    /// True of the shrink seal bit is present.
+    #[inline]
+    pub fn shrink_seal(self) -> bool {
+        self.0 & F_SEAL_SHRINK != 0
+    }
+
+    /// Sets the shrink seal bit.
+    #[inline]
+    pub fn set_shrink_seal(&mut self) {
+        self.0 |= F_SEAL_SHRINK;
+    }
+
+    /// True of the write seal bit is present.
+    #[inline]
+    pub fn write_seal(self) -> bool {
+        self.0 & F_SEAL_WRITE != 0
+    }
+
+    /// Sets the write seal bit.
+    #[inline]
+    pub fn set_write_seal(&mut self) {
+        self.0 |= F_SEAL_WRITE;
+    }
+
+    /// True of the seal seal bit is present.
+    #[inline]
+    pub fn seal_seal(self) -> bool {
+        self.0 & F_SEAL_SEAL != 0
+    }
+
+    /// Sets the seal seal bit.
+    #[inline]
+    pub fn set_seal_seal(&mut self) {
+        self.0 |= F_SEAL_SEAL;
+    }
+}
+
+impl SharedMemory {
+    /// Creates a new shared memory file descriptor with zero size.
+    ///
+    /// If a name is given, it will appear in `/proc/self/fd/<shm fd>` for the purposes of
+    /// debugging. The name does not need to be unique.
+    ///
+    /// The file descriptor is opened with the close on exec flag and allows memfd sealing.
+    pub fn new(name: Option<&CStr>) -> Result<SharedMemory> {
+        let shm_name = name
+            .map(|n| n.as_ptr())
+            .unwrap_or(b"/crosvm_shm\0".as_ptr() as *const c_char);
+        // The following are safe because we give a valid C string and check the
+        // results of the memfd_create call.
+        let fd = unsafe { memfd_create(shm_name, MFD_CLOEXEC | MFD_ALLOW_SEALING) };
+        if fd < 0 {
+            return errno_result();
+        }
+
+        let file = unsafe { File::from_raw_fd(fd) };
+
+        Ok(SharedMemory { fd: file, size: 0 })
+    }
+
+    /// Constructs a `SharedMemory` instance from a file descriptor that represents shared memory.
+    ///
+    /// The size of the resulting shared memory will be determined using `File::seek`. If the given
+    /// file's size can not be determined this way, this will return an error.
+    pub fn from_raw_fd<T: IntoRawFd>(fd: T) -> Result<SharedMemory> {
+        // Safe because the IntoRawFd trait indicates fd has unique ownership.
+        let mut file = unsafe { File::from_raw_fd(fd.into_raw_fd()) };
+        let file_size = file.seek(SeekFrom::End(0))?;
+        Ok(SharedMemory {
+            fd: file,
+            size: file_size as u64,
+        })
+    }
+
+    /// Gets the memfd seals that have already been added to this.
+    ///
+    /// This may fail if this instance was not constructed from a memfd.
+    pub fn get_seals(&self) -> Result<MemfdSeals> {
+        let ret = unsafe { fcntl(self.fd.as_raw_fd(), F_GET_SEALS) };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(MemfdSeals(ret))
+    }
+
+    /// Adds the given set of memfd seals.
+    ///
+    /// This may fail if this instance was not constructed from a memfd with sealing allowed or if
+    /// the seal seal (`F_SEAL_SEAL`) bit was already added.
+    pub fn add_seals(&mut self, seals: MemfdSeals) -> Result<()> {
+        let ret = unsafe { fcntl(self.fd.as_raw_fd(), F_ADD_SEALS, seals) };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
+    /// Gets the size in bytes of the shared memory.
+    ///
+    /// The size returned here does not reflect changes by other interfaces or users of the shared
+    /// memory file descriptor..
+    pub fn size(&self) -> u64 {
+        self.size
+    }
+
+    /// Sets the size in bytes of the shared memory.
+    ///
+    /// Note that if some process has already mapped this shared memory and the new size is smaller,
+    /// that process may get signaled with SIGBUS if they access any page past the new size.
+    pub fn set_size(&mut self, size: u64) -> Result<()> {
+        let ret = unsafe { ftruncate64(self.fd.as_raw_fd(), size as off64_t) };
+        if ret < 0 {
+            return errno_result();
+        }
+        self.size = size;
+        Ok(())
+    }
+}
+
+impl Read for SharedMemory {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.fd.read(buf)
+    }
+}
+
+impl Read for &SharedMemory {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (&self.fd).read(buf)
+    }
+}
+
+impl Write for SharedMemory {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.fd.write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.fd.flush()
+    }
+}
+
+impl Write for &SharedMemory {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        (&self.fd).write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        (&self.fd).flush()
+    }
+}
+
+impl Seek for SharedMemory {
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+        self.fd.seek(pos)
+    }
+}
+
+impl Seek for &SharedMemory {
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+        (&self.fd).seek(pos)
+    }
+}
+
+impl AsRawFd for SharedMemory {
+    fn as_raw_fd(&self) -> RawFd {
+        self.fd.as_raw_fd()
+    }
+}
+
+impl AsRawFd for &SharedMemory {
+    fn as_raw_fd(&self) -> RawFd {
+        self.fd.as_raw_fd()
+    }
+}
+
+impl Into<File> for SharedMemory {
+    fn into(self) -> File {
+        self.fd
+    }
+}
+
+/// Checks if the kernel we are running on has memfd_create. It was introduced in 3.17.
+/// Only to be used from tests to prevent running on ancient kernels that won't
+/// support the functionality anyways.
+pub fn kernel_has_memfd() -> bool {
+    unsafe {
+        let fd = memfd_create(b"/test_memfd_create\0".as_ptr() as *const c_char, 0);
+        if fd < 0 {
+            if errno::Error::last().errno() == libc::ENOSYS {
+                return false;
+            }
+            return true;
+        }
+        close(fd);
+    }
+    true
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use std::ffi::CString;
+    use std::fs::read_link;
+
+    use data_model::VolatileMemory;
+
+    use crate::MemoryMapping;
+
+    #[test]
+    fn new() {
+        if !kernel_has_memfd() {
+            return;
+        }
+        let shm = SharedMemory::new(None).expect("failed to create shared memory");
+        assert_eq!(shm.size(), 0);
+    }
+
+    #[test]
+    fn new_sized() {
+        if !kernel_has_memfd() {
+            return;
+        }
+        let mut shm = SharedMemory::new(None).expect("failed to create shared memory");
+        shm.set_size(1024)
+            .expect("failed to set shared memory size");
+        assert_eq!(shm.size(), 1024);
+    }
+
+    #[test]
+    fn new_huge() {
+        if !kernel_has_memfd() {
+            return;
+        }
+        let mut shm = SharedMemory::new(None).expect("failed to create shared memory");
+        shm.set_size(0x7fff_ffff_ffff_ffff)
+            .expect("failed to set shared memory size");
+        assert_eq!(shm.size(), 0x7fff_ffff_ffff_ffff);
+    }
+
+    #[test]
+    fn new_too_huge() {
+        if !kernel_has_memfd() {
+            return;
+        }
+        let mut shm = SharedMemory::new(None).expect("failed to create shared memory");
+        shm.set_size(0x8000_0000_0000_0000).unwrap_err();
+        assert_eq!(shm.size(), 0);
+    }
+
+    #[test]
+    fn new_named() {
+        if !kernel_has_memfd() {
+            return;
+        }
+        let name = "very unique name";
+        let cname = CString::new(name).unwrap();
+        let shm = SharedMemory::new(Some(&cname)).expect("failed to create shared memory");
+        let fd_path = format!("/proc/self/fd/{}", shm.as_raw_fd());
+        let link_name =
+            read_link(fd_path).expect("failed to read link of shared memory /proc/self/fd entry");
+        assert!(link_name.to_str().unwrap().contains(name));
+    }
+
+    #[test]
+    fn new_sealed() {
+        if !kernel_has_memfd() {
+            return;
+        }
+        let mut shm = SharedMemory::new(None).expect("failed to create shared memory");
+        let mut seals = shm.get_seals().expect("failed to get seals");
+        assert_eq!(seals.bitmask(), 0);
+        seals.set_seal_seal();
+        shm.add_seals(seals).expect("failed to add seals");
+        seals = shm.get_seals().expect("failed to get seals");
+        assert!(seals.seal_seal());
+        // Adding more seals should be rejected by the kernel.
+        shm.add_seals(seals).unwrap_err();
+    }
+
+    #[test]
+    fn mmap_page() {
+        if !kernel_has_memfd() {
+            return;
+        }
+        let mut shm = SharedMemory::new(None).expect("failed to create shared memory");
+        shm.set_size(4096)
+            .expect("failed to set shared memory size");
+
+        let mmap1 =
+            MemoryMapping::from_fd(&shm, shm.size() as usize).expect("failed to map shared memory");
+        let mmap2 =
+            MemoryMapping::from_fd(&shm, shm.size() as usize).expect("failed to map shared memory");
+
+        assert_ne!(
+            mmap1.get_slice(0, 1).unwrap().as_ptr(),
+            mmap2.get_slice(0, 1).unwrap().as_ptr()
+        );
+
+        mmap1
+            .get_slice(0, 4096)
+            .expect("failed to get mmap slice")
+            .write_bytes(0x45);
+
+        for i in 0..4096 {
+            assert_eq!(mmap2.get_ref::<u8>(i).unwrap().load(), 0x45u8);
+        }
+    }
+
+    #[test]
+    fn mmap_page_offset() {
+        if !kernel_has_memfd() {
+            return;
+        }
+        let mut shm = SharedMemory::new(None).expect("failed to create shared memory");
+        shm.set_size(8092)
+            .expect("failed to set shared memory size");
+
+        let mmap1 = MemoryMapping::from_fd_offset(&shm, shm.size() as usize, 4096)
+            .expect("failed to map shared memory");
+        let mmap2 =
+            MemoryMapping::from_fd(&shm, shm.size() as usize).expect("failed to map shared memory");
+
+        mmap1
+            .get_slice(0, 4096)
+            .expect("failed to get mmap slice")
+            .write_bytes(0x45);
+
+        for i in 0..4096 {
+            assert_eq!(mmap2.get_ref::<u8>(i).unwrap().load(), 0);
+        }
+        for i in 4096..8092 {
+            assert_eq!(mmap2.get_ref::<u8>(i).unwrap().load(), 0x45u8);
+        }
+    }
+}
diff --git a/sys_util/src/signal.rs b/sys_util/src/signal.rs
new file mode 100644
index 0000000..882da90
--- /dev/null
+++ b/sys_util/src/signal.rs
@@ -0,0 +1,285 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use libc::{
+    c_int, pthread_kill, pthread_sigmask, pthread_t, sigaction, sigaddset, sigemptyset, siginfo_t,
+    sigismember, sigpending, sigset_t, sigtimedwait, timespec, EAGAIN, EINTR, EINVAL, SA_RESTART,
+    SIG_BLOCK, SIG_UNBLOCK,
+};
+
+use std::fmt::{self, Display};
+use std::io;
+use std::mem;
+use std::os::unix::thread::JoinHandleExt;
+use std::ptr::{null, null_mut};
+use std::result;
+use std::thread::JoinHandle;
+
+use crate::{errno, errno_result};
+
+#[derive(Debug)]
+pub enum Error {
+    /// Couldn't create a sigset.
+    CreateSigset(errno::Error),
+    /// The wrapped signal has already been blocked.
+    SignalAlreadyBlocked(c_int),
+    /// Failed to check if the requested signal is in the blocked set already.
+    CompareBlockedSignals(errno::Error),
+    /// The signal could not be blocked.
+    BlockSignal(errno::Error),
+    /// The signal mask could not be retrieved.
+    RetrieveSignalMask(i32),
+    /// The signal could not be unblocked.
+    UnblockSignal(errno::Error),
+    /// Failed to wait for given signal.
+    ClearWaitPending(errno::Error),
+    /// Failed to get pending signals.
+    ClearGetPending(errno::Error),
+    /// Failed to check if given signal is in the set of pending signals.
+    ClearCheckPending(errno::Error),
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            CreateSigset(e) => write!(f, "couldn't create a sigset: {}", e),
+            SignalAlreadyBlocked(num) => write!(f, "signal {} already blocked", num),
+            CompareBlockedSignals(e) => write!(
+                f,
+                "failed to check whether requested signal is in the blocked set: {}",
+                e,
+            ),
+            BlockSignal(e) => write!(f, "signal could not be blocked: {}", e),
+            RetrieveSignalMask(errno) => write!(
+                f,
+                "failed to retrieve signal mask: {}",
+                io::Error::from_raw_os_error(*errno),
+            ),
+            UnblockSignal(e) => write!(f, "signal could not be unblocked: {}", e),
+            ClearWaitPending(e) => write!(f, "failed to wait for given signal: {}", e),
+            ClearGetPending(e) => write!(f, "failed to get pending signals: {}", e),
+            ClearCheckPending(e) => write!(
+                f,
+                "failed to check whether given signal is in the pending set: {}",
+                e,
+            ),
+        }
+    }
+}
+
+pub type SignalResult<T> = result::Result<T, Error>;
+
+#[link(name = "c")]
+extern "C" {
+    fn __libc_current_sigrtmin() -> c_int;
+    fn __libc_current_sigrtmax() -> c_int;
+}
+
+/// Returns the minimum (inclusive) real-time signal number.
+#[allow(non_snake_case)]
+pub fn SIGRTMIN() -> c_int {
+    unsafe { __libc_current_sigrtmin() }
+}
+
+/// Returns the maximum (inclusive) real-time signal number.
+#[allow(non_snake_case)]
+pub fn SIGRTMAX() -> c_int {
+    unsafe { __libc_current_sigrtmax() }
+}
+
+fn valid_signal_num(num: c_int) -> bool {
+    num >= SIGRTMIN() && num <= SIGRTMAX()
+}
+
+/// Registers `handler` as the signal handler of signum `num`.
+///
+/// The value of `num` must be within [`SIGRTMIN`, `SIGRTMAX`] range.
+///
+/// This is considered unsafe because the given handler will be called asynchronously, interrupting
+/// whatever the thread was doing and therefore must only do async-signal-safe operations.
+pub unsafe fn register_signal_handler(
+    num: c_int,
+    handler: extern "C" fn() -> (),
+) -> errno::Result<()> {
+    if !valid_signal_num(num) {
+        return Err(errno::Error::new(EINVAL));
+    }
+
+    let mut sigact: sigaction = mem::zeroed();
+    sigact.sa_flags = SA_RESTART;
+    sigact.sa_sigaction = handler as *const () as usize;
+
+    let ret = sigaction(num, &sigact, null_mut());
+    if ret < 0 {
+        return errno_result();
+    }
+
+    Ok(())
+}
+
+/// Creates `sigset` from an array of signal numbers.
+///
+/// This is a helper function used when we want to manipulate signals.
+pub fn create_sigset(signals: &[c_int]) -> errno::Result<sigset_t> {
+    // sigset will actually be initialized by sigemptyset below.
+    let mut sigset: sigset_t = unsafe { mem::zeroed() };
+
+    // Safe - return value is checked.
+    let ret = unsafe { sigemptyset(&mut sigset) };
+    if ret < 0 {
+        return errno_result();
+    }
+
+    for signal in signals {
+        // Safe - return value is checked.
+        let ret = unsafe { sigaddset(&mut sigset, *signal) };
+        if ret < 0 {
+            return errno_result();
+        }
+    }
+
+    Ok(sigset)
+}
+
+/// Retrieves the signal mask of the current thread as a vector of c_ints.
+pub fn get_blocked_signals() -> SignalResult<Vec<c_int>> {
+    let mut mask = Vec::new();
+
+    // Safe - return values are checked.
+    unsafe {
+        let mut old_sigset: sigset_t = mem::zeroed();
+        let ret = pthread_sigmask(SIG_BLOCK, null(), &mut old_sigset as *mut sigset_t);
+        if ret < 0 {
+            return Err(Error::RetrieveSignalMask(ret));
+        }
+
+        for num in 0..=SIGRTMAX() {
+            if sigismember(&old_sigset, num) > 0 {
+                mask.push(num);
+            }
+        }
+    }
+
+    Ok(mask)
+}
+
+/// Masks given signal.
+///
+/// If signal is already blocked the call will fail with Error::SignalAlreadyBlocked
+/// result.
+pub fn block_signal(num: c_int) -> SignalResult<()> {
+    let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
+
+    // Safe - return values are checked.
+    unsafe {
+        let mut old_sigset: sigset_t = mem::zeroed();
+        let ret = pthread_sigmask(SIG_BLOCK, &sigset, &mut old_sigset as *mut sigset_t);
+        if ret < 0 {
+            return Err(Error::BlockSignal(errno::Error::last()));
+        }
+        let ret = sigismember(&old_sigset, num);
+        if ret < 0 {
+            return Err(Error::CompareBlockedSignals(errno::Error::last()));
+        } else if ret > 0 {
+            return Err(Error::SignalAlreadyBlocked(num));
+        }
+    }
+    Ok(())
+}
+
+/// Unmasks given signal.
+pub fn unblock_signal(num: c_int) -> SignalResult<()> {
+    let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
+
+    // Safe - return value is checked.
+    let ret = unsafe { pthread_sigmask(SIG_UNBLOCK, &sigset, null_mut()) };
+    if ret < 0 {
+        return Err(Error::UnblockSignal(errno::Error::last()));
+    }
+    Ok(())
+}
+
+/// Clears pending signal.
+pub fn clear_signal(num: c_int) -> SignalResult<()> {
+    let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
+
+    while {
+        // This is safe as we are rigorously checking return values
+        // of libc calls.
+        unsafe {
+            let mut siginfo: siginfo_t = mem::zeroed();
+            let ts = timespec {
+                tv_sec: 0,
+                tv_nsec: 0,
+            };
+            // Attempt to consume one instance of pending signal. If signal
+            // is not pending, the call will fail with EAGAIN or EINTR.
+            let ret = sigtimedwait(&sigset, &mut siginfo, &ts);
+            if ret < 0 {
+                let e = errno::Error::last();
+                match e.errno() {
+                    EAGAIN | EINTR => {}
+                    _ => {
+                        return Err(Error::ClearWaitPending(errno::Error::last()));
+                    }
+                }
+            }
+
+            // This sigset will be actually filled with `sigpending` call.
+            let mut chkset: sigset_t = mem::zeroed();
+            // See if more instances of the signal are pending.
+            let ret = sigpending(&mut chkset);
+            if ret < 0 {
+                return Err(Error::ClearGetPending(errno::Error::last()));
+            }
+
+            let ret = sigismember(&chkset, num);
+            if ret < 0 {
+                return Err(Error::ClearCheckPending(errno::Error::last()));
+            }
+
+            // This is do-while loop condition.
+            ret != 0
+        }
+    } {}
+
+    Ok(())
+}
+
+/// Trait for threads that can be signalled via `pthread_kill`.
+///
+/// Note that this is only useful for signals between SIGRTMIN and SIGRTMAX because these are
+/// guaranteed to not be used by the C runtime.
+///
+/// This is marked unsafe because the implementation of this trait must guarantee that the returned
+/// pthread_t is valid and has a lifetime at least that of the trait object.
+pub unsafe trait Killable {
+    fn pthread_handle(&self) -> pthread_t;
+
+    /// Sends the signal `num` to this killable thread.
+    ///
+    /// The value of `num` must be within [`SIGRTMIN`, `SIGRTMAX`] range.
+    fn kill(&self, num: c_int) -> errno::Result<()> {
+        if !valid_signal_num(num) {
+            return Err(errno::Error::new(EINVAL));
+        }
+
+        // Safe because we ensure we are using a valid pthread handle, a valid signal number, and
+        // check the return result.
+        let ret = unsafe { pthread_kill(self.pthread_handle(), num) };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+}
+
+// Safe because we fulfill our contract of returning a genuine pthread handle.
+unsafe impl<T> Killable for JoinHandle<T> {
+    fn pthread_handle(&self) -> pthread_t {
+        self.as_pthread_t()
+    }
+}
diff --git a/sys_util/src/signalfd.rs b/sys_util/src/signalfd.rs
new file mode 100644
index 0000000..0b50ea4
--- /dev/null
+++ b/sys_util/src/signalfd.rs
@@ -0,0 +1,195 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::mem;
+use std::os::raw::c_int;
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::result;
+
+use libc::{c_void, read, signalfd, signalfd_siginfo};
+use libc::{EAGAIN, SFD_CLOEXEC, SFD_NONBLOCK};
+
+use crate::errno;
+use crate::signal;
+
+#[derive(Debug)]
+pub enum Error {
+    /// Failed to construct sigset when creating signalfd.
+    CreateSigset(errno::Error),
+    /// Failed to create a new signalfd.
+    CreateSignalFd(errno::Error),
+    /// Failed to block the signal when creating signalfd.
+    CreateBlockSignal(signal::Error),
+    /// Unable to read from signalfd.
+    SignalFdRead(errno::Error),
+    /// Signalfd could be read, but didn't return a full siginfo struct.
+    /// This wraps the number of bytes that were actually read.
+    SignalFdPartialRead(usize),
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            CreateSigset(e) => write!(
+                f,
+                "failed to construct sigset when creating signalfd: {}",
+                e,
+            ),
+            CreateSignalFd(e) => write!(f, "failed to create a new signalfd: {}", e),
+            CreateBlockSignal(e) => write!(
+                f,
+                "failed to block the signal when creating signalfd: {}",
+                e,
+            ),
+            SignalFdRead(e) => write!(f, "unable to read from signalfd: {}", e),
+            SignalFdPartialRead(read) => write!(
+                f,
+                "signalfd failed to return a full siginfo struct, read only {} bytes",
+                read,
+            ),
+        }
+    }
+}
+
+pub type Result<T> = result::Result<T, Error>;
+
+/// A safe wrapper around a Linux signalfd (man 2 signalfd).
+///
+/// A signalfd can be used for non-synchronous signals (such as SIGCHLD) so that
+/// signals can be processed without the use of a signal handler.
+pub struct SignalFd {
+    signalfd: File,
+    signal: c_int,
+}
+
+impl SignalFd {
+    /// Creates a new SignalFd for the given signal, blocking the normal handler
+    /// for the signal as well. Since we mask out the normal handler, this is
+    /// a risky operation - signal masking will persist across fork and even
+    /// **exec** so the user of SignalFd should think long and hard about
+    /// when to mask signals.
+    pub fn new(signal: c_int) -> Result<SignalFd> {
+        let sigset = signal::create_sigset(&[signal]).map_err(Error::CreateSigset)?;
+
+        // This is safe as we check the return value and know that fd is valid.
+        let fd = unsafe { signalfd(-1, &sigset, SFD_CLOEXEC | SFD_NONBLOCK) };
+        if fd < 0 {
+            return Err(Error::CreateSignalFd(errno::Error::last()));
+        }
+
+        // Mask out the normal handler for the signal.
+        signal::block_signal(signal).map_err(Error::CreateBlockSignal)?;
+
+        // This is safe because we checked fd for success and know the
+        // kernel gave us an fd that we own.
+        unsafe {
+            Ok(SignalFd {
+                signalfd: File::from_raw_fd(fd),
+                signal,
+            })
+        }
+    }
+
+    /// Read a siginfo struct from the signalfd, if available.
+    pub fn read(&self) -> Result<Option<signalfd_siginfo>> {
+        // signalfd_siginfo doesn't have a default, so just zero it.
+        let mut siginfo: signalfd_siginfo = unsafe { mem::zeroed() };
+        let siginfo_size = mem::size_of::<signalfd_siginfo>();
+
+        // This read is safe since we've got the space allocated for a
+        // single signalfd_siginfo, and that's exactly how much we're
+        // reading. Handling of EINTR is not required since SFD_NONBLOCK
+        // was specified. signalfds will always read in increments of
+        // sizeof(signalfd_siginfo); see man 2 signalfd.
+        let ret = unsafe {
+            read(
+                self.signalfd.as_raw_fd(),
+                &mut siginfo as *mut signalfd_siginfo as *mut c_void,
+                siginfo_size,
+            )
+        };
+
+        if ret < 0 {
+            let err = errno::Error::last();
+            if err.errno() == EAGAIN {
+                Ok(None)
+            } else {
+                Err(Error::SignalFdRead(err))
+            }
+        } else if ret == (siginfo_size as isize) {
+            Ok(Some(siginfo))
+        } else {
+            Err(Error::SignalFdPartialRead(ret as usize))
+        }
+    }
+}
+
+impl AsRawFd for SignalFd {
+    fn as_raw_fd(&self) -> RawFd {
+        self.signalfd.as_raw_fd()
+    }
+}
+
+impl Drop for SignalFd {
+    fn drop(&mut self) {
+        // This is thread-safe and safe in the sense that we're doing what
+        // was promised - unmasking the signal when we go out of scope.
+        let res = signal::unblock_signal(self.signal);
+        if let Err(e) = res {
+            error!("signalfd failed to unblock signal {}: {}", self.signal, e);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use crate::signal::SIGRTMIN;
+    use libc::{pthread_sigmask, raise, sigismember, sigset_t};
+    use std::mem;
+    use std::ptr::null;
+
+    #[test]
+    fn new() {
+        SignalFd::new(SIGRTMIN()).unwrap();
+    }
+
+    #[test]
+    fn read() {
+        let sigid = SIGRTMIN() + 1;
+        let sigrt_fd = SignalFd::new(sigid).unwrap();
+
+        let ret = unsafe { raise(sigid) };
+        assert_eq!(ret, 0);
+
+        let siginfo = sigrt_fd.read().unwrap().unwrap();
+        assert_eq!(siginfo.ssi_signo, sigid as u32);
+    }
+
+    #[test]
+    fn drop() {
+        let sigid = SIGRTMIN() + 2;
+
+        let sigrt_fd = SignalFd::new(sigid).unwrap();
+        unsafe {
+            let mut sigset: sigset_t = mem::zeroed();
+            pthread_sigmask(0, null(), &mut sigset as *mut sigset_t);
+            assert_eq!(sigismember(&sigset, sigid), 1);
+        }
+
+        mem::drop(sigrt_fd);
+
+        // The signal should no longer be masked.
+        unsafe {
+            let mut sigset: sigset_t = mem::zeroed();
+            pthread_sigmask(0, null(), &mut sigset as *mut sigset_t);
+            assert_eq!(sigismember(&sigset, sigid), 0);
+        }
+    }
+}
diff --git a/sys_util/src/sock_ctrl_msg.rs b/sys_util/src/sock_ctrl_msg.rs
new file mode 100644
index 0000000..96a072d
--- /dev/null
+++ b/sys_util/src/sock_ctrl_msg.rs
@@ -0,0 +1,473 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Used to send and receive messages with file descriptors on sockets that accept control messages
+//! (e.g. Unix domain sockets).
+
+use std::fs::File;
+use std::mem::size_of;
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::os::unix::net::{UnixDatagram, UnixStream};
+use std::ptr::{copy_nonoverlapping, null_mut, write_unaligned};
+
+use libc::{
+    c_long, c_void, cmsghdr, iovec, msghdr, recvmsg, sendmsg, MSG_NOSIGNAL, SCM_RIGHTS, SOL_SOCKET,
+};
+
+use data_model::VolatileSlice;
+
+use crate::net::UnixSeqpacket;
+use crate::{Error, Result};
+
+// Each of the following macros performs the same function as their C counterparts. They are each
+// macros because they are used to size statically allocated arrays.
+
+macro_rules! CMSG_ALIGN {
+    ($len:expr) => {
+        (($len) + size_of::<c_long>() - 1) & !(size_of::<c_long>() - 1)
+    };
+}
+
+macro_rules! CMSG_SPACE {
+    ($len:expr) => {
+        size_of::<cmsghdr>() + CMSG_ALIGN!($len)
+    };
+}
+
+macro_rules! CMSG_LEN {
+    ($len:expr) => {
+        size_of::<cmsghdr>() + ($len)
+    };
+}
+
+// This function (macro in the C version) is not used in any compile time constant slots, so is just
+// an ordinary function. The returned pointer is hard coded to be RawFd because that's all that this
+// module supports.
+#[allow(non_snake_case)]
+#[inline(always)]
+fn CMSG_DATA(cmsg_buffer: *mut cmsghdr) -> *mut RawFd {
+    // Essentially returns a pointer to just past the header.
+    cmsg_buffer.wrapping_offset(1) as *mut RawFd
+}
+
+// This function is like CMSG_NEXT, but safer because it reads only from references, although it
+// does some pointer arithmetic on cmsg_ptr.
+#[allow(clippy::cast_ptr_alignment)]
+fn get_next_cmsg(msghdr: &msghdr, cmsg: &cmsghdr, cmsg_ptr: *mut cmsghdr) -> *mut cmsghdr {
+    let next_cmsg = (cmsg_ptr as *mut u8).wrapping_add(CMSG_ALIGN!(cmsg.cmsg_len)) as *mut cmsghdr;
+    if next_cmsg
+        .wrapping_offset(1)
+        .wrapping_sub(msghdr.msg_control as usize) as usize
+        > msghdr.msg_controllen
+    {
+        null_mut()
+    } else {
+        next_cmsg
+    }
+}
+
+const CMSG_BUFFER_INLINE_CAPACITY: usize = CMSG_SPACE!(size_of::<RawFd>() * 32);
+
+enum CmsgBuffer {
+    Inline([u64; (CMSG_BUFFER_INLINE_CAPACITY + 7) / 8]),
+    Heap(Box<[cmsghdr]>),
+}
+
+impl CmsgBuffer {
+    fn with_capacity(capacity: usize) -> CmsgBuffer {
+        let cap_in_cmsghdr_units =
+            (capacity.checked_add(size_of::<cmsghdr>()).unwrap() - 1) / size_of::<cmsghdr>();
+        if capacity <= CMSG_BUFFER_INLINE_CAPACITY {
+            CmsgBuffer::Inline([0u64; (CMSG_BUFFER_INLINE_CAPACITY + 7) / 8])
+        } else {
+            CmsgBuffer::Heap(
+                vec![
+                    cmsghdr {
+                        cmsg_len: 0,
+                        cmsg_level: 0,
+                        cmsg_type: 0,
+                    };
+                    cap_in_cmsghdr_units
+                ]
+                .into_boxed_slice(),
+            )
+        }
+    }
+
+    fn as_mut_ptr(&mut self) -> *mut cmsghdr {
+        match self {
+            CmsgBuffer::Inline(a) => a.as_mut_ptr() as *mut cmsghdr,
+            CmsgBuffer::Heap(a) => a.as_mut_ptr(),
+        }
+    }
+}
+
+fn raw_sendmsg<D: IntoIovec>(fd: RawFd, out_data: D, out_fds: &[RawFd]) -> Result<usize> {
+    let cmsg_capacity = CMSG_SPACE!(size_of::<RawFd>() * out_fds.len());
+    let mut cmsg_buffer = CmsgBuffer::with_capacity(cmsg_capacity);
+
+    let mut iovec = iovec {
+        iov_base: out_data.as_ptr() as *mut c_void,
+        iov_len: out_data.size(),
+    };
+
+    let mut msg = msghdr {
+        msg_name: null_mut(),
+        msg_namelen: 0,
+        msg_iov: &mut iovec as *mut iovec,
+        msg_iovlen: 1,
+        msg_control: null_mut(),
+        msg_controllen: 0,
+        msg_flags: 0,
+    };
+
+    if !out_fds.is_empty() {
+        let cmsg = cmsghdr {
+            cmsg_len: CMSG_LEN!(size_of::<RawFd>() * out_fds.len()),
+            cmsg_level: SOL_SOCKET,
+            cmsg_type: SCM_RIGHTS,
+        };
+        unsafe {
+            // Safe because cmsg_buffer was allocated to be large enough to contain cmsghdr.
+            write_unaligned(cmsg_buffer.as_mut_ptr() as *mut cmsghdr, cmsg);
+            // Safe because the cmsg_buffer was allocated to be large enough to hold out_fds.len()
+            // file descriptors.
+            copy_nonoverlapping(
+                out_fds.as_ptr(),
+                CMSG_DATA(cmsg_buffer.as_mut_ptr()),
+                out_fds.len(),
+            );
+        }
+
+        msg.msg_control = cmsg_buffer.as_mut_ptr() as *mut c_void;
+        msg.msg_controllen = cmsg_capacity;
+    }
+
+    // Safe because the msghdr was properly constructed from valid (or null) pointers of the
+    // indicated length and we check the return value.
+    let write_count = unsafe { sendmsg(fd, &msg, MSG_NOSIGNAL) };
+
+    if write_count == -1 {
+        Err(Error::last())
+    } else {
+        Ok(write_count as usize)
+    }
+}
+
+fn raw_recvmsg(fd: RawFd, in_data: &mut [u8], in_fds: &mut [RawFd]) -> Result<(usize, usize)> {
+    let cmsg_capacity = CMSG_SPACE!(size_of::<RawFd>() * in_fds.len());
+    let mut cmsg_buffer = CmsgBuffer::with_capacity(cmsg_capacity);
+
+    let mut iovec = iovec {
+        iov_base: in_data.as_mut_ptr() as *mut c_void,
+        iov_len: in_data.len(),
+    };
+
+    let mut msg = msghdr {
+        msg_name: null_mut(),
+        msg_namelen: 0,
+        msg_iov: &mut iovec as *mut iovec,
+        msg_iovlen: 1,
+        msg_control: null_mut(),
+        msg_controllen: 0,
+        msg_flags: 0,
+    };
+
+    if !in_fds.is_empty() {
+        msg.msg_control = cmsg_buffer.as_mut_ptr() as *mut c_void;
+        msg.msg_controllen = cmsg_capacity;
+    }
+
+    // Safe because the msghdr was properly constructed from valid (or null) pointers of the
+    // indicated length and we check the return value.
+    let total_read = unsafe { recvmsg(fd, &mut msg, 0) };
+
+    if total_read == -1 {
+        return Err(Error::last());
+    }
+
+    if total_read == 0 && msg.msg_controllen < size_of::<cmsghdr>() {
+        return Ok((0, 0));
+    }
+
+    let mut cmsg_ptr = msg.msg_control as *mut cmsghdr;
+    let mut in_fds_count = 0;
+    while !cmsg_ptr.is_null() {
+        // Safe because we checked that cmsg_ptr was non-null, and the loop is constructed such that
+        // that only happens when there is at least sizeof(cmsghdr) space after the pointer to read.
+        let cmsg = unsafe { (cmsg_ptr as *mut cmsghdr).read_unaligned() };
+
+        if cmsg.cmsg_level == SOL_SOCKET && cmsg.cmsg_type == SCM_RIGHTS {
+            let fd_count = (cmsg.cmsg_len - CMSG_LEN!(0)) / size_of::<RawFd>();
+            unsafe {
+                copy_nonoverlapping(
+                    CMSG_DATA(cmsg_ptr),
+                    in_fds[in_fds_count..(in_fds_count + fd_count)].as_mut_ptr(),
+                    fd_count,
+                );
+            }
+            in_fds_count += fd_count;
+        }
+
+        cmsg_ptr = get_next_cmsg(&msg, &cmsg, cmsg_ptr);
+    }
+
+    Ok((total_read as usize, in_fds_count))
+}
+
+/// Trait for file descriptors can send and receive socket control messages via `sendmsg` and
+/// `recvmsg`.
+pub trait ScmSocket {
+    /// Gets the file descriptor of this socket.
+    fn socket_fd(&self) -> RawFd;
+
+    /// Sends the given data and file descriptor over the socket.
+    ///
+    /// On success, returns the number of bytes sent.
+    ///
+    /// # Arguments
+    ///
+    /// * `buf` - A buffer of data to send on the `socket`.
+    /// * `fd` - A file descriptors to be sent.
+    fn send_with_fd<D: IntoIovec>(&self, buf: D, fd: RawFd) -> Result<usize> {
+        self.send_with_fds(buf, &[fd])
+    }
+
+    /// Sends the given data and file descriptors over the socket.
+    ///
+    /// On success, returns the number of bytes sent.
+    ///
+    /// # Arguments
+    ///
+    /// * `buf` - A buffer of data to send on the `socket`.
+    /// * `fds` - A list of file descriptors to be sent.
+    fn send_with_fds<D: IntoIovec>(&self, buf: D, fd: &[RawFd]) -> Result<usize> {
+        raw_sendmsg(self.socket_fd(), buf, fd)
+    }
+
+    /// Receives data and potentially a file descriptor from the socket.
+    ///
+    /// On success, returns the number of bytes and an optional file descriptor.
+    ///
+    /// # Arguments
+    ///
+    /// * `buf` - A buffer to receive data from the socket.vm
+    fn recv_with_fd(&self, buf: &mut [u8]) -> Result<(usize, Option<File>)> {
+        let mut fd = [0];
+        let (read_count, fd_count) = self.recv_with_fds(buf, &mut fd)?;
+        let file = if fd_count == 0 {
+            None
+        } else {
+            // Safe because the first fd from recv_with_fds is owned by us and valid because this
+            // branch was taken.
+            Some(unsafe { File::from_raw_fd(fd[0]) })
+        };
+        Ok((read_count, file))
+    }
+
+    /// Receives data and file descriptors from the socket.
+    ///
+    /// On success, returns the number of bytes and file descriptors received as a tuple
+    /// `(bytes count, files count)`.
+    ///
+    /// # Arguments
+    ///
+    /// * `buf` - A buffer to receive data from the socket.
+    /// * `fds` - A slice of `RawFd`s to put the received file descriptors into. On success, the
+    ///           number of valid file descriptors is indicated by the second element of the
+    ///           returned tuple. The caller owns these file descriptors, but they will not be
+    ///           closed on drop like a `File`-like type would be. It is recommended that each valid
+    ///           file descriptor gets wrapped in a drop type that closes it after this returns.
+    fn recv_with_fds(&self, buf: &mut [u8], fds: &mut [RawFd]) -> Result<(usize, usize)> {
+        raw_recvmsg(self.socket_fd(), buf, fds)
+    }
+}
+
+impl ScmSocket for UnixDatagram {
+    fn socket_fd(&self) -> RawFd {
+        self.as_raw_fd()
+    }
+}
+
+impl ScmSocket for UnixStream {
+    fn socket_fd(&self) -> RawFd {
+        self.as_raw_fd()
+    }
+}
+impl ScmSocket for UnixSeqpacket {
+    fn socket_fd(&self) -> RawFd {
+        self.as_raw_fd()
+    }
+}
+
+/// Trait for types that can be converted into an `iovec` that can be referenced by a syscall for
+/// the lifetime of this object.
+///
+/// This trait is unsafe because interfaces that use this trait depend on the base pointer and size
+/// being accurate.
+pub unsafe trait IntoIovec {
+    /// Gets the base pointer of this `iovec`.
+    fn as_ptr(&self) -> *const c_void;
+
+    /// Gets the size in bytes of this `iovec`.
+    fn size(&self) -> usize;
+}
+
+// Safe because this slice can not have another mutable reference and it's pointer and size are
+// guaranteed to be valid.
+unsafe impl<'a> IntoIovec for &'a [u8] {
+    // Clippy false positive: https://github.com/rust-lang/rust-clippy/issues/3480
+    #[allow(clippy::useless_asref)]
+    fn as_ptr(&self) -> *const c_void {
+        self.as_ref().as_ptr() as *const c_void
+    }
+
+    fn size(&self) -> usize {
+        self.len()
+    }
+}
+
+// Safe because volatile slices are only ever accessed with other volatile interfaces and the
+// pointer and size are guaranteed to be accurate.
+unsafe impl<'a> IntoIovec for VolatileSlice<'a> {
+    fn as_ptr(&self) -> *const c_void {
+        self.as_ptr() as *const c_void
+    }
+
+    fn size(&self) -> usize {
+        self.size() as usize
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use std::io::Write;
+    use std::mem::size_of;
+    use std::os::raw::c_long;
+    use std::os::unix::net::UnixDatagram;
+    use std::slice::from_raw_parts;
+
+    use libc::cmsghdr;
+
+    use crate::EventFd;
+
+    #[test]
+    fn buffer_len() {
+        assert_eq!(CMSG_SPACE!(0 * size_of::<RawFd>()), size_of::<cmsghdr>());
+        assert_eq!(
+            CMSG_SPACE!(1 * size_of::<RawFd>()),
+            size_of::<cmsghdr>() + size_of::<c_long>()
+        );
+        if size_of::<RawFd>() == 4 {
+            assert_eq!(
+                CMSG_SPACE!(2 * size_of::<RawFd>()),
+                size_of::<cmsghdr>() + size_of::<c_long>()
+            );
+            assert_eq!(
+                CMSG_SPACE!(3 * size_of::<RawFd>()),
+                size_of::<cmsghdr>() + size_of::<c_long>() * 2
+            );
+            assert_eq!(
+                CMSG_SPACE!(4 * size_of::<RawFd>()),
+                size_of::<cmsghdr>() + size_of::<c_long>() * 2
+            );
+        } else if size_of::<RawFd>() == 8 {
+            assert_eq!(
+                CMSG_SPACE!(2 * size_of::<RawFd>()),
+                size_of::<cmsghdr>() + size_of::<c_long>() * 2
+            );
+            assert_eq!(
+                CMSG_SPACE!(3 * size_of::<RawFd>()),
+                size_of::<cmsghdr>() + size_of::<c_long>() * 3
+            );
+            assert_eq!(
+                CMSG_SPACE!(4 * size_of::<RawFd>()),
+                size_of::<cmsghdr>() + size_of::<c_long>() * 4
+            );
+        }
+    }
+
+    #[test]
+    fn send_recv_no_fd() {
+        let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair");
+
+        let write_count = s1
+            .send_with_fds([1u8, 1, 2, 21, 34, 55].as_ref(), &[])
+            .expect("failed to send data");
+
+        assert_eq!(write_count, 6);
+
+        let mut buf = [0; 6];
+        let mut files = [0; 1];
+        let (read_count, file_count) = s2
+            .recv_with_fds(&mut buf[..], &mut files)
+            .expect("failed to recv data");
+
+        assert_eq!(read_count, 6);
+        assert_eq!(file_count, 0);
+        assert_eq!(buf, [1, 1, 2, 21, 34, 55]);
+    }
+
+    #[test]
+    fn send_recv_only_fd() {
+        let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair");
+
+        let evt = EventFd::new().expect("failed to create eventfd");
+        let write_count = s1
+            .send_with_fd([].as_ref(), evt.as_raw_fd())
+            .expect("failed to send fd");
+
+        assert_eq!(write_count, 0);
+
+        let (read_count, file_opt) = s2.recv_with_fd(&mut []).expect("failed to recv fd");
+
+        let mut file = file_opt.unwrap();
+
+        assert_eq!(read_count, 0);
+        assert!(file.as_raw_fd() >= 0);
+        assert_ne!(file.as_raw_fd(), s1.as_raw_fd());
+        assert_ne!(file.as_raw_fd(), s2.as_raw_fd());
+        assert_ne!(file.as_raw_fd(), evt.as_raw_fd());
+
+        file.write(unsafe { from_raw_parts(&1203u64 as *const u64 as *const u8, 8) })
+            .expect("failed to write to sent fd");
+
+        assert_eq!(evt.read().expect("failed to read from eventfd"), 1203);
+    }
+
+    #[test]
+    fn send_recv_with_fd() {
+        let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair");
+
+        let evt = EventFd::new().expect("failed to create eventfd");
+        let write_count = s1
+            .send_with_fds([237].as_ref(), &[evt.as_raw_fd()])
+            .expect("failed to send fd");
+
+        assert_eq!(write_count, 1);
+
+        let mut files = [0; 2];
+        let mut buf = [0u8];
+        let (read_count, file_count) = s2
+            .recv_with_fds(&mut buf, &mut files)
+            .expect("failed to recv fd");
+
+        assert_eq!(read_count, 1);
+        assert_eq!(buf[0], 237);
+        assert_eq!(file_count, 1);
+        assert!(files[0] >= 0);
+        assert_ne!(files[0], s1.as_raw_fd());
+        assert_ne!(files[0], s2.as_raw_fd());
+        assert_ne!(files[0], evt.as_raw_fd());
+
+        let mut file = unsafe { File::from_raw_fd(files[0]) };
+
+        file.write(unsafe { from_raw_parts(&1203u64 as *const u64 as *const u8, 8) })
+            .expect("failed to write to sent fd");
+
+        assert_eq!(evt.read().expect("failed to read from eventfd"), 1203);
+    }
+}
diff --git a/sys_util/src/struct_util.rs b/sys_util/src/struct_util.rs
new file mode 100644
index 0000000..3d8def2
--- /dev/null
+++ b/sys_util/src/struct_util.rs
@@ -0,0 +1,146 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std;
+use std::io::Read;
+use std::mem;
+
+#[derive(Debug)]
+pub enum Error {
+    ReadStruct,
+}
+pub type Result<T> = std::result::Result<T, Error>;
+
+/// Reads a struct from an input buffer.
+/// This is unsafe because the struct is initialized to unverified data read from the input.
+/// `read_struct` should only be called to fill plain old data structs.  It is not endian safe.
+///
+/// # Arguments
+///
+/// * `f` - The input to read from.  Often this is a file.
+/// * `out` - The struct to fill with data read from `f`.
+pub unsafe fn read_struct<T: Copy, F: Read>(f: &mut F, out: &mut T) -> Result<()> {
+    let out_slice = std::slice::from_raw_parts_mut(out as *mut T as *mut u8, mem::size_of::<T>());
+    f.read_exact(out_slice).map_err(|_| Error::ReadStruct)?;
+    Ok(())
+}
+
+/// Reads an array of structs from an input buffer.  Returns a Vec of structs initialized with data
+/// from the specified input.
+/// This is unsafe because the structs are initialized to unverified data read from the input.
+/// `read_struct_slice` should only be called for plain old data structs.  It is not endian safe.
+///
+/// # Arguments
+///
+/// * `f` - The input to read from.  Often this is a file.
+/// * `len` - The number of structs to fill with data read from `f`.
+pub unsafe fn read_struct_slice<T: Copy, F: Read>(f: &mut F, len: usize) -> Result<Vec<T>> {
+    let mut out: Vec<T> = Vec::with_capacity(len);
+    out.set_len(len);
+    let out_slice = std::slice::from_raw_parts_mut(
+        out.as_ptr() as *mut T as *mut u8,
+        mem::size_of::<T>() * len,
+    );
+    f.read_exact(out_slice).map_err(|_| Error::ReadStruct)?;
+    Ok(out)
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::io::Cursor;
+    use std::mem;
+
+    #[derive(Clone, Copy, Debug, Default, PartialEq)]
+    struct TestRead {
+        a: u64,
+        b: u8,
+        c: u8,
+        d: u8,
+        e: u8,
+    }
+
+    #[test]
+    fn struct_basic_read() {
+        let orig = TestRead {
+            a: 0x7766554433221100,
+            b: 0x88,
+            c: 0x99,
+            d: 0xaa,
+            e: 0xbb,
+        };
+        let source = unsafe {
+            // Don't worry it's a test
+            std::slice::from_raw_parts(
+                &orig as *const _ as *const u8,
+                std::mem::size_of::<TestRead>(),
+            )
+        };
+        assert_eq!(mem::size_of::<TestRead>(), mem::size_of_val(&source));
+        let mut tr: TestRead = Default::default();
+        unsafe {
+            read_struct(&mut Cursor::new(source), &mut tr).unwrap();
+        }
+        assert_eq!(orig, tr);
+    }
+
+    #[test]
+    fn struct_read_past_end() {
+        let orig = TestRead {
+            a: 0x7766554433221100,
+            b: 0x88,
+            c: 0x99,
+            d: 0xaa,
+            e: 0xbb,
+        };
+        let source = unsafe {
+            // Don't worry it's a test
+            std::slice::from_raw_parts(
+                &orig as *const _ as *const u8,
+                std::mem::size_of::<TestRead>() - 1,
+            )
+        };
+        let mut tr: TestRead = Default::default();
+        unsafe {
+            assert!(read_struct(&mut Cursor::new(source), &mut tr).is_err());
+        }
+    }
+
+    #[test]
+    fn struct_slice_read() {
+        let orig = vec![
+            TestRead {
+                a: 0x7766554433221100,
+                b: 0x88,
+                c: 0x99,
+                d: 0xaa,
+                e: 0xbb,
+            },
+            TestRead {
+                a: 0x7867564534231201,
+                b: 0x02,
+                c: 0x13,
+                d: 0x24,
+                e: 0x35,
+            },
+            TestRead {
+                a: 0x7a69584736251403,
+                b: 0x04,
+                c: 0x15,
+                d: 0x26,
+                e: 0x37,
+            },
+        ];
+        let source = unsafe {
+            // Don't worry it's a test
+            std::slice::from_raw_parts(
+                orig.as_ptr() as *const u8,
+                std::mem::size_of::<TestRead>() * 3,
+            )
+        };
+
+        let tr: Vec<TestRead> = unsafe { read_struct_slice(&mut Cursor::new(source), 3).unwrap() };
+        assert_eq!(orig, tr);
+    }
+}
diff --git a/sys_util/src/syslog.rs b/sys_util/src/syslog.rs
new file mode 100644
index 0000000..da23229
--- /dev/null
+++ b/sys_util/src/syslog.rs
@@ -0,0 +1,681 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Facilities for sending log message to syslog.
+//!
+//! Every function exported by this module is thread-safe. Each function will silently fail until
+//! `syslog::init()` is called and returns `Ok`.
+//!
+//! # Examples
+//!
+//! ```
+//! use sys_util::{error, syslog, warn};
+//!
+//! fn main() {
+//!     if let Err(e) = syslog::init() {
+//!         println!("failed to initiailize syslog: {}", e);
+//!         return;
+//!     }
+//!     warn!("this is your {} warning", "final");
+//!     error!("something went horribly wrong: {}", "out of RAMs");
+//! }
+//! ```
+
+use std::env;
+use std::ffi::{OsStr, OsString};
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::io;
+use std::io::{stderr, Cursor, ErrorKind, Write};
+use std::mem;
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::os::unix::net::UnixDatagram;
+use std::path::PathBuf;
+use std::ptr::null;
+use std::sync::{MutexGuard, Once, ONCE_INIT};
+
+use libc::{
+    closelog, fcntl, localtime_r, openlog, time, time_t, tm, F_GETFD, LOG_NDELAY, LOG_PERROR,
+    LOG_PID, LOG_USER,
+};
+
+use sync::Mutex;
+
+use crate::getpid;
+
+const SYSLOG_PATH: &str = "/dev/log";
+
+/// The priority (i.e. severity) of a syslog message.
+///
+/// See syslog man pages for information on their semantics.
+#[derive(Copy, Clone, Debug)]
+pub enum Priority {
+    Emergency = 0,
+    Alert = 1,
+    Critical = 2,
+    Error = 3,
+    Warning = 4,
+    Notice = 5,
+    Info = 6,
+    Debug = 7,
+}
+
+impl Display for Priority {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Priority::*;
+
+        let string = match self {
+            Emergency => "EMERGENCY",
+            Alert => "ALERT",
+            Critical => "CRITICAL",
+            Error => "ERROR",
+            Warning => "WARNING",
+            Notice => "NOTICE",
+            Info => "INFO",
+            Debug => "DEBUG",
+        };
+
+        write!(f, "{}", string)
+    }
+}
+
+/// The facility of a syslog message.
+///
+/// See syslog man pages for information on their semantics.
+#[derive(Copy, Clone)]
+pub enum Facility {
+    Kernel = 0,
+    User = 1 << 3,
+    Mail = 2 << 3,
+    Daemon = 3 << 3,
+    Auth = 4 << 3,
+    Syslog = 5 << 3,
+    Lpr = 6 << 3,
+    News = 7 << 3,
+    Uucp = 8 << 3,
+    Local0 = 16 << 3,
+    Local1 = 17 << 3,
+    Local2 = 18 << 3,
+    Local3 = 19 << 3,
+    Local4 = 20 << 3,
+    Local5 = 21 << 3,
+    Local6 = 22 << 3,
+    Local7 = 23 << 3,
+}
+
+/// Errors returned by `syslog::init()`.
+#[derive(Debug)]
+pub enum Error {
+    /// Initialization was never attempted.
+    NeverInitialized,
+    /// Initialization has previously failed and can not be retried.
+    Poisoned,
+    /// Error while creating socket.
+    Socket(io::Error),
+    /// Error while attempting to connect socket.
+    Connect(io::Error),
+    // There was an error using `open` to get the lowest file descriptor.
+    GetLowestFd(io::Error),
+    // The guess of libc's file descriptor for the syslog connection was invalid.
+    InvalidFd,
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            NeverInitialized => write!(f, "initialization was never attempted"),
+            Poisoned => write!(f, "initialization previously failed and cannot be retried"),
+            Socket(e) => write!(f, "failed to create socket: {}", e),
+            Connect(e) => write!(f, "failed to connect socket: {}", e),
+            GetLowestFd(e) => write!(f, "failed to get lowest file descriptor: {}", e),
+            InvalidFd => write!(f, "guess of fd for syslog connection was invalid"),
+        }
+    }
+}
+
+fn get_proc_name() -> Option<String> {
+    env::args_os()
+        .next()
+        .map(PathBuf::from)
+        .and_then(|s| s.file_name().map(OsStr::to_os_string))
+        .map(OsString::into_string)
+        .and_then(Result::ok)
+}
+
+// Uses libc's openlog function to get a socket to the syslogger. By getting the socket this way, as
+// opposed to connecting to the syslogger directly, libc's internal state gets initialized for other
+// libraries (e.g. minijail) that make use of libc's syslog function. Note that this function
+// depends on no other threads or signal handlers being active in this process because they might
+// create FDs.
+//
+// TODO(zachr): Once https://android-review.googlesource.com/470998 lands, there won't be any
+// libraries in use that hard depend on libc's syslogger. Remove this and go back to making the
+// connection directly once minjail is ready.
+fn openlog_and_get_socket() -> Result<UnixDatagram, Error> {
+    // closelog first in case there was already a file descriptor open.  Safe because it takes no
+    // arguments and just closes an open file descriptor.  Does nothing if the file descriptor
+    // was not already open.
+    unsafe {
+        closelog();
+    }
+
+    // Ordinarily libc's FD for the syslog connection can't be accessed, but we can guess that the
+    // FD that openlog will be getting is the lowest unused FD. To guarantee that an FD is opened in
+    // this function we use the LOG_NDELAY to tell openlog to connect to the syslog now. To get the
+    // lowest unused FD, we open a dummy file (which the manual says will always return the lowest
+    // fd), and then close that fd. Voilà, we now know the lowest numbered FD. The call to openlog
+    // will make use of that FD, and then we just wrap a `UnixDatagram` around it for ease of use.
+    let fd = File::open("/dev/null")
+        .map_err(Error::GetLowestFd)?
+        .as_raw_fd();
+
+    unsafe {
+        // Safe because openlog accesses no pointers because `ident` is null, only valid flags are
+        // used, and it returns no error.
+        openlog(null(), LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
+        // For safety, ensure the fd we guessed is valid. The `fcntl` call itself only reads the
+        // file descriptor table of the current process, which is trivially safe.
+        if fcntl(fd, F_GETFD) >= 0 {
+            Ok(UnixDatagram::from_raw_fd(fd))
+        } else {
+            Err(Error::InvalidFd)
+        }
+    }
+}
+
+struct State {
+    stderr: bool,
+    socket: Option<UnixDatagram>,
+    file: Option<File>,
+    proc_name: Option<String>,
+}
+
+impl State {
+    fn new() -> Result<State, Error> {
+        let s = openlog_and_get_socket()?;
+        Ok(State {
+            stderr: true,
+            socket: Some(s),
+            file: None,
+            proc_name: get_proc_name(),
+        })
+    }
+}
+
+static STATE_ONCE: Once = ONCE_INIT;
+static mut STATE: *const Mutex<State> = 0 as *const _;
+
+fn new_mutex_ptr<T>(inner: T) -> *const Mutex<T> {
+    Box::into_raw(Box::new(Mutex::new(inner)))
+}
+
+/// Initialize the syslog connection and internal variables.
+///
+/// This should only be called once per process before any other threads have been spawned or any
+/// signal handlers have been registered. Every call made after the first will have no effect
+/// besides return `Ok` or `Err` appropriately.
+pub fn init() -> Result<(), Error> {
+    let mut err = Error::Poisoned;
+    STATE_ONCE.call_once(|| match State::new() {
+        // Safe because STATE mutation is guarded by `Once`.
+        Ok(state) => unsafe { STATE = new_mutex_ptr(state) },
+        Err(e) => err = e,
+    });
+
+    if unsafe { STATE.is_null() } {
+        Err(err)
+    } else {
+        Ok(())
+    }
+}
+
+fn lock() -> Result<MutexGuard<'static, State>, Error> {
+    // Safe because we assume that STATE is always in either a valid or NULL state.
+    let state_ptr = unsafe { STATE };
+    if state_ptr.is_null() {
+        return Err(Error::NeverInitialized);
+    }
+    // Safe because STATE only mutates once and we checked for NULL.
+    let state = unsafe { &*state_ptr };
+    let guard = state.lock();
+    Ok(guard)
+}
+
+// Attempts to lock and retrieve the state. Returns from the function silently on failure.
+macro_rules! lock {
+    () => {
+        match lock() {
+            Ok(s) => s,
+            _ => return,
+        };
+    };
+}
+
+/// Replaces the process name reported in each syslog message.
+///
+/// The default process name is the _file name_ of `argv[0]`. For example, if this program was
+/// invoked as
+///
+/// ```bash
+/// $ path/to/app --delete everything
+/// ```
+///
+/// the default process name would be _app_.
+///
+/// Does nothing if syslog was never initialized.
+pub fn set_proc_name<T: Into<String>>(proc_name: T) {
+    let mut state = lock!();
+    state.proc_name = Some(proc_name.into());
+}
+
+/// Enables or disables echoing log messages to the syslog.
+///
+/// The default behavior is **enabled**.
+///
+/// If `enable` goes from `true` to `false`, the syslog connection is closed. The connection is
+/// reopened if `enable` is set to `true` after it became `false`.
+///
+/// Returns an error if syslog was never initialized or the syslog connection failed to be
+/// established.
+///
+/// # Arguments
+/// * `enable` - `true` to enable echoing to syslog, `false` to disable echoing to syslog.
+pub fn echo_syslog(enable: bool) -> Result<(), Error> {
+    let state_ptr = unsafe { STATE };
+    if state_ptr.is_null() {
+        return Err(Error::NeverInitialized);
+    }
+    let mut state = lock().map_err(|_| Error::Poisoned)?;
+
+    match state.socket.take() {
+        Some(_) if enable => {}
+        Some(s) => {
+            // Because `openlog_and_get_socket` actually just "borrows" the syslog FD, this module
+            // does not own the syslog connection and therefore should not destroy it.
+            mem::forget(s);
+        }
+        None if enable => {
+            let s = openlog_and_get_socket()?;
+            state.socket = Some(s);
+        }
+        _ => {}
+    }
+    Ok(())
+}
+
+/// Replaces the optional `File` to echo log messages to.
+///
+/// The default behavior is to not echo to a file. Passing `None` to this function restores that
+/// behavior.
+///
+/// Does nothing if syslog was never initialized.
+///
+/// # Arguments
+/// * `file` - `Some(file)` to echo to `file`, `None` to disable echoing to the file previously passed to `echo_file`.
+pub fn echo_file(file: Option<File>) {
+    let mut state = lock!();
+    state.file = file;
+}
+
+/// Enables or disables echoing log messages to the `std::io::stderr()`.
+///
+/// The default behavior is **enabled**.
+///
+/// Does nothing if syslog was never initialized.
+///
+/// # Arguments
+/// * `enable` - `true` to enable echoing to stderr, `false` to disable echoing to stderr.
+pub fn echo_stderr(enable: bool) {
+    let mut state = lock!();
+    state.stderr = enable;
+}
+
+/// Retrieves the file descriptors owned by the global syslogger.
+///
+/// Does nothing if syslog was never initialized. If their are any file descriptors, they will be
+/// pushed into `fds`.
+///
+/// Note that the `stderr` file descriptor is never added, as it is not owned by syslog.
+pub fn push_fds(fds: &mut Vec<RawFd>) {
+    let state = lock!();
+    fds.extend(state.socket.iter().map(|s| s.as_raw_fd()));
+    fds.extend(state.file.iter().map(|f| f.as_raw_fd()));
+}
+
+/// Should only be called after `init()` was called.
+fn send_buf(socket: &UnixDatagram, buf: &[u8]) {
+    const SEND_RETRY: usize = 2;
+
+    for _ in 0..SEND_RETRY {
+        match socket.send(&buf[..]) {
+            Ok(_) => break,
+            Err(e) => match e.kind() {
+                ErrorKind::ConnectionRefused
+                | ErrorKind::ConnectionReset
+                | ErrorKind::ConnectionAborted
+                | ErrorKind::NotConnected => {
+                    let res = socket.connect(SYSLOG_PATH);
+                    if res.is_err() {
+                        break;
+                    }
+                }
+                _ => {}
+            },
+        }
+    }
+}
+
+fn get_localtime() -> tm {
+    unsafe {
+        // Safe because tm is just a struct of plain data.
+        let mut tm: tm = mem::zeroed();
+        let mut now: time_t = 0;
+        // Safe because we give time a valid pointer and can never fail.
+        time(&mut now as *mut _);
+        // Safe because we give localtime_r valid pointers and can never fail.
+        localtime_r(&now, &mut tm as *mut _);
+        tm
+    }
+}
+
+/// Records a log message with the given details.
+///
+/// Note that this will fail silently if syslog was not initialized.
+///
+/// # Arguments
+/// * `pri` - The `Priority` (i.e. severity) of the log message.
+/// * `fac` - The `Facility` of the log message. Usually `Facility::User` should be used.
+/// * `file_line` - Optional tuple of the name of the file that generated the
+///                 log and the line number within that file.
+/// * `args` - The log's message to record, in the form of `format_args!()`  return value
+///
+/// # Examples
+///
+/// ```
+/// # use sys_util::syslog;
+/// # fn main() {
+/// #   if let Err(e) = syslog::init() {
+/// #       println!("failed to initiailize syslog: {}", e);
+/// #       return;
+/// #   }
+/// syslog::log(syslog::Priority::Error,
+///             syslog::Facility::User,
+///             Some((file!(), line!())),
+///             format_args!("hello syslog"));
+/// # }
+/// ```
+pub fn log(pri: Priority, fac: Facility, file_line: Option<(&str, u32)>, args: fmt::Arguments) {
+    const MONTHS: [&str; 12] = [
+        "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+    ];
+
+    let mut state = lock!();
+    let mut buf = [0u8; 1024];
+    if let Some(socket) = &state.socket {
+        let tm = get_localtime();
+        let prifac = (pri as u8) | (fac as u8);
+        let res = {
+            let mut buf_cursor = Cursor::new(&mut buf[..]);
+            write!(
+                &mut buf_cursor,
+                "<{}>{} {:02} {:02}:{:02}:{:02} {}[{}]: ",
+                prifac,
+                MONTHS[tm.tm_mon as usize],
+                tm.tm_mday,
+                tm.tm_hour,
+                tm.tm_min,
+                tm.tm_sec,
+                state.proc_name.as_ref().map(|s| s.as_ref()).unwrap_or("-"),
+                getpid()
+            )
+            .and_then(|()| {
+                if let Some((file_name, line)) = &file_line {
+                    write!(&mut buf_cursor, " [{}:{}] ", file_name, line)
+                } else {
+                    Ok(())
+                }
+            })
+            .and_then(|()| write!(&mut buf_cursor, "{}", args))
+            .and_then(|()| Ok(buf_cursor.position() as usize))
+        };
+
+        if let Ok(len) = &res {
+            send_buf(&socket, &buf[..*len])
+        }
+    }
+
+    let res = {
+        let mut buf_cursor = Cursor::new(&mut buf[..]);
+        if let Some((file_name, line)) = &file_line {
+            write!(&mut buf_cursor, "[{}:{}:{}] ", pri, file_name, line)
+        } else {
+            Ok(())
+        }
+        .and_then(|()| writeln!(&mut buf_cursor, "{}", args))
+        .and_then(|()| Ok(buf_cursor.position() as usize))
+    };
+    if let Ok(len) = &res {
+        if let Some(file) = &mut state.file {
+            let _ = file.write_all(&buf[..*len]);
+        }
+        if state.stderr {
+            let _ = stderr().write_all(&buf[..*len]);
+        }
+    }
+}
+
+/// A macro for logging at an arbitrary priority level.
+///
+/// Note that this will fail silently if syslog was not initialized.
+#[macro_export]
+macro_rules! log {
+    ($pri:expr, $($args:tt)+) => ({
+        $crate::syslog::log($pri, $crate::syslog::Facility::User, Some((file!(), line!())), format_args!($($args)+))
+    })
+}
+
+/// A macro for logging an error.
+///
+/// Note that this will fail silently if syslog was not initialized.
+#[macro_export]
+macro_rules! error {
+    ($($args:tt)+) => ($crate::log!($crate::syslog::Priority::Error, $($args)*))
+}
+
+/// A macro for logging a warning.
+///
+/// Note that this will fail silently if syslog was not initialized.
+#[macro_export]
+macro_rules! warn {
+    ($($args:tt)+) => ($crate::log!($crate::syslog::Priority::Warning, $($args)*))
+}
+
+/// A macro for logging info.
+///
+/// Note that this will fail silently if syslog was not initialized.
+#[macro_export]
+macro_rules! info {
+    ($($args:tt)+) => ($crate::log!($crate::syslog::Priority::Info, $($args)*))
+}
+
+/// A macro for logging debug information.
+///
+/// Note that this will fail silently if syslog was not initialized.
+#[macro_export]
+macro_rules! debug {
+    ($($args:tt)+) => ($crate::log!($crate::syslog::Priority::Debug, $($args)*))
+}
+
+// Struct that implements io::Write to be used for writing directly to the syslog
+pub struct Syslogger {
+    buf: String,
+    priority: Priority,
+    facility: Facility,
+}
+
+impl Syslogger {
+    pub fn new(p: Priority, f: Facility) -> Syslogger {
+        Syslogger {
+            buf: String::new(),
+            priority: p,
+            facility: f,
+        }
+    }
+}
+
+impl io::Write for Syslogger {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let parsed_str = String::from_utf8_lossy(buf);
+        self.buf.push_str(&parsed_str);
+
+        if let Some(last_newline_idx) = self.buf.rfind('\n') {
+            for line in self.buf[..last_newline_idx].lines() {
+                log(self.priority, self.facility, None, format_args!("{}", line));
+            }
+
+            self.buf.drain(..=last_newline_idx);
+        }
+
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use libc::{shm_open, shm_unlink, O_CREAT, O_EXCL, O_RDWR};
+
+    use std::ffi::CStr;
+    use std::io::{Read, Seek, SeekFrom};
+    use std::os::unix::io::FromRawFd;
+
+    #[test]
+    fn init_syslog() {
+        init().unwrap();
+    }
+
+    #[test]
+    fn fds() {
+        init().unwrap();
+        let mut fds = Vec::new();
+        push_fds(&mut fds);
+        assert!(fds.len() >= 1);
+        for fd in fds {
+            assert!(fd >= 0);
+        }
+    }
+
+    #[test]
+    fn syslog_log() {
+        init().unwrap();
+        log(
+            Priority::Error,
+            Facility::User,
+            Some((file!(), line!())),
+            format_args!("hello syslog"),
+        );
+    }
+
+    #[test]
+    fn proc_name() {
+        init().unwrap();
+        log(
+            Priority::Error,
+            Facility::User,
+            Some((file!(), line!())),
+            format_args!("before proc name"),
+        );
+        set_proc_name("sys_util-test");
+        log(
+            Priority::Error,
+            Facility::User,
+            Some((file!(), line!())),
+            format_args!("after proc name"),
+        );
+    }
+
+    #[test]
+    fn syslog_file() {
+        init().unwrap();
+        let shm_name = CStr::from_bytes_with_nul(b"/crosvm_shm\0").unwrap();
+        let mut file = unsafe {
+            shm_unlink(shm_name.as_ptr());
+            let fd = shm_open(shm_name.as_ptr(), O_RDWR | O_CREAT | O_EXCL, 0666);
+            assert!(fd >= 0, "error creating shared memory;");
+            File::from_raw_fd(fd)
+        };
+
+        let syslog_file = file.try_clone().expect("error cloning shared memory file");
+        echo_file(Some(syslog_file));
+
+        const TEST_STR: &'static str = "hello shared memory file";
+        log(
+            Priority::Error,
+            Facility::User,
+            Some((file!(), line!())),
+            format_args!("{}", TEST_STR),
+        );
+
+        file.seek(SeekFrom::Start(0))
+            .expect("error seeking shared memory file");
+        let mut buf = String::new();
+        file.read_to_string(&mut buf)
+            .expect("error reading shared memory file");
+        assert!(buf.contains(TEST_STR));
+    }
+
+    #[test]
+    fn macros() {
+        init().unwrap();
+        error!("this is an error {}", 3);
+        warn!("this is a warning {}", "uh oh");
+        info!("this is info {}", true);
+        debug!("this is debug info {:?}", Some("helpful stuff"));
+    }
+
+    #[test]
+    fn syslogger_char() {
+        init().unwrap();
+        let mut syslogger = Syslogger::new(Priority::Info, Facility::Daemon);
+
+        let string = "Writing chars to syslog";
+        for c in string.chars() {
+            syslogger.write(&[c as u8]).expect("error writing char");
+        }
+
+        syslogger
+            .write(&['\n' as u8])
+            .expect("error writing newline char");
+    }
+
+    #[test]
+    fn syslogger_line() {
+        init().unwrap();
+        let mut syslogger = Syslogger::new(Priority::Info, Facility::Daemon);
+
+        let s = "Writing string to syslog\n";
+        syslogger
+            .write(&s.as_bytes())
+            .expect("error writing string");
+    }
+
+    #[test]
+    fn syslogger_partial() {
+        init().unwrap();
+        let mut syslogger = Syslogger::new(Priority::Info, Facility::Daemon);
+
+        let s = "Writing partial string";
+        // Should not log because there is no newline character
+        syslogger
+            .write(&s.as_bytes())
+            .expect("error writing string");
+    }
+}
diff --git a/sys_util/src/tempdir.rs b/sys_util/src/tempdir.rs
new file mode 100644
index 0000000..045f245
--- /dev/null
+++ b/sys_util/src/tempdir.rs
@@ -0,0 +1,102 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::ffi::CString;
+use std::ffi::OsStr;
+use std::ffi::OsString;
+use std::fs;
+use std::os::unix::ffi::OsStringExt;
+use std::path::Path;
+use std::path::PathBuf;
+
+use libc;
+
+use crate::{errno_result, Result};
+
+/// Create and remove a temporary directory.  The directory will be maintained for the lifetime of
+/// the `TempDir` object.
+pub struct TempDir {
+    path: Option<PathBuf>,
+}
+
+impl TempDir {
+    /// Creates a new tempory directory.
+    /// The directory will be removed when the object goes out of scope.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use std::path::Path;
+    /// # use std::path::PathBuf;
+    /// # use sys_util::TempDir;
+    /// # fn test_create_temp_dir() -> Result<(), ()> {
+    ///       let t = TempDir::new("/tmp/testdir").map_err(|_| ())?;
+    ///       assert!(t.as_path().unwrap().exists());
+    /// #     Ok(())
+    /// # }
+    /// ```
+    pub fn new<P: AsRef<OsStr>>(prefix: P) -> Result<TempDir> {
+        let mut dir_string = prefix.as_ref().to_os_string();
+        dir_string.push("XXXXXX");
+        // unwrap this result as the internal bytes can't have a null with a valid path.
+        let dir_name = CString::new(dir_string.into_vec()).unwrap();
+        let mut dir_bytes = dir_name.into_bytes_with_nul();
+        let ret = unsafe {
+            // Creating the directory isn't unsafe.  The fact that it modifies the guts of the path
+            // is also OK because it only overwrites the last 6 Xs added above.
+            libc::mkdtemp(dir_bytes.as_mut_ptr() as *mut libc::c_char)
+        };
+        if ret.is_null() {
+            return errno_result();
+        }
+        dir_bytes.pop(); // Remove the null becasue from_vec can't handle it.
+        Ok(TempDir {
+            path: Some(PathBuf::from(OsString::from_vec(dir_bytes))),
+        })
+    }
+
+    /// Removes the temporary directory.  Calling this is optional as dropping a `TempDir` object
+    /// will also remove the directory.  Calling remove explicitly allows for better error handling.
+    pub fn remove(mut self) -> Result<()> {
+        let path = self.path.take();
+        path.map_or(Ok(()), fs::remove_dir_all)?;
+        Ok(())
+    }
+
+    /// Returns the path to the tempdir if it is currently valid
+    pub fn as_path(&self) -> Option<&Path> {
+        self.path.as_ref().map(PathBuf::as_path)
+    }
+}
+
+impl Drop for TempDir {
+    fn drop(&mut self) {
+        if let Some(p) = &self.path {
+            // Nothing can be done here if this returns an error.
+            let _ = fs::remove_dir_all(p);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn create_dir() {
+        let t = TempDir::new("/tmp/asdf").unwrap();
+        let path = t.as_path().unwrap();
+        assert!(path.exists());
+        assert!(path.is_dir());
+        assert!(path.starts_with("/tmp/"));
+    }
+
+    #[test]
+    fn remove_dir() {
+        let t = TempDir::new("/tmp/asdf").unwrap();
+        let path = t.as_path().unwrap().to_owned();
+        assert!(t.remove().is_ok());
+        assert!(!path.exists());
+    }
+}
diff --git a/sys_util/src/terminal.rs b/sys_util/src/terminal.rs
new file mode 100644
index 0000000..fc90e45
--- /dev/null
+++ b/sys_util/src/terminal.rs
@@ -0,0 +1,114 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::io::StdinLock;
+use std::mem::zeroed;
+use std::os::unix::io::RawFd;
+
+use libc::{
+    c_int, fcntl, isatty, read, tcgetattr, tcsetattr, termios, ECHO, F_GETFL, F_SETFL, ICANON,
+    ISIG, O_NONBLOCK, STDIN_FILENO, TCSANOW,
+};
+
+use crate::{errno_result, Result};
+
+fn modify_mode<F: FnOnce(&mut termios)>(fd: RawFd, f: F) -> Result<()> {
+    // Safe because we check the return value of isatty.
+    if unsafe { isatty(fd) } != 1 {
+        return Ok(());
+    }
+
+    // The following pair are safe because termios gets totally overwritten by tcgetattr and we
+    // check the return result.
+    let mut termios: termios = unsafe { zeroed() };
+    let ret = unsafe { tcgetattr(fd, &mut termios as *mut _) };
+    if ret < 0 {
+        return errno_result();
+    }
+    let mut new_termios = termios;
+    f(&mut new_termios);
+    // Safe because the syscall will only read the extent of termios and we check the return result.
+    let ret = unsafe { tcsetattr(fd, TCSANOW, &new_termios as *const _) };
+    if ret < 0 {
+        return errno_result();
+    }
+
+    Ok(())
+}
+
+fn get_flags(fd: RawFd) -> Result<c_int> {
+    // Safe because no third parameter is expected and we check the return result.
+    let ret = unsafe { fcntl(fd, F_GETFL) };
+    if ret < 0 {
+        return errno_result();
+    }
+    Ok(ret)
+}
+
+fn set_flags(fd: RawFd, flags: c_int) -> Result<()> {
+    // Safe because we supply the third parameter and we check the return result.
+    let ret = unsafe { fcntl(fd, F_SETFL, flags) };
+    if ret < 0 {
+        return errno_result();
+    }
+    Ok(())
+}
+
+/// Trait for file descriptors that are TTYs, according to `isatty(3)`.
+///
+/// This is marked unsafe because the implementation must promise that the returned RawFd is a valid
+/// fd and that the lifetime of the returned fd is at least that of the trait object.
+pub unsafe trait Terminal {
+    /// Gets the file descriptor of the TTY.
+    fn tty_fd(&self) -> RawFd;
+
+    /// Set this terminal's mode to canonical mode (`ICANON | ECHO | ISIG`).
+    fn set_canon_mode(&self) -> Result<()> {
+        modify_mode(self.tty_fd(), |t| t.c_lflag |= ICANON | ECHO | ISIG)
+    }
+
+    /// Set this terminal's mode to raw mode (`!(ICANON | ECHO | ISIG)`).
+    fn set_raw_mode(&self) -> Result<()> {
+        modify_mode(self.tty_fd(), |t| t.c_lflag &= !(ICANON | ECHO | ISIG))
+    }
+
+    /// Sets the non-blocking mode of this terminal's file descriptor.
+    ///
+    /// If `non_block` is `true`, then `read_raw` will not block. If `non_block` is `false`, then
+    /// `read_raw` may block if there is nothing to read.
+    fn set_non_block(&self, non_block: bool) -> Result<()> {
+        let old_flags = get_flags(self.tty_fd())?;
+        let new_flags = if non_block {
+            old_flags | O_NONBLOCK
+        } else {
+            old_flags & !O_NONBLOCK
+        };
+        if new_flags != old_flags {
+            set_flags(self.tty_fd(), new_flags)?
+        }
+        Ok(())
+    }
+
+    /// Reads up to `out.len()` bytes from this terminal without any buffering.
+    ///
+    /// This may block, depending on if non-blocking was enabled with `set_non_block` or if there
+    /// are any bytes to read. If there is at least one byte that is readable, this will not block.
+    fn read_raw(&self, out: &mut [u8]) -> Result<usize> {
+        // Safe because read will only modify the pointer up to the length we give it and we check
+        // the return result.
+        let ret = unsafe { read(self.tty_fd(), out.as_mut_ptr() as *mut _, out.len()) };
+        if ret < 0 {
+            return errno_result();
+        }
+
+        Ok(ret as usize)
+    }
+}
+
+// Safe because we return a genuine terminal fd that never changes and shares our lifetime.
+unsafe impl<'a> Terminal for StdinLock<'a> {
+    fn tty_fd(&self) -> RawFd {
+        STDIN_FILENO
+    }
+}
diff --git a/sys_util/src/timerfd.rs b/sys_util/src/timerfd.rs
new file mode 100644
index 0000000..8e5d91b
--- /dev/null
+++ b/sys_util/src/timerfd.rs
@@ -0,0 +1,292 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fs::File;
+use std::mem;
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use std::ptr;
+use std::sync::Arc;
+use std::time::Duration;
+use sync::Mutex;
+
+use libc::{self, timerfd_create, timerfd_gettime, timerfd_settime, CLOCK_MONOTONIC, TFD_CLOEXEC};
+
+use crate::{errno_result, EventFd, FakeClock, Result};
+
+/// A safe wrapper around a Linux timerfd (man 2 timerfd_create).
+pub struct TimerFd(File);
+
+impl TimerFd {
+    /// Creates a new timerfd.  The timer is initally disarmed and must be armed by calling
+    /// `reset`.
+    pub fn new() -> Result<TimerFd> {
+        // Safe because this doesn't modify any memory and we check the return value.
+        let ret = unsafe { timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC) };
+        if ret < 0 {
+            return errno_result();
+        }
+
+        // Safe because we uniquely own the file descriptor.
+        Ok(TimerFd(unsafe { File::from_raw_fd(ret) }))
+    }
+
+    /// Sets the timer to expire after `dur`.  If `interval` is not `None` it represents
+    /// the period for repeated expirations after the initial expiration.  Otherwise
+    /// the timer will expire just once.  Cancels any existing duration and repeating interval.
+    pub fn reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()> {
+        // Safe because we are zero-initializing a struct with only primitive member fields.
+        let mut spec: libc::itimerspec = unsafe { mem::zeroed() };
+        spec.it_value.tv_sec = dur.as_secs() as libc::time_t;
+        // nsec always fits in i32 because subsec_nanos is defined to be less than one billion.
+        let nsec = dur.subsec_nanos() as i32;
+        spec.it_value.tv_nsec = libc::c_long::from(nsec);
+
+        if let Some(int) = interval {
+            spec.it_interval.tv_sec = int.as_secs() as libc::time_t;
+            // nsec always fits in i32 because subsec_nanos is defined to be less than one billion.
+            let nsec = int.subsec_nanos() as i32;
+            spec.it_interval.tv_nsec = libc::c_long::from(nsec);
+        }
+
+        // Safe because this doesn't modify any memory and we check the return value.
+        let ret = unsafe { timerfd_settime(self.as_raw_fd(), 0, &spec, ptr::null_mut()) };
+        if ret < 0 {
+            return errno_result();
+        }
+
+        Ok(())
+    }
+
+    /// Waits until the timer expires.  The return value represents the number of times the timer
+    /// has expired since the last time `wait` was called.  If the timer has not yet expired once
+    /// this call will block until it does.
+    pub fn wait(&mut self) -> Result<u64> {
+        let mut count = 0u64;
+
+        // Safe because this will only modify |buf| and we check the return value.
+        let ret = unsafe {
+            libc::read(
+                self.as_raw_fd(),
+                &mut count as *mut _ as *mut libc::c_void,
+                mem::size_of_val(&count),
+            )
+        };
+        if ret < 0 {
+            return errno_result();
+        }
+
+        // The bytes in the buffer are guaranteed to be in native byte-order so we don't need to
+        // use from_le or from_be.
+        Ok(count)
+    }
+
+    /// Returns `true` if the timer is currently armed.
+    pub fn is_armed(&self) -> Result<bool> {
+        // Safe because we are zero-initializing a struct with only primitive member fields.
+        let mut spec: libc::itimerspec = unsafe { mem::zeroed() };
+
+        // Safe because timerfd_gettime is trusted to only modify `spec`.
+        let ret = unsafe { timerfd_gettime(self.as_raw_fd(), &mut spec) };
+        if ret < 0 {
+            return errno_result();
+        }
+
+        Ok(spec.it_value.tv_sec != 0 || spec.it_value.tv_nsec != 0)
+    }
+
+    /// Disarms the timer.
+    pub fn clear(&mut self) -> Result<()> {
+        // Safe because we are zero-initializing a struct with only primitive member fields.
+        let spec: libc::itimerspec = unsafe { mem::zeroed() };
+
+        // Safe because this doesn't modify any memory and we check the return value.
+        let ret = unsafe { timerfd_settime(self.as_raw_fd(), 0, &spec, ptr::null_mut()) };
+        if ret < 0 {
+            return errno_result();
+        }
+
+        Ok(())
+    }
+}
+
+impl AsRawFd for TimerFd {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl FromRawFd for TimerFd {
+    unsafe fn from_raw_fd(fd: RawFd) -> Self {
+        TimerFd(File::from_raw_fd(fd))
+    }
+}
+
+impl IntoRawFd for TimerFd {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
+/// FakeTimerFd: For use in tests.
+pub struct FakeTimerFd {
+    clock: Arc<Mutex<FakeClock>>,
+    deadline_ns: Option<u64>,
+    interval: Option<Duration>,
+    fd: EventFd,
+}
+
+impl FakeTimerFd {
+    /// Creates a new fake timerfd.  The timer is initally disarmed and must be armed by calling
+    /// `reset`.
+    pub fn new(clock: Arc<Mutex<FakeClock>>) -> Self {
+        FakeTimerFd {
+            clock,
+            deadline_ns: None,
+            interval: None,
+            fd: EventFd::new().unwrap(),
+        }
+    }
+
+    fn duration_to_nanos(d: Duration) -> u64 {
+        d.as_secs() * 1_000_000_000 + u64::from(d.subsec_nanos())
+    }
+
+    /// Sets the timer to expire after `dur`.  If `interval` is not `None` it represents
+    /// the period for repeated expirations after the initial expiration.  Otherwise
+    /// the timer will expire just once.  Cancels any existing duration and repeating interval.
+    pub fn reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()> {
+        let mut guard = self.clock.lock();
+        let deadline = guard.nanos() + FakeTimerFd::duration_to_nanos(dur);
+        self.deadline_ns = Some(deadline);
+        self.interval = interval;
+        guard.add_event_fd(deadline, self.fd.try_clone()?);
+        Ok(())
+    }
+
+    /// Waits until the timer expires.  The return value represents the number of times the timer
+    /// has expired since the last time `wait` was called.  If the timer has not yet expired once
+    /// this call will block until it does.
+    pub fn wait(&mut self) -> Result<u64> {
+        loop {
+            self.fd.read()?;
+            if let Some(deadline_ns) = &mut self.deadline_ns {
+                let mut guard = self.clock.lock();
+                let now = guard.nanos();
+                if now >= *deadline_ns {
+                    let mut expirys = 0;
+                    if let Some(interval) = self.interval {
+                        let interval_ns = FakeTimerFd::duration_to_nanos(interval);
+                        if interval_ns > 0 {
+                            expirys += (now - *deadline_ns) / interval_ns;
+                            *deadline_ns += (expirys + 1) * interval_ns;
+                            guard.add_event_fd(*deadline_ns, self.fd.try_clone()?);
+                        }
+                    }
+                    return Ok(expirys + 1);
+                }
+            }
+        }
+    }
+
+    /// Returns `true` if the timer is currently armed.
+    pub fn is_armed(&self) -> Result<bool> {
+        Ok(self.deadline_ns.is_some())
+    }
+
+    /// Disarms the timer.
+    pub fn clear(&mut self) -> Result<()> {
+        self.deadline_ns = None;
+        self.interval = None;
+        Ok(())
+    }
+}
+
+impl AsRawFd for FakeTimerFd {
+    fn as_raw_fd(&self) -> RawFd {
+        self.fd.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for FakeTimerFd {
+    fn into_raw_fd(self) -> RawFd {
+        self.fd.into_raw_fd()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::thread::sleep;
+    use std::time::{Duration, Instant};
+
+    #[test]
+    fn one_shot() {
+        let mut tfd = TimerFd::new().expect("failed to create timerfd");
+        assert_eq!(tfd.is_armed().unwrap(), false);
+
+        let dur = Duration::from_millis(200);
+        let now = Instant::now();
+        tfd.reset(dur.clone(), None).expect("failed to arm timer");
+
+        assert_eq!(tfd.is_armed().unwrap(), true);
+
+        let count = tfd.wait().expect("unable to wait for timer");
+
+        assert_eq!(count, 1);
+        assert!(now.elapsed() >= dur);
+    }
+
+    #[test]
+    fn repeating() {
+        let mut tfd = TimerFd::new().expect("failed to create timerfd");
+
+        let dur = Duration::from_millis(200);
+        let interval = Duration::from_millis(100);
+        tfd.reset(dur.clone(), Some(interval))
+            .expect("failed to arm timer");
+
+        sleep(dur * 3);
+
+        let count = tfd.wait().expect("unable to wait for timer");
+        assert!(count >= 5, "count = {}", count);
+    }
+
+    #[test]
+    fn fake_one_shot() {
+        let clock = Arc::new(Mutex::new(FakeClock::new()));
+        let mut tfd = FakeTimerFd::new(clock.clone());
+        assert_eq!(tfd.is_armed().unwrap(), false);
+
+        let dur = Duration::from_nanos(200);
+        tfd.reset(dur.clone(), None).expect("failed to arm timer");
+
+        assert_eq!(tfd.is_armed().unwrap(), true);
+        clock.lock().add_ns(200);
+
+        let count = tfd.wait().expect("unable to wait for timer");
+
+        assert_eq!(count, 1);
+    }
+
+    #[test]
+    fn fake_repeating() {
+        let clock = Arc::new(Mutex::new(FakeClock::new()));
+        let mut tfd = FakeTimerFd::new(clock.clone());
+
+        let dur = Duration::from_nanos(200);
+        let interval = Duration::from_nanos(100);
+        tfd.reset(dur.clone(), Some(interval))
+            .expect("failed to arm timer");
+
+        clock.lock().add_ns(300);
+
+        let mut count = tfd.wait().expect("unable to wait for timer");
+        // An expiration from the initial expiry and from 1 repeat.
+        assert_eq!(count, 2);
+
+        clock.lock().add_ns(300);
+        count = tfd.wait().expect("unable to wait for timer");
+        assert_eq!(count, 3);
+    }
+}
diff --git a/sys_util/src/write_zeroes.rs b/sys_util/src/write_zeroes.rs
new file mode 100644
index 0000000..51f0dbe
--- /dev/null
+++ b/sys_util/src/write_zeroes.rs
@@ -0,0 +1,169 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::cmp::min;
+use std::fs::File;
+use std::io::{self, Seek, SeekFrom, Write};
+
+use crate::fallocate;
+use crate::FallocateMode;
+
+/// A trait for deallocating space in a file.
+pub trait PunchHole {
+    /// Replace a range of bytes with a hole.
+    fn punch_hole(&mut self, offset: u64, length: u64) -> io::Result<()>;
+}
+
+impl PunchHole for File {
+    fn punch_hole(&mut self, offset: u64, length: u64) -> io::Result<()> {
+        fallocate(self, FallocateMode::PunchHole, true, offset, length as u64)
+            .map_err(|e| io::Error::from_raw_os_error(e.errno()))
+    }
+}
+
+/// A trait for writing zeroes to a stream.
+pub trait WriteZeroes {
+    /// Write `length` bytes of zeroes to the stream, returning how many bytes were written.
+    fn write_zeroes(&mut self, length: usize) -> io::Result<usize>;
+}
+
+impl<T: PunchHole + Seek + Write> WriteZeroes for T {
+    fn write_zeroes(&mut self, length: usize) -> io::Result<usize> {
+        // Try to punch a hole first.
+        let offset = self.seek(SeekFrom::Current(0))?;
+        if let Ok(()) = self.punch_hole(offset, length as u64) {
+            // Advance the seek cursor as if we had done a real write().
+            self.seek(SeekFrom::Current(length as i64))?;
+            return Ok(length);
+        }
+
+        // fall back to write()
+
+        // punch_hole() failed; fall back to writing a buffer of zeroes
+        // until we have written up to length.
+        let buf_size = min(length, 0x10000);
+        let buf = vec![0u8; buf_size];
+        let mut nwritten: usize = 0;
+        while nwritten < length {
+            let remaining = length - nwritten;
+            let write_size = min(remaining, buf_size);
+            nwritten += self.write(&buf[0..write_size])?;
+        }
+        Ok(length)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::fs::OpenOptions;
+    use std::io::{Read, Seek, SeekFrom};
+    use std::path::PathBuf;
+
+    use crate::TempDir;
+
+    #[test]
+    fn simple_test() {
+        let tempdir = TempDir::new("/tmp/write_zeroes_test").unwrap();
+        let mut path = PathBuf::from(tempdir.as_path().unwrap());
+        path.push("file");
+        let mut f = OpenOptions::new()
+            .read(true)
+            .write(true)
+            .create(true)
+            .open(&path)
+            .unwrap();
+        f.set_len(16384).unwrap();
+
+        // Write buffer of non-zero bytes to offset 1234
+        let orig_data = [0x55u8; 5678];
+        f.seek(SeekFrom::Start(1234)).unwrap();
+        f.write(&orig_data).unwrap();
+
+        // Read back the data plus some overlap on each side
+        let mut readback = [0u8; 16384];
+        f.seek(SeekFrom::Start(0)).unwrap();
+        f.read(&mut readback).unwrap();
+        // Bytes before the write should still be 0
+        for read in &readback[0..1234] {
+            assert_eq!(*read, 0);
+        }
+        // Bytes that were just written should be 0x55
+        for read in &readback[1234..(1234 + 5678)] {
+            assert_eq!(*read, 0x55);
+        }
+        // Bytes after the written area should still be 0
+        for read in &readback[(1234 + 5678)..] {
+            assert_eq!(*read, 0);
+        }
+
+        // Overwrite some of the data with zeroes
+        f.seek(SeekFrom::Start(2345)).unwrap();
+        f.write_zeroes(4321).expect("write_zeroes failed");
+        // Verify seek position after write_zeroes()
+        assert_eq!(f.seek(SeekFrom::Current(0)).unwrap(), 2345 + 4321);
+
+        // Read back the data and verify that it is now zero
+        f.seek(SeekFrom::Start(0)).unwrap();
+        f.read(&mut readback).unwrap();
+        // Bytes before the write should still be 0
+        for read in &readback[0..1234] {
+            assert_eq!(*read, 0);
+        }
+        // Original data should still exist before the write_zeroes region
+        for read in &readback[1234..2345] {
+            assert_eq!(*read, 0x55);
+        }
+        // The write_zeroes region should now be zero
+        for read in &readback[2345..(2345 + 4321)] {
+            assert_eq!(*read, 0);
+        }
+        // Original data should still exist after the write_zeroes region
+        for read in &readback[(2345 + 4321)..(1234 + 5678)] {
+            assert_eq!(*read, 0x55);
+        }
+        // The rest of the file should still be 0
+        for read in &readback[(1234 + 5678)..] {
+            assert_eq!(*read, 0);
+        }
+    }
+
+    #[test]
+    fn large_write_zeroes() {
+        let tempdir = TempDir::new("/tmp/write_zeroes_test").unwrap();
+        let mut path = PathBuf::from(tempdir.as_path().unwrap());
+        path.push("file");
+        let mut f = OpenOptions::new()
+            .read(true)
+            .write(true)
+            .create(true)
+            .open(&path)
+            .unwrap();
+        f.set_len(16384).unwrap();
+
+        // Write buffer of non-zero bytes
+        let orig_data = [0x55u8; 0x20000];
+        f.seek(SeekFrom::Start(0)).unwrap();
+        f.write(&orig_data).unwrap();
+
+        // Overwrite some of the data with zeroes
+        f.seek(SeekFrom::Start(0)).unwrap();
+        f.write_zeroes(0x10001).expect("write_zeroes failed");
+        // Verify seek position after write_zeroes()
+        assert_eq!(f.seek(SeekFrom::Current(0)).unwrap(), 0x10001);
+
+        // Read back the data and verify that it is now zero
+        let mut readback = [0u8; 0x20000];
+        f.seek(SeekFrom::Start(0)).unwrap();
+        f.read(&mut readback).unwrap();
+        // The write_zeroes region should now be zero
+        for read in &readback[0..0x10001] {
+            assert_eq!(*read, 0);
+        }
+        // Original data should still exist after the write_zeroes region
+        for read in &readback[0x10001..0x20000] {
+            assert_eq!(*read, 0x55);
+        }
+    }
+}
diff --git a/syscall_defines/Cargo.toml b/syscall_defines/Cargo.toml
new file mode 100644
index 0000000..d99cd2c
--- /dev/null
+++ b/syscall_defines/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "syscall_defines"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+include = ["src/**/*", "Cargo.toml"]
+
+[dependencies]
+
+[workspace]
diff --git a/syscall_defines/src/lib.rs b/syscall_defines/src/lib.rs
new file mode 100644
index 0000000..cf016ab
--- /dev/null
+++ b/syscall_defines/src/lib.rs
@@ -0,0 +1,19 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#[cfg(target_arch = "x86_64")]
+#[path = "linux-x86_64/mod.rs"]
+pub mod linux;
+
+#[cfg(target_arch = "x86")]
+#[path = "linux-x86/mod.rs"]
+pub mod linux;
+
+#[cfg(target_arch = "aarch64")]
+#[path = "linux-aarch64/mod.rs"]
+pub mod linux;
+
+#[cfg(target_arch = "arm")]
+#[path = "linux-arm/mod.rs"]
+pub mod linux;
diff --git a/syscall_defines/src/linux-aarch64/mod.rs b/syscall_defines/src/linux-aarch64/mod.rs
new file mode 100644
index 0000000..8136d00
--- /dev/null
+++ b/syscall_defines/src/linux-aarch64/mod.rs
@@ -0,0 +1,330 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generated with: cat include/uapi/asm-generic/unistd.h |
+//    awk ' { print "SYS_" $2 " = " $2"," } '
+#[allow(dead_code)]
+#[allow(non_camel_case_types)]
+pub enum LinuxSyscall {
+    SYS_io_setup = 0,
+    SYS_io_destroy = 1,
+    SYS_io_submit = 2,
+    SYS_io_cancel = 3,
+    SYS_io_getevents = 4,
+    SYS_setxattr = 5,
+    SYS_lsetxattr = 6,
+    SYS_fsetxattr = 7,
+    SYS_getxattr = 8,
+    SYS_lgetxattr = 9,
+    SYS_fgetxattr = 10,
+    SYS_listxattr = 11,
+    SYS_llistxattr = 12,
+    SYS_flistxattr = 13,
+    SYS_removexattr = 14,
+    SYS_lremovexattr = 15,
+    SYS_fremovexattr = 16,
+    SYS_getcwd = 17,
+    SYS_lookup_dcookie = 18,
+    SYS_eventfd2 = 19,
+    SYS_epoll_create1 = 20,
+    SYS_epoll_ctl = 21,
+    SYS_epoll_pwait = 22,
+    SYS_dup = 23,
+    SYS_dup3 = 24,
+    SYS_inotify_init1 = 26,
+    SYS_inotify_add_watch = 27,
+    SYS_inotify_rm_watch = 28,
+    SYS_ioctl = 29,
+    SYS_ioprio_set = 30,
+    SYS_ioprio_get = 31,
+    SYS_flock = 32,
+    SYS_mknodat = 33,
+    SYS_mkdirat = 34,
+    SYS_unlinkat = 35,
+    SYS_symlinkat = 36,
+    SYS_linkat = 37,
+    SYS_renameat = 38,
+    SYS_umount2 = 39,
+    SYS_mount = 40,
+    SYS_pivot_root = 41,
+    SYS_nfsservctl = 42,
+    SYS_fallocate = 47,
+    SYS_faccessat = 48,
+    SYS_chdir = 49,
+    SYS_fchdir = 50,
+    SYS_chroot = 51,
+    SYS_fchmod = 52,
+    SYS_fchmodat = 53,
+    SYS_fchownat = 54,
+    SYS_fchown = 55,
+    SYS_openat = 56,
+    SYS_close = 57,
+    SYS_vhangup = 58,
+    SYS_pipe2 = 59,
+    SYS_quotactl = 60,
+    SYS_getdents64 = 61,
+    SYS_read = 63,
+    SYS_write = 64,
+    SYS_readv = 65,
+    SYS_writev = 66,
+    SYS_pread64 = 67,
+    SYS_pwrite64 = 68,
+    SYS_preadv = 69,
+    SYS_pwritev = 70,
+    SYS_pselect6 = 72,
+    SYS_ppoll = 73,
+    SYS_signalfd4 = 74,
+    SYS_vmsplice = 75,
+    SYS_splice = 76,
+    SYS_tee = 77,
+    SYS_readlinkat = 78,
+    SYS_sync = 81,
+    SYS_fsync = 82,
+    SYS_fdatasync = 83,
+    SYS_sync_file_range = 84,
+    SYS_timerfd_create = 85,
+    SYS_timerfd_settime = 86,
+    SYS_timerfd_gettime = 87,
+    SYS_utimensat = 88,
+    SYS_acct = 89,
+    SYS_capget = 90,
+    SYS_capset = 91,
+    SYS_personality = 92,
+    SYS_exit = 93,
+    SYS_exit_group = 94,
+    SYS_waitid = 95,
+    SYS_set_tid_address = 96,
+    SYS_unshare = 97,
+    SYS_futex = 98,
+    SYS_set_robust_list = 99,
+    SYS_get_robust_list = 100,
+    SYS_nanosleep = 101,
+    SYS_getitimer = 102,
+    SYS_setitimer = 103,
+    SYS_kexec_load = 104,
+    SYS_init_module = 105,
+    SYS_delete_module = 106,
+    SYS_timer_create = 107,
+    SYS_timer_gettime = 108,
+    SYS_timer_getoverrun = 109,
+    SYS_timer_settime = 110,
+    SYS_timer_delete = 111,
+    SYS_clock_settime = 112,
+    SYS_clock_gettime = 113,
+    SYS_clock_getres = 114,
+    SYS_clock_nanosleep = 115,
+    SYS_syslog = 116,
+    SYS_ptrace = 117,
+    SYS_sched_setparam = 118,
+    SYS_sched_setscheduler = 119,
+    SYS_sched_getscheduler = 120,
+    SYS_sched_getparam = 121,
+    SYS_sched_setaffinity = 122,
+    SYS_sched_getaffinity = 123,
+    SYS_sched_yield = 124,
+    SYS_sched_get_priority_max = 125,
+    SYS_sched_get_priority_min = 126,
+    SYS_sched_rr_get_interval = 127,
+    SYS_restart_syscall = 128,
+    SYS_kill = 129,
+    SYS_tkill = 130,
+    SYS_tgkill = 131,
+    SYS_sigaltstack = 132,
+    SYS_rt_sigsuspend = 133,
+    SYS_rt_sigaction = 134,
+    SYS_rt_sigprocmask = 135,
+    SYS_rt_sigpending = 136,
+    SYS_rt_sigtimedwait = 137,
+    SYS_rt_sigqueueinfo = 138,
+    SYS_rt_sigreturn = 139,
+    SYS_setpriority = 140,
+    SYS_getpriority = 141,
+    SYS_reboot = 142,
+    SYS_setregid = 143,
+    SYS_setgid = 144,
+    SYS_setreuid = 145,
+    SYS_setuid = 146,
+    SYS_setresuid = 147,
+    SYS_getresuid = 148,
+    SYS_setresgid = 149,
+    SYS_getresgid = 150,
+    SYS_setfsuid = 151,
+    SYS_setfsgid = 152,
+    SYS_times = 153,
+    SYS_setpgid = 154,
+    SYS_getpgid = 155,
+    SYS_getsid = 156,
+    SYS_setsid = 157,
+    SYS_getgroups = 158,
+    SYS_setgroups = 159,
+    SYS_uname = 160,
+    SYS_sethostname = 161,
+    SYS_setdomainname = 162,
+    SYS_getrlimit = 163,
+    SYS_setrlimit = 164,
+    SYS_getrusage = 165,
+    SYS_umask = 166,
+    SYS_prctl = 167,
+    SYS_getcpu = 168,
+    SYS_gettimeofday = 169,
+    SYS_settimeofday = 170,
+    SYS_adjtimex = 171,
+    SYS_getpid = 172,
+    SYS_getppid = 173,
+    SYS_getuid = 174,
+    SYS_geteuid = 175,
+    SYS_getgid = 176,
+    SYS_getegid = 177,
+    SYS_gettid = 178,
+    SYS_sysinfo = 179,
+    SYS_mq_open = 180,
+    SYS_mq_unlink = 181,
+    SYS_mq_timedsend = 182,
+    SYS_mq_timedreceive = 183,
+    SYS_mq_notify = 184,
+    SYS_mq_getsetattr = 185,
+    SYS_msgget = 186,
+    SYS_msgctl = 187,
+    SYS_msgrcv = 188,
+    SYS_msgsnd = 189,
+    SYS_semget = 190,
+    SYS_semctl = 191,
+    SYS_semtimedop = 192,
+    SYS_semop = 193,
+    SYS_shmget = 194,
+    SYS_shmctl = 195,
+    SYS_shmat = 196,
+    SYS_shmdt = 197,
+    SYS_socket = 198,
+    SYS_socketpair = 199,
+    SYS_bind = 200,
+    SYS_listen = 201,
+    SYS_accept = 202,
+    SYS_connect = 203,
+    SYS_getsockname = 204,
+    SYS_getpeername = 205,
+    SYS_sendto = 206,
+    SYS_recvfrom = 207,
+    SYS_setsockopt = 208,
+    SYS_getsockopt = 209,
+    SYS_shutdown = 210,
+    SYS_sendmsg = 211,
+    SYS_recvmsg = 212,
+    SYS_readahead = 213,
+    SYS_brk = 214,
+    SYS_munmap = 215,
+    SYS_mremap = 216,
+    SYS_add_key = 217,
+    SYS_request_key = 218,
+    SYS_keyctl = 219,
+    SYS_clone = 220,
+    SYS_execve = 221,
+    SYS_swapon = 224,
+    SYS_swapoff = 225,
+    SYS_mprotect = 226,
+    SYS_msync = 227,
+    SYS_mlock = 228,
+    SYS_munlock = 229,
+    SYS_mlockall = 230,
+    SYS_munlockall = 231,
+    SYS_mincore = 232,
+    SYS_madvise = 233,
+    SYS_remap_file_pages = 234,
+    SYS_mbind = 235,
+    SYS_get_mempolicy = 236,
+    SYS_set_mempolicy = 237,
+    SYS_migrate_pages = 238,
+    SYS_move_pages = 239,
+    SYS_rt_tgsigqueueinfo = 240,
+    SYS_perf_event_open = 241,
+    SYS_accept4 = 242,
+    SYS_recvmmsg = 243,
+    SYS_arch_specific_syscall = 244,
+    SYS_wait4 = 260,
+    SYS_prlimit64 = 261,
+    SYS_fanotify_init = 262,
+    SYS_fanotify_mark = 263,
+    SYS_name_to_handle_at = 264,
+    SYS_open_by_handle_at = 265,
+    SYS_clock_adjtime = 266,
+    SYS_syncfs = 267,
+    SYS_setns = 268,
+    SYS_sendmmsg = 269,
+    SYS_process_vm_readv = 270,
+    SYS_process_vm_writev = 271,
+    SYS_kcmp = 272,
+    SYS_finit_module = 273,
+    SYS_sched_setattr = 274,
+    SYS_sched_getattr = 275,
+    SYS_renameat2 = 276,
+    SYS_seccomp = 277,
+    SYS_getrandom = 278,
+    SYS_memfd_create = 279,
+    SYS_bpf = 280,
+    SYS_execveat = 281,
+    SYS_userfaultfd = 282,
+    SYS_membarrier = 283,
+    SYS_mlock2 = 284,
+    SYS_copy_file_range = 285,
+    SYS_preadv2 = 286,
+    SYS_pwritev2 = 287,
+    SYS_pkey_mprotect = 288,
+    SYS_pkey_alloc = 289,
+    SYS_pkey_free = 290,
+    SYS_syscalls = 291,
+    SYS_open = 1024,
+    SYS_link = 1025,
+    SYS_unlink = 1026,
+    SYS_mknod = 1027,
+    SYS_chmod = 1028,
+    SYS_chown = 1029,
+    SYS_mkdir = 1030,
+    SYS_rmdir = 1031,
+    SYS_lchown = 1032,
+    SYS_access = 1033,
+    SYS_rename = 1034,
+    SYS_readlink = 1035,
+    SYS_symlink = 1036,
+    SYS_utimes = 1037,
+    SYS_pipe = 1040,
+    SYS_dup2 = 1041,
+    SYS_epoll_create = 1042,
+    SYS_inotify_init = 1043,
+    SYS_eventfd = 1044,
+    SYS_signalfd = 1045,
+    SYS_sendfile = 1046,
+    SYS_ftruncate = 1047,
+    SYS_truncate = 1048,
+    SYS_stat = 1049,
+    SYS_lstat = 1050,
+    SYS_fstat = 1051,
+    SYS_fcntl = 1052,
+    SYS_fadvise64 = 1053,
+    SYS_newfstatat = 1054,
+    SYS_fstatfs = 1055,
+    SYS_statfs = 1056,
+    SYS_lseek = 1057,
+    SYS_mmap = 1058,
+    SYS_alarm = 1059,
+    SYS_getpgrp = 1060,
+    SYS_pause = 1061,
+    SYS_time = 1062,
+    SYS_utime = 1063,
+    SYS_creat = 1064,
+    SYS_getdents = 1065,
+    SYS_futimesat = 1066,
+    SYS_select = 1067,
+    SYS_poll = 1068,
+    SYS_epoll_wait = 1069,
+    SYS_ustat = 1070,
+    SYS_vfork = 1071,
+    SYS_oldwait4 = 1072,
+    SYS_recv = 1073,
+    SYS_send = 1074,
+    SYS_bdflush = 1075,
+    SYS_umount = 1076,
+    SYS_uselib = 1077,
+    SYS__sysctl = 1078,
+    SYS_fork = 1079,
+}
diff --git a/syscall_defines/src/linux-arm/mod.rs b/syscall_defines/src/linux-arm/mod.rs
new file mode 100644
index 0000000..fbaf4a2
--- /dev/null
+++ b/syscall_defines/src/linux-arm/mod.rs
@@ -0,0 +1,364 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Based on /usr/include/asm/unistd.h from the sysroot of an arm32 board.
+#[allow(dead_code)]
+#[allow(non_camel_case_types)]
+pub enum LinuxSyscall {
+    SYS_restart_syscall = 0,
+    SYS_exit = 1,
+    SYS_fork = 2,
+    SYS_read = 3,
+    SYS_write = 4,
+    SYS_open = 5,
+    SYS_close = 6,
+    SYS_creat = 8,
+    SYS_link = 9,
+    SYS_unlink = 10,
+    SYS_execve = 11,
+    SYS_chdir = 12,
+    SYS_time = 13,
+    SYS_mknod = 14,
+    SYS_chmod = 15,
+    SYS_lchown = 16,
+    SYS_lseek = 19,
+    SYS_getpid = 20,
+    SYS_mount = 21,
+    SYS_umount = 22,
+    SYS_setuid = 23,
+    SYS_getuid = 24,
+    SYS_stime = 25,
+    SYS_ptrace = 26,
+    SYS_alarm = 27,
+    SYS_pause = 29,
+    SYS_utime = 30,
+    SYS_access = 33,
+    SYS_nice = 34,
+    SYS_sync = 36,
+    SYS_kill = 37,
+    SYS_rename = 38,
+    SYS_mkdir = 39,
+    SYS_rmdir = 40,
+    SYS_dup = 41,
+    SYS_pipe = 42,
+    SYS_times = 43,
+    SYS_brk = 45,
+    SYS_setgid = 46,
+    SYS_getgid = 47,
+    SYS_geteuid = 49,
+    SYS_getegid = 50,
+    SYS_acct = 51,
+    SYS_umount2 = 52,
+    SYS_ioctl = 54,
+    SYS_fcntl = 55,
+    SYS_setpgid = 57,
+    SYS_umask = 60,
+    SYS_chroot = 61,
+    SYS_ustat = 62,
+    SYS_dup2 = 63,
+    SYS_getppid = 64,
+    SYS_getpgrp = 65,
+    SYS_setsid = 66,
+    SYS_sigaction = 67,
+    SYS_setreuid = 70,
+    SYS_setregid = 71,
+    SYS_sigsuspend = 72,
+    SYS_sigpending = 73,
+    SYS_sethostname = 74,
+    SYS_setrlimit = 75,
+    SYS_getrlimit = 76,
+    SYS_getrusage = 77,
+    SYS_gettimeofday = 78,
+    SYS_settimeofday = 79,
+    SYS_getgroups = 80,
+    SYS_setgroups = 81,
+    SYS_select = 82,
+    SYS_symlink = 83,
+    SYS_readlink = 85,
+    SYS_uselib = 86,
+    SYS_swapon = 87,
+    SYS_reboot = 88,
+    SYS_readdir = 89,
+    SYS_mmap = 90,
+    SYS_munmap = 91,
+    SYS_truncate = 92,
+    SYS_ftruncate = 93,
+    SYS_fchmod = 94,
+    SYS_fchown = 95,
+    SYS_getpriority = 96,
+    SYS_setpriority = 97,
+    SYS_statfs = 99,
+    SYS_fstatfs = 100,
+    SYS_socketcall = 102,
+    SYS_syslog = 103,
+    SYS_setitimer = 104,
+    SYS_getitimer = 105,
+    SYS_stat = 106,
+    SYS_lstat = 107,
+    SYS_fstat = 108,
+    SYS_vhangup = 111,
+    SYS_syscall = 113,
+    SYS_wait4 = 114,
+    SYS_swapoff = 115,
+    SYS_sysinfo = 116,
+    SYS_ipc = 117,
+    SYS_fsync = 118,
+    SYS_sigreturn = 119,
+    SYS_clone = 120,
+    SYS_setdomainname = 121,
+    SYS_uname = 122,
+    SYS_adjtimex = 124,
+    SYS_mprotect = 125,
+    SYS_sigprocmask = 126,
+    SYS_init_module = 128,
+    SYS_delete_module = 129,
+    SYS_quotactl = 131,
+    SYS_getpgid = 132,
+    SYS_fchdir = 133,
+    SYS_bdflush = 134,
+    SYS_sysfs = 135,
+    SYS_personality = 136,
+    SYS_setfsuid = 138,
+    SYS_setfsgid = 139,
+    SYS__llseek = 140,
+    SYS_getdents = 141,
+    SYS__newselect = 142,
+    SYS_flock = 143,
+    SYS_msync = 144,
+    SYS_readv = 145,
+    SYS_writev = 146,
+    SYS_getsid = 147,
+    SYS_fdatasync = 148,
+    SYS__sysctl = 149,
+    SYS_mlock = 150,
+    SYS_munlock = 151,
+    SYS_mlockall = 152,
+    SYS_munlockall = 153,
+    SYS_sched_setparam = 154,
+    SYS_sched_getparam = 155,
+    SYS_sched_setscheduler = 156,
+    SYS_sched_getscheduler = 157,
+    SYS_sched_yield = 158,
+    SYS_sched_get_priority_max = 159,
+    SYS_sched_get_priority_min = 160,
+    SYS_sched_rr_get_interval = 161,
+    SYS_nanosleep = 162,
+    SYS_mremap = 163,
+    SYS_setresuid = 164,
+    SYS_getresuid = 165,
+    SYS_poll = 168,
+    SYS_nfsservctl = 169,
+    SYS_setresgid = 170,
+    SYS_getresgid = 171,
+    SYS_prctl = 172,
+    SYS_rt_sigreturn = 173,
+    SYS_rt_sigaction = 174,
+    SYS_rt_sigprocmask = 175,
+    SYS_rt_sigpending = 176,
+    SYS_rt_sigtimedwait = 177,
+    SYS_rt_sigqueueinfo = 178,
+    SYS_rt_sigsuspend = 179,
+    SYS_pread64 = 180,
+    SYS_pwrite64 = 181,
+    SYS_chown = 182,
+    SYS_getcwd = 183,
+    SYS_capget = 184,
+    SYS_capset = 185,
+    SYS_sigaltstack = 186,
+    SYS_sendfile = 187,
+    SYS_vfork = 190,
+    SYS_ugetrlimit = 191,
+    SYS_mmap2 = 192,
+    SYS_truncate64 = 193,
+    SYS_ftruncate64 = 194,
+    SYS_stat64 = 195,
+    SYS_lstat64 = 196,
+    SYS_fstat64 = 197,
+    SYS_lchown32 = 198,
+    SYS_getuid32 = 199,
+    SYS_getgid32 = 200,
+    SYS_geteuid32 = 201,
+    SYS_getegid32 = 202,
+    SYS_setreuid32 = 203,
+    SYS_setregid32 = 204,
+    SYS_getgroups32 = 205,
+    SYS_setgroups32 = 206,
+    SYS_fchown32 = 207,
+    SYS_setresuid32 = 208,
+    SYS_getresuid32 = 209,
+    SYS_setresgid32 = 210,
+    SYS_getresgid32 = 211,
+    SYS_chown32 = 212,
+    SYS_setuid32 = 213,
+    SYS_setgid32 = 214,
+    SYS_setfsuid32 = 215,
+    SYS_setfsgid32 = 216,
+    SYS_getdents64 = 217,
+    SYS_pivot_root = 218,
+    SYS_mincore = 219,
+    SYS_madvise = 220,
+    SYS_fcntl64 = 221,
+    SYS_gettid = 224,
+    SYS_readahead = 225,
+    SYS_setxattr = 226,
+    SYS_lsetxattr = 227,
+    SYS_fsetxattr = 228,
+    SYS_getxattr = 229,
+    SYS_lgetxattr = 230,
+    SYS_fgetxattr = 231,
+    SYS_listxattr = 232,
+    SYS_llistxattr = 233,
+    SYS_flistxattr = 234,
+    SYS_removexattr = 235,
+    SYS_lremovexattr = 236,
+    SYS_fremovexattr = 237,
+    SYS_tkill = 238,
+    SYS_sendfile64 = 239,
+    SYS_futex = 240,
+    SYS_sched_setaffinity = 241,
+    SYS_sched_getaffinity = 242,
+    SYS_io_setup = 243,
+    SYS_io_destroy = 244,
+    SYS_io_getevents = 245,
+    SYS_io_submit = 246,
+    SYS_io_cancel = 247,
+    SYS_exit_group = 248,
+    SYS_lookup_dcookie = 249,
+    SYS_epoll_create = 250,
+    SYS_epoll_ctl = 251,
+    SYS_epoll_wait = 252,
+    SYS_remap_file_pages = 253,
+    SYS_set_tid_address = 256,
+    SYS_timer_create = 257,
+    SYS_timer_settime = 258,
+    SYS_timer_gettime = 259,
+    SYS_timer_getoverrun = 260,
+    SYS_timer_delete = 261,
+    SYS_clock_settime = 262,
+    SYS_clock_gettime = 263,
+    SYS_clock_getres = 264,
+    SYS_clock_nanosleep = 265,
+    SYS_statfs64 = 266,
+    SYS_fstatfs64 = 267,
+    SYS_tgkill = 268,
+    SYS_utimes = 269,
+    SYS_arm_fadvise64_64 = 270,
+    SYS_pciconfig_iobase = 271,
+    SYS_pciconfig_read = 272,
+    SYS_pciconfig_write = 273,
+    SYS_mq_open = 274,
+    SYS_mq_unlink = 275,
+    SYS_mq_timedsend = 276,
+    SYS_mq_timedreceive = 277,
+    SYS_mq_notify = 278,
+    SYS_mq_getsetattr = 279,
+    SYS_waitid = 280,
+    SYS_socket = 281,
+    SYS_bind = 282,
+    SYS_connect = 283,
+    SYS_listen = 284,
+    SYS_accept = 285,
+    SYS_getsockname = 286,
+    SYS_getpeername = 287,
+    SYS_socketpair = 288,
+    SYS_send = 289,
+    SYS_sendto = 290,
+    SYS_recv = 291,
+    SYS_recvfrom = 292,
+    SYS_shutdown = 293,
+    SYS_setsockopt = 294,
+    SYS_getsockopt = 295,
+    SYS_sendmsg = 296,
+    SYS_recvmsg = 297,
+    SYS_semop = 298,
+    SYS_semget = 299,
+    SYS_semctl = 300,
+    SYS_msgsnd = 301,
+    SYS_msgrcv = 302,
+    SYS_msgget = 303,
+    SYS_msgctl = 304,
+    SYS_shmat = 305,
+    SYS_shmdt = 306,
+    SYS_shmget = 307,
+    SYS_shmctl = 308,
+    SYS_add_key = 309,
+    SYS_request_key = 310,
+    SYS_keyctl = 311,
+    SYS_semtimedop = 312,
+    SYS_vserver = 313,
+    SYS_ioprio_set = 314,
+    SYS_ioprio_get = 315,
+    SYS_inotify_init = 316,
+    SYS_inotify_add_watch = 317,
+    SYS_inotify_rm_watch = 318,
+    SYS_mbind = 319,
+    SYS_get_mempolicy = 320,
+    SYS_set_mempolicy = 321,
+    SYS_openat = 322,
+    SYS_mkdirat = 323,
+    SYS_mknodat = 324,
+    SYS_fchownat = 325,
+    SYS_futimesat = 326,
+    SYS_fstatat64 = 327,
+    SYS_unlinkat = 328,
+    SYS_renameat = 329,
+    SYS_linkat = 330,
+    SYS_symlinkat = 331,
+    SYS_readlinkat = 332,
+    SYS_fchmodat = 333,
+    SYS_faccessat = 334,
+    SYS_pselect6 = 335,
+    SYS_ppoll = 336,
+    SYS_unshare = 337,
+    SYS_set_robust_list = 338,
+    SYS_get_robust_list = 339,
+    SYS_splice = 340,
+    SYS_arm_sync_file_range = 341,
+    SYS_tee = 342,
+    SYS_vmsplice = 343,
+    SYS_move_pages = 344,
+    SYS_getcpu = 345,
+    SYS_epoll_pwait = 346,
+    SYS_kexec_load = 347,
+    SYS_utimensat = 348,
+    SYS_signalfd = 349,
+    SYS_timerfd_create = 350,
+    SYS_eventfd = 351,
+    SYS_fallocate = 352,
+    SYS_timerfd_settime = 353,
+    SYS_timerfd_gettime = 354,
+    SYS_signalfd4 = 355,
+    SYS_eventfd2 = 356,
+    SYS_epoll_create1 = 357,
+    SYS_dup3 = 358,
+    SYS_pipe2 = 359,
+    SYS_inotify_init1 = 360,
+    SYS_preadv = 361,
+    SYS_pwritev = 362,
+    SYS_rt_tgsigqueueinfo = 363,
+    SYS_perf_event_open = 364,
+    SYS_recvmmsg = 365,
+    SYS_accept4 = 366,
+    SYS_fanotify_init = 367,
+    SYS_fanotify_mark = 368,
+    SYS_prlimit64 = 369,
+    SYS_name_to_handle_at = 370,
+    SYS_open_by_handle_at = 371,
+    SYS_clock_adjtime = 372,
+    SYS_syncfs = 373,
+    SYS_sendmmsg = 374,
+    SYS_setns = 375,
+    SYS_process_vm_readv = 376,
+    SYS_process_vm_writev = 377,
+    SYS_kcmp = 378,
+    SYS_finit_module = 379,
+    SYS_sched_setattr = 380,
+    SYS_sched_getattr = 381,
+    SYS_renameat2 = 382,
+    SYS_seccomp = 383,
+    SYS_getrandom = 384,
+    SYS_memfd_create = 385,
+    SYS_bpf = 386,
+    SYS_execveat = 387,
+}
diff --git a/syscall_defines/src/linux-x86/mod.rs b/syscall_defines/src/linux-x86/mod.rs
new file mode 100644
index 0000000..c6a3302
--- /dev/null
+++ b/syscall_defines/src/linux-x86/mod.rs
@@ -0,0 +1,384 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generated with: cat arch/x86/entry/syscalls/syscall_32.tbl |
+//    awk ' { print "SYS_" $3 " = " $1"," } '
+#[allow(dead_code)]
+#[allow(non_camel_case_types)]
+pub enum LinuxSyscall {
+    SYS_restart_syscall = 0,
+    SYS_exit = 1,
+    SYS_fork = 2,
+    SYS_read = 3,
+    SYS_write = 4,
+    SYS_open = 5,
+    SYS_close = 6,
+    SYS_waitpid = 7,
+    SYS_creat = 8,
+    SYS_link = 9,
+    SYS_unlink = 10,
+    SYS_execve = 11,
+    SYS_chdir = 12,
+    SYS_time = 13,
+    SYS_mknod = 14,
+    SYS_chmod = 15,
+    SYS_lchown = 16,
+    SYS_break = 17,
+    SYS_oldstat = 18,
+    SYS_lseek = 19,
+    SYS_getpid = 20,
+    SYS_mount = 21,
+    SYS_umount = 22,
+    SYS_setuid = 23,
+    SYS_getuid = 24,
+    SYS_stime = 25,
+    SYS_ptrace = 26,
+    SYS_alarm = 27,
+    SYS_oldfstat = 28,
+    SYS_pause = 29,
+    SYS_utime = 30,
+    SYS_stty = 31,
+    SYS_gtty = 32,
+    SYS_access = 33,
+    SYS_nice = 34,
+    SYS_ftime = 35,
+    SYS_sync = 36,
+    SYS_kill = 37,
+    SYS_rename = 38,
+    SYS_mkdir = 39,
+    SYS_rmdir = 40,
+    SYS_dup = 41,
+    SYS_pipe = 42,
+    SYS_times = 43,
+    SYS_prof = 44,
+    SYS_brk = 45,
+    SYS_setgid = 46,
+    SYS_getgid = 47,
+    SYS_signal = 48,
+    SYS_geteuid = 49,
+    SYS_getegid = 50,
+    SYS_acct = 51,
+    SYS_umount2 = 52,
+    SYS_lock = 53,
+    SYS_ioctl = 54,
+    SYS_fcntl = 55,
+    SYS_mpx = 56,
+    SYS_setpgid = 57,
+    SYS_ulimit = 58,
+    SYS_oldolduname = 59,
+    SYS_umask = 60,
+    SYS_chroot = 61,
+    SYS_ustat = 62,
+    SYS_dup2 = 63,
+    SYS_getppid = 64,
+    SYS_getpgrp = 65,
+    SYS_setsid = 66,
+    SYS_sigaction = 67,
+    SYS_sgetmask = 68,
+    SYS_ssetmask = 69,
+    SYS_setreuid = 70,
+    SYS_setregid = 71,
+    SYS_sigsuspend = 72,
+    SYS_sigpending = 73,
+    SYS_sethostname = 74,
+    SYS_setrlimit = 75,
+    SYS_getrlimit = 76,
+    SYS_getrusage = 77,
+    SYS_gettimeofday = 78,
+    SYS_settimeofday = 79,
+    SYS_getgroups = 80,
+    SYS_setgroups = 81,
+    SYS_select = 82,
+    SYS_symlink = 83,
+    SYS_oldlstat = 84,
+    SYS_readlink = 85,
+    SYS_uselib = 86,
+    SYS_swapon = 87,
+    SYS_reboot = 88,
+    SYS_readdir = 89,
+    SYS_mmap = 90,
+    SYS_munmap = 91,
+    SYS_truncate = 92,
+    SYS_ftruncate = 93,
+    SYS_fchmod = 94,
+    SYS_fchown = 95,
+    SYS_getpriority = 96,
+    SYS_setpriority = 97,
+    SYS_profil = 98,
+    SYS_statfs = 99,
+    SYS_fstatfs = 100,
+    SYS_ioperm = 101,
+    SYS_socketcall = 102,
+    SYS_syslog = 103,
+    SYS_setitimer = 104,
+    SYS_getitimer = 105,
+    SYS_stat = 106,
+    SYS_lstat = 107,
+    SYS_fstat = 108,
+    SYS_olduname = 109,
+    SYS_iopl = 110,
+    SYS_vhangup = 111,
+    SYS_idle = 112,
+    SYS_vm86old = 113,
+    SYS_wait4 = 114,
+    SYS_swapoff = 115,
+    SYS_sysinfo = 116,
+    SYS_ipc = 117,
+    SYS_fsync = 118,
+    SYS_sigreturn = 119,
+    SYS_clone = 120,
+    SYS_setdomainname = 121,
+    SYS_uname = 122,
+    SYS_modify_ldt = 123,
+    SYS_adjtimex = 124,
+    SYS_mprotect = 125,
+    SYS_sigprocmask = 126,
+    SYS_create_module = 127,
+    SYS_init_module = 128,
+    SYS_delete_module = 129,
+    SYS_get_kernel_syms = 130,
+    SYS_quotactl = 131,
+    SYS_getpgid = 132,
+    SYS_fchdir = 133,
+    SYS_bdflush = 134,
+    SYS_sysfs = 135,
+    SYS_personality = 136,
+    SYS_afs_syscall = 137,
+    SYS_setfsuid = 138,
+    SYS_setfsgid = 139,
+    SYS__llseek = 140,
+    SYS_getdents = 141,
+    SYS__newselect = 142,
+    SYS_flock = 143,
+    SYS_msync = 144,
+    SYS_readv = 145,
+    SYS_writev = 146,
+    SYS_getsid = 147,
+    SYS_fdatasync = 148,
+    SYS__sysctl = 149,
+    SYS_mlock = 150,
+    SYS_munlock = 151,
+    SYS_mlockall = 152,
+    SYS_munlockall = 153,
+    SYS_sched_setparam = 154,
+    SYS_sched_getparam = 155,
+    SYS_sched_setscheduler = 156,
+    SYS_sched_getscheduler = 157,
+    SYS_sched_yield = 158,
+    SYS_sched_get_priority_max = 159,
+    SYS_sched_get_priority_min = 160,
+    SYS_sched_rr_get_interval = 161,
+    SYS_nanosleep = 162,
+    SYS_mremap = 163,
+    SYS_setresuid = 164,
+    SYS_getresuid = 165,
+    SYS_vm86 = 166,
+    SYS_query_module = 167,
+    SYS_poll = 168,
+    SYS_nfsservctl = 169,
+    SYS_setresgid = 170,
+    SYS_getresgid = 171,
+    SYS_prctl = 172,
+    SYS_rt_sigreturn = 173,
+    SYS_rt_sigaction = 174,
+    SYS_rt_sigprocmask = 175,
+    SYS_rt_sigpending = 176,
+    SYS_rt_sigtimedwait = 177,
+    SYS_rt_sigqueueinfo = 178,
+    SYS_rt_sigsuspend = 179,
+    SYS_pread64 = 180,
+    SYS_pwrite64 = 181,
+    SYS_chown = 182,
+    SYS_getcwd = 183,
+    SYS_capget = 184,
+    SYS_capset = 185,
+    SYS_sigaltstack = 186,
+    SYS_sendfile = 187,
+    SYS_getpmsg = 188,
+    SYS_putpmsg = 189,
+    SYS_vfork = 190,
+    SYS_ugetrlimit = 191,
+    SYS_mmap2 = 192,
+    SYS_truncate64 = 193,
+    SYS_ftruncate64 = 194,
+    SYS_stat64 = 195,
+    SYS_lstat64 = 196,
+    SYS_fstat64 = 197,
+    SYS_lchown32 = 198,
+    SYS_getuid32 = 199,
+    SYS_getgid32 = 200,
+    SYS_geteuid32 = 201,
+    SYS_getegid32 = 202,
+    SYS_setreuid32 = 203,
+    SYS_setregid32 = 204,
+    SYS_getgroups32 = 205,
+    SYS_setgroups32 = 206,
+    SYS_fchown32 = 207,
+    SYS_setresuid32 = 208,
+    SYS_getresuid32 = 209,
+    SYS_setresgid32 = 210,
+    SYS_getresgid32 = 211,
+    SYS_chown32 = 212,
+    SYS_setuid32 = 213,
+    SYS_setgid32 = 214,
+    SYS_setfsuid32 = 215,
+    SYS_setfsgid32 = 216,
+    SYS_pivot_root = 217,
+    SYS_mincore = 218,
+    SYS_madvise = 219,
+    SYS_getdents64 = 220,
+    SYS_fcntl64 = 221,
+    SYS_gettid = 224,
+    SYS_readahead = 225,
+    SYS_setxattr = 226,
+    SYS_lsetxattr = 227,
+    SYS_fsetxattr = 228,
+    SYS_getxattr = 229,
+    SYS_lgetxattr = 230,
+    SYS_fgetxattr = 231,
+    SYS_listxattr = 232,
+    SYS_llistxattr = 233,
+    SYS_flistxattr = 234,
+    SYS_removexattr = 235,
+    SYS_lremovexattr = 236,
+    SYS_fremovexattr = 237,
+    SYS_tkill = 238,
+    SYS_sendfile64 = 239,
+    SYS_futex = 240,
+    SYS_sched_setaffinity = 241,
+    SYS_sched_getaffinity = 242,
+    SYS_set_thread_area = 243,
+    SYS_get_thread_area = 244,
+    SYS_io_setup = 245,
+    SYS_io_destroy = 246,
+    SYS_io_getevents = 247,
+    SYS_io_submit = 248,
+    SYS_io_cancel = 249,
+    SYS_fadvise64 = 250,
+    SYS_exit_group = 252,
+    SYS_lookup_dcookie = 253,
+    SYS_epoll_create = 254,
+    SYS_epoll_ctl = 255,
+    SYS_epoll_wait = 256,
+    SYS_remap_file_pages = 257,
+    SYS_set_tid_address = 258,
+    SYS_timer_create = 259,
+    SYS_timer_settime = 260,
+    SYS_timer_gettime = 261,
+    SYS_timer_getoverrun = 262,
+    SYS_timer_delete = 263,
+    SYS_clock_settime = 264,
+    SYS_clock_gettime = 265,
+    SYS_clock_getres = 266,
+    SYS_clock_nanosleep = 267,
+    SYS_statfs64 = 268,
+    SYS_fstatfs64 = 269,
+    SYS_tgkill = 270,
+    SYS_utimes = 271,
+    SYS_fadvise64_64 = 272,
+    SYS_vserver = 273,
+    SYS_mbind = 274,
+    SYS_get_mempolicy = 275,
+    SYS_set_mempolicy = 276,
+    SYS_mq_open = 277,
+    SYS_mq_unlink = 278,
+    SYS_mq_timedsend = 279,
+    SYS_mq_timedreceive = 280,
+    SYS_mq_notify = 281,
+    SYS_mq_getsetattr = 282,
+    SYS_kexec_load = 283,
+    SYS_waitid = 284,
+    SYS_sys_setaltroot = 285,
+    SYS_add_key = 286,
+    SYS_request_key = 287,
+    SYS_keyctl = 288,
+    SYS_ioprio_set = 289,
+    SYS_ioprio_get = 290,
+    SYS_inotify_init = 291,
+    SYS_inotify_add_watch = 292,
+    SYS_inotify_rm_watch = 293,
+    SYS_migrate_pages = 294,
+    SYS_openat = 295,
+    SYS_mkdirat = 296,
+    SYS_mknodat = 297,
+    SYS_fchownat = 298,
+    SYS_futimesat = 299,
+    SYS_fstatat64 = 300,
+    SYS_unlinkat = 301,
+    SYS_renameat = 302,
+    SYS_linkat = 303,
+    SYS_symlinkat = 304,
+    SYS_readlinkat = 305,
+    SYS_fchmodat = 306,
+    SYS_faccessat = 307,
+    SYS_pselect6 = 308,
+    SYS_ppoll = 309,
+    SYS_unshare = 310,
+    SYS_set_robust_list = 311,
+    SYS_get_robust_list = 312,
+    SYS_splice = 313,
+    SYS_sync_file_range = 314,
+    SYS_tee = 315,
+    SYS_vmsplice = 316,
+    SYS_move_pages = 317,
+    SYS_getcpu = 318,
+    SYS_epoll_pwait = 319,
+    SYS_utimensat = 320,
+    SYS_signalfd = 321,
+    SYS_timerfd_create = 322,
+    SYS_eventfd = 323,
+    SYS_fallocate = 324,
+    SYS_timerfd_settime = 325,
+    SYS_timerfd_gettime = 326,
+    SYS_signalfd4 = 327,
+    SYS_eventfd2 = 328,
+    SYS_epoll_create1 = 329,
+    SYS_dup3 = 330,
+    SYS_pipe2 = 331,
+    SYS_inotify_init1 = 332,
+    SYS_preadv = 333,
+    SYS_pwritev = 334,
+    SYS_rt_tgsigqueueinfo = 335,
+    SYS_perf_event_open = 336,
+    SYS_recvmmsg = 337,
+    SYS_fanotify_init = 338,
+    SYS_fanotify_mark = 339,
+    SYS_prlimit64 = 340,
+    SYS_name_to_handle_at = 341,
+    SYS_open_by_handle_at = 342,
+    SYS_clock_adjtime = 343,
+    SYS_syncfs = 344,
+    SYS_sendmmsg = 345,
+    SYS_setns = 346,
+    SYS_process_vm_readv = 347,
+    SYS_process_vm_writev = 348,
+    SYS_kcmp = 349,
+    SYS_finit_module = 350,
+    SYS_sched_setattr = 351,
+    SYS_sched_getattr = 352,
+    SYS_renameat2 = 353,
+    SYS_seccomp = 354,
+    SYS_getrandom = 355,
+    SYS_memfd_create = 356,
+    SYS_bpf = 357,
+    SYS_execveat = 358,
+    SYS_socket = 359,
+    SYS_socketpair = 360,
+    SYS_bind = 361,
+    SYS_connect = 362,
+    SYS_listen = 363,
+    SYS_accept4 = 364,
+    SYS_getsockopt = 365,
+    SYS_setsockopt = 366,
+    SYS_getsockname = 367,
+    SYS_getpeername = 368,
+    SYS_sendto = 369,
+    SYS_sendmsg = 370,
+    SYS_recvfrom = 371,
+    SYS_recvmsg = 372,
+    SYS_shutdown = 373,
+    SYS_userfaultfd = 374,
+    SYS_membarrier = 375,
+    SYS_mlock2 = 376,
+}
diff --git a/syscall_defines/src/linux-x86_64/mod.rs b/syscall_defines/src/linux-x86_64/mod.rs
new file mode 100644
index 0000000..f58961a
--- /dev/null
+++ b/syscall_defines/src/linux-x86_64/mod.rs
@@ -0,0 +1,370 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generated with: cat arch/x86/entry/syscalls/syscall_64.tbl |
+//    awk ' { print "SYS_" $3 " = " $1"," } '
+#[allow(dead_code)]
+#[allow(non_camel_case_types)]
+pub enum LinuxSyscall {
+    SYS_read = 0,
+    SYS_write = 1,
+    SYS_open = 2,
+    SYS_close = 3,
+    SYS_stat = 4,
+    SYS_fstat = 5,
+    SYS_lstat = 6,
+    SYS_poll = 7,
+    SYS_lseek = 8,
+    SYS_mmap = 9,
+    SYS_mprotect = 10,
+    SYS_munmap = 11,
+    SYS_brk = 12,
+    SYS_rt_sigaction = 13,
+    SYS_rt_sigprocmask = 14,
+    SYS_rt_sigreturn = 15,
+    SYS_ioctl = 16,
+    SYS_pread64 = 17,
+    SYS_pwrite64 = 18,
+    SYS_readv = 19,
+    SYS_writev = 20,
+    SYS_access = 21,
+    SYS_pipe = 22,
+    SYS_select = 23,
+    SYS_sched_yield = 24,
+    SYS_mremap = 25,
+    SYS_msync = 26,
+    SYS_mincore = 27,
+    SYS_madvise = 28,
+    SYS_shmget = 29,
+    SYS_shmat = 30,
+    SYS_shmctl = 31,
+    SYS_dup = 32,
+    SYS_dup2 = 33,
+    SYS_pause = 34,
+    SYS_nanosleep = 35,
+    SYS_getitimer = 36,
+    SYS_alarm = 37,
+    SYS_setitimer = 38,
+    SYS_getpid = 39,
+    SYS_sendfile = 40,
+    SYS_socket = 41,
+    SYS_connect = 42,
+    SYS_accept = 43,
+    SYS_sendto = 44,
+    SYS_recvfrom = 45,
+    SYS_sendmsg = 46,
+    SYS_recvmsg = 47,
+    SYS_shutdown = 48,
+    SYS_bind = 49,
+    SYS_listen = 50,
+    SYS_getsockname = 51,
+    SYS_getpeername = 52,
+    SYS_socketpair = 53,
+    SYS_setsockopt = 54,
+    SYS_getsockopt = 55,
+    SYS_clone = 56,
+    SYS_fork = 57,
+    SYS_vfork = 58,
+    SYS_execve = 59,
+    SYS_exit = 60,
+    SYS_wait4 = 61,
+    SYS_kill = 62,
+    SYS_uname = 63,
+    SYS_semget = 64,
+    SYS_semop = 65,
+    SYS_semctl = 66,
+    SYS_shmdt = 67,
+    SYS_msgget = 68,
+    SYS_msgsnd = 69,
+    SYS_msgrcv = 70,
+    SYS_msgctl = 71,
+    SYS_fcntl = 72,
+    SYS_flock = 73,
+    SYS_fsync = 74,
+    SYS_fdatasync = 75,
+    SYS_truncate = 76,
+    SYS_ftruncate = 77,
+    SYS_getdents = 78,
+    SYS_getcwd = 79,
+    SYS_chdir = 80,
+    SYS_fchdir = 81,
+    SYS_rename = 82,
+    SYS_mkdir = 83,
+    SYS_rmdir = 84,
+    SYS_creat = 85,
+    SYS_link = 86,
+    SYS_unlink = 87,
+    SYS_symlink = 88,
+    SYS_readlink = 89,
+    SYS_chmod = 90,
+    SYS_fchmod = 91,
+    SYS_chown = 92,
+    SYS_fchown = 93,
+    SYS_lchown = 94,
+    SYS_umask = 95,
+    SYS_gettimeofday = 96,
+    SYS_getrlimit = 97,
+    SYS_getrusage = 98,
+    SYS_sysinfo = 99,
+    SYS_times = 100,
+    SYS_ptrace = 101,
+    SYS_getuid = 102,
+    SYS_syslog = 103,
+    SYS_getgid = 104,
+    SYS_setuid = 105,
+    SYS_setgid = 106,
+    SYS_geteuid = 107,
+    SYS_getegid = 108,
+    SYS_setpgid = 109,
+    SYS_getppid = 110,
+    SYS_getpgrp = 111,
+    SYS_setsid = 112,
+    SYS_setreuid = 113,
+    SYS_setregid = 114,
+    SYS_getgroups = 115,
+    SYS_setgroups = 116,
+    SYS_setresuid = 117,
+    SYS_getresuid = 118,
+    SYS_setresgid = 119,
+    SYS_getresgid = 120,
+    SYS_getpgid = 121,
+    SYS_setfsuid = 122,
+    SYS_setfsgid = 123,
+    SYS_getsid = 124,
+    SYS_capget = 125,
+    SYS_capset = 126,
+    SYS_rt_sigpending = 127,
+    SYS_rt_sigtimedwait = 128,
+    SYS_rt_sigqueueinfo = 129,
+    SYS_rt_sigsuspend = 130,
+    SYS_sigaltstack = 131,
+    SYS_utime = 132,
+    SYS_mknod = 133,
+    SYS_uselib = 134,
+    SYS_personality = 135,
+    SYS_ustat = 136,
+    SYS_statfs = 137,
+    SYS_fstatfs = 138,
+    SYS_sysfs = 139,
+    SYS_getpriority = 140,
+    SYS_setpriority = 141,
+    SYS_sched_setparam = 142,
+    SYS_sched_getparam = 143,
+    SYS_sched_setscheduler = 144,
+    SYS_sched_getscheduler = 145,
+    SYS_sched_get_priority_max = 146,
+    SYS_sched_get_priority_min = 147,
+    SYS_sched_rr_get_interval = 148,
+    SYS_mlock = 149,
+    SYS_munlock = 150,
+    SYS_mlockall = 151,
+    SYS_munlockall = 152,
+    SYS_vhangup = 153,
+    SYS_modify_ldt = 154,
+    SYS_pivot_root = 155,
+    SYS__sysctl = 156,
+    SYS_prctl = 157,
+    SYS_arch_prctl = 158,
+    SYS_adjtimex = 159,
+    SYS_setrlimit = 160,
+    SYS_chroot = 161,
+    SYS_sync = 162,
+    SYS_acct = 163,
+    SYS_settimeofday = 164,
+    SYS_mount = 165,
+    SYS_umount2 = 166,
+    SYS_swapon = 167,
+    SYS_swapoff = 168,
+    SYS_reboot = 169,
+    SYS_sethostname = 170,
+    SYS_setdomainname = 171,
+    SYS_iopl = 172,
+    SYS_ioperm = 173,
+    SYS_create_module = 174,
+    SYS_init_module = 175,
+    SYS_delete_module = 176,
+    SYS_get_kernel_syms = 177,
+    SYS_query_module = 178,
+    SYS_quotactl = 179,
+    SYS_nfsservctl = 180,
+    SYS_getpmsg = 181,
+    SYS_putpmsg = 182,
+    SYS_afs_syscall = 183,
+    SYS_tuxcall = 184,
+    SYS_security = 185,
+    SYS_gettid = 186,
+    SYS_readahead = 187,
+    SYS_setxattr = 188,
+    SYS_lsetxattr = 189,
+    SYS_fsetxattr = 190,
+    SYS_getxattr = 191,
+    SYS_lgetxattr = 192,
+    SYS_fgetxattr = 193,
+    SYS_listxattr = 194,
+    SYS_llistxattr = 195,
+    SYS_flistxattr = 196,
+    SYS_removexattr = 197,
+    SYS_lremovexattr = 198,
+    SYS_fremovexattr = 199,
+    SYS_tkill = 200,
+    SYS_time = 201,
+    SYS_futex = 202,
+    SYS_sched_setaffinity = 203,
+    SYS_sched_getaffinity = 204,
+    SYS_set_thread_area = 205,
+    SYS_io_setup = 206,
+    SYS_io_destroy = 207,
+    SYS_io_getevents = 208,
+    SYS_io_submit = 209,
+    SYS_io_cancel = 210,
+    SYS_get_thread_area = 211,
+    SYS_lookup_dcookie = 212,
+    SYS_epoll_create = 213,
+    SYS_epoll_ctl_old = 214,
+    SYS_epoll_wait_old = 215,
+    SYS_remap_file_pages = 216,
+    SYS_getdents64 = 217,
+    SYS_set_tid_address = 218,
+    SYS_restart_syscall = 219,
+    SYS_semtimedop = 220,
+    SYS_fadvise64 = 221,
+    SYS_timer_create = 222,
+    SYS_timer_settime = 223,
+    SYS_timer_gettime = 224,
+    SYS_timer_getoverrun = 225,
+    SYS_timer_delete = 226,
+    SYS_clock_settime = 227,
+    SYS_clock_gettime = 228,
+    SYS_clock_getres = 229,
+    SYS_clock_nanosleep = 230,
+    SYS_exit_group = 231,
+    SYS_epoll_wait = 232,
+    SYS_epoll_ctl = 233,
+    SYS_tgkill = 234,
+    SYS_utimes = 235,
+    SYS_vserver = 236,
+    SYS_mbind = 237,
+    SYS_set_mempolicy = 238,
+    SYS_get_mempolicy = 239,
+    SYS_mq_open = 240,
+    SYS_mq_unlink = 241,
+    SYS_mq_timedsend = 242,
+    SYS_mq_timedreceive = 243,
+    SYS_mq_notify = 244,
+    SYS_mq_getsetattr = 245,
+    SYS_kexec_load = 246,
+    SYS_waitid = 247,
+    SYS_add_key = 248,
+    SYS_request_key = 249,
+    SYS_keyctl = 250,
+    SYS_ioprio_set = 251,
+    SYS_ioprio_get = 252,
+    SYS_inotify_init = 253,
+    SYS_inotify_add_watch = 254,
+    SYS_inotify_rm_watch = 255,
+    SYS_migrate_pages = 256,
+    SYS_openat = 257,
+    SYS_mkdirat = 258,
+    SYS_mknodat = 259,
+    SYS_fchownat = 260,
+    SYS_futimesat = 261,
+    SYS_newfstatat = 262,
+    SYS_unlinkat = 263,
+    SYS_renameat = 264,
+    SYS_linkat = 265,
+    SYS_symlinkat = 266,
+    SYS_readlinkat = 267,
+    SYS_fchmodat = 268,
+    SYS_faccessat = 269,
+    SYS_pselect6 = 270,
+    SYS_ppoll = 271,
+    SYS_unshare = 272,
+    SYS_set_robust_list = 273,
+    SYS_get_robust_list = 274,
+    SYS_splice = 275,
+    SYS_tee = 276,
+    SYS_sync_file_range = 277,
+    SYS_vmsplice = 278,
+    SYS_move_pages = 279,
+    SYS_utimensat = 280,
+    SYS_epoll_pwait = 281,
+    SYS_signalfd = 282,
+    SYS_timerfd_create = 283,
+    SYS_eventfd = 284,
+    SYS_fallocate = 285,
+    SYS_timerfd_settime = 286,
+    SYS_timerfd_gettime = 287,
+    SYS_accept4 = 288,
+    SYS_signalfd4 = 289,
+    SYS_eventfd2 = 290,
+    SYS_epoll_create1 = 291,
+    SYS_dup3 = 292,
+    SYS_pipe2 = 293,
+    SYS_inotify_init1 = 294,
+    SYS_preadv = 295,
+    SYS_pwritev = 296,
+    SYS_rt_tgsigqueueinfo = 297,
+    SYS_perf_event_open = 298,
+    SYS_recvmmsg = 299,
+    SYS_fanotify_init = 300,
+    SYS_fanotify_mark = 301,
+    SYS_prlimit64 = 302,
+    SYS_name_to_handle_at = 303,
+    SYS_open_by_handle_at = 304,
+    SYS_clock_adjtime = 305,
+    SYS_syncfs = 306,
+    SYS_sendmmsg = 307,
+    SYS_setns = 308,
+    SYS_getcpu = 309,
+    SYS_process_vm_readv = 310,
+    SYS_process_vm_writev = 311,
+    SYS_kcmp = 312,
+    SYS_finit_module = 313,
+    SYS_sched_setattr = 314,
+    SYS_sched_getattr = 315,
+    SYS_renameat2 = 316,
+    SYS_seccomp = 317,
+    SYS_getrandom = 318,
+    SYS_memfd_create = 319,
+    SYS_kexec_file_load = 320,
+    SYS_bpf = 321,
+    SYS_execveat = 322,
+    SYS_userfaultfd = 323,
+    SYS_membarrier = 324,
+    SYS_mlock2 = 325,
+    compat_SYS_rt_sigaction = 512,
+    compat_SYS_rt_sigreturn = 513,
+    compat_SYS_ioctl = 514,
+    compat_SYS_readv = 515,
+    compat_SYS_writev = 516,
+    compat_SYS_recvfrom = 517,
+    compat_SYS_sendmsg = 518,
+    compat_SYS_recvmsg = 519,
+    compat_SYS_execve = 520,
+    compat_SYS_ptrace = 521,
+    compat_SYS_rt_sigpending = 522,
+    compat_SYS_rt_sigtimedwait = 523,
+    compat_SYS_rt_sigqueueinfo = 524,
+    compat_SYS_sigaltstack = 525,
+    compat_SYS_timer_create = 526,
+    compat_SYS_mq_notify = 527,
+    compat_SYS_kexec_load = 528,
+    compat_SYS_waitid = 529,
+    compat_SYS_set_robust_list = 530,
+    compat_SYS_get_robust_list = 531,
+    compat_SYS_vmsplice = 532,
+    compat_SYS_move_pages = 533,
+    compat_SYS_preadv = 534,
+    compat_SYS_pwritev = 535,
+    compat_SYS_rt_tgsigqueueinfo = 536,
+    compat_SYS_recvmmsg = 537,
+    compat_SYS_sendmmsg = 538,
+    compat_SYS_process_vm_readv = 539,
+    compat_SYS_process_vm_writev = 540,
+    compat_SYS_setsockopt = 541,
+    compat_SYS_getsockopt = 542,
+    compat_SYS_io_setup = 543,
+    compat_SYS_io_submit = 544,
+    compat_SYS_execveat = 545,
+}
diff --git a/tempfile/Cargo.toml b/tempfile/Cargo.toml
new file mode 100644
index 0000000..b12e976
--- /dev/null
+++ b/tempfile/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "tempfile"
+version = "3.0.7"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+rand_ish = { path = "../rand_ish" }
diff --git a/tempfile/src/lib.rs b/tempfile/src/lib.rs
new file mode 100644
index 0000000..14f235b
--- /dev/null
+++ b/tempfile/src/lib.rs
@@ -0,0 +1,75 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Simplified tempfile which doesn't depend on the `rand` crate, instead using
+//! /dev/urandom as a source of entropy
+
+use rand_ish::urandom_str;
+use std::env;
+use std::fs;
+use std::io::{Error, ErrorKind, Result};
+use std::path::{Path, PathBuf};
+
+pub struct Builder {
+    prefix: String,
+}
+
+impl Builder {
+    pub fn new() -> Self {
+        Builder {
+            prefix: ".tmp".to_owned(),
+        }
+    }
+
+    /// Set a custom filename prefix.
+    ///
+    /// Default: `.tmp`
+    pub fn prefix(&mut self, prefix: &str) -> &mut Self {
+        self.prefix = prefix.to_owned();
+        self
+    }
+
+    /// Tries to make a tempdir inside of `env::temp_dir()` with a specified
+    /// prefix. The directory and it's content is destroyed when TempDir is
+    /// dropped.
+    /// If the directory can not be created, `Err` is returned.
+    pub fn tempdir(&self) -> Result<TempDir> {
+        for _ in 0..NUM_RETRIES {
+            let suffix = urandom_str(12)?;
+            let path = env::temp_dir().join(format!("{}.{}", self.prefix, suffix));
+
+            match fs::create_dir(&path) {
+                Ok(_) => return Ok(TempDir { path }),
+                Err(ref e) if e.kind() == ErrorKind::AlreadyExists => {}
+                Err(e) => return Err(e),
+            }
+        }
+
+        Err(Error::new(
+            ErrorKind::AlreadyExists,
+            "too many tempdirs exist",
+        ))
+    }
+}
+
+pub struct TempDir {
+    path: PathBuf,
+}
+
+const NUM_RETRIES: u32 = 4;
+
+impl TempDir {
+    /// Accesses the tempdir's [`Path`].
+    ///
+    /// [`Path`]: http://doc.rust-lang.org/std/path/struct.Path.html
+    pub fn path(&self) -> &Path {
+        self.path.as_ref()
+    }
+}
+
+impl Drop for TempDir {
+    fn drop(&mut self) {
+        let _ = fs::remove_dir_all(&self.path);
+    }
+}
diff --git a/tests/mini_plugin_template.c b/tests/mini_plugin_template.c
new file mode 100644
index 0000000..684b473
--- /dev/null
+++ b/tests/mini_plugin_template.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/memfd.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "crosvm.h"
+
+#ifndef F_LINUX_SPECIFIC_BASE
+#define F_LINUX_SPECIFIC_BASE 1024
+#endif
+
+#ifndef F_ADD_SEALS
+#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
+#endif
+
+#ifndef F_SEAL_SHRINK
+#define F_SEAL_SHRINK 0x0002
+#endif
+
+#define LOAD_ADDRESS {load_address}
+
+const uint8_t g_assembly_code[] = {{
+    {assembly_code}
+}};
+
+/* These get defined by the code inserted below. */
+int setup_vm(struct crosvm *, void *mem);
+int handle_vpcu_init(struct crosvm_vcpu *, struct kvm_regs *, struct kvm_sregs *);
+int handle_vpcu_evt(struct crosvm_vcpu *, struct crosvm_vcpu_event evt);
+int check_result(struct crosvm *, void *mem);
+{src}
+
+struct vcpu_context {{
+    struct crosvm_vcpu *vcpu;
+}};
+
+void *vcpu_thread(void *arg) {{
+    struct vcpu_context *ctx = arg;
+    struct crosvm_vcpu *vcpu = ctx->vcpu;
+    struct crosvm_vcpu_event evt;
+    int ret;
+    while (crosvm_vcpu_wait(vcpu, &evt) == 0) {{
+        if (evt.kind == CROSVM_VCPU_EVENT_KIND_INIT) {{
+            struct kvm_regs regs;
+            crosvm_vcpu_get_regs(vcpu, &regs);
+            regs.rflags = 2;
+            regs.rip = LOAD_ADDRESS;
+
+            struct kvm_sregs sregs;
+            crosvm_vcpu_get_sregs(vcpu, &sregs);
+            sregs.cs.base = 0;
+            sregs.cs.selector = 0;
+
+            handle_vpcu_init(vcpu, &regs, &sregs);
+            crosvm_vcpu_set_regs(vcpu, &regs);
+            crosvm_vcpu_set_sregs(vcpu, &sregs);
+        }} else {{
+            ret = handle_vpcu_evt(vcpu, evt);
+            if (ret)
+                return NULL;
+        }}
+
+        crosvm_vcpu_resume(vcpu);
+    }}
+
+    return NULL;
+}}
+
+int main(int argc, char** argv) {{
+    int i;
+    uint64_t dummy = 1;
+    struct crosvm *crosvm;
+    int ret = crosvm_connect(&crosvm);
+    if (ret) {{
+        fprintf(stderr, "failed to connect to crosvm: %d\n", ret);
+        return 1;
+    }}
+
+    int kill_evt = crosvm_get_shutdown_eventfd(crosvm);
+    if (kill_evt < 0) {{
+        fprintf(stderr, "failed to get kill eventfd: %d\n", kill_evt);
+        return 1;
+    }}
+
+    int mem_size = {mem_size};
+    int mem_fd = syscall(SYS_memfd_create, "guest_mem", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+    if (mem_fd < 0) {{
+        fprintf(stderr, "failed to create guest memfd: %d\n", errno);
+        return 1;
+    }}
+    ret = ftruncate(mem_fd, mem_size);
+    if (ret) {{
+        fprintf(stderr, "failed to set size of guest memory: %d\n", errno);
+        return 1;
+    }}
+    uint8_t *mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0);
+    if (mem == MAP_FAILED) {{
+        fprintf(stderr, "failed to mmap guest memory: %d\n", errno);
+        return 1;
+    }}
+    fcntl(mem_fd, F_ADD_SEALS, F_SEAL_SHRINK);
+    memcpy(mem + LOAD_ADDRESS, g_assembly_code, sizeof(g_assembly_code));
+
+    struct crosvm_memory *mem_obj;
+    ret = crosvm_create_memory(crosvm, mem_fd, 0, mem_size, 0, false, false, &mem_obj);
+    if (ret) {{
+        fprintf(stderr, "failed to create memory in crosvm: %d\n", ret);
+        return 1;
+    }}
+
+    ret = setup_vm(crosvm, mem);
+    if (ret)
+        return ret;
+
+    struct crosvm_vcpu *vcpus[32];
+    struct vcpu_context ctxs[32];
+    pthread_t vcpu_threads[32];
+    uint32_t vcpu_count;
+    for (vcpu_count = 0; vcpu_count < 32; vcpu_count++) {{
+        ret = crosvm_get_vcpu(crosvm, vcpu_count, &vcpus[vcpu_count]);
+        if (ret == -ENOENT)
+            break;
+
+        if (ret) {{
+            fprintf(stderr, "error while getting all vcpus: %d\n", ret);
+            return 1;
+        }}
+        ctxs[vcpu_count].vcpu = vcpus[vcpu_count];
+        pthread_create(&vcpu_threads[vcpu_count], NULL, vcpu_thread, &ctxs[vcpu_count]);
+    }}
+
+    ret = crosvm_start(crosvm);
+    if (ret) {{
+        fprintf(stderr, "failed to tell crosvm to start: %d\n", ret);
+        return 1;
+    }}
+
+    ret = read(kill_evt, &dummy, sizeof(dummy));
+    if (ret == -1) {{
+        fprintf(stderr, "failed to read kill eventfd: %d\n", errno);
+        return 1;
+    }}
+
+    return check_result(crosvm, mem);
+}}
diff --git a/tests/plugin.policy b/tests/plugin.policy
new file mode 100644
index 0000000..a3ab2f7
--- /dev/null
+++ b/tests/plugin.policy
@@ -0,0 +1,51 @@
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+close: 1
+dup: 1
+dup2: 1
+execve: 1
+exit_group: 1
+futex: 1
+lseek: 1
+mprotect: 1
+munmap: 1
+read: 1
+recvfrom: 1
+sched_getaffinity: 1
+set_robust_list: 1
+sigaltstack: 1
+# Disallow clone's other than new threads.
+clone: arg0 & 0x00010000
+write: 1
+eventfd2: 1
+poll: 1
+getpid: 1
+# Allow PR_SET_NAME only.
+prctl: arg0 == 15
+access: 1
+arch_prctl: 1
+brk: 1
+exit: 1
+fcntl: 1
+fstat: 1
+ftruncate: 1
+getcwd: 1
+getrlimit: 1
+# TUNGETFEATURES
+ioctl: arg1 == 0x800454CF
+madvise: 1
+memfd_create: 1
+mmap: 1
+open: 1
+openat: 1
+prlimit64: arg2 == 0 && arg3 != 0
+recvmsg: 1
+restart_syscall: 1
+rt_sigaction: 1
+rt_sigprocmask: 1
+sendmsg: 1
+set_tid_address: 1
+stat: 1
+writev: 1
diff --git a/tests/plugin_adder.c b/tests/plugin_adder.c
new file mode 100644
index 0000000..8728614
--- /dev/null
+++ b/tests/plugin_adder.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/memfd.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "crosvm.h"
+
+#ifndef F_LINUX_SPECIFIC_BASE
+#define F_LINUX_SPECIFIC_BASE 1024
+#endif
+
+#ifndef F_ADD_SEALS
+#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
+#endif
+
+#ifndef F_SEAL_SHRINK
+#define F_SEAL_SHRINK 0x0002
+#endif
+
+#define SERIAL_ADDRESS 0x3f8
+#define KILL_ADDRESS 0x3f9
+
+char g_serial_out[16];
+int g_kill_evt;
+
+void *vcpu_thread(void *arg) {
+    struct crosvm_vcpu *vcpu = arg;
+    struct crosvm_vcpu_event evt;
+    int i = 0;
+    while (crosvm_vcpu_wait(vcpu, &evt) == 0) {
+        if (evt.kind == CROSVM_VCPU_EVENT_KIND_INIT) {
+            struct kvm_sregs sregs;
+            crosvm_vcpu_get_sregs(vcpu, &sregs);
+            sregs.cs.base = 0;
+            sregs.cs.selector = 0;
+            sregs.es.base = KILL_ADDRESS;
+            sregs.es.selector = 0;
+            crosvm_vcpu_set_sregs(vcpu, &sregs);
+
+            struct kvm_regs regs;
+            crosvm_vcpu_get_regs(vcpu, &regs);
+            regs.rip = 0x1000;
+            regs.rax = 2;
+            regs.rbx = 7;
+            regs.rflags = 2;
+            crosvm_vcpu_set_regs(vcpu, &regs);
+        }
+        if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS) {
+            if (evt.io_access.address_space == CROSVM_ADDRESS_SPACE_IOPORT &&
+                evt.io_access.address == SERIAL_ADDRESS &&
+                evt.io_access.is_write &&
+                evt.io_access.length == 1) {
+                g_serial_out[i] = evt.io_access.data[0];
+                i++;
+            }
+            if (evt.io_access.address_space == CROSVM_ADDRESS_SPACE_IOPORT &&
+                evt.io_access.address == KILL_ADDRESS &&
+                evt.io_access.is_write &&
+                evt.io_access.length == 1 &&
+                evt.io_access.data[0] == 1)
+            {
+                uint64_t dummy = 1;
+                write(g_kill_evt, &dummy, sizeof(dummy));
+                return NULL;
+            }
+        }
+
+        crosvm_vcpu_resume(vcpu);
+    }
+
+    return NULL;
+}
+
+int main(int argc, char** argv) {
+    const uint8_t code[] = {
+    /*
+    0000  BAF803  mov dx,0x3f8
+    0003  00D8    add al,bl
+    0005  0430    add al,0x30
+    0007  EE      out dx,al
+    0008  B05C    mov al,0x0a
+    000A  EE      out dx,al
+    000B  BAF903  mov dx,0x3f9
+    000E  B001    mov al,0x1
+    0010  EE      out dx,al
+    0011  F4      hlt
+    */
+        0xba, 0xf8, 0x03,
+        0x00, 0xd8,
+        0x04, '0',
+        0xee,
+        0xb0, '\n',
+        0xee,
+        0xba, 0xf9, 0x03,
+        0xb0, 0x01,
+        0xee,
+        0xf4
+    };
+
+    struct crosvm *crosvm;
+    int ret = crosvm_connect(&crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to connect to crosvm: %d\n", ret);
+        return 1;
+    }
+
+    /*
+     * Not strictly necessary, but demonstrates we can have as many connections
+     * as we please.
+     */
+    struct crosvm *extra_crosvm;
+    ret = crosvm_new_connection(crosvm, &extra_crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to make new socket: %d\n", ret);
+        return 1;
+    }
+
+    /* We needs this eventfd to know when to exit before being killed. */
+    g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
+    if (g_kill_evt < 0) {
+        fprintf(stderr, "failed to get kill eventfd: %d\n", g_kill_evt);
+        return 1;
+    }
+
+    ret = crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_IOPORT, SERIAL_ADDRESS, 1);
+    if (ret) {
+        fprintf(stderr, "failed to reserve ioport range: %d\n", ret);
+        return 1;
+    }
+
+    ret = crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_IOPORT, KILL_ADDRESS, 1);
+    if (ret) {
+        fprintf(stderr, "failed to reserve mmio range: %d\n", ret);
+        return 1;
+    }
+
+    int mem_size = 0x2000;
+    int mem_fd = syscall(SYS_memfd_create, "guest_mem", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+    if (mem_fd < 0) {
+        fprintf(stderr, "failed to create guest memfd: %d\n", errno);
+        return 1;
+    }
+    ret = ftruncate(mem_fd, mem_size);
+    if (ret) {
+        fprintf(stderr, "failed to set size of guest memory: %d\n", errno);
+        return 1;
+    }
+    uint8_t *mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0x1000);
+    if (mem == MAP_FAILED) {
+        fprintf(stderr, "failed to mmap guest memory: %d\n", errno);
+        return 1;
+    }
+    fcntl(mem_fd, F_ADD_SEALS, F_SEAL_SHRINK);
+    memcpy(mem, code, sizeof(code));
+
+    struct crosvm_memory *mem_obj;
+    ret = crosvm_create_memory(crosvm, mem_fd, 0x1000, 0x1000, 0x1000, false, false, &mem_obj);
+    if (ret) {
+        fprintf(stderr, "failed to create memory in crosvm: %d\n", ret);
+        return 1;
+    }
+
+    /* get and creat a thread for each vcpu */
+    struct crosvm_vcpu *vcpus[32];
+    pthread_t vcpu_threads[32];
+    uint32_t vcpu_count;
+    for (vcpu_count = 0; vcpu_count < 32; vcpu_count++) {
+        ret = crosvm_get_vcpu(crosvm, vcpu_count, &vcpus[vcpu_count]);
+        if (ret == -ENOENT)
+            break;
+
+        if (ret) {
+            fprintf(stderr, "error while getting all vcpus: %d\n", ret);
+            return 1;
+        }
+        pthread_create(&vcpu_threads[vcpu_count], NULL, vcpu_thread, vcpus[vcpu_count]);
+    }
+
+    ret = crosvm_start(extra_crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to tell crosvm to start: %d\n", ret);
+        return 1;
+    }
+
+    /* Wait for crosvm to request that we exit otherwise we will be killed. */
+    uint64_t dummy;
+    read(g_kill_evt, &dummy, 8);
+
+    ret = crosvm_destroy_memory(crosvm, &mem_obj);
+    if (ret) {
+        fprintf(stderr, "failed to destroy memory in crosvm: %d\n", ret);
+        return 1;
+    }
+
+    ret = crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_IOPORT, SERIAL_ADDRESS, 0);
+    if (ret) {
+        fprintf(stderr, "failed to unreserve ioport range: %d\n", ret);
+        return 1;
+    }
+
+    ret = crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_IOPORT, KILL_ADDRESS, 0);
+    if (ret) {
+        fprintf(stderr, "failed to unreserve mmio range: %d\n", ret);
+        return 1;
+    }
+
+    return strcmp(g_serial_out, "9\n");
+}
diff --git a/tests/plugin_dirty_log.c b/tests/plugin_dirty_log.c
new file mode 100644
index 0000000..f266cdf
--- /dev/null
+++ b/tests/plugin_dirty_log.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/memfd.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "crosvm.h"
+
+#ifndef F_LINUX_SPECIFIC_BASE
+#define F_LINUX_SPECIFIC_BASE 1024
+#endif
+
+#ifndef F_ADD_SEALS
+#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
+#endif
+
+#ifndef F_SEAL_SHRINK
+#define F_SEAL_SHRINK 0x0002
+#endif
+
+#define LOAD_ADDRESS 0x1000
+#define SI_ADDRESS 0x8000
+#define BL_VALUE 0x12
+#define KILL_ADDRESS 0x9000
+
+int g_kill_evt;
+
+void *vcpu_thread(void *arg) {
+    struct crosvm_vcpu *vcpu = arg;
+    struct crosvm_vcpu_event evt;
+    int i = 0;
+    while (crosvm_vcpu_wait(vcpu, &evt) == 0) {
+        if (evt.kind == CROSVM_VCPU_EVENT_KIND_INIT) {
+            struct kvm_sregs sregs;
+            crosvm_vcpu_get_sregs(vcpu, &sregs);
+            sregs.cs.base = 0;
+            sregs.cs.selector = 0;
+            sregs.es.base = KILL_ADDRESS;
+            sregs.es.selector = 0;
+            crosvm_vcpu_set_sregs(vcpu, &sregs);
+
+            struct kvm_regs regs;
+            crosvm_vcpu_get_regs(vcpu, &regs);
+            regs.rflags = 2;
+            regs.rip = LOAD_ADDRESS;
+            regs.rbx = BL_VALUE;
+            regs.rsi = SI_ADDRESS;
+            crosvm_vcpu_set_regs(vcpu, &regs);
+        }
+
+        if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
+            evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
+            evt.io_access.address == KILL_ADDRESS &&
+            evt.io_access.is_write &&
+            evt.io_access.length == 1 &&
+            evt.io_access.data[0] == 1)
+        {
+            uint64_t dummy = 1;
+            write(g_kill_evt, &dummy, sizeof(dummy));
+            return NULL;
+        }
+
+        crosvm_vcpu_resume(vcpu);
+    }
+
+    return NULL;
+}
+
+int main(int argc, char** argv) {
+    const uint8_t code[] = {
+    /*
+    0000  881C          mov [si],bl
+    0014  26C606000001  mov byte [es:0x0],0x1
+    0002  F4            hlt
+    */
+        0x88, 0x1c, 0x26, 0xc6, 0x06, 0x00, 0x00, 0x01, 0xf4
+    };
+
+    struct crosvm *crosvm;
+    int ret = crosvm_connect(&crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to connect to crosvm: %d\n", ret);
+        return 1;
+    }
+
+    g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
+    if (g_kill_evt < 0) {
+        fprintf(stderr, "failed to get kill eventfd: %d\n", g_kill_evt);
+        return 1;
+    }
+
+    ret = crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
+    if (ret) {
+        fprintf(stderr, "failed to reserve mmio range: %d\n", ret);
+        return 1;
+    }
+
+    int mem_size = 0x9000;
+    int mem_fd = syscall(SYS_memfd_create, "guest_mem", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+    if (mem_fd < 0) {
+        fprintf(stderr, "failed to create guest memfd: %d\n", errno);
+        return 1;
+    }
+    ret = ftruncate(mem_fd, mem_size);
+    if (ret) {
+        fprintf(stderr, "failed to set size of guest memory: %d\n", errno);
+        return 1;
+    }
+    uint8_t *mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0);
+    if (mem == MAP_FAILED) {
+        fprintf(stderr, "failed to mmap guest memory: %d\n", errno);
+        return 1;
+    }
+    fcntl(mem_fd, F_ADD_SEALS, F_SEAL_SHRINK);
+    memcpy(mem + LOAD_ADDRESS, code, sizeof(code));
+
+    struct crosvm_memory *mem_obj;
+    ret = crosvm_create_memory(crosvm, mem_fd, 0, mem_size, 0, false, true, &mem_obj);
+    if (ret) {
+        fprintf(stderr, "failed to create memory in crosvm: %d\n", ret);
+        return 1;
+    }
+
+    struct crosvm_vcpu *vcpus[32];
+    pthread_t vcpu_threads[32];
+    uint32_t vcpu_count;
+    for (vcpu_count = 0; vcpu_count < 32; vcpu_count++) {
+        ret = crosvm_get_vcpu(crosvm, vcpu_count, &vcpus[vcpu_count]);
+        if (ret == -ENOENT)
+            break;
+
+        if (ret) {
+            fprintf(stderr, "error while getting all vcpus: %d\n", ret);
+            return 1;
+        }
+        pthread_create(&vcpu_threads[vcpu_count], NULL, vcpu_thread, vcpus[vcpu_count]);
+    }
+
+    ret = crosvm_start(crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to tell crosvm to start: %d\n", ret);
+        return 1;
+    }
+
+    uint64_t dummy;
+    read(g_kill_evt, &dummy, 8);
+
+    uint8_t dirty_log[2] = {0};
+    ret = crosvm_memory_get_dirty_log(crosvm, mem_obj, dirty_log);
+    if (ret) {
+        fprintf(stderr, "failed to get dirty log: %d\n", ret);
+        return 1;
+    }
+
+    if (dirty_log[1] != 0x1) {
+        fprintf(stderr, "dirty log does not have expected bits: %x\n", dirty_log[1]);
+        return 1;
+    }
+
+    uint64_t val = *(uint64_t*)(&mem[SI_ADDRESS]);
+    if (val != BL_VALUE) {
+        fprintf(stderr, "memory does not have expected value %d\n", val);
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/tests/plugin_extensions.c b/tests/plugin_extensions.c
new file mode 100644
index 0000000..4e3ea87
--- /dev/null
+++ b/tests/plugin_extensions.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/memfd.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "crosvm.h"
+
+int main(int argc, char** argv) {
+    struct crosvm *crosvm;
+    int ret = crosvm_connect(&crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to connect to crosvm: %d\n", ret);
+        return 1;
+    }
+
+    bool supported;
+    ret = crosvm_check_extension(crosvm, KVM_CAP_IRQCHIP, &supported);
+    if (ret) {
+        fprintf(stderr, "failed to check for KVM extension: %d\n", ret);
+        return 1;
+    }
+    if (!supported) {
+        fprintf(stderr, "expected KVM extension to be supported\n");
+        return 1;
+    }
+
+    // Assume s390 extensions aren't supported because we shouldn't be running on one.
+    ret = crosvm_check_extension(crosvm, KVM_CAP_S390_PSW, &supported);
+    if (ret) {
+        fprintf(stderr, "failed to check for KVM extension: %d\n", ret);
+        return 1;
+    }
+    if (supported) {
+        fprintf(stderr, "unexpected KVM extension is supported\n");
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/tests/plugin_ioevent.c b/tests/plugin_ioevent.c
new file mode 100644
index 0000000..2a0eca9
--- /dev/null
+++ b/tests/plugin_ioevent.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/memfd.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "crosvm.h"
+
+#ifndef F_LINUX_SPECIFIC_BASE
+#define F_LINUX_SPECIFIC_BASE 1024
+#endif
+
+#ifndef F_ADD_SEALS
+#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
+#endif
+
+#ifndef F_SEAL_SHRINK
+#define F_SEAL_SHRINK 0x0002
+#endif
+
+#define LOAD_ADDRESS 0x1000
+#define DATAMATCH_VAL 0x88
+#define KILL_ADDRESS 0x4000
+
+int g_kill_evt;
+
+void *vcpu_thread(void *arg) {
+    struct crosvm_vcpu *vcpu = arg;
+    struct crosvm_vcpu_event evt;
+    int i = 0;
+    while (crosvm_vcpu_wait(vcpu, &evt) == 0) {
+        if (evt.kind == CROSVM_VCPU_EVENT_KIND_INIT) {
+            struct kvm_sregs sregs;
+            crosvm_vcpu_get_sregs(vcpu, &sregs);
+            sregs.cs.base = 0;
+            sregs.cs.selector = 0;
+            sregs.es.base = KILL_ADDRESS;
+            sregs.es.selector = 0;
+            crosvm_vcpu_set_sregs(vcpu, &sregs);
+
+            struct kvm_regs regs;
+            crosvm_vcpu_get_regs(vcpu, &regs);
+            regs.rflags = 2;
+            regs.rip = LOAD_ADDRESS;
+            regs.rax = DATAMATCH_VAL;
+            regs.rbx = DATAMATCH_VAL - 1;
+            crosvm_vcpu_set_regs(vcpu, &regs);
+        }
+
+        if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
+            evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
+            evt.io_access.address == KILL_ADDRESS &&
+            evt.io_access.is_write &&
+            evt.io_access.length == 1 &&
+            evt.io_access.data[0] == 1)
+        {
+            uint64_t dummy = 1;
+            write(g_kill_evt, &dummy, sizeof(dummy));
+            return NULL;
+        }
+
+        crosvm_vcpu_resume(vcpu);
+    }
+
+    return NULL;
+}
+
+int main(int argc, char** argv) {
+    const uint8_t code[] = {
+    /*
+    0000  BAF803        mov dx,0x3f8
+    0003  88C3          mov bl,al
+    0005  EE            out dx,al
+    0006  B000          mov al,0x0
+    0008  EE            out dx,al
+    0009  88D8          mov al,bl
+    000B  EE            out dx,al
+    0014  26C606000001  mov byte [es:0x0],0x1
+    000C  F4            hlt
+    */
+        0xba, 0xf8, 0x03,
+        0x88, 0xc3,
+        0xee,
+        0xb0, 0x00,
+        0xee,
+        0x88, 0xd8,
+        0xee,
+        0x26, 0xc6, 0x06, 0x00, 0x00, 0x01,
+        0xf4,
+    };
+
+    struct crosvm *crosvm;
+    int ret = crosvm_connect(&crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to connect to crosvm: %d\n", ret);
+        return 1;
+    }
+
+    g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
+    if (g_kill_evt < 0) {
+        fprintf(stderr, "failed to get kill eventfd: %d\n", g_kill_evt);
+        return 1;
+    }
+
+    ret = crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
+    if (ret) {
+        fprintf(stderr, "failed to reserve mmio range: %d\n", ret);
+        return 1;
+    }
+
+    uint8_t datamatch = DATAMATCH_VAL;
+    struct crosvm_io *io;
+    ret = crosvm_create_io_event(crosvm, CROSVM_ADDRESS_SPACE_IOPORT, 0x3f8, 1, &datamatch, &io);
+    if (ret) {
+        fprintf(stderr, "failed to create ioevent: %d\n", ret);
+        return 1;
+    }
+
+    int ioeventfd = crosvm_io_event_fd(io);
+
+    int mem_size = 0x4000;
+    int mem_fd = syscall(SYS_memfd_create, "guest_mem", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+    if (mem_fd < 0) {
+        fprintf(stderr, "failed to create guest memfd: %d\n", errno);
+        return 1;
+    }
+    ret = ftruncate(mem_fd, mem_size);
+    if (ret) {
+        fprintf(stderr, "failed to set size of guest memory: %d\n", errno);
+        return 1;
+    }
+    uint8_t *mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0);
+    if (mem == MAP_FAILED) {
+        fprintf(stderr, "failed to mmap guest memory: %d\n", errno);
+        return 1;
+    }
+    fcntl(mem_fd, F_ADD_SEALS, F_SEAL_SHRINK);
+    memcpy(mem + LOAD_ADDRESS, code, sizeof(code));
+
+    struct crosvm_memory *mem_obj;
+    ret = crosvm_create_memory(crosvm, mem_fd, 0, mem_size, 0, false, false, &mem_obj);
+    if (ret) {
+        fprintf(stderr, "failed to create memory in crosvm: %d\n", ret);
+        return 1;
+    }
+
+    /* get and creat a thread for each vcpu */
+    struct crosvm_vcpu *vcpus[32];
+    pthread_t vcpu_threads[32];
+    uint32_t vcpu_count;
+    for (vcpu_count = 0; vcpu_count < 32; vcpu_count++) {
+        ret = crosvm_get_vcpu(crosvm, vcpu_count, &vcpus[vcpu_count]);
+        if (ret == -ENOENT)
+            break;
+
+        if (ret) {
+            fprintf(stderr, "error while getting all vcpus: %d\n", ret);
+            return 1;
+        }
+        pthread_create(&vcpu_threads[vcpu_count], NULL, vcpu_thread, vcpus[vcpu_count]);
+    }
+
+    ret = crosvm_start(crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to tell crosvm to start: %d\n", ret);
+        return 1;
+    }
+
+    uint64_t dummy;
+    read(g_kill_evt, &dummy, 8);
+
+    ret = read(ioeventfd, &dummy, sizeof(dummy));
+    if (ret == -1) {
+        fprintf(stderr, "failed to read ioeventfd: %d\n", errno);
+        return 1;
+    }
+
+    if (dummy != 2) {
+        fprintf(stderr, "ioeventfd was not triggered the expected number of times: %d\n", dummy);
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/tests/plugin_irqfd.c b/tests/plugin_irqfd.c
new file mode 100644
index 0000000..490ebab
--- /dev/null
+++ b/tests/plugin_irqfd.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/memfd.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "crosvm.h"
+
+#ifndef F_LINUX_SPECIFIC_BASE
+#define F_LINUX_SPECIFIC_BASE 1024
+#endif
+
+#ifndef F_ADD_SEALS
+#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
+#endif
+
+#ifndef F_SEAL_SHRINK
+#define F_SEAL_SHRINK 0x0002
+#endif
+
+#define LOAD_ADDRESS 0x1000
+#define STACK_BASE (LOAD_ADDRESS + 0x1000)
+#define STACK_SIZE 0x1000
+#define SUCCESS_ADDRESS 0x3000
+#define KILL_ADDRESS 0x4000
+
+/*
+org 0x1000
+bits 16
+
+cli
+
+; Set entry 0x0 in the interrupt vector table
+mov word [0x0], handle
+mov word [0x2], 0x0
+
+sti
+
+; Loop until interrupt is handled
+loop:
+    cmp byte [si], 0x01
+    jne loop
+
+cli
+
+; Signal that we are ready to end
+end:
+    mov byte [es:0], 0x01
+    hlt
+
+; Handle the interrupt by halting
+handle:
+    mov byte [si], 0x01
+    iret
+*/
+const uint8_t g_code[] = {
+      0xfa, 0xc7, 0x06, 0x00, 0x00, 0x1b, 0x10, 0xc7, 0x06, 0x02, 0x00, 0x00,
+      0x00, 0xfb, 0x80, 0x3c, 0x01, 0x75, 0xfb, 0xfa, 0x26, 0xc6, 0x06, 0x00,
+      0x00, 0x01, 0xf4, 0xc6, 0x04, 0x01, 0xcf
+};
+
+struct vcpu_context {
+    struct crosvm_vcpu *vcpu;
+    int irqeventfd;
+    int kill_evt;
+};
+
+void *vcpu_thread(void *arg) {
+    struct vcpu_context *ctx = arg;
+    struct crosvm_vcpu *vcpu = ctx->vcpu;
+    struct crosvm_vcpu_event evt;
+    uint64_t dummy = 1;
+    int i = 0;
+    int ret;
+    while (crosvm_vcpu_wait(vcpu, &evt) == 0) {
+        if (evt.kind == CROSVM_VCPU_EVENT_KIND_INIT) {
+            struct kvm_sregs sregs;
+            crosvm_vcpu_get_sregs(vcpu, &sregs);
+            sregs.cs.base = 0;
+            sregs.cs.selector = 0x0;
+            sregs.ss.base = 0;
+            sregs.ss.selector = 0x0;
+            sregs.es.base = KILL_ADDRESS;
+            sregs.es.selector = 0x0;
+            crosvm_vcpu_set_sregs(vcpu, &sregs);
+
+            struct kvm_regs regs;
+            crosvm_vcpu_get_regs(vcpu, &regs);
+            regs.rflags = 2;
+            regs.rip = LOAD_ADDRESS;
+            regs.rsp = STACK_BASE + STACK_SIZE;
+            regs.rsi = SUCCESS_ADDRESS;
+            crosvm_vcpu_set_regs(vcpu, &regs);
+
+            write(ctx->irqeventfd, &dummy, sizeof(dummy));
+        }
+
+        if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
+            evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
+            evt.io_access.address == KILL_ADDRESS &&
+            evt.io_access.is_write &&
+            evt.io_access.length == 1 &&
+            evt.io_access.data[0] == 1)
+        {
+            write(ctx->kill_evt, &dummy, sizeof(dummy));
+            return NULL;
+        }
+
+        crosvm_vcpu_resume(vcpu);
+    }
+
+    return NULL;
+}
+
+int main(int argc, char** argv) {
+    int i;
+    uint64_t dummy = 1;
+    struct crosvm *crosvm;
+    int ret = crosvm_connect(&crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to connect to crosvm: %d\n", ret);
+        return 1;
+    }
+
+    int kill_evt = crosvm_get_shutdown_eventfd(crosvm);
+    if (kill_evt < 0) {
+        fprintf(stderr, "failed to get kill eventfd: %d\n", kill_evt);
+        return 1;
+    }
+
+    crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
+
+    struct crosvm_irq *irq;
+    ret = crosvm_create_irq_event(crosvm, 0, &irq);
+    if (ret) {
+        fprintf(stderr, "failed to create irq event: %d\n", ret);
+        return 1;
+    }
+
+    int irqeventfd = crosvm_irq_event_get_fd(irq);
+
+    int mem_size = 0x4000;
+    int mem_fd = syscall(SYS_memfd_create, "guest_mem", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+    if (mem_fd < 0) {
+        fprintf(stderr, "failed to create guest memfd: %d\n", errno);
+        return 1;
+    }
+    ret = ftruncate(mem_fd, mem_size);
+    if (ret) {
+        fprintf(stderr, "failed to set size of guest memory: %d\n", errno);
+        return 1;
+    }
+    uint8_t *mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0);
+    if (mem == MAP_FAILED) {
+        fprintf(stderr, "failed to mmap guest memory: %d\n", errno);
+        return 1;
+    }
+    fcntl(mem_fd, F_ADD_SEALS, F_SEAL_SHRINK);
+    memcpy(mem + LOAD_ADDRESS, g_code, sizeof(g_code));
+
+    struct crosvm_memory *mem_obj;
+    ret = crosvm_create_memory(crosvm, mem_fd, 0, mem_size, 0, false, false, &mem_obj);
+    if (ret) {
+        fprintf(stderr, "failed to create memory in crosvm: %d\n", ret);
+        return 1;
+    }
+
+    struct crosvm_vcpu *vcpus[32];
+    struct vcpu_context ctxs[32];
+    pthread_t vcpu_threads[32];
+    uint32_t vcpu_count;
+    for (vcpu_count = 0; vcpu_count < 32; vcpu_count++) {
+        ret = crosvm_get_vcpu(crosvm, vcpu_count, &vcpus[vcpu_count]);
+        if (ret == -ENOENT)
+            break;
+
+        if (ret) {
+            fprintf(stderr, "error while getting all vcpus: %d\n", ret);
+            return 1;
+        }
+        ctxs[vcpu_count].vcpu = vcpus[vcpu_count];
+        ctxs[vcpu_count].irqeventfd = irqeventfd;
+        ctxs[vcpu_count].kill_evt = kill_evt;
+        pthread_create(&vcpu_threads[vcpu_count], NULL, vcpu_thread, &ctxs[vcpu_count]);
+    }
+
+    ret = crosvm_start(crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to tell crosvm to start: %d\n", ret);
+        return 1;
+    }
+
+    ret = read(kill_evt, &dummy, sizeof(dummy));
+    if (ret == -1) {
+        fprintf(stderr, "failed to read kill eventfd: %d\n", errno);
+        return 1;
+    }
+
+    if (mem[SUCCESS_ADDRESS] != 0x01) {
+        fprintf(stderr, "interrupt was not handled: 0x%x\n", mem[SUCCESS_ADDRESS]);
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/tests/plugin_msr_index_list.c b/tests/plugin_msr_index_list.c
new file mode 100644
index 0000000..0a940ae
--- /dev/null
+++ b/tests/plugin_msr_index_list.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "crosvm.h"
+
+int main(int argc, char** argv) {
+    struct crosvm *crosvm;
+    int ret = crosvm_connect(&crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to connect to crosvm: %d\n", ret);
+        return 1;
+    }
+
+    uint32_t msr_indices[256];
+    int n_entries;
+    ret = crosvm_get_msr_index_list(crosvm, 1, msr_indices, &n_entries);
+    if (ret >= 0) {
+        fprintf(stderr,
+                "expected crosvm_get_msr_index_list to fail with E2BIG\n");
+        return 1;
+    }
+
+
+    memset(msr_indices, 0, sizeof(msr_indices));
+    ret = crosvm_get_msr_index_list(crosvm, 256, msr_indices, &n_entries);
+    if (ret < 0) {
+        fprintf(stderr,
+                "unexpected failure of crosvm_get_msr_index_list: %d\n", ret);
+        return 1;
+    }
+
+    if (n_entries <= 1) {
+        fprintf(stderr,
+                "unexpected number of supported msr entries: %d\n",
+                n_entries);
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/tests/plugin_net_config.c b/tests/plugin_net_config.c
new file mode 100644
index 0000000..f11fa10
--- /dev/null
+++ b/tests/plugin_net_config.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <arpa/inet.h>
+#include <linux/if_tun.h>
+#include <sys/ioctl.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "crosvm.h"
+
+/*
+ * These must match the network arguments supplied to the plugin in plugins.rs.
+ * IPv4 addresses here are in host-native byte order.
+ */
+const uint32_t expected_ip = 0x64735c05; // 100.115.92.5
+const uint32_t expected_netmask = 0xfffffffc; // 255.255.255.252
+const uint8_t expected_mac[] = {0xde, 0x21, 0xe8, 0x47, 0x6b, 0x6a};
+
+int main(int argc, char** argv) {
+    struct crosvm *crosvm;
+    struct crosvm_net_config net_config;
+    int ret = crosvm_connect(&crosvm);
+
+    if (ret) {
+        fprintf(stderr, "failed to connect to crosvm: %d\n", ret);
+        return 1;
+    }
+
+    ret = crosvm_net_get_config(crosvm, &net_config);
+    if (ret) {
+        fprintf(stderr, "failed to get crosvm net config: %d\n", ret);
+        return 1;
+    }
+
+    if (net_config.tap_fd < 0) {
+        fprintf(stderr, "fd %d is < 0\n", net_config.tap_fd);
+        return 1;
+    }
+
+    unsigned int features;
+    if (ioctl(net_config.tap_fd, TUNGETFEATURES, &features) < 0) {
+        fprintf(stderr,
+                "failed to read tap features: %s\n",
+                strerror(errno));
+        return 1;
+    }
+
+    if (net_config.host_ip != htonl(expected_ip)) {
+        char ip_addr[INET_ADDRSTRLEN];
+        inet_ntop(AF_INET, &net_config.host_ip, ip_addr, sizeof(ip_addr));
+        fprintf(stderr, "ip %s != 100.115.92.5\n", ip_addr);
+        return 1;
+    }
+
+    if (net_config.netmask != htonl(expected_netmask)) {
+        char netmask[INET_ADDRSTRLEN];
+        inet_ntop(AF_INET, &net_config.netmask, netmask, sizeof(netmask));
+        fprintf(stderr, "netmask %s != 255.255.255.252\n", netmask);
+        return 1;
+    }
+
+    if (memcmp(net_config.host_mac_address,
+               expected_mac,
+               sizeof(expected_mac)) != 0) {
+        fprintf(stderr,
+                "mac %02X:%02X:%02X:%02X:%02X:%02X != de:21:e8:47:6b:6a\n",
+                net_config.host_mac_address[0],
+                net_config.host_mac_address[1],
+                net_config.host_mac_address[2],
+                net_config.host_mac_address[3],
+                net_config.host_mac_address[4],
+                net_config.host_mac_address[5]);
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/tests/plugin_supported_cpuid.c b/tests/plugin_supported_cpuid.c
new file mode 100644
index 0000000..0acb134
--- /dev/null
+++ b/tests/plugin_supported_cpuid.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "crosvm.h"
+
+int main(int argc, char** argv) {
+    struct crosvm *crosvm;
+    int ret = crosvm_connect(&crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to connect to crosvm: %d\n", ret);
+        return 1;
+    }
+
+    struct kvm_cpuid_entry2 cpuids[100];
+    int n_entries;
+    ret = crosvm_get_supported_cpuid(crosvm, 1, cpuids, &n_entries);
+    if (ret >= 0) {
+        fprintf(stderr,
+                "expected crosvm_get_supported_cpuids to fail with E2BIG\n");
+        return 1;
+    }
+
+    ret = crosvm_get_supported_cpuid(crosvm, 100, cpuids, &n_entries);
+    if (ret < 0) {
+        fprintf(stderr,
+                "unexpected failure of crosvm_get_supported_cpuids: %d\n", ret);
+        return 1;
+    }
+
+    if (n_entries <= 1) {
+        fprintf(stderr,
+                "unexpected number of supported cpuid entries: %d\n",
+                n_entries);
+        return 1;
+    }
+
+    ret = crosvm_get_emulated_cpuid(crosvm, 1, cpuids, &n_entries);
+    if (ret >= 0) {
+        fprintf(stderr,
+                "expected crosvm_get_emulated_cpuids to fail with E2BIG\n");
+        return 1;
+    }
+
+    ret = crosvm_get_emulated_cpuid(crosvm, 100, cpuids, &n_entries);
+    if (ret < 0) {
+        fprintf(stderr,
+                "unexpected failure of crosvm_get_emulated_cpuid: %d\n", ret);
+        return 1;
+    }
+
+    if (n_entries < 1) {
+        fprintf(stderr,
+                "unexpected number of emulated cpuid entries: %d\n", n_entries);
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/tests/plugin_vcpu_pause.c b/tests/plugin_vcpu_pause.c
new file mode 100644
index 0000000..ff69b04
--- /dev/null
+++ b/tests/plugin_vcpu_pause.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/memfd.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "crosvm.h"
+
+#ifndef F_LINUX_SPECIFIC_BASE
+#define F_LINUX_SPECIFIC_BASE 1024
+#endif
+
+#ifndef F_ADD_SEALS
+#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
+#endif
+
+#ifndef F_SEAL_SHRINK
+#define F_SEAL_SHRINK 0x0002
+#endif
+
+#define SERIAL_ADDRESS 0x3f8
+#define KILL_ADDRESS 0x3f9
+
+static char g_serial_out[16];
+static int g_kill_evt;
+
+static bool g_paused;
+static bool g_exit_loop;
+static pthread_mutex_t g_pause_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t g_pause_cond = PTHREAD_COND_INITIALIZER;
+
+static volatile int count;
+
+static void *vcpu_thread_fn(void *arg) {
+    struct crosvm_vcpu *vcpu = arg;
+    struct crosvm_vcpu_event evt;
+    int i = 0;
+
+    while (crosvm_vcpu_wait(vcpu, &evt) == 0) {
+        if (evt.kind == CROSVM_VCPU_EVENT_KIND_INIT) {
+            struct kvm_sregs sregs;
+            crosvm_vcpu_get_sregs(vcpu, &sregs);
+            sregs.cs.base = 0;
+            sregs.cs.selector = 0;
+            sregs.es.base = KILL_ADDRESS;
+            sregs.es.selector = 0;
+            crosvm_vcpu_set_sregs(vcpu, &sregs);
+
+            struct kvm_regs regs;
+            crosvm_vcpu_get_regs(vcpu, &regs);
+            regs.rip = 0x1000;
+            regs.rax = 2;
+            regs.rbx = 7;
+            regs.rflags = 2;
+            crosvm_vcpu_set_regs(vcpu, &regs);
+
+            /* Signal the main thread that init is done */
+            uint64_t dummy = 1;
+            write(g_kill_evt, &dummy, sizeof(dummy));
+        }
+        else if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
+                 evt.io_access.address_space == CROSVM_ADDRESS_SPACE_IOPORT &&
+                 evt.io_access.address == KILL_ADDRESS &&
+                 evt.io_access.is_write &&
+                 evt.io_access.length == 1 &&
+                 evt.io_access.data[0] == 1) {
+            uint64_t dummy = 1;
+            write(g_kill_evt, &dummy, sizeof(dummy));
+            return NULL;
+        }
+        else if (evt.kind == CROSVM_VCPU_EVENT_KIND_PAUSED) {
+            /* Signal that we paused */
+            uint64_t dummy = 1;
+            write(g_kill_evt, &dummy, sizeof(dummy));
+
+            /* Wait till we can continue again */
+            pthread_mutex_lock(&g_pause_mutex);
+            while (g_paused)
+                pthread_cond_wait(&g_pause_cond, &g_pause_mutex);
+
+            /* Kick the VM from infinite loop if requested */
+            if (g_exit_loop) {
+                struct kvm_regs regs;
+                crosvm_vcpu_get_regs(vcpu, &regs);
+                regs.rbx = 1;
+                crosvm_vcpu_set_regs(vcpu, &regs);
+            }
+
+            /* Signal that we are no longer paused */
+            write(g_kill_evt, &dummy, sizeof(dummy));
+
+            pthread_mutex_unlock(&g_pause_mutex);
+        }
+        crosvm_vcpu_resume(vcpu);
+    }
+
+    return NULL;
+}
+
+static int signal_pause(struct crosvm *crosvm) {
+    pthread_mutex_lock(&g_pause_mutex);
+    g_paused = true;
+    pthread_mutex_unlock(&g_pause_mutex);
+
+    return crosvm_pause_vcpus(crosvm, 1, NULL);
+}
+
+static void signal_unpause(struct crosvm *crosvm, bool exit_loop) {
+    pthread_mutex_lock(&g_pause_mutex);
+    g_paused = false;
+    g_exit_loop = exit_loop;
+    pthread_cond_broadcast(&g_pause_cond);
+    pthread_mutex_unlock(&g_pause_mutex);
+}
+
+int main(int argc, char** argv) {
+    const uint8_t code[] = {
+    /*
+    0000  00D8    add al,bl
+    0002  80FB01  cmp bl, 0x1
+    0005  75F9    jne 0x0
+    0007  BAF903  mov dx,0x3f8
+    000A  B001    mov al,0x1
+    000C  EE      out dx,al
+    000D  F4      hlt
+    */
+        0x00, 0xd8,
+        0x80, 0xfb, 0x01,
+        0x75, 0xf9,
+        0xba, 0xf9, 0x03,
+        0xb0, 0x01,
+        0xee,
+        0xf4
+    };
+
+    struct crosvm *crosvm;
+    int ret = crosvm_connect(&crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to connect to crosvm: %d\n", ret);
+        return 1;
+    }
+
+    /* We needs this eventfd to know when to exit before being killed. */
+    g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
+    if (g_kill_evt < 0) {
+        fprintf(stderr, "failed to get kill eventfd: %d\n", g_kill_evt);
+        return 1;
+    }
+
+    ret = crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_IOPORT,
+                               KILL_ADDRESS, 1);
+    if (ret) {
+        fprintf(stderr, "failed to reserve mmio range: %d\n", ret);
+        return 1;
+    }
+
+    int mem_size = 0x2000;
+    int mem_fd = syscall(SYS_memfd_create,
+                         "guest_mem", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+    if (mem_fd < 0) {
+        fprintf(stderr, "failed to create guest memfd: %d\n", errno);
+        return 1;
+    }
+    ret = ftruncate(mem_fd, mem_size);
+    if (ret) {
+        fprintf(stderr, "failed to set size of guest memory: %d\n", errno);
+        return 1;
+    }
+    uint8_t *mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                        mem_fd, 0x1000);
+    if (mem == MAP_FAILED) {
+        fprintf(stderr, "failed to mmap guest memory: %d\n", errno);
+        return 1;
+    }
+    fcntl(mem_fd, F_ADD_SEALS, F_SEAL_SHRINK);
+    memcpy(mem, code, sizeof(code));
+
+    struct crosvm_memory *mem_obj;
+    ret = crosvm_create_memory(crosvm, mem_fd, 0x1000, 0x1000, 0x1000,
+                               false, false, &mem_obj);
+    if (ret) {
+        fprintf(stderr, "failed to create memory in crosvm: %d\n", ret);
+        return 1;
+    }
+
+    /* get and create a thread for the vcpu */
+    struct crosvm_vcpu *vcpu;
+    ret = crosvm_get_vcpu(crosvm, 0, &vcpu);
+    if (ret) {
+       fprintf(stderr, "error while getting vcpu: %d\n", ret);
+       return 1;
+    }
+
+    pthread_t vcpu_thread;
+    ret = pthread_create(&vcpu_thread, NULL, vcpu_thread_fn, vcpu);
+    if (ret) {
+        fprintf(stderr, "failed to createvcpu thread\n");
+        return 1;
+    }
+
+    ret = crosvm_start(crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to tell crosvm to start: %d\n", ret);
+        return 1;
+    }
+
+    /* Wait till VCPU thread tells us that its initialization is done */
+    uint64_t dummy;
+    read(g_kill_evt, &dummy, sizeof(dummy));
+
+    ret = signal_pause(crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to pause vcpus (1st time): %d\n", ret);
+        return 1;
+    }
+
+    /* Wait till VCPU thread tells us it is paused */
+    read(g_kill_evt, &dummy, sizeof(dummy));
+
+    /* Try pausing VCPUs 2nd time to make sure we do not deadlock */
+    ret = signal_pause(crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to pause vcpus (2nd time): %d\n", ret);
+        return 1;
+    }
+
+    signal_unpause(crosvm, false);
+
+    /* Wait until VCPU thread tells us that it is no longer paused */
+    read(g_kill_evt, &dummy, sizeof(dummy));
+
+    /*
+     * Try pausing VCPUs 3rd time to see if we will miss pause
+     * request as we are exiting previous pause.
+     */
+    ret = signal_pause(crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to pause vcpus (2nd time): %d\n", ret);
+        return 1;
+    }
+
+    signal_unpause(crosvm, true);
+
+    /* Wait until VCPU thread tells us that it is no longer paused */
+    read(g_kill_evt, &dummy, sizeof(dummy));
+
+    /* Wait for crosvm to request that we exit otherwise we will be killed. */
+    read(g_kill_evt, &dummy, sizeof(dummy));
+
+    ret = crosvm_destroy_memory(crosvm, &mem_obj);
+    if (ret) {
+        fprintf(stderr, "failed to destroy memory in crosvm: %d\n", ret);
+        return 1;
+    }
+
+    ret = crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_IOPORT,
+                               KILL_ADDRESS, 0);
+    if (ret) {
+        fprintf(stderr, "failed to unreserve mmio range: %d\n", ret);
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/tests/plugin_vm_state.c b/tests/plugin_vm_state.c
new file mode 100644
index 0000000..450d324
--- /dev/null
+++ b/tests/plugin_vm_state.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "crosvm.h"
+
+int main(int argc, char** argv) {
+    struct crosvm *crosvm;
+    int ret = crosvm_connect(&crosvm);
+    if (ret) {
+        fprintf(stderr, "failed to connect to crosvm: %d\n", ret);
+        return 1;
+    }
+
+    struct kvm_pic_state pic_state;
+    ret = crosvm_get_pic_state(crosvm, false, &pic_state);
+    if (ret < 0) {
+        fprintf(stderr, "failed to get initial PIC1 state: %d\n", ret);
+        return 1;
+    }
+
+    if (pic_state.auto_eoi) {
+        fprintf(stderr, "unexpected value of auto_eoi flag\n");
+        return 1;
+    }
+
+    pic_state.auto_eoi = true;
+    ret = crosvm_set_pic_state(crosvm, false, &pic_state);
+    if (ret < 0) {
+        fprintf(stderr, "failed to update PIC1 state: %d\n", ret);
+        return 1;
+    }
+
+    ret = crosvm_get_pic_state(crosvm, false, &pic_state);
+    if (ret < 0) {
+        fprintf(stderr, "failed to get updated PIC1 state: %d\n", ret);
+        return 1;
+    }
+
+    if (!pic_state.auto_eoi) {
+        fprintf(stderr, "unexpected value of auto_eoi flag after update\n");
+        return 1;
+    }
+
+    // Test retrieving and setting IOAPIC state.
+    struct kvm_ioapic_state ioapic_state;
+    ret = crosvm_get_ioapic_state(crosvm, &ioapic_state);
+    if (ret < 0) {
+        fprintf(stderr, "failed to get initial PIC1 state: %d\n", ret);
+        return 1;
+    }
+
+    fprintf(stderr, "IOAPIC ID: %d\n", ioapic_state.id);
+
+    if (ioapic_state.id != 0) {
+        fprintf(stderr, "unexpected value of IOAPIC ID: %d\n", ioapic_state.id);
+        return 1;
+    }
+
+    ioapic_state.id = 1;
+    ret = crosvm_set_ioapic_state(crosvm, &ioapic_state);
+    if (ret < 0) {
+        fprintf(stderr, "failed to update PIC1 state: %d\n", ret);
+        return 1;
+    }
+
+    ret = crosvm_get_ioapic_state(crosvm, &ioapic_state);
+    if (ret < 0) {
+        fprintf(stderr, "failed to get updated PIC1 state: %d\n", ret);
+        return 1;
+    }
+
+    if (ioapic_state.id != 1) {
+        fprintf(stderr, "unexpected value of IOAPIC ID after update: %d\n",
+                ioapic_state.id);
+        return 1;
+    }
+
+    // Test retrieving and setting PIT state.
+    struct kvm_pit_state2 pit_state;
+    ret = crosvm_get_pit_state(crosvm, &pit_state);
+    if (ret < 0) {
+        fprintf(stderr, "failed to get initial PIT state: %d\n", ret);
+        return 1;
+    }
+
+    if (pit_state.flags & KVM_PIT_FLAGS_HPET_LEGACY) {
+        fprintf(stderr, "unexpected value of KVM_PIT_FLAGS_HPET_LEGACY flag\n");
+        return 1;
+    }
+
+    pit_state.flags |= KVM_PIT_FLAGS_HPET_LEGACY;
+    ret = crosvm_set_pit_state(crosvm, &pit_state);
+    if (ret < 0) {
+        fprintf(stderr, "failed to update PIT state: %d\n", ret);
+        return 1;
+    }
+
+    ret = crosvm_get_pit_state(crosvm, &pit_state);
+    if (ret < 0) {
+        fprintf(stderr, "failed to get updated PIT state: %d\n", ret);
+        return 1;
+    }
+
+    if (!(pit_state.flags & KVM_PIT_FLAGS_HPET_LEGACY)) {
+        fprintf(stderr,
+                "unexpected value of KVM_PIT_FLAGS_HPET_LEGACY after update\n");
+        return 1;
+    }
+
+    // Test retrieving and setting clock state.
+    struct kvm_clock_data clock_data = { .clock = 0, .flags = -1U, };
+    ret = crosvm_get_clock(crosvm, &clock_data);
+    if (ret < 0) {
+        fprintf(stderr, "failed to get initial clock state: %d\n", ret);
+        return 1;
+    }
+
+    if (clock_data.clock == 0 || clock_data.flags != 0) {
+        fprintf(stderr, "invalid clock data returned (%llu, %u)\n",
+                clock_data.clock, clock_data.flags);
+    }
+
+    clock_data.clock += 10000000;
+
+    ret = crosvm_set_clock(crosvm, &clock_data);
+    if (ret < 0) {
+        fprintf(stderr, "failed to update clock: %d\n", ret);
+        return 1;
+    }
+
+    clock_data.flags = -1U;
+    ret = crosvm_set_clock(crosvm, &clock_data);
+    if (ret >= 0) {
+        fprintf(stderr, "unexpected success updating clock\n");
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/tests/plugins.rs b/tests/plugins.rs
new file mode 100644
index 0000000..ec094d1
--- /dev/null
+++ b/tests/plugins.rs
@@ -0,0 +1,708 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![cfg(feature = "plugin")]
+
+use std::env::{current_exe, var_os};
+use std::ffi::OsString;
+use std::fs::{remove_file, File};
+use std::io::{Read, Write};
+use std::os::unix::io::AsRawFd;
+use std::path::{Path, PathBuf};
+use std::process::{Command, Stdio};
+use std::thread::sleep;
+use std::time::Duration;
+
+use rand_ish::urandom_str;
+use sys_util::{ioctl, SharedMemory};
+
+struct RemovePath(PathBuf);
+impl Drop for RemovePath {
+    fn drop(&mut self) {
+        if let Err(e) = remove_file(&self.0) {
+            eprintln!("failed to remove path: {}", e);
+        }
+    }
+}
+
+fn get_target_path() -> PathBuf {
+    current_exe()
+        .ok()
+        .map(|mut path| {
+            path.pop();
+            path
+        })
+        .expect("failed to get crosvm binary directory")
+}
+
+fn get_crosvm_path() -> PathBuf {
+    current_exe()
+        .ok()
+        .map(|mut path| {
+            path.pop();
+            if path.ends_with("deps") {
+                path.pop();
+            }
+            path
+        })
+        .expect("failed to get crosvm binary directory")
+}
+
+fn build_plugin(src: &str) -> RemovePath {
+    let libcrosvm_plugin_dir = get_target_path();
+    let mut out_bin = libcrosvm_plugin_dir.clone();
+    let randbin = urandom_str(10).expect("failed to generate random bin name");
+    out_bin.push(randbin);
+    let mut child = Command::new(var_os("CC").unwrap_or(OsString::from("cc")))
+        .args(&["-Icrosvm_plugin", "-pthread", "-o"]) // crosvm.h location and set output path.
+        .arg(&out_bin)
+        .arg("-L") // Path of shared object to link to.
+        .arg(&libcrosvm_plugin_dir)
+        .arg("-lcrosvm_plugin")
+        .arg("-Wl,-rpath") // Search for shared object in the same path when exec'd.
+        .arg(&libcrosvm_plugin_dir)
+        .args(&["-Wl,-rpath", "."]) // Also check current directory in case of sandboxing.
+        .args(&["-xc", "-"]) // Read source code from piped stdin.
+        .stdin(Stdio::piped())
+        .spawn()
+        .expect("failed to spawn compiler");
+    let stdin = child.stdin.as_mut().expect("failed to open stdin");
+    stdin
+        .write_all(src.as_bytes())
+        .expect("failed to write source to stdin");
+
+    let status = child.wait().expect("failed to wait for compiler");
+    assert!(status.success(), "failed to build plugin");
+
+    RemovePath(PathBuf::from(out_bin))
+}
+
+fn run_plugin(bin_path: &Path, with_sandbox: bool) {
+    let mut crosvm_path = get_crosvm_path();
+    crosvm_path.push("crosvm");
+    let mut cmd = Command::new(crosvm_path);
+    cmd.args(&[
+        "run",
+        "-c",
+        "1",
+        "--host_ip",
+        "100.115.92.5",
+        "--netmask",
+        "255.255.255.252",
+        "--mac",
+        "de:21:e8:47:6b:6a",
+        "--seccomp-policy-dir",
+        "tests",
+        "--plugin",
+    ])
+    .arg(
+        bin_path
+            .canonicalize()
+            .expect("failed to canonicalize plugin path"),
+    );
+    if !with_sandbox {
+        cmd.arg("--disable-sandbox");
+    }
+
+    let mut child = cmd.spawn().expect("failed to spawn crosvm");
+    for _ in 0..12 {
+        match child.try_wait().expect("failed to wait for crosvm") {
+            Some(status) => {
+                assert!(status.success());
+                return;
+            }
+            None => sleep(Duration::from_millis(100)),
+        }
+    }
+    child.kill().expect("failed to kill crosvm");
+    panic!("crosvm process has timed out");
+}
+
+fn test_plugin(src: &str) {
+    let bin_path = build_plugin(src);
+    // Run with and without the sandbox enabled.
+    run_plugin(&bin_path.0, false);
+    run_plugin(&bin_path.0, true);
+}
+
+fn keep_fd_on_exec<F: AsRawFd>(f: &F) {
+    unsafe {
+        ioctl(f, 0x5450 /* FIONCLEX */);
+    }
+}
+
+/// Takes assembly source code and returns the resulting assembly code.
+fn build_assembly(src: &str) -> Vec<u8> {
+    // Creates a shared memory region with the assembly source code in it.
+    let in_shm = SharedMemory::new(None).unwrap();
+    let mut in_shm_file: File = in_shm.into();
+    keep_fd_on_exec(&in_shm_file);
+    in_shm_file.write_all(src.as_bytes()).unwrap();
+
+    // Creates a shared memory region that will hold the nasm output.
+    let mut out_shm_file: File = SharedMemory::new(None).unwrap().into();
+    keep_fd_on_exec(&out_shm_file);
+
+    // Runs nasm with the input and output files set to the FDs of the above shared memory regions,
+    // which we have preserved accross exec.
+    let status = Command::new("nasm")
+        .arg(format!("/proc/self/fd/{}", in_shm_file.as_raw_fd()))
+        .args(&["-f", "bin", "-o"])
+        .arg(format!("/proc/self/fd/{}", out_shm_file.as_raw_fd()))
+        .status()
+        .expect("failed to spawn assembler");
+    assert!(status.success());
+
+    let mut out_bytes = Vec::new();
+    out_shm_file.read_to_end(&mut out_bytes).unwrap();
+    out_bytes
+}
+
+// Converts the input bytes to an output string in the format "0x01,0x02,0x03...".
+fn format_as_hex(data: &[u8]) -> String {
+    let mut out = String::new();
+    for (i, d) in data.iter().enumerate() {
+        out.push_str(&format!("0x{:02x}", d));
+        if i < data.len() - 1 {
+            out.push(',')
+        }
+    }
+    out
+}
+
+// A testing framework for creating simple plugins.
+struct MiniPlugin {
+    // The size in bytes of the guest memory based at 0x0000.
+    mem_size: u64,
+    // The address in guest memory to load the assembly code.
+    load_address: u32,
+    // The nasm syntax 16-bit assembly code that will assembled and loaded into guest memory.
+    assembly_src: &'static str,
+    // The C source code that will be included in the mini_plugin_template.c file. This code must
+    // define the forward declarations above the {src} line so that the completed plugin source will
+    // compile.
+    src: &'static str,
+}
+
+impl Default for MiniPlugin {
+    fn default() -> Self {
+        MiniPlugin {
+            mem_size: 0x2000,
+            load_address: 0x1000,
+            assembly_src: "hlt",
+            src: "",
+        }
+    }
+}
+
+// Builds and tests the given MiniPlugin definiton.
+fn test_mini_plugin(plugin: &MiniPlugin) {
+    // Adds a preamble to ensure the output opcodes are 16-bit real mode and the lables start at the
+    // load address.
+    let assembly_src = format!(
+        "org 0x{:x}\nbits 16\n{}",
+        plugin.load_address, plugin.assembly_src
+    );
+
+    // Builds the assembly and convert it to a C literal array format.
+    let assembly = build_assembly(&assembly_src);
+    let assembly_hex = format_as_hex(&assembly);
+
+    // Glues the pieces of this plugin together and tests the completed plugin.
+    let generated_src = format!(
+        include_str!("mini_plugin_template.c"),
+        mem_size = plugin.mem_size,
+        load_address = plugin.load_address,
+        assembly_code = assembly_hex,
+        src = plugin.src
+    );
+    test_plugin(&generated_src);
+}
+
+#[test]
+fn test_adder() {
+    test_plugin(include_str!("plugin_adder.c"));
+}
+
+#[test]
+fn test_dirty_log() {
+    test_plugin(include_str!("plugin_dirty_log.c"));
+}
+
+#[test]
+fn test_ioevent() {
+    test_plugin(include_str!("plugin_ioevent.c"));
+}
+
+#[test]
+fn test_irqfd() {
+    test_plugin(include_str!("plugin_irqfd.c"));
+}
+
+#[test]
+fn test_extensions() {
+    test_plugin(include_str!("plugin_extensions.c"));
+}
+
+#[test]
+fn test_supported_cpuid() {
+    test_plugin(include_str!("plugin_supported_cpuid.c"));
+}
+
+#[test]
+fn test_msr_index_list() {
+    test_plugin(include_str!("plugin_msr_index_list.c"));
+}
+
+#[test]
+fn test_vm_state_manipulation() {
+    test_plugin(include_str!("plugin_vm_state.c"));
+}
+
+#[test]
+fn test_vcpu_pause() {
+    test_plugin(include_str!("plugin_vcpu_pause.c"));
+}
+
+#[test]
+fn test_net_config() {
+    test_plugin(include_str!("plugin_net_config.c"));
+}
+
+#[test]
+fn test_debugregs() {
+    let mini_plugin = MiniPlugin {
+        assembly_src: "org 0x1000
+             bits 16
+             mov dr0, ebx
+             mov eax, dr1
+             mov byte [0x3000], 1",
+        src: r#"
+            #define DR1_VALUE 0x12
+            #define RBX_VALUE 0xabcdef00
+            #define KILL_ADDRESS 0x3000
+
+            int g_kill_evt;
+            struct kvm_regs g_regs;
+            struct kvm_debugregs g_dregs;
+
+            int setup_vm(struct crosvm *crosvm, void *mem) {
+                g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
+                crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
+                return 0;
+            }
+
+            int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
+                                 struct kvm_sregs *sregs)
+            {
+                regs->rbx = RBX_VALUE;
+                struct kvm_debugregs dregs;
+                crosvm_vcpu_get_debugregs(vcpu, &dregs);
+                dregs.db[1] = DR1_VALUE;
+                crosvm_vcpu_set_debugregs(vcpu, &dregs);
+                return 0;
+            }
+
+            int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
+                if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
+                        evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
+                        evt.io_access.address == KILL_ADDRESS &&
+                        evt.io_access.is_write &&
+                        evt.io_access.length == 1 &&
+                        evt.io_access.data[0] == 1)
+                {
+                    uint64_t dummy = 1;
+                    crosvm_vcpu_get_debugregs(vcpu, &g_dregs);
+                    crosvm_vcpu_get_regs(vcpu, &g_regs);
+                    write(g_kill_evt, &dummy, sizeof(dummy));
+                    return 1;
+                }
+                return 0;
+            }
+
+            int check_result(struct crosvm *vcpu, void *mem) {
+                if (g_dregs.db[1] != DR1_VALUE) {
+                    fprintf(stderr, "dr1 register has unexpected value: 0x%x\n", g_dregs.db[1]);
+                    return 1;
+                }
+                if (g_dregs.db[0] != RBX_VALUE) {
+                    fprintf(stderr, "dr0 register has unexpected value: 0x%x\n", g_dregs.db[0]);
+                    return 1;
+                }
+                if (g_regs.rax != DR1_VALUE) {
+                    fprintf(stderr, "eax register has unexpected value: 0x%x\n", g_regs.rax);
+                    return 1;
+                }
+                return 0;
+            }"#,
+        ..Default::default()
+    };
+    test_mini_plugin(&mini_plugin);
+}
+
+#[test]
+fn test_xcrs() {
+    let mini_plugin = MiniPlugin {
+        assembly_src: "org 0x1000
+             bits 16
+             mov byte [0x3000], 1",
+        src: r#"
+            #define XCR0_VALUE 0x1
+            #define KILL_ADDRESS 0x3000
+
+            int g_kill_evt;
+            struct kvm_xcrs g_xcrs;
+
+            int setup_vm(struct crosvm *crosvm, void *mem) {
+                g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
+                crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
+                return 0;
+            }
+
+            int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
+                                 struct kvm_sregs *sregs)
+            {
+                struct kvm_xcrs xcrs = {};
+                xcrs.nr_xcrs = 1;
+                xcrs.xcrs[0].value = XCR0_VALUE;
+                crosvm_vcpu_set_xcrs(vcpu, &xcrs);
+                return 0;
+            }
+
+            int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
+                if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
+                        evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
+                        evt.io_access.address == KILL_ADDRESS &&
+                        evt.io_access.is_write &&
+                        evt.io_access.length == 1 &&
+                        evt.io_access.data[0] == 1)
+                {
+                    uint64_t dummy = 1;
+                    crosvm_vcpu_get_xcrs(vcpu, &g_xcrs);
+                    write(g_kill_evt, &dummy, sizeof(dummy));
+                    return 1;
+                }
+                return 0;
+            }
+
+            int check_result(struct crosvm *vcpu, void *mem) {
+                if (g_xcrs.xcrs[0].value != XCR0_VALUE) {
+                    fprintf(stderr, "xcr0 register has unexpected value: 0x%x\n",
+                            g_xcrs.xcrs[0].value);
+                    return 1;
+                }
+                return 0;
+            }"#,
+        ..Default::default()
+    };
+    test_mini_plugin(&mini_plugin);
+}
+
+#[test]
+fn test_msrs() {
+    let mini_plugin = MiniPlugin {
+        assembly_src: "org 0x1000
+             bits 16
+             rdmsr
+             mov [0x0], eax
+             mov [0x4], edx
+             mov ecx, ebx
+             mov eax, [0x8]
+             mov edx, [0xc]
+             wrmsr
+             mov byte [es:0], 1",
+        src: r#"
+            #define MSR1_INDEX 0x00000174
+            #define MSR1_DATA 1
+            #define MSR2_INDEX 0x00000175
+            #define MSR2_DATA 2
+            #define KILL_ADDRESS 0x3000
+
+            int g_kill_evt;
+            uint32_t g_msr2_count;
+            struct kvm_msr_entry g_msr2;
+
+            int setup_vm(struct crosvm *crosvm, void *mem) {
+                g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
+                crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
+                ((uint64_t*)mem)[1] = MSR2_DATA;
+                return 0;
+            }
+
+            int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
+                                 struct kvm_sregs *sregs)
+            {
+                regs->rcx = MSR1_INDEX;
+                regs->rbx = MSR2_INDEX;
+                sregs->es.base = KILL_ADDRESS;
+
+                struct kvm_msr_entry msr1 = {0};
+                msr1.index = MSR1_INDEX;
+                msr1.data = MSR1_DATA;
+                crosvm_vcpu_set_msrs(vcpu, 1, &msr1);
+
+                return 0;
+            }
+
+            int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
+                if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
+                        evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
+                        evt.io_access.address == KILL_ADDRESS &&
+                        evt.io_access.is_write &&
+                        evt.io_access.length == 1 &&
+                        evt.io_access.data[0] == 1)
+                {
+                    uint64_t dummy = 1;
+                    g_msr2.index = MSR2_INDEX;
+                    crosvm_vcpu_get_msrs(vcpu, 1, &g_msr2, &g_msr2_count);
+                    write(g_kill_evt, &dummy, sizeof(dummy));
+                    return 1;
+                }
+                return 0;
+            }
+
+            int check_result(struct crosvm *vcpu, void *mem) {
+                uint64_t msr1_data = ((uint64_t*)mem)[0];
+                if (msr1_data != MSR1_DATA) {
+                    fprintf(stderr, "msr1 has unexpected value: 0x%x\n", msr1_data);
+                    return 1;
+                }
+                if (g_msr2_count != 1) {
+                    fprintf(stderr, "incorrect number of returned MSRSs: %d\n", g_msr2_count);
+                    return 1;
+                }
+                if (g_msr2.data != MSR2_DATA) {
+                    fprintf(stderr, "msr2 has unexpected value: 0x%x\n", g_msr2.data);
+                    return 1;
+                }
+                return 0;
+            }"#,
+        ..Default::default()
+    };
+    test_mini_plugin(&mini_plugin);
+}
+
+#[test]
+fn test_cpuid() {
+    let mini_plugin = MiniPlugin {
+        assembly_src: "org 0x1000
+             bits 16
+             push eax
+             push ecx
+             cpuid
+             mov [0x0], eax
+             mov [0x4], ebx
+             mov [0x8], ecx
+             mov [0xc], edx
+             pop ecx
+             pop eax
+             add ecx, 1
+             cpuid
+             mov [0x10], eax
+             mov [0x14], ebx
+             mov [0x18], ecx
+             mov [0x1c], edx
+             mov byte [es:0], 1",
+        src: r#"
+            #define ENTRY1_INDEX 0
+            #define ENTRY1_EAX 0x40414243
+            #define ENTRY1_EBX 0x50515253
+            #define ENTRY1_ECX 0x60616263
+            #define ENTRY1_EDX 0x71727374
+            #define ENTRY2_INDEX 1
+            #define ENTRY2_EAX 0xAABBCCDD
+            #define ENTRY2_EBX 0xEEFF0011
+            #define ENTRY2_ECX 0x22334455
+            #define ENTRY2_EDX 0x66778899
+            #define KILL_ADDRESS 0x3000
+
+            int g_kill_evt;
+            struct kvm_msr_entry g_msr2;
+
+            int setup_vm(struct crosvm *crosvm, void *mem) {
+                g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
+                crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
+                return 0;
+            }
+
+            int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
+                                 struct kvm_sregs *sregs)
+            {
+                regs->rax = ENTRY1_INDEX;
+                regs->rcx = 0;
+                regs->rsp = 0x1000;
+                sregs->es.base = KILL_ADDRESS;
+
+                struct kvm_cpuid_entry2 entries[2];
+                entries[0].function = 0;
+                entries[0].index = ENTRY1_INDEX;
+                entries[0].flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+                entries[0].eax = ENTRY1_EAX;
+                entries[0].ebx = ENTRY1_EBX;
+                entries[0].ecx = ENTRY1_ECX;
+                entries[0].edx = ENTRY1_EDX;
+                entries[1].function = 0;
+                entries[1].index = ENTRY2_INDEX;
+                entries[1].flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+                entries[1].eax = ENTRY2_EAX;
+                entries[1].ebx = ENTRY2_EBX;
+                entries[1].ecx = ENTRY2_ECX;
+                entries[1].edx = ENTRY2_EDX;
+                return crosvm_vcpu_set_cpuid(vcpu, 2, entries);
+            }
+
+            int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
+                if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
+                        evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
+                        evt.io_access.address == KILL_ADDRESS &&
+                        evt.io_access.is_write &&
+                        evt.io_access.length == 1 &&
+                        evt.io_access.data[0] == 1)
+                {
+                    uint64_t dummy = 1;
+                    write(g_kill_evt, &dummy, sizeof(dummy));
+                    return 1;
+                }
+                return 0;
+            }
+
+            int check_result(struct crosvm *vcpu, void *memory) {
+                uint32_t *mem = (uint32_t*)memory;
+                if (mem[0] != ENTRY1_EAX) {
+                    fprintf(stderr, "entry 1 eax has unexpected value: 0x%x\n", mem[0]);
+                    return 1;
+                }
+                if (mem[1] != ENTRY1_EBX) {
+                    fprintf(stderr, "entry 1 ebx has unexpected value: 0x%x\n", mem[1]);
+                    return 1;
+                }
+                if (mem[2] != ENTRY1_ECX) {
+                    fprintf(stderr, "entry 1 ecx has unexpected value: 0x%x\n", mem[2]);
+                    return 1;
+                }
+                if (mem[3] != ENTRY1_EDX) {
+                    fprintf(stderr, "entry 1 edx has unexpected value: 0x%x\n", mem[3]);
+                    return 1;
+                }
+                if (mem[4] != ENTRY2_EAX) {
+                    fprintf(stderr, "entry 2 eax has unexpected value: 0x%x\n", mem[4]);
+                    return 1;
+                }
+                if (mem[5] != ENTRY2_EBX) {
+                    fprintf(stderr, "entry 2 ebx has unexpected value: 0x%x\n", mem[5]);
+                    return 1;
+                }
+                if (mem[6] != ENTRY2_ECX) {
+                    fprintf(stderr, "entry 2 ecx has unexpected value: 0x%x\n", mem[6]);
+                    return 1;
+                }
+                if (mem[7] != ENTRY2_EDX) {
+                    fprintf(stderr, "entry 2 edx has unexpected value: 0x%x\n", mem[7]);
+                    return 1;
+                }
+                return 0;
+            }"#,
+        ..Default::default()
+    };
+    test_mini_plugin(&mini_plugin);
+}
+
+#[test]
+fn test_vcpu_state_manipulation() {
+    let mini_plugin = MiniPlugin {
+        assembly_src: "org 0x1000
+             bits 16
+             mov byte [0x3000], 1",
+        src: r#"
+            #define KILL_ADDRESS 0x3000
+
+            int g_kill_evt;
+            bool success = false;
+
+            int setup_vm(struct crosvm *crosvm, void *mem) {
+                g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
+                crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
+                return 0;
+            }
+
+            int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
+                                 struct kvm_sregs *sregs)
+            {
+                int ret;
+
+                struct kvm_lapic_state lapic;
+                ret = crosvm_vcpu_get_lapic_state(vcpu, &lapic);
+                if (ret < 0) {
+                    fprintf(stderr, "failed to get initial LAPIC state: %d\n", ret);
+                    return 1;
+                }
+
+                ret = crosvm_vcpu_set_lapic_state(vcpu, &lapic);
+                if (ret < 0) {
+                    fprintf(stderr, "failed to update LAPIC state: %d\n", ret);
+                    return 1;
+                }
+
+                ret = crosvm_vcpu_get_lapic_state(vcpu, &lapic);
+                if (ret < 0) {
+                    fprintf(stderr, "failed to get updated LAPIC state: %d\n", ret);
+                    return 1;
+                }
+
+                struct kvm_mp_state mp_state;
+                ret = crosvm_vcpu_get_mp_state(vcpu, &mp_state);
+                if (ret < 0) {
+                    fprintf(stderr, "failed to get initial MP state: %d\n", ret);
+                    return 1;
+                }
+
+                ret = crosvm_vcpu_set_mp_state(vcpu, &mp_state);
+                if (ret < 0) {
+                    fprintf(stderr, "failed to update MP state: %d\n", ret);
+                    return 1;
+                }
+
+                struct kvm_vcpu_events events;
+                ret = crosvm_vcpu_get_vcpu_events(vcpu, &events);
+                if (ret < 0) {
+                    fprintf(stderr, "failed to get VCPU events: %d\n", ret);
+                    return 1;
+                }
+
+                ret = crosvm_vcpu_set_vcpu_events(vcpu, &events);
+                if (ret < 0) {
+                    fprintf(stderr, "failed to set VCPU events: %d\n", ret);
+                    return 1;
+                }
+
+                success = true;
+                return 0;
+            }
+
+            int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
+                if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
+                        evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
+                        evt.io_access.address == KILL_ADDRESS &&
+                        evt.io_access.is_write &&
+                        evt.io_access.length == 1 &&
+                        evt.io_access.data[0] == 1)
+                {
+                    uint64_t dummy = 1;
+                    write(g_kill_evt, &dummy, sizeof(dummy));
+                    return 1;
+                }
+                return 0;
+            }
+
+            int check_result(struct crosvm *vcpu, void *mem) {
+                if (!success) {
+                    fprintf(stderr, "test failed\n");
+                    return 1;
+                }
+                return 0;
+            }"#,
+        ..Default::default()
+    };
+    test_mini_plugin(&mini_plugin);
+}
diff --git a/tpm2-sys/Cargo.toml b/tpm2-sys/Cargo.toml
new file mode 100644
index 0000000..12dc5ac
--- /dev/null
+++ b/tpm2-sys/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "tpm2-sys"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+links = "tpm2"
+
+[build-dependencies]
+num_cpus = "*"
+pkg-config = "*"
diff --git a/tpm2-sys/build.rs b/tpm2-sys/build.rs
new file mode 100644
index 0000000..604d936
--- /dev/null
+++ b/tpm2-sys/build.rs
@@ -0,0 +1,51 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::env;
+use std::io;
+use std::path::Path;
+use std::process::{self, Command};
+
+fn main() -> io::Result<()> {
+    if pkg_config::Config::new()
+        .statik(true)
+        .probe("libtpm2")
+        .is_ok()
+    {
+        // Use tpm2 package from the standard system location if available.
+        return Ok(());
+    }
+
+    // Build with `RUSTFLAGS='--cfg hermetic'` to disallow building our own
+    // libtpm2 in a production build context. Building from the libtpm2
+    // submodule is a convenience only intended for developer environments.
+    if cfg!(hermetic) {
+        eprintln!("libtpm2 not found; unable to perform hermetic build");
+        process::exit(1);
+    }
+
+    if !Path::new("libtpm2/.git").exists() {
+        Command::new("git")
+            .args(&["submodule", "update", "--init"])
+            .status()?;
+    }
+
+    if !Path::new("libtpm2/build/libtpm2.a").exists() {
+        let ncpu = num_cpus::get();
+        let status = Command::new("make")
+            .arg(format!("-j{}", ncpu))
+            .current_dir("libtpm2")
+            .status()?;
+        if !status.success() {
+            process::exit(status.code().unwrap_or(1));
+        }
+    }
+
+    let dir = env::var("CARGO_MANIFEST_DIR").unwrap();
+    println!("cargo:rustc-link-search={}/libtpm2/build", dir);
+    println!("cargo:rustc-link-lib=static=tpm2");
+    println!("cargo:rustc-link-lib=ssl");
+    println!("cargo:rustc-link-lib=crypto");
+    Ok(())
+}
diff --git a/tpm2-sys/libtpm2 b/tpm2-sys/libtpm2
new file mode 160000
index 0000000..15260c8
--- /dev/null
+++ b/tpm2-sys/libtpm2
@@ -0,0 +1 @@
+Subproject commit 15260c8cd98eb10b4976d2161cd5cb9bc0c3adac
diff --git a/tpm2-sys/src/lib.rs b/tpm2-sys/src/lib.rs
new file mode 100644
index 0000000..456cc87
--- /dev/null
+++ b/tpm2-sys/src/lib.rs
@@ -0,0 +1,18 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::os::raw::{c_int, c_uchar, c_uint};
+
+extern "C" {
+    pub fn TPM_Manufacture(firstTime: c_int) -> c_int;
+    pub fn _plat__SetNvAvail();
+    pub fn _plat__Signal_PowerOn() -> c_int;
+    pub fn _TPM_Init();
+    pub fn ExecuteCommand(
+        requestSize: c_uint,
+        request: *mut c_uchar,
+        responseSize: *mut c_uint,
+        response: *mut *mut c_uchar,
+    );
+}
diff --git a/tpm2/Cargo.toml b/tpm2/Cargo.toml
new file mode 100644
index 0000000..56ee5fb
--- /dev/null
+++ b/tpm2/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "tpm2"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+tpm2-sys = { path = "../tpm2-sys" }
diff --git a/tpm2/src/lib.rs b/tpm2/src/lib.rs
new file mode 100644
index 0000000..e8d6a1e
--- /dev/null
+++ b/tpm2/src/lib.rs
@@ -0,0 +1,223 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::os::raw::{c_int, c_uint};
+use std::ptr;
+use std::slice;
+use std::sync::atomic::{AtomicBool, Ordering};
+
+static SIMULATOR_EXISTS: AtomicBool = AtomicBool::new(false);
+
+/// A libtpm2-based TPM simulator.
+///
+/// At most one simulator may exist per process because libtpm2 uses a static
+/// global response buffer.
+///
+/// # Examples
+///
+/// ```no_run
+/// let mut simulator = tpm2::Simulator::singleton_in_current_directory();
+///
+/// let command = &[ /* ... */ ];
+/// let response = simulator.execute_command(command);
+/// println!("{:?}", response);
+/// ```
+pub struct Simulator {
+    _priv: (),
+}
+
+impl Simulator {
+    /// Initializes a TPM simulator in the current working directory.
+    ///
+    /// # Panics
+    ///
+    /// Panics if a TPM simulator has already been initialized by this process.
+    pub fn singleton_in_current_directory() -> Self {
+        let already_existed = SIMULATOR_EXISTS.swap(true, Ordering::SeqCst);
+        if already_existed {
+            panic!("libtpm2 simulator singleton already exists");
+        }
+
+        // Based on trunks:
+        // https://chromium.googlesource.com/chromiumos/platform2/+/e4cf13c05773f3446bd76a13c4e37f0b80728711/trunks/tpm_simulator_handle.cc
+        tpm_manufacture(true);
+        plat_set_nv_avail();
+        plat_signal_power_on();
+        tpm_init();
+
+        let mut simulator = Simulator { _priv: () };
+
+        // Send TPM2_Startup(TPM_SU_CLEAR), ignore the result. This is normally
+        // done by firmware.
+        let startup_command = &[
+            0x80, 0x01, // TPM_ST_NO_SESSIONS
+            0x00, 0x00, 0x00, 0x0c, // commandSize = 12
+            0x00, 0x00, 0x01, 0x44, // TPM_CC_Startup
+            0x00, 0x00, // TPM_SU_CLEAR
+        ];
+        let _ = simulator.execute_command(startup_command);
+
+        simulator
+    }
+
+    /// Sends a TPM command to the TPM simulator, waits for the work to be
+    /// performed, and receives back the TPM response.
+    ///
+    /// Executing a command requires exclusive access to the TPM simulator
+    /// because it mutates libtpm2 static state.
+    ///
+    /// The returned response buffer remains valid until the next TPM command is
+    /// executed.
+    #[must_use]
+    pub fn execute_command<'a>(&'a mut self, command: &[u8]) -> &'a [u8] {
+        let request_size = command.len() as c_uint;
+        let request = command.as_ptr() as *mut u8;
+        let mut response_size: c_uint = 0;
+        let mut response: *mut u8 = ptr::null_mut();
+
+        // We need to provide the following guarantees in order for this block
+        // of code to be safe:
+        //
+        //   - The TPM must have been initialized.
+        //
+        //   - There must not be a concurrently executing call to
+        //     ExecuteCommand.
+        //
+        //   - The `request` pointer must be a valid pointer to `request_size`
+        //     bytes of data that remain valid and constant for the full
+        //     duration of the call to ExecuteCommand. The implementation may
+        //     read up to `request_size` bytes of data from this address.
+        //
+        //   - The `response_size` pointer must be a valid pointer to a mutable
+        //     unsigned int. The implementation will write the response buffer
+        //     size to this address.
+        //
+        //   - The `response` pointer must be a valid pointer to a mutable
+        //     unsigned char pointer. The implementation will write a pointer to
+        //     the start of the response buffer to this address.
+        //
+        //   - No more than `response_size` bytes may be read from the response
+        //     buffer after the call returns.
+        //
+        //   - Data may be read from the response buffer only until the next
+        //     call to ExecuteCommand.
+        //
+        // The first guarantee is enforced by the public API of the Simulator
+        // struct, and in particular the singleton_in_current_directory
+        // constructor, which only makes a value of type Simulator available
+        // outside of this module after TPM initialization has been performed.
+        // Thus any Simulator on which the caller may be calling execute_command
+        // from outside of this module is witness that initialization has taken
+        // place.
+        //
+        // The second guarantee is made jointly by the &mut self reference in
+        // execute_command and the singleton_in_current_directory constructor
+        // which uses the SIMULATOR_EXISTS atomic flag to ensure that at most
+        // one value of type Simulator is ever made available to code outside of
+        // this module. Since at most one Simulator exists, and the caller is
+        // holding an exclusive reference to a Simulator, we know that no other
+        // code can be calling execute_command at the same time because they too
+        // would need their own exclusive reference to the same Simulator. We
+        // assume here that all use of libtpm2 within crosvm happens through the
+        // safe bindings provided by this tpm2 crate, so that the codebase
+        // contains no other unsafe calls to ExecuteCommand.
+        //
+        // The remaining guarantees are upheld by the signature and
+        // implementation of execute_command. In particular, note the lifetime
+        // 'a which ties the lifetime of the response slice we return to the
+        // caller to the lifetime of their exclusively held reference to
+        // Simulator. This signature looks the same to Rust as if the response
+        // buffer were a field inside the Simulator struct, rather than a
+        // statically allocated buffer inside libtpm2. As soon as the caller
+        // "mutates" the Simulator by performing another call to
+        // execute_command, the response buffer returned by the previous call is
+        // assumed to be invalidated and is made inaccessible by the borrow
+        // checker.
+        //
+        // Altogether we have guaranteed that execute_command is a safe
+        // abstraction around unsafe code and is entirely safe to call from
+        // outside of this module.
+        //
+        // Note additionally that the call to ExecuteCommand is over FFI so we
+        // need to know that the signature declared by tpm2-sys is
+        // ABI-compatible with the symbol provided by libtpm2.
+        unsafe {
+            tpm2_sys::ExecuteCommand(request_size, request, &mut response_size, &mut response);
+            slice::from_raw_parts(response, response_size as usize)
+        }
+    }
+}
+
+fn tpm_manufacture(first_time: bool) {
+    // From libtpm2 documentation:
+    //
+    //     This function initializes the TPM values in preparation for the TPM's
+    //     first use. This function will fail if previously called. The TPM can
+    //     be re-manufactured by calling TPM_Teardown() first and then calling
+    //     this function again.
+    //
+    //     Arguments
+    //
+    //         firstTime: indicates if this is the first call from main()
+    //
+    //     Return value
+    //
+    //         0 = success
+    //         1 = manufacturing process previously performed
+    //
+    // Unsafe only because this is over FFI and we need to know that the
+    // signature declared by tpm2-sys is ABI-compatible with the symbol provided
+    // by libtpm2. There are no other invariants to uphold.
+    let ret: c_int = unsafe { tpm2_sys::TPM_Manufacture(first_time as c_int) };
+
+    // We expect that the TPM must not already have been manufactured. The
+    // SIMULATOR_EXISTS atomic flag guards calls to this function such that only
+    // one call can ever be performed by a process.
+    assert!(ret == 0);
+}
+
+fn plat_set_nv_avail() {
+    // From libtpm2 documentation:
+    //
+    //     Set the current NV state to available. This function is for testing
+    //     purpose only. It is not part of the platform NV logic.
+    //
+    // The "for testing purpose only" is unsettling but trunks performs the same
+    // call during initialization so we trust that it is okay.
+    //
+    // Unsafe only because this is over FFI and we need to know that the
+    // signature declared by tpm2-sys is ABI-compatible with the symbol provided
+    // by libtpm2. There are no other invariants to uphold.
+    unsafe {
+        tpm2_sys::_plat__SetNvAvail();
+    }
+}
+
+fn plat_signal_power_on() {
+    // From libtpm2 documentation:
+    //
+    //     Signal platform power on.
+    //
+    // The libtpm2 implementation always returns 0 but does not document what
+    // the return value means, so we aren't checking it.
+    //
+    // Unsafe only because this is over FFI and we need to know that the
+    // signature declared by tpm2-sys is ABI-compatible with the symbol provided
+    // by libtpm2. There are no other invariants to uphold.
+    unsafe {
+        let _: c_int = tpm2_sys::_plat__Signal_PowerOn();
+    }
+}
+
+fn tpm_init() {
+    // This function is not documented in libtpm2. Trunks performs the same call
+    // during initialization so we trust that it is okay.
+    //
+    // Unsafe only because this is over FFI and we need to know that the
+    // signature declared by tpm2-sys is ABI-compatible with the symbol provided
+    // by libtpm2. There are no other invariants to uphold.
+    unsafe {
+        tpm2_sys::_TPM_Init();
+    }
+}
diff --git a/usb_util/Cargo.toml b/usb_util/Cargo.toml
new file mode 100644
index 0000000..fab07d6
--- /dev/null
+++ b/usb_util/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "usb_util"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+build = "build.rs"
+
+[features]
+sandboxed-libusb = []
+
+[dependencies]
+assertions = { path = "../assertions" }
+data_model = { path = "../data_model" }
+sync = { path = "../sync" }
+
+[build-dependencies]
+pkg-config = "=0.3.11"
diff --git a/usb_util/build.rs b/usb_util/build.rs
new file mode 100644
index 0000000..34e14da
--- /dev/null
+++ b/usb_util/build.rs
@@ -0,0 +1,10 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::env;
+
+fn main() {
+    env::set_var("PKG_CONFIG_ALLOW_CROSS", "1");
+    pkg_config::probe_library("libusb-1.0").unwrap();
+}
diff --git a/usb_util/src/bindings.rs b/usb_util/src/bindings.rs
new file mode 100644
index 0000000..a3e7152
--- /dev/null
+++ b/usb_util/src/bindings.rs
@@ -0,0 +1,4648 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+#[repr(C)]
+#[derive(Default)]
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
+impl<T> __IncompleteArrayField<T> {
+    #[inline]
+    pub fn new() -> Self {
+        __IncompleteArrayField(::std::marker::PhantomData)
+    }
+    #[inline]
+    pub unsafe fn as_ptr(&self) -> *const T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_slice(&self, len: usize) -> &[T] {
+        ::std::slice::from_raw_parts(self.as_ptr(), len)
+    }
+    #[inline]
+    pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
+        ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
+    }
+}
+impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        fmt.write_str("__IncompleteArrayField")
+    }
+}
+impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self::new()
+    }
+}
+impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
+pub const _STDINT_H: u32 = 1;
+pub const _FEATURES_H: u32 = 1;
+pub const _DEFAULT_SOURCE: u32 = 1;
+pub const __USE_ISOC11: u32 = 1;
+pub const __USE_ISOC99: u32 = 1;
+pub const __USE_ISOC95: u32 = 1;
+pub const __USE_POSIX_IMPLICITLY: u32 = 1;
+pub const _POSIX_SOURCE: u32 = 1;
+pub const _POSIX_C_SOURCE: u32 = 200809;
+pub const __USE_POSIX: u32 = 1;
+pub const __USE_POSIX2: u32 = 1;
+pub const __USE_POSIX199309: u32 = 1;
+pub const __USE_POSIX199506: u32 = 1;
+pub const __USE_XOPEN2K: u32 = 1;
+pub const __USE_XOPEN2K8: u32 = 1;
+pub const _ATFILE_SOURCE: u32 = 1;
+pub const __USE_MISC: u32 = 1;
+pub const __USE_ATFILE: u32 = 1;
+pub const __USE_FORTIFY_LEVEL: u32 = 0;
+pub const _STDC_PREDEF_H: u32 = 1;
+pub const __STDC_IEC_559__: u32 = 1;
+pub const __STDC_IEC_559_COMPLEX__: u32 = 1;
+pub const __STDC_ISO_10646__: u32 = 201605;
+pub const __STDC_NO_THREADS__: u32 = 1;
+pub const __GNU_LIBRARY__: u32 = 6;
+pub const __GLIBC__: u32 = 2;
+pub const __GLIBC_MINOR__: u32 = 24;
+pub const _SYS_CDEFS_H: u32 = 1;
+pub const __WORDSIZE: u32 = 64;
+pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1;
+pub const __SYSCALL_WORDSIZE: u32 = 64;
+pub const _BITS_WCHAR_H: u32 = 1;
+pub const INT8_MIN: i32 = -128;
+pub const INT16_MIN: i32 = -32768;
+pub const INT32_MIN: i32 = -2147483648;
+pub const INT8_MAX: u32 = 127;
+pub const INT16_MAX: u32 = 32767;
+pub const INT32_MAX: u32 = 2147483647;
+pub const UINT8_MAX: u32 = 255;
+pub const UINT16_MAX: u32 = 65535;
+pub const UINT32_MAX: u32 = 4294967295;
+pub const INT_LEAST8_MIN: i32 = -128;
+pub const INT_LEAST16_MIN: i32 = -32768;
+pub const INT_LEAST32_MIN: i32 = -2147483648;
+pub const INT_LEAST8_MAX: u32 = 127;
+pub const INT_LEAST16_MAX: u32 = 32767;
+pub const INT_LEAST32_MAX: u32 = 2147483647;
+pub const UINT_LEAST8_MAX: u32 = 255;
+pub const UINT_LEAST16_MAX: u32 = 65535;
+pub const UINT_LEAST32_MAX: u32 = 4294967295;
+pub const INT_FAST8_MIN: i32 = -128;
+pub const INT_FAST16_MIN: i64 = -9223372036854775808;
+pub const INT_FAST32_MIN: i64 = -9223372036854775808;
+pub const INT_FAST8_MAX: u32 = 127;
+pub const INT_FAST16_MAX: u64 = 9223372036854775807;
+pub const INT_FAST32_MAX: u64 = 9223372036854775807;
+pub const UINT_FAST8_MAX: u32 = 255;
+pub const UINT_FAST16_MAX: i32 = -1;
+pub const UINT_FAST32_MAX: i32 = -1;
+pub const INTPTR_MIN: i64 = -9223372036854775808;
+pub const INTPTR_MAX: u64 = 9223372036854775807;
+pub const UINTPTR_MAX: i32 = -1;
+pub const PTRDIFF_MIN: i64 = -9223372036854775808;
+pub const PTRDIFF_MAX: u64 = 9223372036854775807;
+pub const SIG_ATOMIC_MIN: i32 = -2147483648;
+pub const SIG_ATOMIC_MAX: u32 = 2147483647;
+pub const SIZE_MAX: i32 = -1;
+pub const WINT_MIN: u32 = 0;
+pub const WINT_MAX: u32 = 4294967295;
+pub const _SYS_TYPES_H: u32 = 1;
+pub const _BITS_TYPES_H: u32 = 1;
+pub const _BITS_TYPESIZES_H: u32 = 1;
+pub const __OFF_T_MATCHES_OFF64_T: u32 = 1;
+pub const __INO_T_MATCHES_INO64_T: u32 = 1;
+pub const __FD_SETSIZE: u32 = 1024;
+pub const __clock_t_defined: u32 = 1;
+pub const __time_t_defined: u32 = 1;
+pub const __clockid_t_defined: u32 = 1;
+pub const __timer_t_defined: u32 = 1;
+pub const __BIT_TYPES_DEFINED__: u32 = 1;
+pub const _ENDIAN_H: u32 = 1;
+pub const __LITTLE_ENDIAN: u32 = 1234;
+pub const __BIG_ENDIAN: u32 = 4321;
+pub const __PDP_ENDIAN: u32 = 3412;
+pub const __BYTE_ORDER: u32 = 1234;
+pub const __FLOAT_WORD_ORDER: u32 = 1234;
+pub const LITTLE_ENDIAN: u32 = 1234;
+pub const BIG_ENDIAN: u32 = 4321;
+pub const PDP_ENDIAN: u32 = 3412;
+pub const BYTE_ORDER: u32 = 1234;
+pub const _BITS_BYTESWAP_H: u32 = 1;
+pub const _SYS_SELECT_H: u32 = 1;
+pub const __FD_ZERO_STOS: &'static [u8; 6usize] = b"stosq\0";
+pub const _SIGSET_H_types: u32 = 1;
+pub const __timespec_defined: u32 = 1;
+pub const _STRUCT_TIMEVAL: u32 = 1;
+pub const FD_SETSIZE: u32 = 1024;
+pub const _SYS_SYSMACROS_H: u32 = 1;
+pub const _BITS_PTHREADTYPES_H: u32 = 1;
+pub const __SIZEOF_PTHREAD_ATTR_T: u32 = 56;
+pub const __SIZEOF_PTHREAD_MUTEX_T: u32 = 40;
+pub const __SIZEOF_PTHREAD_MUTEXATTR_T: u32 = 4;
+pub const __SIZEOF_PTHREAD_COND_T: u32 = 48;
+pub const __SIZEOF_PTHREAD_CONDATTR_T: u32 = 4;
+pub const __SIZEOF_PTHREAD_RWLOCK_T: u32 = 56;
+pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: u32 = 8;
+pub const __SIZEOF_PTHREAD_BARRIER_T: u32 = 32;
+pub const __SIZEOF_PTHREAD_BARRIERATTR_T: u32 = 4;
+pub const __have_pthread_attr_t: u32 = 1;
+pub const __PTHREAD_MUTEX_HAVE_PREV: u32 = 1;
+pub const __PTHREAD_RWLOCK_INT_FLAGS_SHARED: u32 = 1;
+pub const _SYS_TIME_H: u32 = 1;
+pub const _TIME_H: u32 = 1;
+pub const _BITS_TIME_H: u32 = 1;
+pub const CLOCK_REALTIME: u32 = 0;
+pub const CLOCK_MONOTONIC: u32 = 1;
+pub const CLOCK_PROCESS_CPUTIME_ID: u32 = 2;
+pub const CLOCK_THREAD_CPUTIME_ID: u32 = 3;
+pub const CLOCK_MONOTONIC_RAW: u32 = 4;
+pub const CLOCK_REALTIME_COARSE: u32 = 5;
+pub const CLOCK_MONOTONIC_COARSE: u32 = 6;
+pub const CLOCK_BOOTTIME: u32 = 7;
+pub const CLOCK_REALTIME_ALARM: u32 = 8;
+pub const CLOCK_BOOTTIME_ALARM: u32 = 9;
+pub const CLOCK_TAI: u32 = 11;
+pub const TIMER_ABSTIME: u32 = 1;
+pub const TIME_UTC: u32 = 1;
+pub const _XLOCALE_H: u32 = 1;
+pub const _LIBC_LIMITS_H_: u32 = 1;
+pub const MB_LEN_MAX: u32 = 16;
+pub const _BITS_POSIX1_LIM_H: u32 = 1;
+pub const _POSIX_AIO_LISTIO_MAX: u32 = 2;
+pub const _POSIX_AIO_MAX: u32 = 1;
+pub const _POSIX_ARG_MAX: u32 = 4096;
+pub const _POSIX_CHILD_MAX: u32 = 25;
+pub const _POSIX_DELAYTIMER_MAX: u32 = 32;
+pub const _POSIX_HOST_NAME_MAX: u32 = 255;
+pub const _POSIX_LINK_MAX: u32 = 8;
+pub const _POSIX_LOGIN_NAME_MAX: u32 = 9;
+pub const _POSIX_MAX_CANON: u32 = 255;
+pub const _POSIX_MAX_INPUT: u32 = 255;
+pub const _POSIX_MQ_OPEN_MAX: u32 = 8;
+pub const _POSIX_MQ_PRIO_MAX: u32 = 32;
+pub const _POSIX_NAME_MAX: u32 = 14;
+pub const _POSIX_NGROUPS_MAX: u32 = 8;
+pub const _POSIX_OPEN_MAX: u32 = 20;
+pub const _POSIX_PATH_MAX: u32 = 256;
+pub const _POSIX_PIPE_BUF: u32 = 512;
+pub const _POSIX_RE_DUP_MAX: u32 = 255;
+pub const _POSIX_RTSIG_MAX: u32 = 8;
+pub const _POSIX_SEM_NSEMS_MAX: u32 = 256;
+pub const _POSIX_SEM_VALUE_MAX: u32 = 32767;
+pub const _POSIX_SIGQUEUE_MAX: u32 = 32;
+pub const _POSIX_SSIZE_MAX: u32 = 32767;
+pub const _POSIX_STREAM_MAX: u32 = 8;
+pub const _POSIX_SYMLINK_MAX: u32 = 255;
+pub const _POSIX_SYMLOOP_MAX: u32 = 8;
+pub const _POSIX_TIMER_MAX: u32 = 32;
+pub const _POSIX_TTY_NAME_MAX: u32 = 9;
+pub const _POSIX_TZNAME_MAX: u32 = 6;
+pub const _POSIX_CLOCKRES_MIN: u32 = 20000000;
+pub const NR_OPEN: u32 = 1024;
+pub const NGROUPS_MAX: u32 = 65536;
+pub const ARG_MAX: u32 = 131072;
+pub const LINK_MAX: u32 = 127;
+pub const MAX_CANON: u32 = 255;
+pub const MAX_INPUT: u32 = 255;
+pub const NAME_MAX: u32 = 255;
+pub const PATH_MAX: u32 = 4096;
+pub const PIPE_BUF: u32 = 4096;
+pub const XATTR_NAME_MAX: u32 = 255;
+pub const XATTR_SIZE_MAX: u32 = 65536;
+pub const XATTR_LIST_MAX: u32 = 65536;
+pub const RTSIG_MAX: u32 = 32;
+pub const _POSIX_THREAD_KEYS_MAX: u32 = 128;
+pub const PTHREAD_KEYS_MAX: u32 = 1024;
+pub const _POSIX_THREAD_DESTRUCTOR_ITERATIONS: u32 = 4;
+pub const PTHREAD_DESTRUCTOR_ITERATIONS: u32 = 4;
+pub const _POSIX_THREAD_THREADS_MAX: u32 = 64;
+pub const AIO_PRIO_DELTA_MAX: u32 = 20;
+pub const PTHREAD_STACK_MIN: u32 = 16384;
+pub const DELAYTIMER_MAX: u32 = 2147483647;
+pub const TTY_NAME_MAX: u32 = 32;
+pub const LOGIN_NAME_MAX: u32 = 256;
+pub const HOST_NAME_MAX: u32 = 64;
+pub const MQ_PRIO_MAX: u32 = 32768;
+pub const SEM_VALUE_MAX: u32 = 2147483647;
+pub const _BITS_POSIX2_LIM_H: u32 = 1;
+pub const _POSIX2_BC_BASE_MAX: u32 = 99;
+pub const _POSIX2_BC_DIM_MAX: u32 = 2048;
+pub const _POSIX2_BC_SCALE_MAX: u32 = 99;
+pub const _POSIX2_BC_STRING_MAX: u32 = 1000;
+pub const _POSIX2_COLL_WEIGHTS_MAX: u32 = 2;
+pub const _POSIX2_EXPR_NEST_MAX: u32 = 32;
+pub const _POSIX2_LINE_MAX: u32 = 2048;
+pub const _POSIX2_RE_DUP_MAX: u32 = 255;
+pub const _POSIX2_CHARCLASS_NAME_MAX: u32 = 14;
+pub const BC_BASE_MAX: u32 = 99;
+pub const BC_DIM_MAX: u32 = 2048;
+pub const BC_SCALE_MAX: u32 = 99;
+pub const BC_STRING_MAX: u32 = 1000;
+pub const COLL_WEIGHTS_MAX: u32 = 255;
+pub const EXPR_NEST_MAX: u32 = 32;
+pub const LINE_MAX: u32 = 2048;
+pub const CHARCLASS_NAME_MAX: u32 = 2048;
+pub const RE_DUP_MAX: u32 = 32767;
+pub const LIBUSB_API_VERSION: u32 = 16777477;
+pub const LIBUSBX_API_VERSION: u32 = 16777477;
+pub const LIBUSB_DT_DEVICE_SIZE: u32 = 18;
+pub const LIBUSB_DT_CONFIG_SIZE: u32 = 9;
+pub const LIBUSB_DT_INTERFACE_SIZE: u32 = 9;
+pub const LIBUSB_DT_ENDPOINT_SIZE: u32 = 7;
+pub const LIBUSB_DT_ENDPOINT_AUDIO_SIZE: u32 = 9;
+pub const LIBUSB_DT_HUB_NONVAR_SIZE: u32 = 7;
+pub const LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE: u32 = 6;
+pub const LIBUSB_DT_BOS_SIZE: u32 = 5;
+pub const LIBUSB_DT_DEVICE_CAPABILITY_SIZE: u32 = 3;
+pub const LIBUSB_BT_USB_2_0_EXTENSION_SIZE: u32 = 7;
+pub const LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE: u32 = 10;
+pub const LIBUSB_BT_CONTAINER_ID_SIZE: u32 = 20;
+pub const LIBUSB_DT_BOS_MAX_SIZE: u32 = 42;
+pub const LIBUSB_ENDPOINT_ADDRESS_MASK: u32 = 15;
+pub const LIBUSB_ENDPOINT_DIR_MASK: u32 = 128;
+pub const LIBUSB_TRANSFER_TYPE_MASK: u32 = 3;
+pub const LIBUSB_ISO_SYNC_TYPE_MASK: u32 = 12;
+pub const LIBUSB_ISO_USAGE_TYPE_MASK: u32 = 48;
+pub const LIBUSB_ERROR_COUNT: u32 = 14;
+pub const LIBUSB_HOTPLUG_MATCH_ANY: i32 = -1;
+pub type int_least8_t = ::std::os::raw::c_schar;
+pub type int_least16_t = ::std::os::raw::c_short;
+pub type int_least32_t = ::std::os::raw::c_int;
+pub type int_least64_t = ::std::os::raw::c_long;
+pub type uint_least8_t = ::std::os::raw::c_uchar;
+pub type uint_least16_t = ::std::os::raw::c_ushort;
+pub type uint_least32_t = ::std::os::raw::c_uint;
+pub type uint_least64_t = ::std::os::raw::c_ulong;
+pub type int_fast8_t = ::std::os::raw::c_schar;
+pub type int_fast16_t = ::std::os::raw::c_long;
+pub type int_fast32_t = ::std::os::raw::c_long;
+pub type int_fast64_t = ::std::os::raw::c_long;
+pub type uint_fast8_t = ::std::os::raw::c_uchar;
+pub type uint_fast16_t = ::std::os::raw::c_ulong;
+pub type uint_fast32_t = ::std::os::raw::c_ulong;
+pub type uint_fast64_t = ::std::os::raw::c_ulong;
+pub type intmax_t = ::std::os::raw::c_long;
+pub type uintmax_t = ::std::os::raw::c_ulong;
+pub type __u_char = ::std::os::raw::c_uchar;
+pub type __u_short = ::std::os::raw::c_ushort;
+pub type __u_int = ::std::os::raw::c_uint;
+pub type __u_long = ::std::os::raw::c_ulong;
+pub type __int8_t = ::std::os::raw::c_schar;
+pub type __uint8_t = ::std::os::raw::c_uchar;
+pub type __int16_t = ::std::os::raw::c_short;
+pub type __uint16_t = ::std::os::raw::c_ushort;
+pub type __int32_t = ::std::os::raw::c_int;
+pub type __uint32_t = ::std::os::raw::c_uint;
+pub type __int64_t = ::std::os::raw::c_long;
+pub type __uint64_t = ::std::os::raw::c_ulong;
+pub type __quad_t = ::std::os::raw::c_long;
+pub type __u_quad_t = ::std::os::raw::c_ulong;
+pub type __dev_t = ::std::os::raw::c_ulong;
+pub type __uid_t = ::std::os::raw::c_uint;
+pub type __gid_t = ::std::os::raw::c_uint;
+pub type __ino_t = ::std::os::raw::c_ulong;
+pub type __ino64_t = ::std::os::raw::c_ulong;
+pub type __mode_t = ::std::os::raw::c_uint;
+pub type __nlink_t = ::std::os::raw::c_ulong;
+pub type __off_t = ::std::os::raw::c_long;
+pub type __off64_t = ::std::os::raw::c_long;
+pub type __pid_t = ::std::os::raw::c_int;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __fsid_t {
+    pub __val: [::std::os::raw::c_int; 2usize],
+}
+#[test]
+fn bindgen_test_layout___fsid_t() {
+    assert_eq!(
+        ::std::mem::size_of::<__fsid_t>(),
+        8usize,
+        concat!("Size of: ", stringify!(__fsid_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__fsid_t>(),
+        4usize,
+        concat!("Alignment of ", stringify!(__fsid_t))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<__fsid_t>())).__val as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__fsid_t),
+            "::",
+            stringify!(__val)
+        )
+    );
+}
+pub type __clock_t = ::std::os::raw::c_long;
+pub type __rlim_t = ::std::os::raw::c_ulong;
+pub type __rlim64_t = ::std::os::raw::c_ulong;
+pub type __id_t = ::std::os::raw::c_uint;
+pub type __time_t = ::std::os::raw::c_long;
+pub type __useconds_t = ::std::os::raw::c_uint;
+pub type __suseconds_t = ::std::os::raw::c_long;
+pub type __daddr_t = ::std::os::raw::c_int;
+pub type __key_t = ::std::os::raw::c_int;
+pub type __clockid_t = ::std::os::raw::c_int;
+pub type __timer_t = *mut ::std::os::raw::c_void;
+pub type __blksize_t = ::std::os::raw::c_long;
+pub type __blkcnt_t = ::std::os::raw::c_long;
+pub type __blkcnt64_t = ::std::os::raw::c_long;
+pub type __fsblkcnt_t = ::std::os::raw::c_ulong;
+pub type __fsblkcnt64_t = ::std::os::raw::c_ulong;
+pub type __fsfilcnt_t = ::std::os::raw::c_ulong;
+pub type __fsfilcnt64_t = ::std::os::raw::c_ulong;
+pub type __fsword_t = ::std::os::raw::c_long;
+pub type __ssize_t = ::std::os::raw::c_long;
+pub type __syscall_slong_t = ::std::os::raw::c_long;
+pub type __syscall_ulong_t = ::std::os::raw::c_ulong;
+pub type __loff_t = __off64_t;
+pub type __qaddr_t = *mut __quad_t;
+pub type __caddr_t = *mut ::std::os::raw::c_char;
+pub type __intptr_t = ::std::os::raw::c_long;
+pub type __socklen_t = ::std::os::raw::c_uint;
+pub type u_char = __u_char;
+pub type u_short = __u_short;
+pub type u_int = __u_int;
+pub type u_long = __u_long;
+pub type quad_t = __quad_t;
+pub type u_quad_t = __u_quad_t;
+pub type fsid_t = __fsid_t;
+pub type loff_t = __loff_t;
+pub type ino_t = __ino_t;
+pub type dev_t = __dev_t;
+pub type gid_t = __gid_t;
+pub type mode_t = __mode_t;
+pub type nlink_t = __nlink_t;
+pub type uid_t = __uid_t;
+pub type off_t = __off_t;
+pub type pid_t = __pid_t;
+pub type id_t = __id_t;
+pub type daddr_t = __daddr_t;
+pub type caddr_t = __caddr_t;
+pub type key_t = __key_t;
+pub type clock_t = __clock_t;
+pub type time_t = __time_t;
+pub type clockid_t = __clockid_t;
+pub type timer_t = __timer_t;
+pub type ulong = ::std::os::raw::c_ulong;
+pub type ushort = ::std::os::raw::c_ushort;
+pub type uint = ::std::os::raw::c_uint;
+pub type u_int8_t = ::std::os::raw::c_uchar;
+pub type u_int16_t = ::std::os::raw::c_ushort;
+pub type u_int32_t = ::std::os::raw::c_uint;
+pub type u_int64_t = ::std::os::raw::c_ulong;
+pub type register_t = ::std::os::raw::c_long;
+pub type __sig_atomic_t = ::std::os::raw::c_int;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __sigset_t {
+    pub __val: [::std::os::raw::c_ulong; 16usize],
+}
+#[test]
+fn bindgen_test_layout___sigset_t() {
+    assert_eq!(
+        ::std::mem::size_of::<__sigset_t>(),
+        128usize,
+        concat!("Size of: ", stringify!(__sigset_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__sigset_t>(),
+        8usize,
+        concat!("Alignment of ", stringify!(__sigset_t))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<__sigset_t>())).__val as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__sigset_t),
+            "::",
+            stringify!(__val)
+        )
+    );
+}
+pub type sigset_t = __sigset_t;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct timespec {
+    pub tv_sec: __time_t,
+    pub tv_nsec: __syscall_slong_t,
+}
+#[test]
+fn bindgen_test_layout_timespec() {
+    assert_eq!(
+        ::std::mem::size_of::<timespec>(),
+        16usize,
+        concat!("Size of: ", stringify!(timespec))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<timespec>(),
+        8usize,
+        concat!("Alignment of ", stringify!(timespec))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<timespec>())).tv_sec as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(timespec),
+            "::",
+            stringify!(tv_sec)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<timespec>())).tv_nsec as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(timespec),
+            "::",
+            stringify!(tv_nsec)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct timeval {
+    pub tv_sec: __time_t,
+    pub tv_usec: __suseconds_t,
+}
+#[test]
+fn bindgen_test_layout_timeval() {
+    assert_eq!(
+        ::std::mem::size_of::<timeval>(),
+        16usize,
+        concat!("Size of: ", stringify!(timeval))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<timeval>(),
+        8usize,
+        concat!("Alignment of ", stringify!(timeval))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<timeval>())).tv_sec as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(timeval),
+            "::",
+            stringify!(tv_sec)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<timeval>())).tv_usec as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(timeval),
+            "::",
+            stringify!(tv_usec)
+        )
+    );
+}
+pub type suseconds_t = __suseconds_t;
+pub type __fd_mask = ::std::os::raw::c_long;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct fd_set {
+    pub __fds_bits: [__fd_mask; 16usize],
+}
+#[test]
+fn bindgen_test_layout_fd_set() {
+    assert_eq!(
+        ::std::mem::size_of::<fd_set>(),
+        128usize,
+        concat!("Size of: ", stringify!(fd_set))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<fd_set>(),
+        8usize,
+        concat!("Alignment of ", stringify!(fd_set))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<fd_set>())).__fds_bits as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(fd_set),
+            "::",
+            stringify!(__fds_bits)
+        )
+    );
+}
+pub type fd_mask = __fd_mask;
+extern "C" {
+    pub fn select(
+        __nfds: ::std::os::raw::c_int,
+        __readfds: *mut fd_set,
+        __writefds: *mut fd_set,
+        __exceptfds: *mut fd_set,
+        __timeout: *mut timeval,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn pselect(
+        __nfds: ::std::os::raw::c_int,
+        __readfds: *mut fd_set,
+        __writefds: *mut fd_set,
+        __exceptfds: *mut fd_set,
+        __timeout: *const timespec,
+        __sigmask: *const __sigset_t,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn gnu_dev_major(__dev: ::std::os::raw::c_ulonglong) -> ::std::os::raw::c_uint;
+}
+extern "C" {
+    pub fn gnu_dev_minor(__dev: ::std::os::raw::c_ulonglong) -> ::std::os::raw::c_uint;
+}
+extern "C" {
+    pub fn gnu_dev_makedev(
+        __major: ::std::os::raw::c_uint,
+        __minor: ::std::os::raw::c_uint,
+    ) -> ::std::os::raw::c_ulonglong;
+}
+pub type blksize_t = __blksize_t;
+pub type blkcnt_t = __blkcnt_t;
+pub type fsblkcnt_t = __fsblkcnt_t;
+pub type fsfilcnt_t = __fsfilcnt_t;
+pub type pthread_t = ::std::os::raw::c_ulong;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_attr_t {
+    pub __size: [::std::os::raw::c_char; 56usize],
+    pub __align: ::std::os::raw::c_long,
+    _bindgen_union_align: [u64; 7usize],
+}
+#[test]
+fn bindgen_test_layout_pthread_attr_t() {
+    assert_eq!(
+        ::std::mem::size_of::<pthread_attr_t>(),
+        56usize,
+        concat!("Size of: ", stringify!(pthread_attr_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<pthread_attr_t>(),
+        8usize,
+        concat!("Alignment of ", stringify!(pthread_attr_t))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_attr_t>())).__size as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_attr_t),
+            "::",
+            stringify!(__size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_attr_t>())).__align as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_attr_t),
+            "::",
+            stringify!(__align)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __pthread_internal_list {
+    pub __prev: *mut __pthread_internal_list,
+    pub __next: *mut __pthread_internal_list,
+}
+#[test]
+fn bindgen_test_layout___pthread_internal_list() {
+    assert_eq!(
+        ::std::mem::size_of::<__pthread_internal_list>(),
+        16usize,
+        concat!("Size of: ", stringify!(__pthread_internal_list))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__pthread_internal_list>(),
+        8usize,
+        concat!("Alignment of ", stringify!(__pthread_internal_list))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<__pthread_internal_list>())).__prev as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__pthread_internal_list),
+            "::",
+            stringify!(__prev)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<__pthread_internal_list>())).__next as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__pthread_internal_list),
+            "::",
+            stringify!(__next)
+        )
+    );
+}
+pub type __pthread_list_t = __pthread_internal_list;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_mutex_t {
+    pub __data: pthread_mutex_t___pthread_mutex_s,
+    pub __size: [::std::os::raw::c_char; 40usize],
+    pub __align: ::std::os::raw::c_long,
+    _bindgen_union_align: [u64; 5usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct pthread_mutex_t___pthread_mutex_s {
+    pub __lock: ::std::os::raw::c_int,
+    pub __count: ::std::os::raw::c_uint,
+    pub __owner: ::std::os::raw::c_int,
+    pub __nusers: ::std::os::raw::c_uint,
+    pub __kind: ::std::os::raw::c_int,
+    pub __spins: ::std::os::raw::c_short,
+    pub __elision: ::std::os::raw::c_short,
+    pub __list: __pthread_list_t,
+}
+#[test]
+fn bindgen_test_layout_pthread_mutex_t___pthread_mutex_s() {
+    assert_eq!(
+        ::std::mem::size_of::<pthread_mutex_t___pthread_mutex_s>(),
+        40usize,
+        concat!("Size of: ", stringify!(pthread_mutex_t___pthread_mutex_s))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<pthread_mutex_t___pthread_mutex_s>(),
+        8usize,
+        concat!(
+            "Alignment of ",
+            stringify!(pthread_mutex_t___pthread_mutex_s)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__lock as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_mutex_t___pthread_mutex_s),
+            "::",
+            stringify!(__lock)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__count as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_mutex_t___pthread_mutex_s),
+            "::",
+            stringify!(__count)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__owner as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_mutex_t___pthread_mutex_s),
+            "::",
+            stringify!(__owner)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__nusers as *const _
+                as usize
+        },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_mutex_t___pthread_mutex_s),
+            "::",
+            stringify!(__nusers)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__kind as *const _
+                as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_mutex_t___pthread_mutex_s),
+            "::",
+            stringify!(__kind)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__spins as *const _
+                as usize
+        },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_mutex_t___pthread_mutex_s),
+            "::",
+            stringify!(__spins)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__elision as *const _
+                as usize
+        },
+        22usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_mutex_t___pthread_mutex_s),
+            "::",
+            stringify!(__elision)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__list as *const _
+                as usize
+        },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_mutex_t___pthread_mutex_s),
+            "::",
+            stringify!(__list)
+        )
+    );
+}
+#[test]
+fn bindgen_test_layout_pthread_mutex_t() {
+    assert_eq!(
+        ::std::mem::size_of::<pthread_mutex_t>(),
+        40usize,
+        concat!("Size of: ", stringify!(pthread_mutex_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<pthread_mutex_t>(),
+        8usize,
+        concat!("Alignment of ", stringify!(pthread_mutex_t))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_mutex_t>())).__data as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_mutex_t),
+            "::",
+            stringify!(__data)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_mutex_t>())).__size as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_mutex_t),
+            "::",
+            stringify!(__size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_mutex_t>())).__align as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_mutex_t),
+            "::",
+            stringify!(__align)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_mutexattr_t {
+    pub __size: [::std::os::raw::c_char; 4usize],
+    pub __align: ::std::os::raw::c_int,
+    _bindgen_union_align: u32,
+}
+#[test]
+fn bindgen_test_layout_pthread_mutexattr_t() {
+    assert_eq!(
+        ::std::mem::size_of::<pthread_mutexattr_t>(),
+        4usize,
+        concat!("Size of: ", stringify!(pthread_mutexattr_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<pthread_mutexattr_t>(),
+        4usize,
+        concat!("Alignment of ", stringify!(pthread_mutexattr_t))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_mutexattr_t>())).__size as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_mutexattr_t),
+            "::",
+            stringify!(__size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_mutexattr_t>())).__align as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_mutexattr_t),
+            "::",
+            stringify!(__align)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_cond_t {
+    pub __data: pthread_cond_t__bindgen_ty_1,
+    pub __size: [::std::os::raw::c_char; 48usize],
+    pub __align: ::std::os::raw::c_longlong,
+    _bindgen_union_align: [u64; 6usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct pthread_cond_t__bindgen_ty_1 {
+    pub __lock: ::std::os::raw::c_int,
+    pub __futex: ::std::os::raw::c_uint,
+    pub __total_seq: ::std::os::raw::c_ulonglong,
+    pub __wakeup_seq: ::std::os::raw::c_ulonglong,
+    pub __woken_seq: ::std::os::raw::c_ulonglong,
+    pub __mutex: *mut ::std::os::raw::c_void,
+    pub __nwaiters: ::std::os::raw::c_uint,
+    pub __broadcast_seq: ::std::os::raw::c_uint,
+}
+#[test]
+fn bindgen_test_layout_pthread_cond_t__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<pthread_cond_t__bindgen_ty_1>(),
+        48usize,
+        concat!("Size of: ", stringify!(pthread_cond_t__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<pthread_cond_t__bindgen_ty_1>(),
+        8usize,
+        concat!("Alignment of ", stringify!(pthread_cond_t__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__lock as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_cond_t__bindgen_ty_1),
+            "::",
+            stringify!(__lock)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__futex as *const _ as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_cond_t__bindgen_ty_1),
+            "::",
+            stringify!(__futex)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__total_seq as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_cond_t__bindgen_ty_1),
+            "::",
+            stringify!(__total_seq)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__wakeup_seq as *const _
+                as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_cond_t__bindgen_ty_1),
+            "::",
+            stringify!(__wakeup_seq)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__woken_seq as *const _
+                as usize
+        },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_cond_t__bindgen_ty_1),
+            "::",
+            stringify!(__woken_seq)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__mutex as *const _ as usize
+        },
+        32usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_cond_t__bindgen_ty_1),
+            "::",
+            stringify!(__mutex)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__nwaiters as *const _ as usize
+        },
+        40usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_cond_t__bindgen_ty_1),
+            "::",
+            stringify!(__nwaiters)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__broadcast_seq as *const _
+                as usize
+        },
+        44usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_cond_t__bindgen_ty_1),
+            "::",
+            stringify!(__broadcast_seq)
+        )
+    );
+}
+#[test]
+fn bindgen_test_layout_pthread_cond_t() {
+    assert_eq!(
+        ::std::mem::size_of::<pthread_cond_t>(),
+        48usize,
+        concat!("Size of: ", stringify!(pthread_cond_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<pthread_cond_t>(),
+        8usize,
+        concat!("Alignment of ", stringify!(pthread_cond_t))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_cond_t>())).__data as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_cond_t),
+            "::",
+            stringify!(__data)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_cond_t>())).__size as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_cond_t),
+            "::",
+            stringify!(__size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_cond_t>())).__align as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_cond_t),
+            "::",
+            stringify!(__align)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_condattr_t {
+    pub __size: [::std::os::raw::c_char; 4usize],
+    pub __align: ::std::os::raw::c_int,
+    _bindgen_union_align: u32,
+}
+#[test]
+fn bindgen_test_layout_pthread_condattr_t() {
+    assert_eq!(
+        ::std::mem::size_of::<pthread_condattr_t>(),
+        4usize,
+        concat!("Size of: ", stringify!(pthread_condattr_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<pthread_condattr_t>(),
+        4usize,
+        concat!("Alignment of ", stringify!(pthread_condattr_t))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_condattr_t>())).__size as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_condattr_t),
+            "::",
+            stringify!(__size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_condattr_t>())).__align as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_condattr_t),
+            "::",
+            stringify!(__align)
+        )
+    );
+}
+pub type pthread_key_t = ::std::os::raw::c_uint;
+pub type pthread_once_t = ::std::os::raw::c_int;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_rwlock_t {
+    pub __data: pthread_rwlock_t__bindgen_ty_1,
+    pub __size: [::std::os::raw::c_char; 56usize],
+    pub __align: ::std::os::raw::c_long,
+    _bindgen_union_align: [u64; 7usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct pthread_rwlock_t__bindgen_ty_1 {
+    pub __lock: ::std::os::raw::c_int,
+    pub __nr_readers: ::std::os::raw::c_uint,
+    pub __readers_wakeup: ::std::os::raw::c_uint,
+    pub __writer_wakeup: ::std::os::raw::c_uint,
+    pub __nr_readers_queued: ::std::os::raw::c_uint,
+    pub __nr_writers_queued: ::std::os::raw::c_uint,
+    pub __writer: ::std::os::raw::c_int,
+    pub __shared: ::std::os::raw::c_int,
+    pub __rwelision: ::std::os::raw::c_schar,
+    pub __pad1: [::std::os::raw::c_uchar; 7usize],
+    pub __pad2: ::std::os::raw::c_ulong,
+    pub __flags: ::std::os::raw::c_uint,
+}
+#[test]
+fn bindgen_test_layout_pthread_rwlock_t__bindgen_ty_1() {
+    assert_eq!(
+        ::std::mem::size_of::<pthread_rwlock_t__bindgen_ty_1>(),
+        56usize,
+        concat!("Size of: ", stringify!(pthread_rwlock_t__bindgen_ty_1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<pthread_rwlock_t__bindgen_ty_1>(),
+        8usize,
+        concat!("Alignment of ", stringify!(pthread_rwlock_t__bindgen_ty_1))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__lock as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t__bindgen_ty_1),
+            "::",
+            stringify!(__lock)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__nr_readers as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t__bindgen_ty_1),
+            "::",
+            stringify!(__nr_readers)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__readers_wakeup as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t__bindgen_ty_1),
+            "::",
+            stringify!(__readers_wakeup)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__writer_wakeup as *const _
+                as usize
+        },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t__bindgen_ty_1),
+            "::",
+            stringify!(__writer_wakeup)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__nr_readers_queued
+                as *const _ as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t__bindgen_ty_1),
+            "::",
+            stringify!(__nr_readers_queued)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__nr_writers_queued
+                as *const _ as usize
+        },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t__bindgen_ty_1),
+            "::",
+            stringify!(__nr_writers_queued)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__writer as *const _ as usize
+        },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t__bindgen_ty_1),
+            "::",
+            stringify!(__writer)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__shared as *const _ as usize
+        },
+        28usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t__bindgen_ty_1),
+            "::",
+            stringify!(__shared)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__rwelision as *const _
+                as usize
+        },
+        32usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t__bindgen_ty_1),
+            "::",
+            stringify!(__rwelision)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__pad1 as *const _ as usize
+        },
+        33usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t__bindgen_ty_1),
+            "::",
+            stringify!(__pad1)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__pad2 as *const _ as usize
+        },
+        40usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t__bindgen_ty_1),
+            "::",
+            stringify!(__pad2)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__flags as *const _ as usize
+        },
+        48usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t__bindgen_ty_1),
+            "::",
+            stringify!(__flags)
+        )
+    );
+}
+#[test]
+fn bindgen_test_layout_pthread_rwlock_t() {
+    assert_eq!(
+        ::std::mem::size_of::<pthread_rwlock_t>(),
+        56usize,
+        concat!("Size of: ", stringify!(pthread_rwlock_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<pthread_rwlock_t>(),
+        8usize,
+        concat!("Alignment of ", stringify!(pthread_rwlock_t))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_rwlock_t>())).__data as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t),
+            "::",
+            stringify!(__data)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_rwlock_t>())).__size as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t),
+            "::",
+            stringify!(__size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_rwlock_t>())).__align as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlock_t),
+            "::",
+            stringify!(__align)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_rwlockattr_t {
+    pub __size: [::std::os::raw::c_char; 8usize],
+    pub __align: ::std::os::raw::c_long,
+    _bindgen_union_align: u64,
+}
+#[test]
+fn bindgen_test_layout_pthread_rwlockattr_t() {
+    assert_eq!(
+        ::std::mem::size_of::<pthread_rwlockattr_t>(),
+        8usize,
+        concat!("Size of: ", stringify!(pthread_rwlockattr_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<pthread_rwlockattr_t>(),
+        8usize,
+        concat!("Alignment of ", stringify!(pthread_rwlockattr_t))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_rwlockattr_t>())).__size as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlockattr_t),
+            "::",
+            stringify!(__size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_rwlockattr_t>())).__align as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_rwlockattr_t),
+            "::",
+            stringify!(__align)
+        )
+    );
+}
+pub type pthread_spinlock_t = ::std::os::raw::c_int;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_barrier_t {
+    pub __size: [::std::os::raw::c_char; 32usize],
+    pub __align: ::std::os::raw::c_long,
+    _bindgen_union_align: [u64; 4usize],
+}
+#[test]
+fn bindgen_test_layout_pthread_barrier_t() {
+    assert_eq!(
+        ::std::mem::size_of::<pthread_barrier_t>(),
+        32usize,
+        concat!("Size of: ", stringify!(pthread_barrier_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<pthread_barrier_t>(),
+        8usize,
+        concat!("Alignment of ", stringify!(pthread_barrier_t))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_barrier_t>())).__size as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_barrier_t),
+            "::",
+            stringify!(__size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_barrier_t>())).__align as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_barrier_t),
+            "::",
+            stringify!(__align)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union pthread_barrierattr_t {
+    pub __size: [::std::os::raw::c_char; 4usize],
+    pub __align: ::std::os::raw::c_int,
+    _bindgen_union_align: u32,
+}
+#[test]
+fn bindgen_test_layout_pthread_barrierattr_t() {
+    assert_eq!(
+        ::std::mem::size_of::<pthread_barrierattr_t>(),
+        4usize,
+        concat!("Size of: ", stringify!(pthread_barrierattr_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<pthread_barrierattr_t>(),
+        4usize,
+        concat!("Alignment of ", stringify!(pthread_barrierattr_t))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_barrierattr_t>())).__size as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_barrierattr_t),
+            "::",
+            stringify!(__size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<pthread_barrierattr_t>())).__align as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(pthread_barrierattr_t),
+            "::",
+            stringify!(__align)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct timezone {
+    pub tz_minuteswest: ::std::os::raw::c_int,
+    pub tz_dsttime: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_timezone() {
+    assert_eq!(
+        ::std::mem::size_of::<timezone>(),
+        8usize,
+        concat!("Size of: ", stringify!(timezone))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<timezone>(),
+        4usize,
+        concat!("Alignment of ", stringify!(timezone))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<timezone>())).tz_minuteswest as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(timezone),
+            "::",
+            stringify!(tz_minuteswest)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<timezone>())).tz_dsttime as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(timezone),
+            "::",
+            stringify!(tz_dsttime)
+        )
+    );
+}
+pub type __timezone_ptr_t = *mut timezone;
+extern "C" {
+    pub fn gettimeofday(__tv: *mut timeval, __tz: __timezone_ptr_t) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn settimeofday(__tv: *const timeval, __tz: *const timezone) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn adjtime(__delta: *const timeval, __olddelta: *mut timeval) -> ::std::os::raw::c_int;
+}
+pub const ITIMER_REAL: __itimer_which = 0;
+pub const ITIMER_VIRTUAL: __itimer_which = 1;
+pub const ITIMER_PROF: __itimer_which = 2;
+pub type __itimer_which = u32;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct itimerval {
+    pub it_interval: timeval,
+    pub it_value: timeval,
+}
+#[test]
+fn bindgen_test_layout_itimerval() {
+    assert_eq!(
+        ::std::mem::size_of::<itimerval>(),
+        32usize,
+        concat!("Size of: ", stringify!(itimerval))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<itimerval>(),
+        8usize,
+        concat!("Alignment of ", stringify!(itimerval))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<itimerval>())).it_interval as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(itimerval),
+            "::",
+            stringify!(it_interval)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<itimerval>())).it_value as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(itimerval),
+            "::",
+            stringify!(it_value)
+        )
+    );
+}
+pub type __itimer_which_t = ::std::os::raw::c_int;
+extern "C" {
+    pub fn getitimer(__which: __itimer_which_t, __value: *mut itimerval) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn setitimer(
+        __which: __itimer_which_t,
+        __new: *const itimerval,
+        __old: *mut itimerval,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn utimes(
+        __file: *const ::std::os::raw::c_char,
+        __tvp: *const timeval,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn lutimes(
+        __file: *const ::std::os::raw::c_char,
+        __tvp: *const timeval,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn futimes(__fd: ::std::os::raw::c_int, __tvp: *const timeval) -> ::std::os::raw::c_int;
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct tm {
+    pub tm_sec: ::std::os::raw::c_int,
+    pub tm_min: ::std::os::raw::c_int,
+    pub tm_hour: ::std::os::raw::c_int,
+    pub tm_mday: ::std::os::raw::c_int,
+    pub tm_mon: ::std::os::raw::c_int,
+    pub tm_year: ::std::os::raw::c_int,
+    pub tm_wday: ::std::os::raw::c_int,
+    pub tm_yday: ::std::os::raw::c_int,
+    pub tm_isdst: ::std::os::raw::c_int,
+    pub tm_gmtoff: ::std::os::raw::c_long,
+    pub tm_zone: *const ::std::os::raw::c_char,
+}
+#[test]
+fn bindgen_test_layout_tm() {
+    assert_eq!(
+        ::std::mem::size_of::<tm>(),
+        56usize,
+        concat!("Size of: ", stringify!(tm))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<tm>(),
+        8usize,
+        concat!("Alignment of ", stringify!(tm))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<tm>())).tm_sec as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(tm),
+            "::",
+            stringify!(tm_sec)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<tm>())).tm_min as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(tm),
+            "::",
+            stringify!(tm_min)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<tm>())).tm_hour as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(tm),
+            "::",
+            stringify!(tm_hour)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<tm>())).tm_mday as *const _ as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(tm),
+            "::",
+            stringify!(tm_mday)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<tm>())).tm_mon as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(tm),
+            "::",
+            stringify!(tm_mon)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<tm>())).tm_year as *const _ as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(tm),
+            "::",
+            stringify!(tm_year)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<tm>())).tm_wday as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(tm),
+            "::",
+            stringify!(tm_wday)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<tm>())).tm_yday as *const _ as usize },
+        28usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(tm),
+            "::",
+            stringify!(tm_yday)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<tm>())).tm_isdst as *const _ as usize },
+        32usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(tm),
+            "::",
+            stringify!(tm_isdst)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<tm>())).tm_gmtoff as *const _ as usize },
+        40usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(tm),
+            "::",
+            stringify!(tm_gmtoff)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<tm>())).tm_zone as *const _ as usize },
+        48usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(tm),
+            "::",
+            stringify!(tm_zone)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct itimerspec {
+    pub it_interval: timespec,
+    pub it_value: timespec,
+}
+#[test]
+fn bindgen_test_layout_itimerspec() {
+    assert_eq!(
+        ::std::mem::size_of::<itimerspec>(),
+        32usize,
+        concat!("Size of: ", stringify!(itimerspec))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<itimerspec>(),
+        8usize,
+        concat!("Alignment of ", stringify!(itimerspec))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<itimerspec>())).it_interval as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(itimerspec),
+            "::",
+            stringify!(it_interval)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<itimerspec>())).it_value as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(itimerspec),
+            "::",
+            stringify!(it_value)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct sigevent {
+    _unused: [u8; 0],
+}
+extern "C" {
+    pub fn clock() -> clock_t;
+}
+extern "C" {
+    pub fn time(__timer: *mut time_t) -> time_t;
+}
+extern "C" {
+    pub fn difftime(__time1: time_t, __time0: time_t) -> f64;
+}
+extern "C" {
+    pub fn mktime(__tp: *mut tm) -> time_t;
+}
+extern "C" {
+    pub fn strftime(
+        __s: *mut ::std::os::raw::c_char,
+        __maxsize: usize,
+        __format: *const ::std::os::raw::c_char,
+        __tp: *const tm,
+    ) -> usize;
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __locale_struct {
+    pub __locales: [*mut __locale_data; 13usize],
+    pub __ctype_b: *const ::std::os::raw::c_ushort,
+    pub __ctype_tolower: *const ::std::os::raw::c_int,
+    pub __ctype_toupper: *const ::std::os::raw::c_int,
+    pub __names: [*const ::std::os::raw::c_char; 13usize],
+}
+#[test]
+fn bindgen_test_layout___locale_struct() {
+    assert_eq!(
+        ::std::mem::size_of::<__locale_struct>(),
+        232usize,
+        concat!("Size of: ", stringify!(__locale_struct))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__locale_struct>(),
+        8usize,
+        concat!("Alignment of ", stringify!(__locale_struct))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<__locale_struct>())).__locales as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__locale_struct),
+            "::",
+            stringify!(__locales)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<__locale_struct>())).__ctype_b as *const _ as usize },
+        104usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__locale_struct),
+            "::",
+            stringify!(__ctype_b)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<__locale_struct>())).__ctype_tolower as *const _ as usize },
+        112usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__locale_struct),
+            "::",
+            stringify!(__ctype_tolower)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<__locale_struct>())).__ctype_toupper as *const _ as usize },
+        120usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__locale_struct),
+            "::",
+            stringify!(__ctype_toupper)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<__locale_struct>())).__names as *const _ as usize },
+        128usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(__locale_struct),
+            "::",
+            stringify!(__names)
+        )
+    );
+}
+pub type __locale_t = *mut __locale_struct;
+pub type locale_t = __locale_t;
+extern "C" {
+    pub fn strftime_l(
+        __s: *mut ::std::os::raw::c_char,
+        __maxsize: usize,
+        __format: *const ::std::os::raw::c_char,
+        __tp: *const tm,
+        __loc: __locale_t,
+    ) -> usize;
+}
+extern "C" {
+    pub fn gmtime(__timer: *const time_t) -> *mut tm;
+}
+extern "C" {
+    pub fn localtime(__timer: *const time_t) -> *mut tm;
+}
+extern "C" {
+    pub fn gmtime_r(__timer: *const time_t, __tp: *mut tm) -> *mut tm;
+}
+extern "C" {
+    pub fn localtime_r(__timer: *const time_t, __tp: *mut tm) -> *mut tm;
+}
+extern "C" {
+    pub fn asctime(__tp: *const tm) -> *mut ::std::os::raw::c_char;
+}
+extern "C" {
+    pub fn ctime(__timer: *const time_t) -> *mut ::std::os::raw::c_char;
+}
+extern "C" {
+    pub fn asctime_r(
+        __tp: *const tm,
+        __buf: *mut ::std::os::raw::c_char,
+    ) -> *mut ::std::os::raw::c_char;
+}
+extern "C" {
+    pub fn ctime_r(
+        __timer: *const time_t,
+        __buf: *mut ::std::os::raw::c_char,
+    ) -> *mut ::std::os::raw::c_char;
+}
+extern "C" {
+    #[link_name = "\u{1}__tzname"]
+    pub static mut __tzname: [*mut ::std::os::raw::c_char; 2usize];
+}
+extern "C" {
+    #[link_name = "\u{1}__daylight"]
+    pub static mut __daylight: ::std::os::raw::c_int;
+}
+extern "C" {
+    #[link_name = "\u{1}__timezone"]
+    pub static mut __timezone: ::std::os::raw::c_long;
+}
+extern "C" {
+    #[link_name = "\u{1}tzname"]
+    pub static mut tzname: [*mut ::std::os::raw::c_char; 2usize];
+}
+extern "C" {
+    pub fn tzset();
+}
+extern "C" {
+    #[link_name = "\u{1}daylight"]
+    pub static mut daylight: ::std::os::raw::c_int;
+}
+extern "C" {
+    #[link_name = "\u{1}timezone"]
+    pub static mut timezone: ::std::os::raw::c_long;
+}
+extern "C" {
+    pub fn stime(__when: *const time_t) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn timegm(__tp: *mut tm) -> time_t;
+}
+extern "C" {
+    pub fn timelocal(__tp: *mut tm) -> time_t;
+}
+extern "C" {
+    pub fn dysize(__year: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn nanosleep(
+        __requested_time: *const timespec,
+        __remaining: *mut timespec,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn clock_getres(__clock_id: clockid_t, __res: *mut timespec) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn clock_gettime(__clock_id: clockid_t, __tp: *mut timespec) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn clock_settime(__clock_id: clockid_t, __tp: *const timespec) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn clock_nanosleep(
+        __clock_id: clockid_t,
+        __flags: ::std::os::raw::c_int,
+        __req: *const timespec,
+        __rem: *mut timespec,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn clock_getcpuclockid(__pid: pid_t, __clock_id: *mut clockid_t) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn timer_create(
+        __clock_id: clockid_t,
+        __evp: *mut sigevent,
+        __timerid: *mut timer_t,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn timer_delete(__timerid: timer_t) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn timer_settime(
+        __timerid: timer_t,
+        __flags: ::std::os::raw::c_int,
+        __value: *const itimerspec,
+        __ovalue: *mut itimerspec,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn timer_gettime(__timerid: timer_t, __value: *mut itimerspec) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn timer_getoverrun(__timerid: timer_t) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn timespec_get(
+        __ts: *mut timespec,
+        __base: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+/// In the context of a \ref libusb_device_descriptor "device descriptor",
+/// this bDeviceClass value indicates that each interface specifies its
+/// own class information and all interfaces operate independently.
+pub const LIBUSB_CLASS_PER_INTERFACE: libusb_class_code = 0;
+/// Audio class
+pub const LIBUSB_CLASS_AUDIO: libusb_class_code = 1;
+/// Communications class
+pub const LIBUSB_CLASS_COMM: libusb_class_code = 2;
+/// Human Interface Device class
+pub const LIBUSB_CLASS_HID: libusb_class_code = 3;
+/// Physical
+pub const LIBUSB_CLASS_PHYSICAL: libusb_class_code = 5;
+/// Printer class
+pub const LIBUSB_CLASS_PRINTER: libusb_class_code = 7;
+/// Image class
+pub const LIBUSB_CLASS_PTP: libusb_class_code = 6;
+/// Image class
+pub const LIBUSB_CLASS_IMAGE: libusb_class_code = 6;
+/// Mass storage class
+pub const LIBUSB_CLASS_MASS_STORAGE: libusb_class_code = 8;
+/// Hub class
+pub const LIBUSB_CLASS_HUB: libusb_class_code = 9;
+/// Data class
+pub const LIBUSB_CLASS_DATA: libusb_class_code = 10;
+/// Smart Card
+pub const LIBUSB_CLASS_SMART_CARD: libusb_class_code = 11;
+/// Content Security
+pub const LIBUSB_CLASS_CONTENT_SECURITY: libusb_class_code = 13;
+/// Video
+pub const LIBUSB_CLASS_VIDEO: libusb_class_code = 14;
+/// Personal Healthcare
+pub const LIBUSB_CLASS_PERSONAL_HEALTHCARE: libusb_class_code = 15;
+/// Diagnostic Device
+pub const LIBUSB_CLASS_DIAGNOSTIC_DEVICE: libusb_class_code = 220;
+/// Wireless class
+pub const LIBUSB_CLASS_WIRELESS: libusb_class_code = 224;
+/// Application class
+pub const LIBUSB_CLASS_APPLICATION: libusb_class_code = 254;
+/// Class is vendor-specific
+pub const LIBUSB_CLASS_VENDOR_SPEC: libusb_class_code = 255;
+/// \ingroup libusb_desc
+/// Device and/or Interface Class codes
+pub type libusb_class_code = u32;
+/// Device descriptor. See libusb_device_descriptor.
+pub const LIBUSB_DT_DEVICE: libusb_descriptor_type = 1;
+/// Configuration descriptor. See libusb_config_descriptor.
+pub const LIBUSB_DT_CONFIG: libusb_descriptor_type = 2;
+/// String descriptor
+pub const LIBUSB_DT_STRING: libusb_descriptor_type = 3;
+/// Interface descriptor. See libusb_interface_descriptor.
+pub const LIBUSB_DT_INTERFACE: libusb_descriptor_type = 4;
+/// Endpoint descriptor. See libusb_endpoint_descriptor.
+pub const LIBUSB_DT_ENDPOINT: libusb_descriptor_type = 5;
+/// BOS descriptor
+pub const LIBUSB_DT_BOS: libusb_descriptor_type = 15;
+/// Device Capability descriptor
+pub const LIBUSB_DT_DEVICE_CAPABILITY: libusb_descriptor_type = 16;
+/// HID descriptor
+pub const LIBUSB_DT_HID: libusb_descriptor_type = 33;
+/// HID report descriptor
+pub const LIBUSB_DT_REPORT: libusb_descriptor_type = 34;
+/// Physical descriptor
+pub const LIBUSB_DT_PHYSICAL: libusb_descriptor_type = 35;
+/// Hub descriptor
+pub const LIBUSB_DT_HUB: libusb_descriptor_type = 41;
+/// SuperSpeed Hub descriptor
+pub const LIBUSB_DT_SUPERSPEED_HUB: libusb_descriptor_type = 42;
+/// SuperSpeed Endpoint Companion descriptor
+pub const LIBUSB_DT_SS_ENDPOINT_COMPANION: libusb_descriptor_type = 48;
+/// \ingroup libusb_desc
+/// Descriptor types as defined by the USB specification.
+pub type libusb_descriptor_type = u32;
+/// In: device-to-host
+pub const LIBUSB_ENDPOINT_IN: libusb_endpoint_direction = 128;
+/// Out: host-to-device
+pub const LIBUSB_ENDPOINT_OUT: libusb_endpoint_direction = 0;
+/// \ingroup libusb_desc
+/// Endpoint direction. Values for bit 7 of the
+/// \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme.
+pub type libusb_endpoint_direction = u32;
+/// Control endpoint
+pub const LIBUSB_TRANSFER_TYPE_CONTROL: libusb_transfer_type = 0;
+/// Isochronous endpoint
+pub const LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: libusb_transfer_type = 1;
+/// Bulk endpoint
+pub const LIBUSB_TRANSFER_TYPE_BULK: libusb_transfer_type = 2;
+/// Interrupt endpoint
+pub const LIBUSB_TRANSFER_TYPE_INTERRUPT: libusb_transfer_type = 3;
+/// Stream endpoint
+pub const LIBUSB_TRANSFER_TYPE_BULK_STREAM: libusb_transfer_type = 4;
+/// \ingroup libusb_desc
+/// Endpoint transfer type. Values for bits 0:1 of the
+/// \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field.
+pub type libusb_transfer_type = u32;
+/// Request status of the specific recipient
+pub const LIBUSB_REQUEST_GET_STATUS: libusb_standard_request = 0;
+/// Clear or disable a specific feature
+pub const LIBUSB_REQUEST_CLEAR_FEATURE: libusb_standard_request = 1;
+/// Set or enable a specific feature
+pub const LIBUSB_REQUEST_SET_FEATURE: libusb_standard_request = 3;
+/// Set device address for all future accesses
+pub const LIBUSB_REQUEST_SET_ADDRESS: libusb_standard_request = 5;
+/// Get the specified descriptor
+pub const LIBUSB_REQUEST_GET_DESCRIPTOR: libusb_standard_request = 6;
+/// Used to update existing descriptors or add new descriptors
+pub const LIBUSB_REQUEST_SET_DESCRIPTOR: libusb_standard_request = 7;
+/// Get the current device configuration value
+pub const LIBUSB_REQUEST_GET_CONFIGURATION: libusb_standard_request = 8;
+/// Set device configuration
+pub const LIBUSB_REQUEST_SET_CONFIGURATION: libusb_standard_request = 9;
+/// Return the selected alternate setting for the specified interface
+pub const LIBUSB_REQUEST_GET_INTERFACE: libusb_standard_request = 10;
+/// Select an alternate interface for the specified interface
+pub const LIBUSB_REQUEST_SET_INTERFACE: libusb_standard_request = 11;
+/// Set then report an endpoint's synchronization frame
+pub const LIBUSB_REQUEST_SYNCH_FRAME: libusb_standard_request = 12;
+/// Sets both the U1 and U2 Exit Latency
+pub const LIBUSB_REQUEST_SET_SEL: libusb_standard_request = 48;
+/// Delay from the time a host transmits a packet to the time it is
+/// received by the device.
+pub const LIBUSB_SET_ISOCH_DELAY: libusb_standard_request = 49;
+/// \ingroup libusb_misc
+/// Standard requests, as defined in table 9-5 of the USB 3.0 specifications
+pub type libusb_standard_request = u32;
+/// Standard
+pub const LIBUSB_REQUEST_TYPE_STANDARD: libusb_request_type = 0;
+/// Class
+pub const LIBUSB_REQUEST_TYPE_CLASS: libusb_request_type = 32;
+/// Vendor
+pub const LIBUSB_REQUEST_TYPE_VENDOR: libusb_request_type = 64;
+/// Reserved
+pub const LIBUSB_REQUEST_TYPE_RESERVED: libusb_request_type = 96;
+/// \ingroup libusb_misc
+/// Request type bits of the
+/// \ref libusb_control_setup::bmRequestType "bmRequestType" field in control
+/// transfers.
+pub type libusb_request_type = u32;
+/// Device
+pub const LIBUSB_RECIPIENT_DEVICE: libusb_request_recipient = 0;
+/// Interface
+pub const LIBUSB_RECIPIENT_INTERFACE: libusb_request_recipient = 1;
+/// Endpoint
+pub const LIBUSB_RECIPIENT_ENDPOINT: libusb_request_recipient = 2;
+/// Other
+pub const LIBUSB_RECIPIENT_OTHER: libusb_request_recipient = 3;
+/// \ingroup libusb_misc
+/// Recipient bits of the
+/// \ref libusb_control_setup::bmRequestType "bmRequestType" field in control
+/// transfers. Values 4 through 31 are reserved.
+pub type libusb_request_recipient = u32;
+/// No synchronization
+pub const LIBUSB_ISO_SYNC_TYPE_NONE: libusb_iso_sync_type = 0;
+/// Asynchronous
+pub const LIBUSB_ISO_SYNC_TYPE_ASYNC: libusb_iso_sync_type = 1;
+/// Adaptive
+pub const LIBUSB_ISO_SYNC_TYPE_ADAPTIVE: libusb_iso_sync_type = 2;
+/// Synchronous
+pub const LIBUSB_ISO_SYNC_TYPE_SYNC: libusb_iso_sync_type = 3;
+/// \ingroup libusb_desc
+/// Synchronization type for isochronous endpoints. Values for bits 2:3 of the
+/// \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in
+/// libusb_endpoint_descriptor.
+pub type libusb_iso_sync_type = u32;
+/// Data endpoint
+pub const LIBUSB_ISO_USAGE_TYPE_DATA: libusb_iso_usage_type = 0;
+/// Feedback endpoint
+pub const LIBUSB_ISO_USAGE_TYPE_FEEDBACK: libusb_iso_usage_type = 1;
+/// Implicit feedback Data endpoint
+pub const LIBUSB_ISO_USAGE_TYPE_IMPLICIT: libusb_iso_usage_type = 2;
+/// \ingroup libusb_desc
+/// Usage type for isochronous endpoints. Values for bits 4:5 of the
+/// \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in
+/// libusb_endpoint_descriptor.
+pub type libusb_iso_usage_type = u32;
+/// \ingroup libusb_desc
+/// A structure representing the standard USB device descriptor. This
+/// descriptor is documented in section 9.6.1 of the USB 3.0 specification.
+/// All multiple-byte fields are represented in host-endian format.
+#[repr(C)]
+#[derive(Default, Debug, Copy, Clone)]
+pub struct libusb_device_descriptor {
+    /// Size of this descriptor (in bytes)
+    pub bLength: u8,
+    /// Descriptor type. Will have value
+    /// \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this
+    /// context.
+    pub bDescriptorType: u8,
+    /// USB specification release number in binary-coded decimal. A value of
+    /// 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc.
+    pub bcdUSB: u16,
+    /// USB-IF class code for the device. See \ref libusb_class_code.
+    pub bDeviceClass: u8,
+    /// USB-IF subclass code for the device, qualified by the bDeviceClass
+    /// value
+    pub bDeviceSubClass: u8,
+    /// USB-IF protocol code for the device, qualified by the bDeviceClass and
+    /// bDeviceSubClass values
+    pub bDeviceProtocol: u8,
+    /// Maximum packet size for endpoint 0
+    pub bMaxPacketSize0: u8,
+    /// USB-IF vendor ID
+    pub idVendor: u16,
+    /// USB-IF product ID
+    pub idProduct: u16,
+    /// Device release number in binary-coded decimal
+    pub bcdDevice: u16,
+    /// Index of string descriptor describing manufacturer
+    pub iManufacturer: u8,
+    /// Index of string descriptor describing product
+    pub iProduct: u8,
+    /// Index of string descriptor containing device serial number
+    pub iSerialNumber: u8,
+    /// Number of possible configurations
+    pub bNumConfigurations: u8,
+}
+#[test]
+fn bindgen_test_layout_libusb_device_descriptor() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_device_descriptor>(),
+        18usize,
+        concat!("Size of: ", stringify!(libusb_device_descriptor))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_device_descriptor>(),
+        2usize,
+        concat!("Alignment of ", stringify!(libusb_device_descriptor))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_device_descriptor>())).bLength as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_device_descriptor),
+            "::",
+            stringify!(bLength)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_device_descriptor>())).bDescriptorType as *const _
+                as usize
+        },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_device_descriptor),
+            "::",
+            stringify!(bDescriptorType)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_device_descriptor>())).bcdUSB as *const _ as usize },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_device_descriptor),
+            "::",
+            stringify!(bcdUSB)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_device_descriptor>())).bDeviceClass as *const _ as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_device_descriptor),
+            "::",
+            stringify!(bDeviceClass)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_device_descriptor>())).bDeviceSubClass as *const _
+                as usize
+        },
+        5usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_device_descriptor),
+            "::",
+            stringify!(bDeviceSubClass)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_device_descriptor>())).bDeviceProtocol as *const _
+                as usize
+        },
+        6usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_device_descriptor),
+            "::",
+            stringify!(bDeviceProtocol)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_device_descriptor>())).bMaxPacketSize0 as *const _
+                as usize
+        },
+        7usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_device_descriptor),
+            "::",
+            stringify!(bMaxPacketSize0)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_device_descriptor>())).idVendor as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_device_descriptor),
+            "::",
+            stringify!(idVendor)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_device_descriptor>())).idProduct as *const _ as usize
+        },
+        10usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_device_descriptor),
+            "::",
+            stringify!(idProduct)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_device_descriptor>())).bcdDevice as *const _ as usize
+        },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_device_descriptor),
+            "::",
+            stringify!(bcdDevice)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_device_descriptor>())).iManufacturer as *const _ as usize
+        },
+        14usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_device_descriptor),
+            "::",
+            stringify!(iManufacturer)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_device_descriptor>())).iProduct as *const _ as usize
+        },
+        15usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_device_descriptor),
+            "::",
+            stringify!(iProduct)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_device_descriptor>())).iSerialNumber as *const _ as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_device_descriptor),
+            "::",
+            stringify!(iSerialNumber)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_device_descriptor>())).bNumConfigurations as *const _
+                as usize
+        },
+        17usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_device_descriptor),
+            "::",
+            stringify!(bNumConfigurations)
+        )
+    );
+}
+/// \ingroup libusb_desc
+/// A structure representing the standard USB endpoint descriptor. This
+/// descriptor is documented in section 9.6.6 of the USB 3.0 specification.
+/// All multiple-byte fields are represented in host-endian format.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_endpoint_descriptor {
+    /// Size of this descriptor (in bytes)
+    pub bLength: u8,
+    /// Descriptor type. Will have value
+    /// \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT LIBUSB_DT_ENDPOINT in
+    /// this context.
+    pub bDescriptorType: u8,
+    /// The address of the endpoint described by this descriptor. Bits 0:3 are
+    /// the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction,
+    /// see \ref libusb_endpoint_direction.
+    pub bEndpointAddress: u8,
+    /// Attributes which apply to the endpoint when it is configured using
+    /// the bConfigurationValue. Bits 0:1 determine the transfer type and
+    /// correspond to \ref libusb_transfer_type. Bits 2:3 are only used for
+    /// isochronous endpoints and correspond to \ref libusb_iso_sync_type.
+    /// Bits 4:5 are also only used for isochronous endpoints and correspond to
+    /// \ref libusb_iso_usage_type. Bits 6:7 are reserved.
+    pub bmAttributes: u8,
+    /// Maximum packet size this endpoint is capable of sending/receiving.
+    pub wMaxPacketSize: u16,
+    /// Interval for polling endpoint for data transfers.
+    pub bInterval: u8,
+    /// For audio devices only: the rate at which synchronization feedback
+    /// is provided.
+    pub bRefresh: u8,
+    /// For audio devices only: the address if the synch endpoint
+    pub bSynchAddress: u8,
+    /// Extra descriptors. If libusb encounters unknown endpoint descriptors,
+    /// it will store them here, should you wish to parse them.
+    pub extra: *const ::std::os::raw::c_uchar,
+    /// Length of the extra descriptors, in bytes.
+    pub extra_length: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_libusb_endpoint_descriptor() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_endpoint_descriptor>(),
+        32usize,
+        concat!("Size of: ", stringify!(libusb_endpoint_descriptor))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_endpoint_descriptor>(),
+        8usize,
+        concat!("Alignment of ", stringify!(libusb_endpoint_descriptor))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).bLength as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_endpoint_descriptor),
+            "::",
+            stringify!(bLength)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).bDescriptorType as *const _
+                as usize
+        },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_endpoint_descriptor),
+            "::",
+            stringify!(bDescriptorType)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).bEndpointAddress as *const _
+                as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_endpoint_descriptor),
+            "::",
+            stringify!(bEndpointAddress)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).bmAttributes as *const _ as usize
+        },
+        3usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_endpoint_descriptor),
+            "::",
+            stringify!(bmAttributes)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).wMaxPacketSize as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_endpoint_descriptor),
+            "::",
+            stringify!(wMaxPacketSize)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).bInterval as *const _ as usize
+        },
+        6usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_endpoint_descriptor),
+            "::",
+            stringify!(bInterval)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).bRefresh as *const _ as usize
+        },
+        7usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_endpoint_descriptor),
+            "::",
+            stringify!(bRefresh)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).bSynchAddress as *const _
+                as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_endpoint_descriptor),
+            "::",
+            stringify!(bSynchAddress)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).extra as *const _ as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_endpoint_descriptor),
+            "::",
+            stringify!(extra)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).extra_length as *const _ as usize
+        },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_endpoint_descriptor),
+            "::",
+            stringify!(extra_length)
+        )
+    );
+}
+/// \ingroup libusb_desc
+/// A structure representing the standard USB interface descriptor. This
+/// descriptor is documented in section 9.6.5 of the USB 3.0 specification.
+/// All multiple-byte fields are represented in host-endian format.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_interface_descriptor {
+    /// Size of this descriptor (in bytes)
+    pub bLength: u8,
+    /// Descriptor type. Will have value
+    /// \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE LIBUSB_DT_INTERFACE
+    /// in this context.
+    pub bDescriptorType: u8,
+    /// Number of this interface
+    pub bInterfaceNumber: u8,
+    /// Value used to select this alternate setting for this interface
+    pub bAlternateSetting: u8,
+    /// Number of endpoints used by this interface (excluding the control
+    /// endpoint).
+    pub bNumEndpoints: u8,
+    /// USB-IF class code for this interface. See \ref libusb_class_code.
+    pub bInterfaceClass: u8,
+    /// USB-IF subclass code for this interface, qualified by the
+    /// bInterfaceClass value
+    pub bInterfaceSubClass: u8,
+    /// USB-IF protocol code for this interface, qualified by the
+    /// bInterfaceClass and bInterfaceSubClass values
+    pub bInterfaceProtocol: u8,
+    /// Index of string descriptor describing this interface
+    pub iInterface: u8,
+    /// Array of endpoint descriptors. This length of this array is determined
+    /// by the bNumEndpoints field.
+    pub endpoint: *const libusb_endpoint_descriptor,
+    /// Extra descriptors. If libusb encounters unknown interface descriptors,
+    /// it will store them here, should you wish to parse them.
+    pub extra: *const ::std::os::raw::c_uchar,
+    /// Length of the extra descriptors, in bytes.
+    pub extra_length: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_libusb_interface_descriptor() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_interface_descriptor>(),
+        40usize,
+        concat!("Size of: ", stringify!(libusb_interface_descriptor))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_interface_descriptor>(),
+        8usize,
+        concat!("Alignment of ", stringify!(libusb_interface_descriptor))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_interface_descriptor>())).bLength as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_interface_descriptor),
+            "::",
+            stringify!(bLength)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_interface_descriptor>())).bDescriptorType as *const _
+                as usize
+        },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_interface_descriptor),
+            "::",
+            stringify!(bDescriptorType)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_interface_descriptor>())).bInterfaceNumber as *const _
+                as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_interface_descriptor),
+            "::",
+            stringify!(bInterfaceNumber)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_interface_descriptor>())).bAlternateSetting as *const _
+                as usize
+        },
+        3usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_interface_descriptor),
+            "::",
+            stringify!(bAlternateSetting)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_interface_descriptor>())).bNumEndpoints as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_interface_descriptor),
+            "::",
+            stringify!(bNumEndpoints)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_interface_descriptor>())).bInterfaceClass as *const _
+                as usize
+        },
+        5usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_interface_descriptor),
+            "::",
+            stringify!(bInterfaceClass)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_interface_descriptor>())).bInterfaceSubClass as *const _
+                as usize
+        },
+        6usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_interface_descriptor),
+            "::",
+            stringify!(bInterfaceSubClass)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_interface_descriptor>())).bInterfaceProtocol as *const _
+                as usize
+        },
+        7usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_interface_descriptor),
+            "::",
+            stringify!(bInterfaceProtocol)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_interface_descriptor>())).iInterface as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_interface_descriptor),
+            "::",
+            stringify!(iInterface)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_interface_descriptor>())).endpoint as *const _ as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_interface_descriptor),
+            "::",
+            stringify!(endpoint)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_interface_descriptor>())).extra as *const _ as usize
+        },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_interface_descriptor),
+            "::",
+            stringify!(extra)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_interface_descriptor>())).extra_length as *const _
+                as usize
+        },
+        32usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_interface_descriptor),
+            "::",
+            stringify!(extra_length)
+        )
+    );
+}
+/// \ingroup libusb_desc
+/// A collection of alternate settings for a particular USB interface.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_interface {
+    /// Array of interface descriptors. The length of this array is determined
+    /// by the num_altsetting field.
+    pub altsetting: *const libusb_interface_descriptor,
+    /// The number of alternate settings that belong to this interface
+    pub num_altsetting: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_libusb_interface() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_interface>(),
+        16usize,
+        concat!("Size of: ", stringify!(libusb_interface))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_interface>(),
+        8usize,
+        concat!("Alignment of ", stringify!(libusb_interface))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_interface>())).altsetting as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_interface),
+            "::",
+            stringify!(altsetting)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_interface>())).num_altsetting as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_interface),
+            "::",
+            stringify!(num_altsetting)
+        )
+    );
+}
+/// \ingroup libusb_desc
+/// A structure representing the standard USB configuration descriptor. This
+/// descriptor is documented in section 9.6.3 of the USB 3.0 specification.
+/// All multiple-byte fields are represented in host-endian format.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_config_descriptor {
+    /// Size of this descriptor (in bytes)
+    pub bLength: u8,
+    /// Descriptor type. Will have value
+    /// \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG
+    /// in this context.
+    pub bDescriptorType: u8,
+    /// Total length of data returned for this configuration
+    pub wTotalLength: u16,
+    /// Number of interfaces supported by this configuration
+    pub bNumInterfaces: u8,
+    /// Identifier value for this configuration
+    pub bConfigurationValue: u8,
+    /// Index of string descriptor describing this configuration
+    pub iConfiguration: u8,
+    /// Configuration characteristics
+    pub bmAttributes: u8,
+    /// Maximum power consumption of the USB device from this bus in this
+    /// configuration when the device is fully operation. Expressed in units
+    /// of 2 mA when the device is operating in high-speed mode and in units
+    /// of 8 mA when the device is operating in super-speed mode.
+    pub MaxPower: u8,
+    /// Array of interfaces supported by this configuration. The length of
+    /// this array is determined by the bNumInterfaces field.
+    pub interface: *const libusb_interface,
+    /// Extra descriptors. If libusb encounters unknown configuration
+    /// descriptors, it will store them here, should you wish to parse them.
+    pub extra: *const ::std::os::raw::c_uchar,
+    /// Length of the extra descriptors, in bytes.
+    pub extra_length: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_libusb_config_descriptor() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_config_descriptor>(),
+        40usize,
+        concat!("Size of: ", stringify!(libusb_config_descriptor))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_config_descriptor>(),
+        8usize,
+        concat!("Alignment of ", stringify!(libusb_config_descriptor))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_config_descriptor>())).bLength as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_config_descriptor),
+            "::",
+            stringify!(bLength)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_config_descriptor>())).bDescriptorType as *const _
+                as usize
+        },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_config_descriptor),
+            "::",
+            stringify!(bDescriptorType)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_config_descriptor>())).wTotalLength as *const _ as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_config_descriptor),
+            "::",
+            stringify!(wTotalLength)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_config_descriptor>())).bNumInterfaces as *const _ as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_config_descriptor),
+            "::",
+            stringify!(bNumInterfaces)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_config_descriptor>())).bConfigurationValue as *const _
+                as usize
+        },
+        5usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_config_descriptor),
+            "::",
+            stringify!(bConfigurationValue)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_config_descriptor>())).iConfiguration as *const _ as usize
+        },
+        6usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_config_descriptor),
+            "::",
+            stringify!(iConfiguration)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_config_descriptor>())).bmAttributes as *const _ as usize
+        },
+        7usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_config_descriptor),
+            "::",
+            stringify!(bmAttributes)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_config_descriptor>())).MaxPower as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_config_descriptor),
+            "::",
+            stringify!(MaxPower)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_config_descriptor>())).interface as *const _ as usize
+        },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_config_descriptor),
+            "::",
+            stringify!(interface)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_config_descriptor>())).extra as *const _ as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_config_descriptor),
+            "::",
+            stringify!(extra)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_config_descriptor>())).extra_length as *const _ as usize
+        },
+        32usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_config_descriptor),
+            "::",
+            stringify!(extra_length)
+        )
+    );
+}
+/// \ingroup libusb_desc
+/// A structure representing the superspeed endpoint companion
+/// descriptor. This descriptor is documented in section 9.6.7 of
+/// the USB 3.0 specification. All multiple-byte fields are represented in
+/// host-endian format.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_ss_endpoint_companion_descriptor {
+    /// Size of this descriptor (in bytes)
+    pub bLength: u8,
+    /// Descriptor type. Will have value
+    /// \ref libusb_descriptor_type::LIBUSB_DT_SS_ENDPOINT_COMPANION in
+    /// this context.
+    pub bDescriptorType: u8,
+    /// The maximum number of packets the endpoint can send or
+    /// receive as part of a burst.
+    pub bMaxBurst: u8,
+    /// In bulk EP:	bits 4:0 represents the	maximum	number of
+    /// streams the	EP supports. In	isochronous EP:	bits 1:0
+    /// represents the Mult	- a zero based value that determines
+    /// the	maximum	number of packets within a service interval
+    pub bmAttributes: u8,
+    /// The	total number of bytes this EP will transfer every
+    /// service interval. valid only for periodic EPs.
+    pub wBytesPerInterval: u16,
+}
+#[test]
+fn bindgen_test_layout_libusb_ss_endpoint_companion_descriptor() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_ss_endpoint_companion_descriptor>(),
+        6usize,
+        concat!(
+            "Size of: ",
+            stringify!(libusb_ss_endpoint_companion_descriptor)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_ss_endpoint_companion_descriptor>(),
+        2usize,
+        concat!(
+            "Alignment of ",
+            stringify!(libusb_ss_endpoint_companion_descriptor)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_ss_endpoint_companion_descriptor>())).bLength as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_ss_endpoint_companion_descriptor),
+            "::",
+            stringify!(bLength)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_ss_endpoint_companion_descriptor>())).bDescriptorType
+                as *const _ as usize
+        },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_ss_endpoint_companion_descriptor),
+            "::",
+            stringify!(bDescriptorType)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_ss_endpoint_companion_descriptor>())).bMaxBurst
+                as *const _ as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_ss_endpoint_companion_descriptor),
+            "::",
+            stringify!(bMaxBurst)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_ss_endpoint_companion_descriptor>())).bmAttributes
+                as *const _ as usize
+        },
+        3usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_ss_endpoint_companion_descriptor),
+            "::",
+            stringify!(bmAttributes)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_ss_endpoint_companion_descriptor>())).wBytesPerInterval
+                as *const _ as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_ss_endpoint_companion_descriptor),
+            "::",
+            stringify!(wBytesPerInterval)
+        )
+    );
+}
+/// \ingroup libusb_desc
+/// A generic representation of a BOS Device Capability descriptor. It is
+/// advised to check bDevCapabilityType and call the matching
+/// libusb_get_*_descriptor function to get a structure fully matching the type.
+#[repr(C)]
+#[derive(Debug)]
+pub struct libusb_bos_dev_capability_descriptor {
+    /// Size of this descriptor (in bytes)
+    pub bLength: u8,
+    /// Descriptor type. Will have value
+    /// \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
+    /// LIBUSB_DT_DEVICE_CAPABILITY in this context.
+    pub bDescriptorType: u8,
+    /// Device Capability type
+    pub bDevCapabilityType: u8,
+    /// Device Capability data (bLength - 3 bytes)
+    pub dev_capability_data: __IncompleteArrayField<u8>,
+}
+#[test]
+fn bindgen_test_layout_libusb_bos_dev_capability_descriptor() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_bos_dev_capability_descriptor>(),
+        3usize,
+        concat!(
+            "Size of: ",
+            stringify!(libusb_bos_dev_capability_descriptor)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_bos_dev_capability_descriptor>(),
+        1usize,
+        concat!(
+            "Alignment of ",
+            stringify!(libusb_bos_dev_capability_descriptor)
+        )
+    );
+}
+/// \ingroup libusb_desc
+/// A structure representing the Binary Device Object Store (BOS) descriptor.
+/// This descriptor is documented in section 9.6.2 of the USB 3.0 specification.
+/// All multiple-byte fields are represented in host-endian format.
+#[repr(C)]
+#[derive(Debug)]
+pub struct libusb_bos_descriptor {
+    /// Size of this descriptor (in bytes)
+    pub bLength: u8,
+    /// Descriptor type. Will have value
+    /// \ref libusb_descriptor_type::LIBUSB_DT_BOS LIBUSB_DT_BOS
+    /// in this context.
+    pub bDescriptorType: u8,
+    /// Length of this descriptor and all of its sub descriptors
+    pub wTotalLength: u16,
+    /// The number of separate device capability descriptors in
+    /// the BOS
+    pub bNumDeviceCaps: u8,
+    /// bNumDeviceCap Device Capability Descriptors
+    pub dev_capability: __IncompleteArrayField<*mut libusb_bos_dev_capability_descriptor>,
+    pub __bindgen_align: [u64; 0usize],
+}
+#[test]
+fn bindgen_test_layout_libusb_bos_descriptor() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_bos_descriptor>(),
+        8usize,
+        concat!("Size of: ", stringify!(libusb_bos_descriptor))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_bos_descriptor>(),
+        8usize,
+        concat!("Alignment of ", stringify!(libusb_bos_descriptor))
+    );
+}
+/// \ingroup libusb_desc
+/// A structure representing the USB 2.0 Extension descriptor
+/// This descriptor is documented in section 9.6.2.1 of the USB 3.0 specification.
+/// All multiple-byte fields are represented in host-endian format.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_usb_2_0_extension_descriptor {
+    /// Size of this descriptor (in bytes)
+    pub bLength: u8,
+    /// Descriptor type. Will have value
+    /// \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
+    /// LIBUSB_DT_DEVICE_CAPABILITY in this context.
+    pub bDescriptorType: u8,
+    /// Capability type. Will have value
+    /// \ref libusb_capability_type::LIBUSB_BT_USB_2_0_EXTENSION
+    /// LIBUSB_BT_USB_2_0_EXTENSION in this context.
+    pub bDevCapabilityType: u8,
+    /// Bitmap encoding of supported device level features.
+    /// A value of one in a bit location indicates a feature is
+    /// supported; a value of zero indicates it is not supported.
+    /// See \ref libusb_usb_2_0_extension_attributes.
+    pub bmAttributes: u32,
+}
+#[test]
+fn bindgen_test_layout_libusb_usb_2_0_extension_descriptor() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_usb_2_0_extension_descriptor>(),
+        8usize,
+        concat!("Size of: ", stringify!(libusb_usb_2_0_extension_descriptor))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_usb_2_0_extension_descriptor>(),
+        4usize,
+        concat!(
+            "Alignment of ",
+            stringify!(libusb_usb_2_0_extension_descriptor)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_usb_2_0_extension_descriptor>())).bLength as *const _
+                as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_usb_2_0_extension_descriptor),
+            "::",
+            stringify!(bLength)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_usb_2_0_extension_descriptor>())).bDescriptorType
+                as *const _ as usize
+        },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_usb_2_0_extension_descriptor),
+            "::",
+            stringify!(bDescriptorType)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_usb_2_0_extension_descriptor>())).bDevCapabilityType
+                as *const _ as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_usb_2_0_extension_descriptor),
+            "::",
+            stringify!(bDevCapabilityType)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_usb_2_0_extension_descriptor>())).bmAttributes as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_usb_2_0_extension_descriptor),
+            "::",
+            stringify!(bmAttributes)
+        )
+    );
+}
+/// \ingroup libusb_desc
+/// A structure representing the SuperSpeed USB Device Capability descriptor
+/// This descriptor is documented in section 9.6.2.2 of the USB 3.0 specification.
+/// All multiple-byte fields are represented in host-endian format.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_ss_usb_device_capability_descriptor {
+    /// Size of this descriptor (in bytes)
+    pub bLength: u8,
+    /// Descriptor type. Will have value
+    /// \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
+    /// LIBUSB_DT_DEVICE_CAPABILITY in this context.
+    pub bDescriptorType: u8,
+    /// Capability type. Will have value
+    /// \ref libusb_capability_type::LIBUSB_BT_SS_USB_DEVICE_CAPABILITY
+    /// LIBUSB_BT_SS_USB_DEVICE_CAPABILITY in this context.
+    pub bDevCapabilityType: u8,
+    /// Bitmap encoding of supported device level features.
+    /// A value of one in a bit location indicates a feature is
+    /// supported; a value of zero indicates it is not supported.
+    /// See \ref libusb_ss_usb_device_capability_attributes.
+    pub bmAttributes: u8,
+    /// Bitmap encoding of the speed supported by this device when
+    /// operating in SuperSpeed mode. See \ref libusb_supported_speed.
+    pub wSpeedSupported: u16,
+    /// The lowest speed at which all the functionality supported
+    /// by the device is available to the user. For example if the
+    /// device supports all its functionality when connected at
+    /// full speed and above then it sets this value to 1.
+    pub bFunctionalitySupport: u8,
+    /// U1 Device Exit Latency.
+    pub bU1DevExitLat: u8,
+    /// U2 Device Exit Latency.
+    pub bU2DevExitLat: u16,
+}
+#[test]
+fn bindgen_test_layout_libusb_ss_usb_device_capability_descriptor() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_ss_usb_device_capability_descriptor>(),
+        10usize,
+        concat!(
+            "Size of: ",
+            stringify!(libusb_ss_usb_device_capability_descriptor)
+        )
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_ss_usb_device_capability_descriptor>(),
+        2usize,
+        concat!(
+            "Alignment of ",
+            stringify!(libusb_ss_usb_device_capability_descriptor)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>())).bLength
+                as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_ss_usb_device_capability_descriptor),
+            "::",
+            stringify!(bLength)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>())).bDescriptorType
+                as *const _ as usize
+        },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_ss_usb_device_capability_descriptor),
+            "::",
+            stringify!(bDescriptorType)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>()))
+                .bDevCapabilityType as *const _ as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_ss_usb_device_capability_descriptor),
+            "::",
+            stringify!(bDevCapabilityType)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>())).bmAttributes
+                as *const _ as usize
+        },
+        3usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_ss_usb_device_capability_descriptor),
+            "::",
+            stringify!(bmAttributes)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>())).wSpeedSupported
+                as *const _ as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_ss_usb_device_capability_descriptor),
+            "::",
+            stringify!(wSpeedSupported)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>()))
+                .bFunctionalitySupport as *const _ as usize
+        },
+        6usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_ss_usb_device_capability_descriptor),
+            "::",
+            stringify!(bFunctionalitySupport)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>())).bU1DevExitLat
+                as *const _ as usize
+        },
+        7usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_ss_usb_device_capability_descriptor),
+            "::",
+            stringify!(bU1DevExitLat)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>())).bU2DevExitLat
+                as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_ss_usb_device_capability_descriptor),
+            "::",
+            stringify!(bU2DevExitLat)
+        )
+    );
+}
+/// \ingroup libusb_desc
+/// A structure representing the Container ID descriptor.
+/// This descriptor is documented in section 9.6.2.3 of the USB 3.0 specification.
+/// All multiple-byte fields, except UUIDs, are represented in host-endian format.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_container_id_descriptor {
+    /// Size of this descriptor (in bytes)
+    pub bLength: u8,
+    /// Descriptor type. Will have value
+    /// \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
+    /// LIBUSB_DT_DEVICE_CAPABILITY in this context.
+    pub bDescriptorType: u8,
+    /// Capability type. Will have value
+    /// \ref libusb_capability_type::LIBUSB_BT_CONTAINER_ID
+    /// LIBUSB_BT_CONTAINER_ID in this context.
+    pub bDevCapabilityType: u8,
+    /// Reserved field
+    pub bReserved: u8,
+    /// 128 bit UUID
+    pub ContainerID: [u8; 16usize],
+}
+#[test]
+fn bindgen_test_layout_libusb_container_id_descriptor() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_container_id_descriptor>(),
+        20usize,
+        concat!("Size of: ", stringify!(libusb_container_id_descriptor))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_container_id_descriptor>(),
+        1usize,
+        concat!("Alignment of ", stringify!(libusb_container_id_descriptor))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_container_id_descriptor>())).bLength as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_container_id_descriptor),
+            "::",
+            stringify!(bLength)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_container_id_descriptor>())).bDescriptorType as *const _
+                as usize
+        },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_container_id_descriptor),
+            "::",
+            stringify!(bDescriptorType)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_container_id_descriptor>())).bDevCapabilityType
+                as *const _ as usize
+        },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_container_id_descriptor),
+            "::",
+            stringify!(bDevCapabilityType)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_container_id_descriptor>())).bReserved as *const _
+                as usize
+        },
+        3usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_container_id_descriptor),
+            "::",
+            stringify!(bReserved)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_container_id_descriptor>())).ContainerID as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_container_id_descriptor),
+            "::",
+            stringify!(ContainerID)
+        )
+    );
+}
+/// \ingroup libusb_asyncio
+/// Setup packet for control transfers.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_control_setup {
+    /// Request type. Bits 0:4 determine recipient, see
+    /// \ref libusb_request_recipient. Bits 5:6 determine type, see
+    /// \ref libusb_request_type. Bit 7 determines data transfer direction, see
+    /// \ref libusb_endpoint_direction.
+    pub bmRequestType: u8,
+    /// Request. If the type bits of bmRequestType are equal to
+    /// \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD
+    /// "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to
+    /// \ref libusb_standard_request. For other cases, use of this field is
+    /// application-specific.
+    pub bRequest: u8,
+    /// Value. Varies according to request
+    pub wValue: u16,
+    /// Index. Varies according to request, typically used to pass an index
+    /// or offset
+    pub wIndex: u16,
+    /// Number of bytes to transfer
+    pub wLength: u16,
+}
+#[test]
+fn bindgen_test_layout_libusb_control_setup() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_control_setup>(),
+        8usize,
+        concat!("Size of: ", stringify!(libusb_control_setup))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_control_setup>(),
+        2usize,
+        concat!("Alignment of ", stringify!(libusb_control_setup))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_control_setup>())).bmRequestType as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_control_setup),
+            "::",
+            stringify!(bmRequestType)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_control_setup>())).bRequest as *const _ as usize },
+        1usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_control_setup),
+            "::",
+            stringify!(bRequest)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_control_setup>())).wValue as *const _ as usize },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_control_setup),
+            "::",
+            stringify!(wValue)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_control_setup>())).wIndex as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_control_setup),
+            "::",
+            stringify!(wIndex)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_control_setup>())).wLength as *const _ as usize },
+        6usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_control_setup),
+            "::",
+            stringify!(wLength)
+        )
+    );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_context {
+    _unused: [u8; 0],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_device {
+    _unused: [u8; 0],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_device_handle {
+    _unused: [u8; 0],
+}
+/// \ingroup libusb_lib
+/// Structure providing the version of the libusb runtime
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_version {
+    /// Library major version.
+    pub major: u16,
+    /// Library minor version.
+    pub minor: u16,
+    /// Library micro version.
+    pub micro: u16,
+    /// Library nano version.
+    pub nano: u16,
+    /// Library release candidate suffix string, e.g. "-rc4".
+    pub rc: *const ::std::os::raw::c_char,
+    /// For ABI compatibility only.
+    pub describe: *const ::std::os::raw::c_char,
+}
+#[test]
+fn bindgen_test_layout_libusb_version() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_version>(),
+        24usize,
+        concat!("Size of: ", stringify!(libusb_version))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_version>(),
+        8usize,
+        concat!("Alignment of ", stringify!(libusb_version))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_version>())).major as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_version),
+            "::",
+            stringify!(major)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_version>())).minor as *const _ as usize },
+        2usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_version),
+            "::",
+            stringify!(minor)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_version>())).micro as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_version),
+            "::",
+            stringify!(micro)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_version>())).nano as *const _ as usize },
+        6usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_version),
+            "::",
+            stringify!(nano)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_version>())).rc as *const _ as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_version),
+            "::",
+            stringify!(rc)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_version>())).describe as *const _ as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_version),
+            "::",
+            stringify!(describe)
+        )
+    );
+}
+/// The OS doesn't report or know the device speed.
+pub const LIBUSB_SPEED_UNKNOWN: libusb_speed = 0;
+/// The device is operating at low speed (1.5MBit/s).
+pub const LIBUSB_SPEED_LOW: libusb_speed = 1;
+/// The device is operating at full speed (12MBit/s).
+pub const LIBUSB_SPEED_FULL: libusb_speed = 2;
+/// The device is operating at high speed (480MBit/s).
+pub const LIBUSB_SPEED_HIGH: libusb_speed = 3;
+/// The device is operating at super speed (5000MBit/s).
+pub const LIBUSB_SPEED_SUPER: libusb_speed = 4;
+/// \ingroup libusb_dev
+/// Speed codes. Indicates the speed at which the device is operating.
+pub type libusb_speed = u32;
+/// Low speed operation supported (1.5MBit/s).
+pub const LIBUSB_LOW_SPEED_OPERATION: libusb_supported_speed = 1;
+/// Full speed operation supported (12MBit/s).
+pub const LIBUSB_FULL_SPEED_OPERATION: libusb_supported_speed = 2;
+/// High speed operation supported (480MBit/s).
+pub const LIBUSB_HIGH_SPEED_OPERATION: libusb_supported_speed = 4;
+/// Superspeed operation supported (5000MBit/s).
+pub const LIBUSB_SUPER_SPEED_OPERATION: libusb_supported_speed = 8;
+/// \ingroup libusb_dev
+/// Supported speeds (wSpeedSupported) bitfield. Indicates what
+/// speeds the device supports.
+pub type libusb_supported_speed = u32;
+/// Supports Link Power Management (LPM)
+pub const LIBUSB_BM_LPM_SUPPORT: libusb_usb_2_0_extension_attributes = 2;
+/// \ingroup libusb_dev
+/// Masks for the bits of the
+/// \ref libusb_usb_2_0_extension_descriptor::bmAttributes "bmAttributes" field
+/// of the USB 2.0 Extension descriptor.
+pub type libusb_usb_2_0_extension_attributes = u32;
+/// Supports Latency Tolerance Messages (LTM)
+pub const LIBUSB_BM_LTM_SUPPORT: libusb_ss_usb_device_capability_attributes = 2;
+/// \ingroup libusb_dev
+/// Masks for the bits of the
+/// \ref libusb_ss_usb_device_capability_descriptor::bmAttributes "bmAttributes" field
+/// field of the SuperSpeed USB Device Capability descriptor.
+pub type libusb_ss_usb_device_capability_attributes = u32;
+/// Wireless USB device capability
+pub const LIBUSB_BT_WIRELESS_USB_DEVICE_CAPABILITY: libusb_bos_type = 1;
+/// USB 2.0 extensions
+pub const LIBUSB_BT_USB_2_0_EXTENSION: libusb_bos_type = 2;
+/// SuperSpeed USB device capability
+pub const LIBUSB_BT_SS_USB_DEVICE_CAPABILITY: libusb_bos_type = 3;
+/// Container ID type
+pub const LIBUSB_BT_CONTAINER_ID: libusb_bos_type = 4;
+/// \ingroup libusb_dev
+/// USB capability types
+pub type libusb_bos_type = u32;
+/// Success (no error)
+pub const LIBUSB_SUCCESS: libusb_error = 0;
+/// Input/output error
+pub const LIBUSB_ERROR_IO: libusb_error = -1;
+/// Invalid parameter
+pub const LIBUSB_ERROR_INVALID_PARAM: libusb_error = -2;
+/// Access denied (insufficient permissions)
+pub const LIBUSB_ERROR_ACCESS: libusb_error = -3;
+/// No such device (it may have been disconnected)
+pub const LIBUSB_ERROR_NO_DEVICE: libusb_error = -4;
+/// Entity not found
+pub const LIBUSB_ERROR_NOT_FOUND: libusb_error = -5;
+/// Resource busy
+pub const LIBUSB_ERROR_BUSY: libusb_error = -6;
+/// Operation timed out
+pub const LIBUSB_ERROR_TIMEOUT: libusb_error = -7;
+/// Overflow
+pub const LIBUSB_ERROR_OVERFLOW: libusb_error = -8;
+/// Pipe error
+pub const LIBUSB_ERROR_PIPE: libusb_error = -9;
+/// System call interrupted (perhaps due to signal)
+pub const LIBUSB_ERROR_INTERRUPTED: libusb_error = -10;
+/// Insufficient memory
+pub const LIBUSB_ERROR_NO_MEM: libusb_error = -11;
+/// Operation not supported or unimplemented on this platform
+pub const LIBUSB_ERROR_NOT_SUPPORTED: libusb_error = -12;
+/// Other error
+pub const LIBUSB_ERROR_OTHER: libusb_error = -99;
+/// \ingroup libusb_misc
+/// Error codes. Most libusb functions return 0 on success or one of these
+/// codes on failure.
+/// You can call libusb_error_name() to retrieve a string representation of an
+/// error code or libusb_strerror() to get an end-user suitable description of
+/// an error code.
+pub type libusb_error = i32;
+/// Transfer completed without error. Note that this does not indicate
+/// that the entire amount of requested data was transferred.
+pub const LIBUSB_TRANSFER_COMPLETED: libusb_transfer_status = 0;
+/// Transfer failed
+pub const LIBUSB_TRANSFER_ERROR: libusb_transfer_status = 1;
+/// Transfer timed out
+pub const LIBUSB_TRANSFER_TIMED_OUT: libusb_transfer_status = 2;
+/// Transfer was cancelled
+pub const LIBUSB_TRANSFER_CANCELLED: libusb_transfer_status = 3;
+/// For bulk/interrupt endpoints: halt condition detected (endpoint
+/// stalled). For control endpoints: control request not supported.
+pub const LIBUSB_TRANSFER_STALL: libusb_transfer_status = 4;
+/// Device was disconnected
+pub const LIBUSB_TRANSFER_NO_DEVICE: libusb_transfer_status = 5;
+/// Device sent more data than requested
+pub const LIBUSB_TRANSFER_OVERFLOW: libusb_transfer_status = 6;
+/// \ingroup libusb_asyncio
+/// Transfer status codes
+pub type libusb_transfer_status = u32;
+/// Report short frames as errors
+pub const LIBUSB_TRANSFER_SHORT_NOT_OK: libusb_transfer_flags = 1;
+/// Automatically free() transfer buffer during libusb_free_transfer().
+/// Note that buffers allocated with libusb_dev_mem_alloc() should not
+/// be attempted freed in this way, since free() is not an appropriate
+/// way to release such memory.
+pub const LIBUSB_TRANSFER_FREE_BUFFER: libusb_transfer_flags = 2;
+/// Automatically call libusb_free_transfer() after callback returns.
+/// If this flag is set, it is illegal to call libusb_free_transfer()
+/// from your transfer callback, as this will result in a double-free
+/// when this flag is acted upon.
+pub const LIBUSB_TRANSFER_FREE_TRANSFER: libusb_transfer_flags = 4;
+/// Terminate transfers that are a multiple of the endpoint's
+/// wMaxPacketSize with an extra zero length packet. This is useful
+/// when a device protocol mandates that each logical request is
+/// terminated by an incomplete packet (i.e. the logical requests are
+/// not separated by other means).
+///
+/// This flag only affects host-to-device transfers to bulk and interrupt
+/// endpoints. In other situations, it is ignored.
+///
+/// This flag only affects transfers with a length that is a multiple of
+/// the endpoint's wMaxPacketSize. On transfers of other lengths, this
+/// flag has no effect. Therefore, if you are working with a device that
+/// needs a ZLP whenever the end of the logical request falls on a packet
+/// boundary, then it is sensible to set this flag on <em>every</em>
+/// transfer (you do not have to worry about only setting it on transfers
+/// that end on the boundary).
+///
+/// This flag is currently only supported on Linux.
+/// On other systems, libusb_submit_transfer() will return
+/// LIBUSB_ERROR_NOT_SUPPORTED for every transfer where this flag is set.
+///
+/// Available since libusb-1.0.9.
+pub const LIBUSB_TRANSFER_ADD_ZERO_PACKET: libusb_transfer_flags = 8;
+/// \ingroup libusb_asyncio
+/// libusb_transfer.flags values
+pub type libusb_transfer_flags = u32;
+/// \ingroup libusb_asyncio
+/// Isochronous packet descriptor.
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_iso_packet_descriptor {
+    /// Length of data to request in this packet
+    pub length: ::std::os::raw::c_uint,
+    /// Amount of data that was actually transferred
+    pub actual_length: ::std::os::raw::c_uint,
+    /// Status code for this packet
+    pub status: libusb_transfer_status,
+}
+#[test]
+fn bindgen_test_layout_libusb_iso_packet_descriptor() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_iso_packet_descriptor>(),
+        12usize,
+        concat!("Size of: ", stringify!(libusb_iso_packet_descriptor))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_iso_packet_descriptor>(),
+        4usize,
+        concat!("Alignment of ", stringify!(libusb_iso_packet_descriptor))
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_iso_packet_descriptor>())).length as *const _ as usize
+        },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_iso_packet_descriptor),
+            "::",
+            stringify!(length)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_iso_packet_descriptor>())).actual_length as *const _
+                as usize
+        },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_iso_packet_descriptor),
+            "::",
+            stringify!(actual_length)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            &(*(::std::ptr::null::<libusb_iso_packet_descriptor>())).status as *const _ as usize
+        },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_iso_packet_descriptor),
+            "::",
+            stringify!(status)
+        )
+    );
+}
+/// \ingroup libusb_asyncio
+/// Asynchronous transfer callback function type. When submitting asynchronous
+/// transfers, you pass a pointer to a callback function of this type via the
+/// \ref libusb_transfer::callback "callback" member of the libusb_transfer
+/// structure. libusb will call this function later, when the transfer has
+/// completed or failed. See \ref libusb_asyncio for more information.
+/// \param transfer The libusb_transfer struct the callback function is being
+/// notified about.
+pub type libusb_transfer_cb_fn =
+    ::std::option::Option<unsafe extern "C" fn(transfer: *mut libusb_transfer)>;
+/// \ingroup libusb_asyncio
+/// The generic USB transfer structure. The user populates this structure and
+/// then submits it in order to request a transfer. After the transfer has
+/// completed, the library populates the transfer with the results and passes
+/// it back to the user.
+#[repr(C)]
+#[derive(Debug)]
+pub struct libusb_transfer {
+    /// Handle of the device that this transfer will be submitted to
+    pub dev_handle: *mut libusb_device_handle,
+    /// A bitwise OR combination of \ref libusb_transfer_flags.
+    pub flags: u8,
+    /// Address of the endpoint where this transfer will be sent.
+    pub endpoint: ::std::os::raw::c_uchar,
+    /// Type of the endpoint from \ref libusb_transfer_type
+    pub type_: ::std::os::raw::c_uchar,
+    /// Timeout for this transfer in millseconds. A value of 0 indicates no
+    /// timeout.
+    pub timeout: ::std::os::raw::c_uint,
+    /// The status of the transfer. Read-only, and only for use within
+    /// transfer callback function.
+    ///
+    /// If this is an isochronous transfer, this field may read COMPLETED even
+    /// if there were errors in the frames. Use the
+    /// \ref libusb_iso_packet_descriptor::status "status" field in each packet
+    /// to determine if errors occurred.
+    pub status: libusb_transfer_status,
+    /// Length of the data buffer
+    pub length: ::std::os::raw::c_int,
+    /// Actual length of data that was transferred. Read-only, and only for
+    /// use within transfer callback function. Not valid for isochronous
+    /// endpoint transfers.
+    pub actual_length: ::std::os::raw::c_int,
+    /// Callback function. This will be invoked when the transfer completes,
+    /// fails, or is cancelled.
+    pub callback: libusb_transfer_cb_fn,
+    /// User context data to pass to the callback function.
+    pub user_data: *mut ::std::os::raw::c_void,
+    /// Data buffer
+    pub buffer: *mut ::std::os::raw::c_uchar,
+    /// Number of isochronous packets. Only used for I/O with isochronous
+    /// endpoints.
+    pub num_iso_packets: ::std::os::raw::c_int,
+    /// Isochronous packet descriptors, for isochronous transfers only.
+    pub iso_packet_desc: __IncompleteArrayField<libusb_iso_packet_descriptor>,
+}
+#[test]
+fn bindgen_test_layout_libusb_transfer() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_transfer>(),
+        64usize,
+        concat!("Size of: ", stringify!(libusb_transfer))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_transfer>(),
+        8usize,
+        concat!("Alignment of ", stringify!(libusb_transfer))
+    );
+}
+/// The libusb_has_capability() API is available.
+pub const LIBUSB_CAP_HAS_CAPABILITY: libusb_capability = 0;
+/// Hotplug support is available on this platform.
+pub const LIBUSB_CAP_HAS_HOTPLUG: libusb_capability = 1;
+/// The library can access HID devices without requiring user intervention.
+/// Note that before being able to actually access an HID device, you may
+/// still have to call additional libusb functions such as
+/// \ref libusb_detach_kernel_driver().
+pub const LIBUSB_CAP_HAS_HID_ACCESS: libusb_capability = 256;
+/// The library supports detaching of the default USB driver, using
+/// \ref libusb_detach_kernel_driver(), if one is set by the OS kernel
+pub const LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER: libusb_capability = 257;
+/// \ingroup libusb_misc
+/// Capabilities supported by an instance of libusb on the current running
+/// platform. Test if the loaded library supports a given capability by calling
+/// \ref libusb_has_capability().
+pub type libusb_capability = u32;
+pub const LIBUSB_LOG_LEVEL_NONE: libusb_log_level = 0;
+pub const LIBUSB_LOG_LEVEL_ERROR: libusb_log_level = 1;
+pub const LIBUSB_LOG_LEVEL_WARNING: libusb_log_level = 2;
+pub const LIBUSB_LOG_LEVEL_INFO: libusb_log_level = 3;
+pub const LIBUSB_LOG_LEVEL_DEBUG: libusb_log_level = 4;
+/// \ingroup libusb_lib
+/// Log message levels.
+/// - LIBUSB_LOG_LEVEL_NONE (0)    : no messages ever printed by the library (default)
+/// - LIBUSB_LOG_LEVEL_ERROR (1)   : error messages are printed to stderr
+/// - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to stderr
+/// - LIBUSB_LOG_LEVEL_INFO (3)    : informational messages are printed to stdout, warning
+/// and error messages are printed to stderr
+/// - LIBUSB_LOG_LEVEL_DEBUG (4)   : debug and informational messages are printed to stdout,
+/// warnings and errors to stderr
+pub type libusb_log_level = u32;
+extern "C" {
+    pub fn libusb_init(ctx: *mut *mut libusb_context) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_init_jailed(ctx: *mut *mut libusb_context) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_exit(ctx: *mut libusb_context);
+}
+extern "C" {
+    pub fn libusb_get_device_from_fd(
+        ctx: *mut libusb_context,
+        fd: ::std::os::raw::c_int,
+        device: *mut *mut libusb_device,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_set_debug(ctx: *mut libusb_context, level: ::std::os::raw::c_int);
+}
+extern "C" {
+    pub fn libusb_get_version() -> *const libusb_version;
+}
+extern "C" {
+    pub fn libusb_has_capability(capability: u32) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_error_name(errcode: ::std::os::raw::c_int) -> *const ::std::os::raw::c_char;
+}
+extern "C" {
+    pub fn libusb_setlocale(locale: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_strerror(errcode: libusb_error) -> *const ::std::os::raw::c_char;
+}
+extern "C" {
+    pub fn libusb_get_device_list(
+        ctx: *mut libusb_context,
+        list: *mut *mut *mut libusb_device,
+    ) -> isize;
+}
+extern "C" {
+    pub fn libusb_free_device_list(
+        list: *mut *mut libusb_device,
+        unref_devices: ::std::os::raw::c_int,
+    );
+}
+extern "C" {
+    pub fn libusb_ref_device(dev: *mut libusb_device) -> *mut libusb_device;
+}
+extern "C" {
+    pub fn libusb_unref_device(dev: *mut libusb_device);
+}
+extern "C" {
+    pub fn libusb_get_configuration(
+        dev: *mut libusb_device_handle,
+        config: *mut ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_get_device_descriptor(
+        dev: *mut libusb_device,
+        desc: *mut libusb_device_descriptor,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_get_active_config_descriptor(
+        dev: *mut libusb_device,
+        config: *mut *mut libusb_config_descriptor,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_get_config_descriptor(
+        dev: *mut libusb_device,
+        config_index: u8,
+        config: *mut *mut libusb_config_descriptor,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_get_config_descriptor_by_value(
+        dev: *mut libusb_device,
+        bConfigurationValue: u8,
+        config: *mut *mut libusb_config_descriptor,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_free_config_descriptor(config: *mut libusb_config_descriptor);
+}
+extern "C" {
+    pub fn libusb_get_ss_endpoint_companion_descriptor(
+        ctx: *mut libusb_context,
+        endpoint: *const libusb_endpoint_descriptor,
+        ep_comp: *mut *mut libusb_ss_endpoint_companion_descriptor,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_free_ss_endpoint_companion_descriptor(
+        ep_comp: *mut libusb_ss_endpoint_companion_descriptor,
+    );
+}
+extern "C" {
+    pub fn libusb_get_bos_descriptor(
+        dev_handle: *mut libusb_device_handle,
+        bos: *mut *mut libusb_bos_descriptor,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_free_bos_descriptor(bos: *mut libusb_bos_descriptor);
+}
+extern "C" {
+    pub fn libusb_get_usb_2_0_extension_descriptor(
+        ctx: *mut libusb_context,
+        dev_cap: *mut libusb_bos_dev_capability_descriptor,
+        usb_2_0_extension: *mut *mut libusb_usb_2_0_extension_descriptor,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_free_usb_2_0_extension_descriptor(
+        usb_2_0_extension: *mut libusb_usb_2_0_extension_descriptor,
+    );
+}
+extern "C" {
+    pub fn libusb_get_ss_usb_device_capability_descriptor(
+        ctx: *mut libusb_context,
+        dev_cap: *mut libusb_bos_dev_capability_descriptor,
+        ss_usb_device_cap: *mut *mut libusb_ss_usb_device_capability_descriptor,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_free_ss_usb_device_capability_descriptor(
+        ss_usb_device_cap: *mut libusb_ss_usb_device_capability_descriptor,
+    );
+}
+extern "C" {
+    pub fn libusb_get_container_id_descriptor(
+        ctx: *mut libusb_context,
+        dev_cap: *mut libusb_bos_dev_capability_descriptor,
+        container_id: *mut *mut libusb_container_id_descriptor,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_free_container_id_descriptor(container_id: *mut libusb_container_id_descriptor);
+}
+extern "C" {
+    pub fn libusb_get_bus_number(dev: *mut libusb_device) -> u8;
+}
+extern "C" {
+    pub fn libusb_get_port_number(dev: *mut libusb_device) -> u8;
+}
+extern "C" {
+    pub fn libusb_get_port_numbers(
+        dev: *mut libusb_device,
+        port_numbers: *mut u8,
+        port_numbers_len: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_get_port_path(
+        ctx: *mut libusb_context,
+        dev: *mut libusb_device,
+        path: *mut u8,
+        path_length: u8,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_get_parent(dev: *mut libusb_device) -> *mut libusb_device;
+}
+extern "C" {
+    pub fn libusb_get_device_address(dev: *mut libusb_device) -> u8;
+}
+extern "C" {
+    pub fn libusb_get_device_speed(dev: *mut libusb_device) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_get_max_packet_size(
+        dev: *mut libusb_device,
+        endpoint: ::std::os::raw::c_uchar,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_get_max_iso_packet_size(
+        dev: *mut libusb_device,
+        endpoint: ::std::os::raw::c_uchar,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_open(
+        dev: *mut libusb_device,
+        dev_handle: *mut *mut libusb_device_handle,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_open_fd(
+        dev: *mut libusb_device,
+        fd: ::std::os::raw::c_int,
+        handle: *mut *mut libusb_device_handle,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_close(dev_handle: *mut libusb_device_handle);
+}
+extern "C" {
+    pub fn libusb_get_device(dev_handle: *mut libusb_device_handle) -> *mut libusb_device;
+}
+extern "C" {
+    pub fn libusb_set_configuration(
+        dev_handle: *mut libusb_device_handle,
+        configuration: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_claim_interface(
+        dev_handle: *mut libusb_device_handle,
+        interface_number: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_release_interface(
+        dev_handle: *mut libusb_device_handle,
+        interface_number: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_open_device_with_vid_pid(
+        ctx: *mut libusb_context,
+        vendor_id: u16,
+        product_id: u16,
+    ) -> *mut libusb_device_handle;
+}
+extern "C" {
+    pub fn libusb_set_interface_alt_setting(
+        dev_handle: *mut libusb_device_handle,
+        interface_number: ::std::os::raw::c_int,
+        alternate_setting: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_clear_halt(
+        dev_handle: *mut libusb_device_handle,
+        endpoint: ::std::os::raw::c_uchar,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_reset_device(dev_handle: *mut libusb_device_handle) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_alloc_streams(
+        dev_handle: *mut libusb_device_handle,
+        num_streams: u32,
+        endpoints: *mut ::std::os::raw::c_uchar,
+        num_endpoints: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_free_streams(
+        dev_handle: *mut libusb_device_handle,
+        endpoints: *mut ::std::os::raw::c_uchar,
+        num_endpoints: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_dev_mem_alloc(
+        dev_handle: *mut libusb_device_handle,
+        length: usize,
+    ) -> *mut ::std::os::raw::c_uchar;
+}
+extern "C" {
+    pub fn libusb_dev_mem_free(
+        dev_handle: *mut libusb_device_handle,
+        buffer: *mut ::std::os::raw::c_uchar,
+        length: usize,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_kernel_driver_active(
+        dev_handle: *mut libusb_device_handle,
+        interface_number: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_detach_kernel_driver(
+        dev_handle: *mut libusb_device_handle,
+        interface_number: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_attach_kernel_driver(
+        dev_handle: *mut libusb_device_handle,
+        interface_number: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_set_auto_detach_kernel_driver(
+        dev_handle: *mut libusb_device_handle,
+        enable: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_alloc_transfer(iso_packets: ::std::os::raw::c_int) -> *mut libusb_transfer;
+}
+extern "C" {
+    pub fn libusb_submit_transfer(transfer: *mut libusb_transfer) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_cancel_transfer(transfer: *mut libusb_transfer) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_free_transfer(transfer: *mut libusb_transfer);
+}
+extern "C" {
+    pub fn libusb_transfer_set_stream_id(transfer: *mut libusb_transfer, stream_id: u32);
+}
+extern "C" {
+    pub fn libusb_transfer_get_stream_id(transfer: *mut libusb_transfer) -> u32;
+}
+extern "C" {
+    pub fn libusb_control_transfer(
+        dev_handle: *mut libusb_device_handle,
+        request_type: u8,
+        bRequest: u8,
+        wValue: u16,
+        wIndex: u16,
+        data: *mut ::std::os::raw::c_uchar,
+        wLength: u16,
+        timeout: ::std::os::raw::c_uint,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_bulk_transfer(
+        dev_handle: *mut libusb_device_handle,
+        endpoint: ::std::os::raw::c_uchar,
+        data: *mut ::std::os::raw::c_uchar,
+        length: ::std::os::raw::c_int,
+        actual_length: *mut ::std::os::raw::c_int,
+        timeout: ::std::os::raw::c_uint,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_interrupt_transfer(
+        dev_handle: *mut libusb_device_handle,
+        endpoint: ::std::os::raw::c_uchar,
+        data: *mut ::std::os::raw::c_uchar,
+        length: ::std::os::raw::c_int,
+        actual_length: *mut ::std::os::raw::c_int,
+        timeout: ::std::os::raw::c_uint,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_get_string_descriptor_ascii(
+        dev_handle: *mut libusb_device_handle,
+        desc_index: u8,
+        data: *mut ::std::os::raw::c_uchar,
+        length: ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_try_lock_events(ctx: *mut libusb_context) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_lock_events(ctx: *mut libusb_context);
+}
+extern "C" {
+    pub fn libusb_unlock_events(ctx: *mut libusb_context);
+}
+extern "C" {
+    pub fn libusb_event_handling_ok(ctx: *mut libusb_context) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_event_handler_active(ctx: *mut libusb_context) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_interrupt_event_handler(ctx: *mut libusb_context);
+}
+extern "C" {
+    pub fn libusb_lock_event_waiters(ctx: *mut libusb_context);
+}
+extern "C" {
+    pub fn libusb_unlock_event_waiters(ctx: *mut libusb_context);
+}
+extern "C" {
+    pub fn libusb_wait_for_event(
+        ctx: *mut libusb_context,
+        tv: *mut timeval,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_handle_events_timeout(
+        ctx: *mut libusb_context,
+        tv: *mut timeval,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_handle_events_timeout_completed(
+        ctx: *mut libusb_context,
+        tv: *mut timeval,
+        completed: *mut ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_handle_events(ctx: *mut libusb_context) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_handle_events_completed(
+        ctx: *mut libusb_context,
+        completed: *mut ::std::os::raw::c_int,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_handle_events_locked(
+        ctx: *mut libusb_context,
+        tv: *mut timeval,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_pollfds_handle_timeouts(ctx: *mut libusb_context) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    pub fn libusb_get_next_timeout(
+        ctx: *mut libusb_context,
+        tv: *mut timeval,
+    ) -> ::std::os::raw::c_int;
+}
+/// \ingroup libusb_poll
+/// File descriptor for polling
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct libusb_pollfd {
+    /// Numeric file descriptor
+    pub fd: ::std::os::raw::c_int,
+    /// Event flags to poll for from <poll.h>. POLLIN indicates that you
+    /// should monitor this file descriptor for becoming ready to read from,
+    /// and POLLOUT indicates that you should monitor this file descriptor for
+    /// nonblocking write readiness.
+    pub events: ::std::os::raw::c_short,
+}
+#[test]
+fn bindgen_test_layout_libusb_pollfd() {
+    assert_eq!(
+        ::std::mem::size_of::<libusb_pollfd>(),
+        8usize,
+        concat!("Size of: ", stringify!(libusb_pollfd))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<libusb_pollfd>(),
+        4usize,
+        concat!("Alignment of ", stringify!(libusb_pollfd))
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_pollfd>())).fd as *const _ as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_pollfd),
+            "::",
+            stringify!(fd)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(::std::ptr::null::<libusb_pollfd>())).events as *const _ as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(libusb_pollfd),
+            "::",
+            stringify!(events)
+        )
+    );
+}
+/// \ingroup libusb_poll
+/// Callback function, invoked when a new file descriptor should be added
+/// to the set of file descriptors monitored for events.
+/// \param fd the new file descriptor
+/// \param events events to monitor for, see \ref libusb_pollfd for a
+/// description
+/// \param user_data User data pointer specified in
+/// libusb_set_pollfd_notifiers() call
+/// \see libusb_set_pollfd_notifiers()
+pub type libusb_pollfd_added_cb = ::std::option::Option<
+    unsafe extern "C" fn(
+        fd: ::std::os::raw::c_int,
+        events: ::std::os::raw::c_short,
+        user_data: *mut ::std::os::raw::c_void,
+    ),
+>;
+/// \ingroup libusb_poll
+/// Callback function, invoked when a file descriptor should be removed from
+/// the set of file descriptors being monitored for events. After returning
+/// from this callback, do not use that file descriptor again.
+/// \param fd the file descriptor to stop monitoring
+/// \param user_data User data pointer specified in
+/// libusb_set_pollfd_notifiers() call
+/// \see libusb_set_pollfd_notifiers()
+pub type libusb_pollfd_removed_cb = ::std::option::Option<
+    unsafe extern "C" fn(fd: ::std::os::raw::c_int, user_data: *mut ::std::os::raw::c_void),
+>;
+extern "C" {
+    pub fn libusb_get_pollfds(ctx: *mut libusb_context) -> *mut *const libusb_pollfd;
+}
+extern "C" {
+    pub fn libusb_free_pollfds(pollfds: *mut *const libusb_pollfd);
+}
+extern "C" {
+    pub fn libusb_set_pollfd_notifiers(
+        ctx: *mut libusb_context,
+        added_cb: libusb_pollfd_added_cb,
+        removed_cb: libusb_pollfd_removed_cb,
+        user_data: *mut ::std::os::raw::c_void,
+    );
+}
+/// \ingroup libusb_hotplug
+/// Callback handle.
+///
+/// Callbacks handles are generated by libusb_hotplug_register_callback()
+/// and can be used to deregister callbacks. Callback handles are unique
+/// per libusb_context and it is safe to call libusb_hotplug_deregister_callback()
+/// on an already deregisted callback.
+///
+/// Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
+///
+/// For more information, see \ref libusb_hotplug.
+pub type libusb_hotplug_callback_handle = ::std::os::raw::c_int;
+/// Default value when not using any flags.
+pub const LIBUSB_HOTPLUG_NO_FLAGS: libusb_hotplug_flag = 0;
+/// Arm the callback and fire it for all matching currently attached devices.
+pub const LIBUSB_HOTPLUG_ENUMERATE: libusb_hotplug_flag = 1;
+/// \ingroup libusb_hotplug
+///
+/// Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
+///
+/// Flags for hotplug events
+pub type libusb_hotplug_flag = u32;
+/// A device has been plugged in and is ready to use
+pub const LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: libusb_hotplug_event = 1;
+/// A device has left and is no longer available.
+/// It is the user's responsibility to call libusb_close on any handle associated with a disconnected device.
+/// It is safe to call libusb_get_device_descriptor on a device that has left
+pub const LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: libusb_hotplug_event = 2;
+/// \ingroup libusb_hotplug
+///
+/// Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
+///
+/// Hotplug events
+pub type libusb_hotplug_event = u32;
+/// \ingroup libusb_hotplug
+/// Hotplug callback function type. When requesting hotplug event notifications,
+/// you pass a pointer to a callback function of this type.
+///
+/// This callback may be called by an internal event thread and as such it is
+/// recommended the callback do minimal processing before returning.
+///
+/// libusb will call this function later, when a matching event had happened on
+/// a matching device. See \ref libusb_hotplug for more information.
+///
+/// It is safe to call either libusb_hotplug_register_callback() or
+/// libusb_hotplug_deregister_callback() from within a callback function.
+///
+/// Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
+///
+/// \param ctx            context of this notification
+/// \param device         libusb_device this event occurred on
+/// \param event          event that occurred
+/// \param user_data      user data provided when this callback was registered
+/// \returns bool whether this callback is finished processing events.
+/// returning 1 will cause this callback to be deregistered
+pub type libusb_hotplug_callback_fn = ::std::option::Option<
+    unsafe extern "C" fn(
+        ctx: *mut libusb_context,
+        device: *mut libusb_device,
+        event: libusb_hotplug_event,
+        user_data: *mut ::std::os::raw::c_void,
+    ) -> ::std::os::raw::c_int,
+>;
+extern "C" {
+    /// \ingroup libusb_hotplug
+    /// Register a hotplug callback function
+    ///
+    /// Register a callback with the libusb_context. The callback will fire
+    /// when a matching event occurs on a matching device. The callback is
+    /// armed until either it is deregistered with libusb_hotplug_deregister_callback()
+    /// or the supplied callback returns 1 to indicate it is finished processing events.
+    ///
+    /// If the \ref LIBUSB_HOTPLUG_ENUMERATE is passed the callback will be
+    /// called with a \ref LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED for all devices
+    /// already plugged into the machine. Note that libusb modifies its internal
+    /// device list from a separate thread, while calling hotplug callbacks from
+    /// libusb_handle_events(), so it is possible for a device to already be present
+    /// on, or removed from, its internal device list, while the hotplug callbacks
+    /// still need to be dispatched. This means that when using \ref
+    /// LIBUSB_HOTPLUG_ENUMERATE, your callback may be called twice for the arrival
+    /// of the same device, once from libusb_hotplug_register_callback() and once
+    /// from libusb_handle_events(); and/or your callback may be called for the
+    /// removal of a device for which an arrived call was never made.
+    ///
+    /// Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
+    ///
+    /// \param[in] ctx context to register this callback with
+    /// \param[in] events bitwise or of events that will trigger this callback. See \ref
+    /// libusb_hotplug_event
+    /// \param[in] flags hotplug callback flags. See \ref libusb_hotplug_flag
+    /// \param[in] vendor_id the vendor id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
+    /// \param[in] product_id the product id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
+    /// \param[in] dev_class the device class to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
+    /// \param[in] cb_fn the function to be invoked on a matching event/device
+    /// \param[in] user_data user data to pass to the callback function
+    /// \param[out] callback_handle pointer to store the handle of the allocated callback (can be NULL)
+    /// \returns LIBUSB_SUCCESS on success LIBUSB_ERROR code on failure
+    pub fn libusb_hotplug_register_callback(
+        ctx: *mut libusb_context,
+        events: libusb_hotplug_event,
+        flags: libusb_hotplug_flag,
+        vendor_id: ::std::os::raw::c_int,
+        product_id: ::std::os::raw::c_int,
+        dev_class: ::std::os::raw::c_int,
+        cb_fn: libusb_hotplug_callback_fn,
+        user_data: *mut ::std::os::raw::c_void,
+        callback_handle: *mut libusb_hotplug_callback_handle,
+    ) -> ::std::os::raw::c_int;
+}
+extern "C" {
+    /// \ingroup libusb_hotplug
+    /// Deregisters a hotplug callback.
+    ///
+    /// Deregister a callback from a libusb_context. This function is safe to call from within
+    /// a hotplug callback.
+    ///
+    /// Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
+    ///
+    /// \param[in] ctx context this callback is registered with
+    /// \param[in] callback_handle the handle of the callback to deregister
+    pub fn libusb_hotplug_deregister_callback(
+        ctx: *mut libusb_context,
+        callback_handle: libusb_hotplug_callback_handle,
+    );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __locale_data {
+    pub _address: u8,
+}
diff --git a/usb_util/src/config_descriptor.rs b/usb_util/src/config_descriptor.rs
new file mode 100644
index 0000000..8aebbac
--- /dev/null
+++ b/usb_util/src/config_descriptor.rs
@@ -0,0 +1,66 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::ops::Deref;
+
+use crate::bindings::{self, libusb_config_descriptor};
+use crate::interface_descriptor::InterfaceDescriptor;
+
+/// ConfigDescriptor wraps libusb_config_descriptor.
+pub struct ConfigDescriptor {
+    descriptor: *mut libusb_config_descriptor,
+}
+
+impl Drop for ConfigDescriptor {
+    // Free configuration descriptor.
+    // Safe because 'self' is intialized with a valid libusb_config_descriptor from libusb
+    // functions.
+    fn drop(&mut self) {
+        unsafe {
+            bindings::libusb_free_config_descriptor(self.descriptor);
+        }
+    }
+}
+
+impl ConfigDescriptor {
+    /// Build ConfigDescriptor. 'descriptor' should be a valid pointer from
+    /// libusb_config_descriptor. This function will panic if it's null.
+    pub unsafe fn new(descriptor: *mut libusb_config_descriptor) -> ConfigDescriptor {
+        assert!(!descriptor.is_null());
+        ConfigDescriptor { descriptor }
+    }
+
+    /// Get interface by number and alt setting.
+    pub fn get_interface_descriptor(
+        &self,
+        interface_num: u8,
+        alt_setting: i32,
+    ) -> Option<InterfaceDescriptor> {
+        let config_descriptor = self.deref();
+        if interface_num >= config_descriptor.bNumInterfaces {
+            return None;
+        }
+        // Safe because interface num is checked.
+        let interface = unsafe { &*(config_descriptor.interface.offset(interface_num as isize)) };
+
+        if alt_setting >= interface.num_altsetting {
+            return None;
+        }
+        // Safe because setting num is checked.
+        unsafe {
+            Some(InterfaceDescriptor::new(
+                &*(interface.altsetting.offset(alt_setting as isize)),
+            ))
+        }
+    }
+}
+
+impl Deref for ConfigDescriptor {
+    type Target = libusb_config_descriptor;
+
+    fn deref(&self) -> &libusb_config_descriptor {
+        // Safe because 'self.descriptor' is valid.
+        unsafe { &*(self.descriptor) }
+    }
+}
diff --git a/usb_util/src/device_handle.rs b/usb_util/src/device_handle.rs
new file mode 100644
index 0000000..32a963f
--- /dev/null
+++ b/usb_util/src/device_handle.rs
@@ -0,0 +1,148 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::os::raw::c_int;
+use std::sync::Arc;
+
+use crate::bindings;
+use crate::error::{Error, Result};
+use crate::libusb_context::LibUsbContextInner;
+use crate::usb_transfer::{UsbTransfer, UsbTransferBuffer};
+
+/// DeviceHandle wraps libusb_device_handle.
+pub struct DeviceHandle {
+    _context: Arc<LibUsbContextInner>,
+    handle: *mut bindings::libusb_device_handle,
+}
+
+unsafe impl Send for DeviceHandle {}
+
+impl Drop for DeviceHandle {
+    fn drop(&mut self) {
+        // Safe because self.handle is a valid pointer to libusb_device_handle.
+        unsafe {
+            bindings::libusb_close(self.handle);
+        }
+    }
+}
+
+impl DeviceHandle {
+    /// Create a new DeviceHande. 'handle' should be a valid pointer to libusb_device_handle.
+    pub unsafe fn new(
+        ctx: Arc<LibUsbContextInner>,
+        handle: *mut bindings::libusb_device_handle,
+    ) -> DeviceHandle {
+        DeviceHandle {
+            _context: ctx,
+            handle,
+        }
+    }
+
+    /// Reset this usb device.
+    pub fn reset(&self) -> Result<()> {
+        // Safe because 'self.handle' is a valid pointer to device handle.
+        try_libusb!(unsafe { bindings::libusb_reset_device(self.handle) });
+        Ok(())
+    }
+    /// Get bConfigurationValue of the currently active configuration.
+    pub fn get_active_configuration(&self) -> Result<i32> {
+        let mut config: c_int = 0;
+        // Safe because 'self.handle' is a valid pointer to device handle and '&mut config' is a
+        // valid output location.
+        try_libusb!(unsafe { bindings::libusb_get_configuration(self.handle, &mut config) });
+        Ok(config as i32)
+    }
+
+    /// Set active configuration for a device.
+    pub fn set_active_configuration(&mut self, config: i32) -> Result<()> {
+        // Safe because 'self.handle' is a valid pointer to device handle.
+        try_libusb!(unsafe { bindings::libusb_set_configuration(self.handle, config as c_int) });
+        Ok(())
+    }
+
+    /// Claim an interface on this deivce handle.
+    pub fn claim_interface(&self, interface_number: i32) -> Result<()> {
+        // Safe because 'self.handle' is a valid pointer to device handle.
+        try_libusb!(unsafe { bindings::libusb_claim_interface(self.handle, interface_number) });
+        Ok(())
+    }
+
+    /// Release an interface previously claimed with libusb_claim_interface.
+    pub fn release_interface(&self, interface_number: i32) -> Result<()> {
+        // Safe because 'self.handle' is a valid pointer to device handle.
+        try_libusb!(unsafe { bindings::libusb_release_interface(self.handle, interface_number) });
+        Ok(())
+    }
+
+    /// Perform a USB port reset to reinitialize a device.
+    pub fn reset_device(&self) -> Result<()> {
+        // Safe because 'self.handle' is a valid pointer to device handle.
+        try_libusb!(unsafe { bindings::libusb_reset_device(self.handle) });
+        Ok(())
+    }
+
+    /// Determine if a kernel driver is active on an interface.
+    pub fn kernel_driver_active(&self, interface_number: i32) -> Result<bool> {
+        // Safe because 'self.handle' is a valid pointer to device handle.
+        let v = try_libusb!(unsafe {
+            bindings::libusb_kernel_driver_active(self.handle, interface_number)
+        });
+        Ok(v != 0)
+    }
+
+    /// Detach a kernel driver from an interface.
+    pub fn detach_kernel_driver(&self, interface_number: i32) -> Result<()> {
+        // Safe because 'self.handle' is a valid pointer to device handle.
+        try_libusb!(unsafe {
+            bindings::libusb_detach_kernel_driver(self.handle, interface_number)
+        });
+        Ok(())
+    }
+
+    /// Re-attach an interfae's kernel driver, which was previously detached using
+    /// detach_kernel_driver.
+    pub fn attach_kernel_driver(&self, interface_number: i32) -> Result<()> {
+        // Safe because 'self.handle' is a valid pointer to device handle.
+        try_libusb!(unsafe {
+            bindings::libusb_attach_kernel_driver(self.handle, interface_number)
+        });
+        Ok(())
+    }
+
+    /// Active an alternate setting for an interface.
+    pub fn set_interface_alt_setting(
+        &self,
+        interface_number: i32,
+        alternative_setting: i32,
+    ) -> Result<()> {
+        // Safe because 'self.handle' is a valid pointer to device handle.
+        try_libusb!(unsafe {
+            bindings::libusb_set_interface_alt_setting(
+                self.handle,
+                interface_number,
+                alternative_setting,
+            )
+        });
+        Ok(())
+    }
+
+    /// Clear the halt/stall condition for an endpoint.
+    pub fn clear_halt(&self, endpoint: u8) -> Result<()> {
+        // Safe because 'self.handle' is a valid pointer to device handle.
+        try_libusb!(unsafe { bindings::libusb_clear_halt(self.handle, endpoint) });
+        Ok(())
+    }
+
+    /// Libusb asynchronous I/O interface has a 5 step process. It gives lots of
+    /// flexibility but makes it hard to manage object life cycle and easy to
+    /// write unsafe code. We wrap this interface to a simple "transfer" and "cancel"
+    /// interface. Resubmission is not supported and deallocation is handled safely
+    /// here.
+    pub fn submit_async_transfer<T: UsbTransferBuffer>(
+        &self,
+        transfer: UsbTransfer<T>,
+    ) -> Result<()> {
+        unsafe { transfer.submit(self.handle) }
+    }
+}
diff --git a/usb_util/src/endpoint_descriptor.rs b/usb_util/src/endpoint_descriptor.rs
new file mode 100644
index 0000000..29eb4ea
--- /dev/null
+++ b/usb_util/src/endpoint_descriptor.rs
@@ -0,0 +1,57 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::ops::Deref;
+
+use crate::bindings::libusb_endpoint_descriptor;
+use crate::types::{EndpointDirection, EndpointType};
+
+/// EndpointDescriptor wraps libusb_endpoint_descriptor.
+pub struct EndpointDescriptor<'a>(&'a libusb_endpoint_descriptor);
+
+const ENDPOINT_DESCRIPTOR_DIRECTION_MASK: u8 = 1 << 7;
+const ENDPOINT_DESCRIPTOR_NUMBER_MASK: u8 = 0xf;
+const ENDPOINT_DESCRIPTOR_ATTRIBUTES_TYPE_MASK: u8 = 0x3;
+
+impl<'a> EndpointDescriptor<'a> {
+    // Create new endpoint descriptor.
+    pub fn new(descriptor: &libusb_endpoint_descriptor) -> EndpointDescriptor {
+        EndpointDescriptor(descriptor)
+    }
+
+    // Get direction of this endpoint.
+    pub fn get_direction(&self) -> EndpointDirection {
+        let direction = self.0.bEndpointAddress & ENDPOINT_DESCRIPTOR_DIRECTION_MASK;
+        if direction > 0 {
+            EndpointDirection::DeviceToHost
+        } else {
+            EndpointDirection::HostToDevice
+        }
+    }
+
+    // Get endpoint number.
+    pub fn get_endpoint_number(&self) -> u8 {
+        self.0.bEndpointAddress & ENDPOINT_DESCRIPTOR_NUMBER_MASK
+    }
+
+    // Get endpoint type.
+    pub fn get_endpoint_type(&self) -> Option<EndpointType> {
+        let ep_type = self.0.bmAttributes & ENDPOINT_DESCRIPTOR_ATTRIBUTES_TYPE_MASK;
+        match ep_type {
+            0 => Some(EndpointType::Control),
+            1 => Some(EndpointType::Isochronous),
+            2 => Some(EndpointType::Bulk),
+            3 => Some(EndpointType::Interrupt),
+            _ => None,
+        }
+    }
+}
+
+impl<'a> Deref for EndpointDescriptor<'a> {
+    type Target = libusb_endpoint_descriptor;
+
+    fn deref(&self) -> &libusb_endpoint_descriptor {
+        self.0
+    }
+}
diff --git a/usb_util/src/error.rs b/usb_util/src/error.rs
new file mode 100644
index 0000000..b6dd91e
--- /dev/null
+++ b/usb_util/src/error.rs
@@ -0,0 +1,85 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std;
+use std::fmt;
+
+use crate::bindings;
+
+/// Error type for libusb.
+pub enum Error {
+    Success(i32),
+    IO,
+    InvalidParam,
+    Access,
+    NoDevice,
+    NotFound,
+    Busy,
+    Timeout,
+    Overflow,
+    Pipe,
+    Interrupted,
+    NoMem,
+    NotSupported,
+    Other,
+}
+
+impl fmt::Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            Error::Success(_v) => write!(f, "Success (no error)"),
+            Error::IO => write!(f, "Input/output error"),
+            Error::InvalidParam => write!(f, "Invalid parameter"),
+            Error::Access => write!(f, "Access denied (insufficient permissions)"),
+            Error::NoDevice => write!(f, "No such device (it may have been disconnected)"),
+            Error::NotFound => write!(f, "Entity not found"),
+            Error::Busy => write!(f, "Resource busy"),
+            Error::Timeout => write!(f, "Operation timed out"),
+            Error::Overflow => write!(f, "Overflow"),
+            Error::Pipe => write!(f, "Pipe error"),
+            Error::Interrupted => write!(f, "System call interrupted (perhaps due to signal)"),
+            Error::NoMem => write!(f, "Insufficient memory"),
+            Error::NotSupported => write!(
+                f,
+                "Operation not supported or unimplemented on this platform"
+            ),
+            Error::Other => write!(f, "Other error"),
+        }
+    }
+}
+
+impl From<bindings::libusb_error> for Error {
+    fn from(e: bindings::libusb_error) -> Self {
+        match e {
+            bindings::LIBUSB_ERROR_IO => Error::IO,
+            bindings::LIBUSB_ERROR_INVALID_PARAM => Error::InvalidParam,
+            bindings::LIBUSB_ERROR_ACCESS => Error::Access,
+            bindings::LIBUSB_ERROR_NO_DEVICE => Error::NoDevice,
+            bindings::LIBUSB_ERROR_NOT_FOUND => Error::NotFound,
+            bindings::LIBUSB_ERROR_BUSY => Error::Busy,
+            bindings::LIBUSB_ERROR_TIMEOUT => Error::Timeout,
+            bindings::LIBUSB_ERROR_OVERFLOW => Error::Overflow,
+            bindings::LIBUSB_ERROR_PIPE => Error::Pipe,
+            bindings::LIBUSB_ERROR_INTERRUPTED => Error::Interrupted,
+            bindings::LIBUSB_ERROR_NO_MEM => Error::NoMem,
+            bindings::LIBUSB_ERROR_NOT_SUPPORTED => Error::NotSupported,
+            bindings::LIBUSB_ERROR_OTHER => Error::Other,
+            // All possible errors are defined above, other values mean success,
+            // see libusb_get_device_list for example.
+            _ => Error::Success(e),
+        }
+    }
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+#[macro_export]
+macro_rules! try_libusb {
+    ($x:expr) => {
+        match Error::from($x as i32) {
+            Error::Success(e) => e,
+            err => return Err(err),
+        }
+    };
+}
diff --git a/usb_util/src/hotplug.rs b/usb_util/src/hotplug.rs
new file mode 100644
index 0000000..e131ab9
--- /dev/null
+++ b/usb_util/src/hotplug.rs
@@ -0,0 +1,77 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::os::raw::{c_int, c_void};
+use std::sync::Arc;
+
+use crate::bindings;
+use crate::libusb_context::LibUsbContextInner;
+use crate::libusb_device::LibUsbDevice;
+
+#[derive(PartialEq)]
+pub enum HotplugEvent {
+    DeviceArrived,
+    DeviceLeft,
+}
+
+impl HotplugEvent {
+    /// Create a new HotplugEvent from raw libusb_hotplug_event.
+    pub fn new(event: bindings::libusb_hotplug_event) -> Self {
+        match event {
+            bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED => HotplugEvent::DeviceArrived,
+            bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT => HotplugEvent::DeviceLeft,
+            _ => {
+                // TODO(jkwang) handle this with option.
+                // libusb_hotplug_event is a C enum.
+                panic!("Invaild libusb_hotplug_event");
+            }
+        }
+    }
+}
+
+pub trait UsbHotplugHandler: Send + Sync + 'static {
+    fn hotplug_event(&self, device: LibUsbDevice, event: HotplugEvent);
+}
+
+/// UsbHotplugHandlerHolder owns UsbHotplugHandler and LibUsbContext. It will be passed as
+/// user_data to libusb_hotplug_register_callback.
+pub struct UsbHotplugHandlerHolder {
+    context: Arc<LibUsbContextInner>,
+    handler: Box<dyn UsbHotplugHandler>,
+}
+
+impl UsbHotplugHandlerHolder {
+    /// Create UsbHotplugHandlerHodler from context and handler.
+    pub fn new<H: UsbHotplugHandler>(
+        context: Arc<LibUsbContextInner>,
+        handler: H,
+    ) -> Box<UsbHotplugHandlerHolder> {
+        let holder = UsbHotplugHandlerHolder {
+            context,
+            handler: Box::new(handler),
+        };
+        Box::new(holder)
+    }
+}
+
+/// This function is safe when:
+///     libusb_device is allocated by libusb
+///     user_data points to valid UsbHotPlugHandlerHolder released from Box.
+///
+/// Do not invoke this function. It should only be used as a callback for
+/// libusb_hotplug_register_callback.
+pub unsafe extern "C" fn hotplug_cb(
+    _: *mut bindings::libusb_context,
+    device: *mut bindings::libusb_device,
+    event: bindings::libusb_hotplug_event,
+    user_data: *mut c_void,
+) -> c_int {
+    // Safe because user_data was casted from holder.
+    let holder = &*(user_data as *mut UsbHotplugHandlerHolder);
+    let device = LibUsbDevice::new(holder.context.clone(), device);
+    let event = HotplugEvent::new(event);
+    holder.handler.hotplug_event(device, event);
+    // The handler should always succeed.
+    bindings::LIBUSB_SUCCESS
+}
diff --git a/usb_util/src/interface_descriptor.rs b/usb_util/src/interface_descriptor.rs
new file mode 100644
index 0000000..a2bf1b2
--- /dev/null
+++ b/usb_util/src/interface_descriptor.rs
@@ -0,0 +1,40 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::ops::Deref;
+
+use crate::bindings::libusb_interface_descriptor;
+use crate::endpoint_descriptor::EndpointDescriptor;
+
+/// InterfaceDescriptor wraps libusb_interface_descriptor.
+pub struct InterfaceDescriptor<'a>(&'a libusb_interface_descriptor);
+
+impl<'a> InterfaceDescriptor<'a> {
+    /// Create a new Interface descriptor.
+    pub fn new(descriptor: &'a libusb_interface_descriptor) -> InterfaceDescriptor<'a> {
+        InterfaceDescriptor(descriptor)
+    }
+
+    /// Get endpoint descriptor at index.
+    pub fn endpoint_descriptor(&self, ep_idx: u8) -> Option<EndpointDescriptor> {
+        if ep_idx >= self.0.bNumEndpoints {
+            return None;
+        }
+
+        // Safe because idx is checked.
+        unsafe {
+            Some(EndpointDescriptor::new(
+                &*(self.0.endpoint.offset(ep_idx as isize)),
+            ))
+        }
+    }
+}
+
+impl<'a> Deref for InterfaceDescriptor<'a> {
+    type Target = libusb_interface_descriptor;
+
+    fn deref(&self) -> &libusb_interface_descriptor {
+        self.0
+    }
+}
diff --git a/usb_util/src/lib.rs b/usb_util/src/lib.rs
new file mode 100644
index 0000000..07af5ad
--- /dev/null
+++ b/usb_util/src/lib.rs
@@ -0,0 +1,23 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generated with bindgen libusb.h -no-prepend-enum-name -o bindings.rs.
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(non_upper_case_globals)]
+#[allow(clippy::all)]
+mod bindings;
+
+#[macro_use]
+pub mod error;
+pub mod config_descriptor;
+pub mod device_handle;
+pub mod endpoint_descriptor;
+pub mod hotplug;
+pub mod interface_descriptor;
+pub mod libusb_context;
+pub mod libusb_device;
+pub mod types;
+pub mod usb_transfer;
diff --git a/usb_util/src/libusb_context.rs b/usb_util/src/libusb_context.rs
new file mode 100644
index 0000000..a1bab32
--- /dev/null
+++ b/usb_util/src/libusb_context.rs
@@ -0,0 +1,280 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std;
+use std::os::raw::{c_short, c_void};
+use std::os::unix::io::RawFd;
+use std::sync::Arc;
+
+use crate::bindings;
+use crate::error::{Error, Result};
+use crate::hotplug::{hotplug_cb, UsbHotplugHandler, UsbHotplugHandlerHolder};
+use crate::libusb_device::LibUsbDevice;
+
+use sync::Mutex;
+
+pub struct LibUsbContextInner {
+    context: *mut bindings::libusb_context,
+    pollfd_change_handler: Mutex<Option<Box<PollfdChangeHandlerHolder>>>,
+}
+
+// Safe because libusb_context could be accessed from multiple threads safely.
+unsafe impl Send for LibUsbContextInner {}
+unsafe impl Sync for LibUsbContextInner {}
+
+impl LibUsbContextInner {
+    /// Remove the previous registered notifiers.
+    pub fn remove_pollfd_notifiers(&self) {
+        // Safe because 'self.context' is valid.
+        unsafe {
+            bindings::libusb_set_pollfd_notifiers(self.context, None, None, std::ptr::null_mut());
+        }
+    }
+}
+
+impl Drop for LibUsbContextInner {
+    fn drop(&mut self) {
+        // Avoid pollfd change handler call when libusb_exit is called.
+        self.remove_pollfd_notifiers();
+        // Safe beacuse 'self.context' points to a valid context allocated by libusb_init.
+        unsafe {
+            bindings::libusb_exit(self.context);
+        }
+    }
+}
+
+/// Wrapper for libusb_context. The libusb libary initialization/deinitialization
+/// is managed by this context.
+/// See: http://libusb.sourceforge.net/api-1.0/group__libusb__lib.html
+#[derive(Clone)]
+pub struct LibUsbContext {
+    inner: Arc<LibUsbContextInner>,
+}
+
+impl LibUsbContext {
+    /// Create a new LibUsbContext.
+    pub fn new() -> Result<LibUsbContext> {
+        let mut ctx: *mut bindings::libusb_context = std::ptr::null_mut();
+        // Safe because '&mut ctx' points to a valid memory (on stack).
+        try_libusb!(unsafe { bindings::libusb_init(&mut ctx) });
+        Ok(LibUsbContext {
+            inner: Arc::new(LibUsbContextInner {
+                context: ctx,
+                pollfd_change_handler: Mutex::new(None),
+            }),
+        })
+    }
+
+    /// Create a new jailed LibUsbContext.
+    #[cfg(feature = "sandboxed-libusb")]
+    pub fn new_jailed() -> Result<LibUsbContext> {
+        let mut ctx: *mut bindings::libusb_context = std::ptr::null_mut();
+        // Safe because '&mut ctx' points to a valid memory (on stack).
+        try_libusb!(unsafe { bindings::libusb_init_jailed(&mut ctx) });
+        Ok(LibUsbContext {
+            inner: Arc::new(LibUsbContextInner {
+                context: ctx,
+                pollfd_change_handler: Mutex::new(None),
+            }),
+        })
+    }
+
+    /// Build device from File.
+    #[cfg(feature = "sandboxed-libusb")]
+    pub fn get_device_from_fd(&self, fd: std::fs::File) -> Result<LibUsbDevice> {
+        use std::os::unix::io::IntoRawFd;
+
+        let fd = fd.into_raw_fd();
+        let mut device: *mut bindings::libusb_device = std::ptr::null_mut();
+        // Safe because fd is valid and owned, and '&mut device' points to valid memory.
+        try_libusb!(unsafe {
+            bindings::libusb_get_device_from_fd(self.inner.context, fd, &mut device)
+        });
+        unsafe { Ok(LibUsbDevice::new(self.inner.clone(), device)) }
+    }
+
+    /// Returns a list of USB devices currently attached to the system.
+    pub fn get_device_iter(&self) -> Result<DeviceIter> {
+        let mut list: *mut *mut bindings::libusb_device = std::ptr::null_mut();
+        // Safe because 'inner.context' points to a valid context and '&mut list' points to a valid
+        // memory.
+        try_libusb!(unsafe { bindings::libusb_get_device_list(self.inner.context, &mut list) });
+
+        Ok(DeviceIter {
+            context: self.inner.clone(),
+            list,
+            index: 0,
+        })
+    }
+
+    /// Check at runtime if the loaded library has a given capability.
+    pub fn has_capability(&self, cap: u32) -> bool {
+        // Safe because libusb_init is called before this call happens.
+        unsafe { bindings::libusb_has_capability(cap) != 0 }
+    }
+
+    /// Return an iter of poll fds. Those fds that should be polled to handle libusb events.
+    pub fn get_pollfd_iter(&self) -> PollFdIter {
+        // Safe because 'inner.context' is inited.
+        let list: *mut *const bindings::libusb_pollfd =
+            unsafe { bindings::libusb_get_pollfds(self.inner.context) };
+        PollFdIter { list, index: 0 }
+    }
+
+    /// Handle libusb events in a non block way.
+    pub fn handle_events_nonblock(&self) {
+        static mut zero_time: bindings::timeval = bindings::timeval {
+            tv_sec: 0,
+            tv_usec: 0,
+        };
+        // Safe because 'inner.context' points to valid context.
+        unsafe {
+            bindings::libusb_handle_events_timeout_completed(
+                self.inner.context,
+                &mut zero_time as *mut bindings::timeval,
+                std::ptr::null_mut(),
+            );
+        }
+    }
+
+    /// Set a handler that could handle pollfd change events.
+    pub fn set_pollfd_notifiers(&self, handler: Box<dyn LibUsbPollfdChangeHandler>) {
+        // LibUsbContext is alive when any libusb related function is called. It owns the handler,
+        // thus the handler memory is always valid when callback is invoked.
+        let holder = Box::new(PollfdChangeHandlerHolder { handler });
+        let raw_holder = Box::into_raw(holder);
+        unsafe {
+            bindings::libusb_set_pollfd_notifiers(
+                self.inner.context,
+                Some(pollfd_added_cb),
+                Some(pollfd_removed_cb),
+                raw_holder as *mut c_void,
+            );
+        }
+        // Safe because raw_holder is from Boxed pointer.
+        let holder = unsafe { Box::from_raw(raw_holder) };
+        *self.inner.pollfd_change_handler.lock() = Some(holder);
+    }
+
+    /// Remove the previous registered notifiers.
+    pub fn remove_pollfd_notifiers(&self) {
+        self.inner.remove_pollfd_notifiers();
+    }
+
+    /// Set a callback that could handle hotplug events. Currently, this function listen to hotplug
+    /// event of all devices.
+    pub fn set_hotplug_cb<H: UsbHotplugHandler + Sized>(&self, handler: H) -> Result<()> {
+        let event = bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED
+            | bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT;
+        let holder = UsbHotplugHandlerHolder::new(self.inner.clone(), handler);
+        let raw_holder = Box::into_raw(holder);
+        // Safe becuase hotpulg cb is a vaild c function and raw_holder points to memory for that
+        // function argument.
+        try_libusb!(unsafe {
+            bindings::libusb_hotplug_register_callback(
+                self.inner.context,
+                event,
+                bindings::LIBUSB_HOTPLUG_NO_FLAGS,
+                bindings::LIBUSB_HOTPLUG_MATCH_ANY,
+                bindings::LIBUSB_HOTPLUG_MATCH_ANY,
+                bindings::LIBUSB_HOTPLUG_MATCH_ANY,
+                Some(hotplug_cb),
+                raw_holder as *mut c_void,
+                std::ptr::null_mut(),
+            )
+        });
+        Ok(())
+    }
+}
+
+/// Iterator for device list.
+pub struct DeviceIter {
+    context: Arc<LibUsbContextInner>,
+    list: *mut *mut bindings::libusb_device,
+    index: isize,
+}
+
+impl Drop for DeviceIter {
+    fn drop(&mut self) {
+        // Safe because 'self.list' is inited by a valid pointer from libusb_get_device_list.
+        unsafe {
+            bindings::libusb_free_device_list(self.list, 1);
+        }
+    }
+}
+
+impl Iterator for DeviceIter {
+    type Item = LibUsbDevice;
+
+    fn next(&mut self) -> Option<LibUsbDevice> {
+        // Safe becuase 'self.list' is valid, the list is null terminated.
+        unsafe {
+            let current_ptr = self.list.offset(self.index);
+            if (*current_ptr).is_null() {
+                return None;
+            }
+            self.index += 1;
+            Some(LibUsbDevice::new(self.context.clone(), *current_ptr))
+        }
+    }
+}
+
+/// Iterator for pollfds.
+pub struct PollFdIter {
+    list: *mut *const bindings::libusb_pollfd,
+    index: isize,
+}
+
+impl Drop for PollFdIter {
+    fn drop(&mut self) {
+        // Safe because 'self.list' points to valid memory of pollfd list.
+        unsafe {
+            bindings::libusb_free_pollfds(self.list);
+        }
+    }
+}
+
+impl Iterator for PollFdIter {
+    type Item = bindings::libusb_pollfd;
+
+    fn next(&mut self) -> Option<bindings::libusb_pollfd> {
+        // Safe because 'self.index' never grow out of the null pointer index.
+        unsafe {
+            let current_ptr = self.list.offset(self.index);
+            if (*current_ptr).is_null() {
+                return None;
+            }
+
+            self.index += 1;
+            // Safe because '*current_ptr' is not null.
+            Some(**current_ptr)
+        }
+    }
+}
+
+/// Trait for handler that handles Pollfd Change events.
+pub trait LibUsbPollfdChangeHandler: Send + Sync + 'static {
+    fn add_poll_fd(&self, fd: RawFd, events: c_short);
+    fn remove_poll_fd(&self, fd: RawFd);
+}
+
+// This struct owns LibUsbPollfdChangeHandler. We need it because it's not possible to cast void
+// pointer to trait pointer.
+struct PollfdChangeHandlerHolder {
+    handler: Box<dyn LibUsbPollfdChangeHandler>,
+}
+
+// This function is safe when user_data points to valid PollfdChangeHandlerHolder.
+unsafe extern "C" fn pollfd_added_cb(fd: RawFd, events: c_short, user_data: *mut c_void) {
+    // Safe because user_data was casted from holder.
+    let keeper = &*(user_data as *mut PollfdChangeHandlerHolder);
+    keeper.handler.add_poll_fd(fd, events);
+}
+
+// This function is safe when user_data points to valid PollfdChangeHandlerHolder.
+unsafe extern "C" fn pollfd_removed_cb(fd: RawFd, user_data: *mut c_void) {
+    // Safe because user_data was casted from holder.
+    let keeper = &*(user_data as *mut PollfdChangeHandlerHolder);
+    keeper.handler.remove_poll_fd(fd);
+}
diff --git a/usb_util/src/libusb_device.rs b/usb_util/src/libusb_device.rs
new file mode 100644
index 0000000..e8f5120
--- /dev/null
+++ b/usb_util/src/libusb_device.rs
@@ -0,0 +1,120 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std;
+#[cfg(feature = "sandboxed-libusb")]
+use std::os::unix::io::RawFd;
+use std::sync::Arc;
+
+use crate::bindings;
+use crate::config_descriptor::ConfigDescriptor;
+use crate::device_handle::DeviceHandle;
+use crate::error::{Error, Result};
+use crate::libusb_context::LibUsbContextInner;
+use crate::types::Speed;
+
+pub type DeviceDescriptor = bindings::libusb_device_descriptor;
+
+/// LibUsbDevice wraps libusb_device.
+pub struct LibUsbDevice {
+    _context: Arc<LibUsbContextInner>,
+    device: *mut bindings::libusb_device,
+}
+
+unsafe impl Send for LibUsbDevice {}
+
+impl Drop for LibUsbDevice {
+    fn drop(&mut self) {
+        // Safe because 'self.device' is a valid pointer and libusb_ref_device is invoked when
+        // 'self' is built.
+        unsafe {
+            bindings::libusb_unref_device(self.device);
+        }
+    }
+}
+
+impl LibUsbDevice {
+    /// Create a new LibUsbDevice. 'device' should be a valid pointer to libusb_device.
+    pub unsafe fn new(
+        ctx: Arc<LibUsbContextInner>,
+        device: *mut bindings::libusb_device,
+    ) -> LibUsbDevice {
+        bindings::libusb_ref_device(device);
+        LibUsbDevice {
+            _context: ctx,
+            device,
+        }
+    }
+
+    /// Get device descriptor of this device.
+    pub fn get_device_descriptor(&self) -> Result<DeviceDescriptor> {
+        // Safe because memory is initialized later.
+        let mut descriptor: bindings::libusb_device_descriptor = Default::default();
+        // Safe because 'self.device' is valid and '&mut descriptor' is valid.
+        try_libusb!(unsafe {
+            bindings::libusb_get_device_descriptor(self.device, &mut descriptor)
+        });
+        Ok(descriptor)
+    }
+
+    /// Get config descriptor at index of idx.
+    pub fn get_config_descriptor(&self, idx: u8) -> Result<ConfigDescriptor> {
+        let mut descriptor: *mut bindings::libusb_config_descriptor = std::ptr::null_mut();
+        // Safe because 'self.device' is valid and '&mut descriptor' is valid.
+        try_libusb!(unsafe {
+            bindings::libusb_get_config_descriptor(self.device, idx, &mut descriptor)
+        });
+        // Safe because descriptor is inited with valid pointer.
+        Ok(unsafe { ConfigDescriptor::new(descriptor) })
+    }
+
+    /// Get active config descriptor of this device.
+    pub fn get_active_config_descriptor(&self) -> Result<ConfigDescriptor> {
+        let mut descriptor: *mut bindings::libusb_config_descriptor = std::ptr::null_mut();
+        // Safe because 'self.device' is valid and '&mut descriptor' is valid.
+        try_libusb!(unsafe {
+            bindings::libusb_get_active_config_descriptor(self.device, &mut descriptor)
+        });
+        // Safe becuase descriptor points to valid memory.
+        Ok(unsafe { ConfigDescriptor::new(descriptor) })
+    }
+
+    /// Get bus number of this device.
+    pub fn get_bus_number(&self) -> u8 {
+        // Safe because 'self.device' is valid.
+        unsafe { bindings::libusb_get_bus_number(self.device) }
+    }
+
+    /// Get address of this device.
+    pub fn get_address(&self) -> u8 {
+        // Safe because 'self.device' is valid.
+        unsafe { bindings::libusb_get_device_address(self.device) }
+    }
+
+    /// Get speed of this device.
+    pub fn get_speed(&self) -> Speed {
+        // Safe because 'self.device' is valid.
+        let speed = unsafe { bindings::libusb_get_device_speed(self.device) };
+        Speed::from(speed as u32)
+    }
+
+    /// Get device handle of this device.
+    pub fn open(&self) -> Result<DeviceHandle> {
+        let mut handle: *mut bindings::libusb_device_handle = std::ptr::null_mut();
+        // Safe because 'self.device' is constructed from libusb device list and handle is on stack.
+        try_libusb!(unsafe { bindings::libusb_open(self.device, &mut handle) });
+        // Safe because handle points to valid memory.
+        Ok(unsafe { DeviceHandle::new(self._context.clone(), handle) })
+    }
+
+    /// Get device handle of this device. Take an external fd. This function is only safe when fd
+    /// is an fd of this usb device.
+    #[cfg(feature = "sandboxed-libusb")]
+    pub unsafe fn open_fd(&self, fd: RawFd) -> Result<DeviceHandle> {
+        let mut handle: *mut bindings::libusb_device_handle = std::ptr::null_mut();
+        // Safe when 'self.device' is constructed from libusb device list and handle is on stack.
+        try_libusb!(bindings::libusb_open_fd(self.device, fd, &mut handle));
+        Ok(DeviceHandle::new(self._context.clone(), handle))
+    }
+}
diff --git a/usb_util/src/types.rs b/usb_util/src/types.rs
new file mode 100644
index 0000000..f40dd6c
--- /dev/null
+++ b/usb_util/src/types.rs
@@ -0,0 +1,196 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use assertions::const_assert;
+use data_model::DataInit;
+
+use std::mem::size_of;
+
+use crate::bindings;
+
+/// Speed of usb device. See usb spec for more details.
+#[derive(Debug)]
+pub enum Speed {
+    /// The OS doesn't report or know the device speed.
+    Unknown,
+    /// The device is operating at low speed (1.5MBit/s).
+    Low,
+    /// The device is operating at full speed (12MBit/s).
+    Full,
+    /// The device is operating at high speed (480MBit/s).
+    High,
+    /// The device is operating at super speed (5000MBit/s).
+    Super,
+}
+
+impl From<bindings::libusb_speed> for Speed {
+    fn from(speed: bindings::libusb_speed) -> Speed {
+        match speed {
+            bindings::LIBUSB_SPEED_LOW => Speed::Low,
+            bindings::LIBUSB_SPEED_FULL => Speed::Full,
+            bindings::LIBUSB_SPEED_HIGH => Speed::High,
+            bindings::LIBUSB_SPEED_SUPER => Speed::Super,
+            _ => Speed::Unknown,
+        }
+    }
+}
+
+/// Endpoint types.
+#[derive(PartialEq)]
+pub enum EndpointType {
+    Control,
+    Isochronous,
+    Bulk,
+    Interrupt,
+}
+
+/// Endpoint Directions.
+#[derive(PartialEq, Clone, Copy)]
+pub enum EndpointDirection {
+    HostToDevice = 0,
+    DeviceToHost = 1,
+}
+/// Endpoint direction offset.
+pub const ENDPOINT_DIRECTION_OFFSET: u8 = 7;
+
+/// Offset of data phase transfer direction.
+pub const DATA_PHASE_DIRECTION_OFFSET: u8 = 7;
+/// Bit mask of data phase transfer direction.
+pub const DATA_PHASE_DIRECTION: u8 = 1u8 << DATA_PHASE_DIRECTION_OFFSET;
+// Types of data phase transfer directions.
+#[derive(Copy, Clone, PartialEq)]
+pub enum ControlRequestDataPhaseTransferDirection {
+    HostToDevice = 0,
+    DeviceToHost = 1,
+}
+
+/// Offset of control request type.
+pub const CONTROL_REQUEST_TYPE_OFFSET: u8 = 5;
+/// Bit mask of control request type.
+pub const CONTROL_REQUEST_TYPE: u8 = 0b11 << CONTROL_REQUEST_TYPE_OFFSET;
+/// Request types.
+#[derive(PartialEq)]
+pub enum ControlRequestType {
+    Standard = 0,
+    Class = 1,
+    Vendor = 2,
+    Reserved = 3,
+}
+
+/// Recipient type bits.
+pub const REQUEST_RECIPIENT_TYPE: u8 = 0b1111;
+/// Recipient type of control request.
+#[derive(PartialEq)]
+pub enum ControlRequestRecipient {
+    Device = 0,
+    Interface = 1,
+    Endpoint = 2,
+    Other = 3,
+    Reserved,
+}
+
+/// Standard request defined in usb spec.
+#[derive(PartialEq)]
+pub enum StandardControlRequest {
+    GetStatus = 0x00,
+    ClearFeature = 0x01,
+    SetFeature = 0x03,
+    SetAddress = 0x05,
+    GetDescriptor = 0x06,
+    SetDescriptor = 0x07,
+    GetConfiguration = 0x08,
+    SetConfiguration = 0x09,
+    GetInterface = 0x0a,
+    SetInterface = 0x11,
+    SynchFrame = 0x12,
+}
+
+/// RequestSetup is first part of control transfer buffer.
+#[repr(C, packed)]
+#[derive(Copy, Clone, Debug)]
+pub struct UsbRequestSetup {
+    // USB Device Request. USB spec. rev. 2.0 9.3
+    pub request_type: u8, // bmRequestType
+    pub request: u8,      // bRequest
+    pub value: u16,       // wValue
+    pub index: u16,       // wIndex
+    pub length: u16,      // wLength
+}
+
+fn _assert() {
+    const_assert!(size_of::<UsbRequestSetup>() == 8);
+}
+
+unsafe impl DataInit for UsbRequestSetup {}
+
+impl UsbRequestSetup {
+    pub fn new(
+        request_type: u8,
+        request: u8,
+        value: u16,
+        index: u16,
+        length: u16,
+    ) -> UsbRequestSetup {
+        UsbRequestSetup {
+            request_type,
+            request,
+            value,
+            index,
+            length,
+        }
+    }
+
+    /// Get type of request.
+    pub fn get_type(&self) -> ControlRequestType {
+        let ty = (self.request_type & CONTROL_REQUEST_TYPE) >> CONTROL_REQUEST_TYPE_OFFSET;
+        match ty {
+            0 => ControlRequestType::Standard,
+            1 => ControlRequestType::Class,
+            2 => ControlRequestType::Vendor,
+            _ => ControlRequestType::Reserved,
+        }
+    }
+
+    /// Get request direction.
+    pub fn get_direction(&self) -> ControlRequestDataPhaseTransferDirection {
+        let dir = (self.request_type & DATA_PHASE_DIRECTION) >> DATA_PHASE_DIRECTION_OFFSET;
+        match dir {
+            0 => ControlRequestDataPhaseTransferDirection::HostToDevice,
+            _ => ControlRequestDataPhaseTransferDirection::DeviceToHost,
+        }
+    }
+
+    /// Get recipient of this control transfer.
+    pub fn get_recipient(&self) -> ControlRequestRecipient {
+        let recipient = self.request_type & REQUEST_RECIPIENT_TYPE;
+        match recipient {
+            0 => ControlRequestRecipient::Device,
+            1 => ControlRequestRecipient::Interface,
+            2 => ControlRequestRecipient::Endpoint,
+            3 => ControlRequestRecipient::Other,
+            _ => ControlRequestRecipient::Reserved,
+        }
+    }
+
+    /// Return the type of standard control request.
+    pub fn get_standard_request(&self) -> Option<StandardControlRequest> {
+        if self.get_type() != ControlRequestType::Standard {
+            return None;
+        }
+        match self.request {
+            0x00 => Some(StandardControlRequest::GetStatus),
+            0x01 => Some(StandardControlRequest::ClearFeature),
+            0x03 => Some(StandardControlRequest::SetFeature),
+            0x05 => Some(StandardControlRequest::SetAddress),
+            0x06 => Some(StandardControlRequest::GetDescriptor),
+            0x07 => Some(StandardControlRequest::SetDescriptor),
+            0x08 => Some(StandardControlRequest::GetConfiguration),
+            0x09 => Some(StandardControlRequest::SetConfiguration),
+            0x0a => Some(StandardControlRequest::GetInterface),
+            0x11 => Some(StandardControlRequest::SetInterface),
+            0x12 => Some(StandardControlRequest::SynchFrame),
+            _ => None,
+        }
+    }
+}
diff --git a/usb_util/src/usb_transfer.rs b/usb_util/src/usb_transfer.rs
new file mode 100644
index 0000000..e08bc92
--- /dev/null
+++ b/usb_util/src/usb_transfer.rs
@@ -0,0 +1,387 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::mem::size_of;
+use std::os::raw::c_void;
+use std::sync::{Arc, Weak};
+
+use crate::bindings::{
+    libusb_alloc_transfer, libusb_cancel_transfer, libusb_device_handle, libusb_free_transfer,
+    libusb_submit_transfer, libusb_transfer, libusb_transfer_status, LIBUSB_TRANSFER_CANCELLED,
+    LIBUSB_TRANSFER_COMPLETED, LIBUSB_TRANSFER_ERROR, LIBUSB_TRANSFER_NO_DEVICE,
+    LIBUSB_TRANSFER_OVERFLOW, LIBUSB_TRANSFER_STALL, LIBUSB_TRANSFER_TIMED_OUT,
+    LIBUSB_TRANSFER_TYPE_BULK, LIBUSB_TRANSFER_TYPE_CONTROL, LIBUSB_TRANSFER_TYPE_INTERRUPT,
+};
+use crate::error::{Error, Result};
+use crate::types::UsbRequestSetup;
+
+/// Status of transfer.
+#[derive(PartialEq)]
+pub enum TransferStatus {
+    Completed,
+    Error,
+    TimedOut,
+    Cancelled,
+    Stall,
+    NoDevice,
+    Overflow,
+}
+
+impl From<libusb_transfer_status> for TransferStatus {
+    fn from(s: libusb_transfer_status) -> Self {
+        match s {
+            LIBUSB_TRANSFER_COMPLETED => TransferStatus::Completed,
+            LIBUSB_TRANSFER_ERROR => TransferStatus::Error,
+            LIBUSB_TRANSFER_TIMED_OUT => TransferStatus::TimedOut,
+            LIBUSB_TRANSFER_CANCELLED => TransferStatus::Cancelled,
+            LIBUSB_TRANSFER_STALL => TransferStatus::Stall,
+            LIBUSB_TRANSFER_NO_DEVICE => TransferStatus::NoDevice,
+            LIBUSB_TRANSFER_OVERFLOW => TransferStatus::Overflow,
+            _ => TransferStatus::Error,
+        }
+    }
+}
+
+/// Trait for usb transfer buffer.
+pub trait UsbTransferBuffer: Send {
+    fn as_ptr(&mut self) -> *mut u8;
+    fn len(&self) -> i32;
+}
+
+/// Default buffer size for control data transfer.
+const CONTROL_DATA_BUFFER_SIZE: usize = 1024;
+
+/// Buffer type for control transfer. The first 8-bytes is a UsbRequestSetup struct.
+#[repr(C, packed)]
+pub struct ControlTransferBuffer {
+    pub setup_buffer: UsbRequestSetup,
+    pub data_buffer: [u8; CONTROL_DATA_BUFFER_SIZE],
+}
+
+impl ControlTransferBuffer {
+    fn new() -> ControlTransferBuffer {
+        ControlTransferBuffer {
+            setup_buffer: UsbRequestSetup {
+                request_type: 0,
+                request: 0,
+                value: 0,
+                index: 0,
+                length: 0,
+            },
+            data_buffer: [0; CONTROL_DATA_BUFFER_SIZE],
+        }
+    }
+
+    /// Set request setup for this control buffer.
+    pub fn set_request_setup(&mut self, request_setup: &UsbRequestSetup) {
+        self.setup_buffer = *request_setup;
+    }
+}
+
+impl UsbTransferBuffer for ControlTransferBuffer {
+    fn as_ptr(&mut self) -> *mut u8 {
+        self as *mut ControlTransferBuffer as *mut u8
+    }
+
+    fn len(&self) -> i32 {
+        if self.setup_buffer.length as usize > CONTROL_DATA_BUFFER_SIZE {
+            panic!("Setup packet has an oversize length");
+        }
+        self.setup_buffer.length as i32 + size_of::<UsbRequestSetup>() as i32
+    }
+}
+
+/// Buffer type for Bulk transfer.
+pub struct BulkTransferBuffer {
+    buffer: Vec<u8>,
+}
+
+impl BulkTransferBuffer {
+    fn with_size(buffer_size: usize) -> Self {
+        BulkTransferBuffer {
+            buffer: vec![0; buffer_size],
+        }
+    }
+
+    /// Get mutable interal slice of this buffer.
+    pub fn as_mut_slice(&mut self) -> &mut [u8] {
+        &mut self.buffer
+    }
+
+    /// Get interal slice of this buffer.
+    pub fn as_slice(&self) -> &[u8] {
+        &self.buffer
+    }
+}
+
+impl UsbTransferBuffer for BulkTransferBuffer {
+    fn as_ptr(&mut self) -> *mut u8 {
+        if self.buffer.len() == 0 {
+            // Vec::as_mut_ptr() won't give 0x0 even if len() is 0.
+            std::ptr::null_mut()
+        } else {
+            self.buffer.as_mut_ptr()
+        }
+    }
+
+    fn len(&self) -> i32 {
+        self.buffer.len() as i32
+    }
+}
+
+type UsbTransferCompletionCallback<T> = dyn Fn(UsbTransfer<T>) + Send + 'static;
+
+// This wraps libusb_transfer pointer.
+struct LibUsbTransfer {
+    ptr: *mut libusb_transfer,
+}
+
+impl Drop for LibUsbTransfer {
+    fn drop(&mut self) {
+        // Safe because 'self.ptr' is allocated by libusb_alloc_transfer.
+        unsafe {
+            libusb_free_transfer(self.ptr);
+        }
+    }
+}
+
+// It is safe to invoke libusb functions from multiple threads.
+// We cannot modify libusb_transfer safely from multiple threads. All the modifications happens
+// in construct (UsbTransfer::new) or consume (UsbTransfer::into_raw), we can consider this thread
+// safe.
+unsafe impl Send for LibUsbTransfer {}
+unsafe impl Sync for LibUsbTransfer {}
+
+/// TransferCanceller can cancel the transfer.
+pub struct TransferCanceller {
+    transfer: Weak<LibUsbTransfer>,
+}
+
+impl TransferCanceller {
+    /// Return false if fail to cancel.
+    pub fn try_cancel(&self) -> bool {
+        match self.transfer.upgrade() {
+            Some(t) => {
+                // Safe because self.transfer has ownership of the raw pointer.
+                let r = unsafe { libusb_cancel_transfer(t.ptr) };
+                if r == 0 {
+                    true
+                } else {
+                    false
+                }
+            }
+            None => false,
+        }
+    }
+}
+
+struct UsbTransferInner<T: UsbTransferBuffer> {
+    transfer: Arc<LibUsbTransfer>,
+    callback: Option<Box<UsbTransferCompletionCallback<T>>>,
+    buffer: T,
+}
+
+/// UsbTransfer owns a LibUsbTransfer, it's buffer and callback.
+pub struct UsbTransfer<T: UsbTransferBuffer> {
+    inner: Box<UsbTransferInner<T>>,
+}
+
+/// Build a control transfer.
+pub fn control_transfer(timeout: u32) -> UsbTransfer<ControlTransferBuffer> {
+    UsbTransfer::<ControlTransferBuffer>::new(
+        0,
+        LIBUSB_TRANSFER_TYPE_CONTROL as u8,
+        timeout,
+        ControlTransferBuffer::new(),
+    )
+}
+
+/// Build a data transfer.
+pub fn bulk_transfer(endpoint: u8, timeout: u32, size: usize) -> UsbTransfer<BulkTransferBuffer> {
+    UsbTransfer::<BulkTransferBuffer>::new(
+        endpoint,
+        LIBUSB_TRANSFER_TYPE_BULK as u8,
+        timeout,
+        BulkTransferBuffer::with_size(size),
+    )
+}
+
+/// Build a data transfer.
+pub fn interrupt_transfer(
+    endpoint: u8,
+    timeout: u32,
+    size: usize,
+) -> UsbTransfer<BulkTransferBuffer> {
+    UsbTransfer::<BulkTransferBuffer>::new(
+        endpoint,
+        LIBUSB_TRANSFER_TYPE_INTERRUPT as u8,
+        timeout,
+        BulkTransferBuffer::with_size(size),
+    )
+}
+
+impl<T: UsbTransferBuffer> UsbTransfer<T> {
+    fn new(endpoint: u8, type_: u8, timeout: u32, buffer: T) -> Self {
+        // Safe because alloc is safe.
+        let transfer: *mut libusb_transfer = unsafe { libusb_alloc_transfer(0) };
+        // Just panic on OOM.
+        assert!(!transfer.is_null());
+        let inner = Box::new(UsbTransferInner {
+            transfer: Arc::new(LibUsbTransfer { ptr: transfer }),
+            callback: None,
+            buffer,
+        });
+        // Safe because we inited transfer.
+        let raw_transfer: &mut libusb_transfer = unsafe { &mut *(inner.transfer.ptr) };
+        raw_transfer.endpoint = endpoint;
+        raw_transfer.type_ = type_;
+        raw_transfer.timeout = timeout;
+        raw_transfer.callback = Some(UsbTransfer::<T>::on_transfer_completed);
+        UsbTransfer { inner }
+    }
+
+    /// Get canceller of this transfer.
+    pub fn get_canceller(&self) -> TransferCanceller {
+        let weak_transfer = Arc::downgrade(&self.inner.transfer);
+        TransferCanceller {
+            transfer: weak_transfer,
+        }
+    }
+
+    /// Set callback function for transfer completion.
+    pub fn set_callback<C: 'static + Fn(UsbTransfer<T>) + Send>(&mut self, cb: C) {
+        self.inner.callback = Some(Box::new(cb));
+    }
+
+    /// Get a reference to the buffer.
+    pub fn buffer(&self) -> &T {
+        &self.inner.buffer
+    }
+
+    /// Get a mutable reference to the buffer.
+    pub fn buffer_mut(&mut self) -> &mut T {
+        &mut self.inner.buffer
+    }
+
+    /// Get actual length of data that was transferred.
+    pub fn actual_length(&self) -> i32 {
+        let transfer = self.inner.transfer.ptr;
+        // Safe because inner.ptr is always allocated by libusb_alloc_transfer.
+        unsafe { (*transfer).actual_length }
+    }
+
+    /// Get the transfer status of this transfer.
+    pub fn status(&self) -> TransferStatus {
+        let transfer = self.inner.transfer.ptr;
+        // Safe because inner.ptr is always allocated by libusb_alloc_transfer.
+        unsafe { TransferStatus::from((*transfer).status) }
+    }
+
+    /// Submit this transfer to device handle. 'self' is consumed. On success, the memory will be
+    /// 'leaked' (and stored in user_data) and sent to libusb, when the async operation is done,
+    /// on_transfer_completed will recreate 'self' and deliver it to callback/free 'self'. On
+    /// faliure, 'self' is returned with an error.
+    ///
+    /// # Safety
+    ///
+    /// Assumes libusb_device_handle is an handled opened by libusb, self.inner.transfer.ptr is
+    /// initialized with correct buffer and length.
+    pub unsafe fn submit(self, handle: *mut libusb_device_handle) -> Result<()> {
+        let transfer = self.into_raw();
+        (*transfer).dev_handle = handle;
+        match Error::from(libusb_submit_transfer(transfer)) {
+            Error::Success(_e) => Ok(()),
+            err => {
+                UsbTransfer::<T>::from_raw(transfer);
+                Err(err)
+            }
+        }
+    }
+
+    /// Invoke callback when transfer is completed.
+    ///
+    /// # Safety
+    ///
+    /// Assumes libusb_tranfser is finished. This function is called by libusb, don't call it
+    /// manually.
+    unsafe extern "C" fn on_transfer_completed(transfer: *mut libusb_transfer) {
+        let mut transfer = UsbTransfer::<T>::from_raw(transfer);
+        // Callback is reset to None.
+        if let Some(cb) = transfer.inner.callback.take() {
+            cb(transfer);
+        }
+    }
+
+    fn into_raw(mut self) -> *mut libusb_transfer {
+        let transfer: *mut libusb_transfer = self.inner.transfer.ptr;
+        // Safe because transfer is allocated by libusb_alloc_transfer.
+        unsafe {
+            (*transfer).buffer = self.buffer_mut().as_ptr();
+            (*transfer).length = self.buffer_mut().len();
+            (*transfer).user_data = Box::into_raw(self.inner) as *mut c_void;
+        }
+        transfer
+    }
+
+    unsafe fn from_raw(transfer: *mut libusb_transfer) -> Self {
+        UsbTransfer {
+            inner: Box::<UsbTransferInner<T>>::from_raw(
+                (*transfer).user_data as *mut UsbTransferInner<T>,
+            ),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::sync::Mutex;
+
+    pub fn fake_submit_transfer<T: UsbTransferBuffer>(transfer: UsbTransfer<T>) {
+        let transfer = transfer.into_raw();
+        unsafe {
+            match (*transfer).callback {
+                Some(cb) => cb(transfer),
+                // Although no callback is invoked, we still need on_transfer_completed to
+                // free memory.
+                None => panic!("Memory leak!"),
+            };
+        }
+    }
+
+    #[test]
+    fn check_control_buffer_size() {
+        assert_eq!(
+            size_of::<ControlTransferBuffer>(),
+            size_of::<UsbRequestSetup>() + CONTROL_DATA_BUFFER_SIZE
+        );
+    }
+
+    #[test]
+    fn submit_transfer_no_callback_test() {
+        let t = control_transfer(0);
+        fake_submit_transfer(t);
+        let t = bulk_transfer(0, 0, 1);
+        fake_submit_transfer(t);
+    }
+
+    struct FakeTransferController {
+        data: Mutex<u8>,
+    }
+
+    #[test]
+    fn submit_transfer_with_callback() {
+        let c = Arc::new(FakeTransferController {
+            data: Mutex::new(0),
+        });
+        let c1 = Arc::downgrade(&c);
+        let mut t = control_transfer(0);
+        t.set_callback(move |_t| {
+            let c = c1.upgrade().unwrap();
+            *c.data.lock().unwrap() = 3;
+        });
+        fake_submit_transfer(t);
+        assert_eq!(*c.data.lock().unwrap(), 3);
+    }
+}
diff --git a/vhost/Cargo.toml b/vhost/Cargo.toml
new file mode 100644
index 0000000..567e880
--- /dev/null
+++ b/vhost/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "vhost"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+assertions = { path = "../assertions" }
+libc = "*"
+net_util = { path = "../net_util" }
+sys_util = { path = "../sys_util" }
+virtio_sys = { path = "../virtio_sys" }
diff --git a/vhost/src/lib.rs b/vhost/src/lib.rs
new file mode 100644
index 0000000..04ba655
--- /dev/null
+++ b/vhost/src/lib.rs
@@ -0,0 +1,443 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+pub mod net;
+mod vsock;
+
+pub use crate::net::Net;
+pub use crate::net::NetT;
+pub use crate::vsock::Vsock;
+
+use std::alloc::Layout;
+use std::fmt::{self, Display};
+use std::io::Error as IoError;
+use std::mem;
+use std::os::unix::io::AsRawFd;
+use std::ptr::null;
+
+use assertions::const_assert;
+use sys_util::{ioctl, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref};
+use sys_util::{EventFd, GuestAddress, GuestMemory, GuestMemoryError, LayoutAllocation};
+
+#[derive(Debug)]
+pub enum Error {
+    /// Error opening vhost device.
+    VhostOpen(IoError),
+    /// Error while running ioctl.
+    IoctlError(IoError),
+    /// Invalid queue.
+    InvalidQueue,
+    /// Invalid descriptor table address.
+    DescriptorTableAddress(GuestMemoryError),
+    /// Invalid used address.
+    UsedAddress(GuestMemoryError),
+    /// Invalid available address.
+    AvailAddress(GuestMemoryError),
+    /// Invalid log address.
+    LogAddress(GuestMemoryError),
+}
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            VhostOpen(e) => write!(f, "failed to open vhost device: {}", e),
+            IoctlError(e) => write!(f, "failed to run ioctl: {}", e),
+            InvalidQueue => write!(f, "invalid queue"),
+            DescriptorTableAddress(e) => write!(f, "invalid descriptor table address: {}", e),
+            UsedAddress(e) => write!(f, "invalid used address: {}", e),
+            AvailAddress(e) => write!(f, "invalid available address: {}", e),
+            LogAddress(e) => write!(f, "invalid log address: {}", e),
+        }
+    }
+}
+
+fn ioctl_result<T>() -> Result<T> {
+    Err(Error::IoctlError(IoError::last_os_error()))
+}
+
+/// An interface for setting up vhost-based virtio devices.  Vhost-based devices are different
+/// from regular virtio devices because the host kernel takes care of handling all the data
+/// transfer.  The device itself only needs to deal with setting up the kernel driver and
+/// managing the control channel.
+pub trait Vhost: AsRawFd + std::marker::Sized {
+    /// Get the guest memory mapping.
+    fn mem(&self) -> &GuestMemory;
+
+    /// Set the current process as the owner of this file descriptor.
+    /// This must be run before any other vhost ioctls.
+    fn set_owner(&self) -> Result<()> {
+        // This ioctl is called on a valid vhost_net fd and has its
+        // return value checked.
+        let ret = unsafe { ioctl(self, virtio_sys::VHOST_SET_OWNER()) };
+        if ret < 0 {
+            return ioctl_result();
+        }
+        Ok(())
+    }
+
+    /// Get a bitmask of supported virtio/vhost features.
+    fn get_features(&self) -> Result<u64> {
+        let mut avail_features: u64 = 0;
+        // This ioctl is called on a valid vhost_net fd and has its
+        // return value checked.
+        let ret = unsafe {
+            ioctl_with_mut_ref(self, virtio_sys::VHOST_GET_FEATURES(), &mut avail_features)
+        };
+        if ret < 0 {
+            return ioctl_result();
+        }
+        Ok(avail_features)
+    }
+
+    /// Inform the vhost subsystem which features to enable. This should be a subset of
+    /// supported features from VHOST_GET_FEATURES.
+    ///
+    /// # Arguments
+    /// * `features` - Bitmask of features to set.
+    fn set_features(&self, features: u64) -> Result<()> {
+        // This ioctl is called on a valid vhost_net fd and has its
+        // return value checked.
+        let ret = unsafe { ioctl_with_ref(self, virtio_sys::VHOST_SET_FEATURES(), &features) };
+        if ret < 0 {
+            return ioctl_result();
+        }
+        Ok(())
+    }
+
+    /// Set the guest memory mappings for vhost to use.
+    fn set_mem_table(&self) -> Result<()> {
+        const SIZE_OF_MEMORY: usize = mem::size_of::<virtio_sys::vhost_memory>();
+        const SIZE_OF_REGION: usize = mem::size_of::<virtio_sys::vhost_memory_region>();
+        const ALIGN_OF_MEMORY: usize = mem::align_of::<virtio_sys::vhost_memory>();
+        const ALIGN_OF_REGION: usize = mem::align_of::<virtio_sys::vhost_memory_region>();
+        const_assert!(ALIGN_OF_MEMORY >= ALIGN_OF_REGION);
+
+        let num_regions = self.mem().num_regions() as usize;
+        let size = SIZE_OF_MEMORY + num_regions * SIZE_OF_REGION;
+        let layout = Layout::from_size_align(size, ALIGN_OF_MEMORY).expect("impossible layout");
+        let mut allocation = LayoutAllocation::zeroed(layout);
+
+        // Safe to obtain an exclusive reference because there are no other
+        // references to the allocation yet and all-zero is a valid bit pattern.
+        let vhost_memory = unsafe { allocation.as_mut::<virtio_sys::vhost_memory>() };
+
+        vhost_memory.nregions = num_regions as u32;
+        // regions is a zero-length array, so taking a mut slice requires that
+        // we correctly specify the size to match the amount of backing memory.
+        let vhost_regions = unsafe { vhost_memory.regions.as_mut_slice(num_regions as usize) };
+
+        let _ = self
+            .mem()
+            .with_regions::<_, ()>(|index, guest_addr, size, host_addr, _| {
+                vhost_regions[index] = virtio_sys::vhost_memory_region {
+                    guest_phys_addr: guest_addr.offset() as u64,
+                    memory_size: size as u64,
+                    userspace_addr: host_addr as u64,
+                    flags_padding: 0u64,
+                };
+                Ok(())
+            });
+
+        // This ioctl is called with a pointer that is valid for the lifetime
+        // of this function. The kernel will make its own copy of the memory
+        // tables. As always, check the return value.
+        let ret = unsafe { ioctl_with_ptr(self, virtio_sys::VHOST_SET_MEM_TABLE(), vhost_memory) };
+        if ret < 0 {
+            return ioctl_result();
+        }
+
+        Ok(())
+
+        // vhost_memory allocation is deallocated.
+    }
+
+    /// Set the number of descriptors in the vring.
+    ///
+    /// # Arguments
+    /// * `queue_index` - Index of the queue to set descriptor count for.
+    /// * `num` - Number of descriptors in the queue.
+    fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()> {
+        let vring_state = virtio_sys::vhost_vring_state {
+            index: queue_index as u32,
+            num: num as u32,
+        };
+
+        // This ioctl is called on a valid vhost_net fd and has its
+        // return value checked.
+        let ret = unsafe { ioctl_with_ref(self, virtio_sys::VHOST_SET_VRING_NUM(), &vring_state) };
+        if ret < 0 {
+            return ioctl_result();
+        }
+        Ok(())
+    }
+
+    // TODO(smbarber): This is copypasta. Eliminate the copypasta.
+    #[allow(clippy::if_same_then_else)]
+    fn is_valid(
+        &self,
+        queue_max_size: u16,
+        queue_size: u16,
+        desc_addr: GuestAddress,
+        avail_addr: GuestAddress,
+        used_addr: GuestAddress,
+    ) -> bool {
+        let desc_table_size = 16 * queue_size as usize;
+        let avail_ring_size = 6 + 2 * queue_size as usize;
+        let used_ring_size = 6 + 8 * queue_size as usize;
+        if queue_size > queue_max_size || queue_size == 0 || (queue_size & (queue_size - 1)) != 0 {
+            false
+        } else if desc_addr
+            .checked_add(desc_table_size as u64)
+            .map_or(true, |v| !self.mem().address_in_range(v))
+        {
+            false
+        } else if avail_addr
+            .checked_add(avail_ring_size as u64)
+            .map_or(true, |v| !self.mem().address_in_range(v))
+        {
+            false
+        } else if used_addr
+            .checked_add(used_ring_size as u64)
+            .map_or(true, |v| !self.mem().address_in_range(v))
+        {
+            false
+        } else {
+            true
+        }
+    }
+
+    /// Set the addresses for a given vring.
+    ///
+    /// # Arguments
+    /// * `queue_max_size` - Maximum queue size supported by the device.
+    /// * `queue_size` - Actual queue size negotiated by the driver.
+    /// * `queue_index` - Index of the queue to set addresses for.
+    /// * `flags` - Bitmask of vring flags.
+    /// * `desc_addr` - Descriptor table address.
+    /// * `used_addr` - Used ring buffer address.
+    /// * `avail_addr` - Available ring buffer address.
+    /// * `log_addr` - Optional address for logging.
+    fn set_vring_addr(
+        &self,
+        queue_max_size: u16,
+        queue_size: u16,
+        queue_index: usize,
+        flags: u32,
+        desc_addr: GuestAddress,
+        used_addr: GuestAddress,
+        avail_addr: GuestAddress,
+        log_addr: Option<GuestAddress>,
+    ) -> Result<()> {
+        // TODO(smbarber): Refactor out virtio from crosvm so we can
+        // validate a Queue struct directly.
+        if !self.is_valid(queue_max_size, queue_size, desc_addr, used_addr, avail_addr) {
+            return Err(Error::InvalidQueue);
+        }
+
+        let desc_addr = self
+            .mem()
+            .get_host_address(desc_addr)
+            .map_err(Error::DescriptorTableAddress)?;
+        let used_addr = self
+            .mem()
+            .get_host_address(used_addr)
+            .map_err(Error::UsedAddress)?;
+        let avail_addr = self
+            .mem()
+            .get_host_address(avail_addr)
+            .map_err(Error::AvailAddress)?;
+        let log_addr = match log_addr {
+            None => null(),
+            Some(a) => self.mem().get_host_address(a).map_err(Error::LogAddress)?,
+        };
+
+        let vring_addr = virtio_sys::vhost_vring_addr {
+            index: queue_index as u32,
+            flags,
+            desc_user_addr: desc_addr as u64,
+            used_user_addr: used_addr as u64,
+            avail_user_addr: avail_addr as u64,
+            log_guest_addr: log_addr as u64,
+        };
+
+        // This ioctl is called on a valid vhost_net fd and has its
+        // return value checked.
+        let ret = unsafe { ioctl_with_ref(self, virtio_sys::VHOST_SET_VRING_ADDR(), &vring_addr) };
+        if ret < 0 {
+            return ioctl_result();
+        }
+        Ok(())
+    }
+
+    /// Set the first index to look for available descriptors.
+    ///
+    /// # Arguments
+    /// * `queue_index` - Index of the queue to modify.
+    /// * `num` - Index where available descriptors start.
+    fn set_vring_base(&self, queue_index: usize, num: u16) -> Result<()> {
+        let vring_state = virtio_sys::vhost_vring_state {
+            index: queue_index as u32,
+            num: num as u32,
+        };
+
+        // This ioctl is called on a valid vhost_net fd and has its
+        // return value checked.
+        let ret = unsafe { ioctl_with_ref(self, virtio_sys::VHOST_SET_VRING_BASE(), &vring_state) };
+        if ret < 0 {
+            return ioctl_result();
+        }
+        Ok(())
+    }
+
+    /// Set the eventfd to trigger when buffers have been used by the host.
+    ///
+    /// # Arguments
+    /// * `queue_index` - Index of the queue to modify.
+    /// * `fd` - EventFd to trigger.
+    fn set_vring_call(&self, queue_index: usize, fd: &EventFd) -> Result<()> {
+        let vring_file = virtio_sys::vhost_vring_file {
+            index: queue_index as u32,
+            fd: fd.as_raw_fd(),
+        };
+
+        // This ioctl is called on a valid vhost_net fd and has its
+        // return value checked.
+        let ret = unsafe { ioctl_with_ref(self, virtio_sys::VHOST_SET_VRING_CALL(), &vring_file) };
+        if ret < 0 {
+            return ioctl_result();
+        }
+        Ok(())
+    }
+
+    /// Set the eventfd that will be signaled by the guest when buffers are
+    /// available for the host to process.
+    ///
+    /// # Arguments
+    /// * `queue_index` - Index of the queue to modify.
+    /// * `fd` - EventFd that will be signaled from guest.
+    fn set_vring_kick(&self, queue_index: usize, fd: &EventFd) -> Result<()> {
+        let vring_file = virtio_sys::vhost_vring_file {
+            index: queue_index as u32,
+            fd: fd.as_raw_fd(),
+        };
+
+        // This ioctl is called on a valid vhost_net fd and has its
+        // return value checked.
+        let ret = unsafe { ioctl_with_ref(self, virtio_sys::VHOST_SET_VRING_KICK(), &vring_file) };
+        if ret < 0 {
+            return ioctl_result();
+        }
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use crate::net::fakes::FakeNet;
+    use net_util::fakes::FakeTap;
+    use std::result;
+    use sys_util::{GuestAddress, GuestMemory, GuestMemoryError};
+
+    fn create_guest_memory() -> result::Result<GuestMemory, GuestMemoryError> {
+        let start_addr1 = GuestAddress(0x0);
+        let start_addr2 = GuestAddress(0x1000);
+        GuestMemory::new(&vec![(start_addr1, 0x1000), (start_addr2, 0x4000)])
+    }
+
+    fn assert_ok_or_known_failure<T>(res: Result<T>) {
+        match &res {
+            // FakeNet won't respond to ioctl's
+            Ok(_t) => {}
+            Err(Error::IoctlError(ioe)) if ioe.raw_os_error().unwrap() == 25 => {}
+            Err(e) => panic!("Unexpected Error:\n{}", e),
+        }
+    }
+
+    fn create_fake_vhost_net() -> FakeNet<FakeTap> {
+        let gm = create_guest_memory().unwrap();
+        FakeNet::<FakeTap>::new(&gm).unwrap()
+    }
+
+    #[test]
+    fn test_create_fake_vhost_net() {
+        create_fake_vhost_net();
+    }
+
+    #[test]
+    fn set_owner() {
+        let vhost_net = create_fake_vhost_net();
+        let res = vhost_net.set_owner();
+        assert_ok_or_known_failure(res);
+    }
+
+    #[test]
+    fn get_features() {
+        let vhost_net = create_fake_vhost_net();
+        let res = vhost_net.get_features();
+        assert_ok_or_known_failure(res);
+    }
+
+    #[test]
+    fn set_features() {
+        let vhost_net = create_fake_vhost_net();
+        let res = vhost_net.set_features(0);
+        assert_ok_or_known_failure(res);
+    }
+
+    #[test]
+    fn set_mem_table() {
+        let vhost_net = create_fake_vhost_net();
+        let res = vhost_net.set_mem_table();
+        assert_ok_or_known_failure(res);
+    }
+
+    #[test]
+    fn set_vring_num() {
+        let vhost_net = create_fake_vhost_net();
+        let res = vhost_net.set_vring_num(0, 1);
+        assert_ok_or_known_failure(res);
+    }
+
+    #[test]
+    fn set_vring_addr() {
+        let vhost_net = create_fake_vhost_net();
+        let res = vhost_net.set_vring_addr(
+            1,
+            1,
+            0,
+            0x0,
+            GuestAddress(0x0),
+            GuestAddress(0x0),
+            GuestAddress(0x0),
+            None,
+        );
+        assert_ok_or_known_failure(res);
+    }
+
+    #[test]
+    fn set_vring_base() {
+        let vhost_net = create_fake_vhost_net();
+        let res = vhost_net.set_vring_base(0, 1);
+        assert_ok_or_known_failure(res);
+    }
+
+    #[test]
+    fn set_vring_call() {
+        let vhost_net = create_fake_vhost_net();
+        let res = vhost_net.set_vring_call(0, &EventFd::new().unwrap());
+        assert_ok_or_known_failure(res);
+    }
+
+    #[test]
+    fn set_vring_kick() {
+        let vhost_net = create_fake_vhost_net();
+        let res = vhost_net.set_vring_kick(0, &EventFd::new().unwrap());
+        assert_ok_or_known_failure(res);
+    }
+}
diff --git a/vhost/src/net.rs b/vhost/src/net.rs
new file mode 100644
index 0000000..0f1cd86
--- /dev/null
+++ b/vhost/src/net.rs
@@ -0,0 +1,146 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use libc;
+use net_util::TapT;
+use std::fs::{File, OpenOptions};
+use std::marker::PhantomData;
+use std::os::unix::fs::OpenOptionsExt;
+use std::os::unix::io::{AsRawFd, RawFd};
+use virtio_sys;
+
+use sys_util::{ioctl_with_ref, GuestMemory};
+
+use super::{ioctl_result, Error, Result, Vhost};
+
+static DEVICE: &'static str = "/dev/vhost-net";
+
+/// Handle to run VHOST_NET ioctls.
+///
+/// This provides a simple wrapper around a VHOST_NET file descriptor and
+/// methods that safely run ioctls on that file descriptor.
+pub struct Net<T> {
+    // fd must be dropped first, which will stop and tear down the
+    // vhost-net worker before GuestMemory can potentially be unmapped.
+    fd: File,
+    mem: GuestMemory,
+    phantom: PhantomData<T>,
+}
+
+pub trait NetT<T: TapT>: Vhost + AsRawFd + Send + Sized {
+    /// Create a new NetT instance
+    fn new(mem: &GuestMemory) -> Result<Self>;
+
+    /// Set the tap file descriptor that will serve as the VHOST_NET backend.
+    /// This will start the vhost worker for the given queue.
+    ///
+    /// # Arguments
+    /// * `queue_index` - Index of the queue to modify.
+    /// * `fd` - Tap interface that will be used as the backend.
+    fn set_backend(&self, queue_index: usize, fd: &T) -> Result<()>;
+}
+
+impl<T> NetT<T> for Net<T>
+where
+    T: TapT,
+{
+    /// Opens /dev/vhost-net and holds a file descriptor open for it.
+    ///
+    /// # Arguments
+    /// * `mem` - Guest memory mapping.
+    fn new(mem: &GuestMemory) -> Result<Net<T>> {
+        Ok(Net::<T> {
+            fd: OpenOptions::new()
+                .read(true)
+                .write(true)
+                .custom_flags(libc::O_CLOEXEC | libc::O_NONBLOCK)
+                .open(DEVICE)
+                .map_err(Error::VhostOpen)?,
+            mem: mem.clone(),
+            phantom: PhantomData,
+        })
+    }
+
+    fn set_backend(&self, queue_index: usize, fd: &T) -> Result<()> {
+        let vring_file = virtio_sys::vhost_vring_file {
+            index: queue_index as u32,
+            fd: fd.as_raw_fd(),
+        };
+
+        // This ioctl is called on a valid vhost_net fd and has its
+        // return value checked.
+        let ret =
+            unsafe { ioctl_with_ref(&self.fd, virtio_sys::VHOST_NET_SET_BACKEND(), &vring_file) };
+        if ret < 0 {
+            return ioctl_result();
+        }
+        Ok(())
+    }
+}
+
+impl<T> Vhost for Net<T> {
+    fn mem(&self) -> &GuestMemory {
+        &self.mem
+    }
+}
+
+impl<T> AsRawFd for Net<T> {
+    fn as_raw_fd(&self) -> RawFd {
+        self.fd.as_raw_fd()
+    }
+}
+
+pub mod fakes {
+    use super::*;
+    use std::fs::remove_file;
+    use std::fs::OpenOptions;
+
+    const TMP_FILE: &str = "/tmp/crosvm_vhost_test_file";
+
+    pub struct FakeNet<T> {
+        fd: File,
+        mem: GuestMemory,
+        phantom: PhantomData<T>,
+    }
+
+    impl<T> Drop for FakeNet<T> {
+        fn drop(&mut self) {
+            let _ = remove_file(TMP_FILE);
+        }
+    }
+
+    impl<T> NetT<T> for FakeNet<T>
+    where
+        T: TapT,
+    {
+        fn new(mem: &GuestMemory) -> Result<FakeNet<T>> {
+            Ok(FakeNet::<T> {
+                fd: OpenOptions::new()
+                    .read(true)
+                    .append(true)
+                    .create(true)
+                    .open(TMP_FILE)
+                    .unwrap(),
+                mem: mem.clone(),
+                phantom: PhantomData,
+            })
+        }
+
+        fn set_backend(&self, _queue_index: usize, _fd: &T) -> Result<()> {
+            Ok(())
+        }
+    }
+
+    impl<T> Vhost for FakeNet<T> {
+        fn mem(&self) -> &GuestMemory {
+            &self.mem
+        }
+    }
+
+    impl<T> AsRawFd for FakeNet<T> {
+        fn as_raw_fd(&self) -> RawFd {
+            self.fd.as_raw_fd()
+        }
+    }
+}
diff --git a/vhost/src/vsock.rs b/vhost/src/vsock.rs
new file mode 100644
index 0000000..8c96b9f
--- /dev/null
+++ b/vhost/src/vsock.rs
@@ -0,0 +1,82 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use libc;
+use std::fs::{File, OpenOptions};
+use std::os::unix::fs::OpenOptionsExt;
+use std::os::unix::io::{AsRawFd, RawFd};
+
+use sys_util::{ioctl_with_ref, GuestMemory};
+use virtio_sys::{VHOST_VSOCK_SET_GUEST_CID, VHOST_VSOCK_SET_RUNNING};
+
+use super::{ioctl_result, Error, Result, Vhost};
+
+static DEVICE: &'static str = "/dev/vhost-vsock";
+
+/// Handle for running VHOST_VSOCK ioctls.
+pub struct Vsock {
+    fd: File,
+    mem: GuestMemory,
+}
+
+impl Vsock {
+    /// Open a handle to a new VHOST_VSOCK instance.
+    pub fn new(mem: &GuestMemory) -> Result<Vsock> {
+        Ok(Vsock {
+            fd: OpenOptions::new()
+                .read(true)
+                .write(true)
+                .custom_flags(libc::O_CLOEXEC | libc::O_NONBLOCK)
+                .open(DEVICE)
+                .map_err(Error::VhostOpen)?,
+            mem: mem.clone(),
+        })
+    }
+
+    /// Set the CID for the guest.  This number is used for routing all data destined for
+    /// programs
+    /// running in the guest.
+    ///
+    /// # Arguments
+    /// * `cid` - CID to assign to the guest
+    pub fn set_cid(&self, cid: u64) -> Result<()> {
+        let ret = unsafe { ioctl_with_ref(&self.fd, VHOST_VSOCK_SET_GUEST_CID(), &cid) };
+        if ret < 0 {
+            return ioctl_result();
+        }
+        Ok(())
+    }
+
+    /// Tell the VHOST driver to start performing data transfer.
+    pub fn start(&self) -> Result<()> {
+        self.set_running(true)
+    }
+
+    /// Tell the VHOST driver to stop performing data transfer.
+    pub fn stop(&self) -> Result<()> {
+        self.set_running(false)
+    }
+
+    fn set_running(&self, running: bool) -> Result<()> {
+        let on: ::std::os::raw::c_int = if running { 1 } else { 0 };
+        let ret = unsafe { ioctl_with_ref(&self.fd, VHOST_VSOCK_SET_RUNNING(), &on) };
+
+        if ret < 0 {
+            return ioctl_result();
+        }
+        Ok(())
+    }
+}
+
+impl Vhost for Vsock {
+    fn mem(&self) -> &GuestMemory {
+        &self.mem
+    }
+}
+
+impl AsRawFd for Vsock {
+    fn as_raw_fd(&self) -> RawFd {
+        self.fd.as_raw_fd()
+    }
+}
diff --git a/virtio_sys/Cargo.toml b/virtio_sys/Cargo.toml
new file mode 100644
index 0000000..e6d2e03
--- /dev/null
+++ b/virtio_sys/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "virtio_sys"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+sys_util = { path = "../sys_util" }
diff --git a/virtio_sys/src/lib.rs b/virtio_sys/src/lib.rs
new file mode 100644
index 0000000..680d133
--- /dev/null
+++ b/virtio_sys/src/lib.rs
@@ -0,0 +1,64 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+use sys_util::{ioctl_io_nr, ioctl_ior_nr, ioctl_iow_nr, ioctl_iowr_nr};
+
+// generated with bindgen /usr/include/linux/vhost.h --no-unstable-rust --constified-enum '*' --with-derive-default
+pub mod vhost;
+// generated with bindgen /usr/include/linux/virtio_net.h --no-unstable-rust --constified-enum '*' --with-derive-default
+pub mod virtio_net;
+// generated with bindgen /usr/include/linux/virtio_ring.h --no-unstable-rust --constified-enum '*' --with-derive-default
+pub mod virtio_ring;
+pub use crate::vhost::*;
+pub use crate::virtio_net::*;
+pub use crate::virtio_ring::*;
+
+pub const VHOST: ::std::os::raw::c_uint = 0xaf;
+
+ioctl_ior_nr!(VHOST_GET_FEATURES, VHOST, 0x00, ::std::os::raw::c_ulonglong);
+ioctl_iow_nr!(VHOST_SET_FEATURES, VHOST, 0x00, ::std::os::raw::c_ulonglong);
+ioctl_io_nr!(VHOST_SET_OWNER, VHOST, 0x01);
+ioctl_io_nr!(VHOST_RESET_OWNER, VHOST, 0x02);
+ioctl_iow_nr!(VHOST_SET_MEM_TABLE, VHOST, 0x03, vhost_memory);
+ioctl_iow_nr!(VHOST_SET_LOG_BASE, VHOST, 0x04, ::std::os::raw::c_ulonglong);
+ioctl_iow_nr!(VHOST_SET_LOG_FD, VHOST, 0x07, ::std::os::raw::c_int);
+ioctl_iow_nr!(VHOST_SET_VRING_NUM, VHOST, 0x10, vhost_vring_state);
+ioctl_iow_nr!(VHOST_SET_VRING_ADDR, VHOST, 0x11, vhost_vring_addr);
+ioctl_iow_nr!(VHOST_SET_VRING_BASE, VHOST, 0x12, vhost_vring_state);
+ioctl_iowr_nr!(VHOST_GET_VRING_BASE, VHOST, 0x12, vhost_vring_state);
+ioctl_iow_nr!(VHOST_SET_VRING_KICK, VHOST, 0x20, vhost_vring_file);
+ioctl_iow_nr!(VHOST_SET_VRING_CALL, VHOST, 0x21, vhost_vring_file);
+ioctl_iow_nr!(VHOST_SET_VRING_ERR, VHOST, 0x22, vhost_vring_file);
+ioctl_iow_nr!(VHOST_NET_SET_BACKEND, VHOST, 0x30, vhost_vring_file);
+ioctl_iow_nr!(VHOST_SCSI_SET_ENDPOINT, VHOST, 0x40, vhost_scsi_target);
+ioctl_iow_nr!(VHOST_SCSI_CLEAR_ENDPOINT, VHOST, 0x41, vhost_scsi_target);
+ioctl_iow_nr!(
+    VHOST_SCSI_GET_ABI_VERSION,
+    VHOST,
+    0x42,
+    ::std::os::raw::c_int
+);
+ioctl_iow_nr!(
+    VHOST_SCSI_SET_EVENTS_MISSED,
+    VHOST,
+    0x43,
+    ::std::os::raw::c_uint
+);
+ioctl_iow_nr!(
+    VHOST_SCSI_GET_EVENTS_MISSED,
+    VHOST,
+    0x44,
+    ::std::os::raw::c_uint
+);
+ioctl_iow_nr!(
+    VHOST_VSOCK_SET_GUEST_CID,
+    VHOST,
+    0x60,
+    ::std::os::raw::c_ulonglong
+);
+ioctl_iow_nr!(VHOST_VSOCK_SET_RUNNING, VHOST, 0x61, ::std::os::raw::c_int);
diff --git a/virtio_sys/src/vhost.rs b/virtio_sys/src/vhost.rs
new file mode 100644
index 0000000..70d2db6
--- /dev/null
+++ b/virtio_sys/src/vhost.rs
@@ -0,0 +1,891 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+#[repr(C)]
+#[derive(Default)]
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
+impl<T> __IncompleteArrayField<T> {
+    #[inline]
+    pub fn new() -> Self {
+        __IncompleteArrayField(::std::marker::PhantomData)
+    }
+    #[inline]
+    pub unsafe fn as_ptr(&self) -> *const T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_slice(&self, len: usize) -> &[T] {
+        ::std::slice::from_raw_parts(self.as_ptr(), len)
+    }
+    #[inline]
+    pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
+        ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
+    }
+}
+impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        fmt.write_str("__IncompleteArrayField")
+    }
+}
+impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self::new()
+    }
+}
+impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
+pub const __BITS_PER_LONG: ::std::os::raw::c_uint = 64;
+pub const __FD_SETSIZE: ::std::os::raw::c_uint = 1024;
+pub const _IOC_NRBITS: ::std::os::raw::c_uint = 8;
+pub const _IOC_TYPEBITS: ::std::os::raw::c_uint = 8;
+pub const _IOC_SIZEBITS: ::std::os::raw::c_uint = 14;
+pub const _IOC_DIRBITS: ::std::os::raw::c_uint = 2;
+pub const _IOC_NRMASK: ::std::os::raw::c_uint = 255;
+pub const _IOC_TYPEMASK: ::std::os::raw::c_uint = 255;
+pub const _IOC_SIZEMASK: ::std::os::raw::c_uint = 16383;
+pub const _IOC_DIRMASK: ::std::os::raw::c_uint = 3;
+pub const _IOC_NRSHIFT: ::std::os::raw::c_uint = 0;
+pub const _IOC_TYPESHIFT: ::std::os::raw::c_uint = 8;
+pub const _IOC_SIZESHIFT: ::std::os::raw::c_uint = 16;
+pub const _IOC_DIRSHIFT: ::std::os::raw::c_uint = 30;
+pub const _IOC_NONE: ::std::os::raw::c_uint = 0;
+pub const _IOC_WRITE: ::std::os::raw::c_uint = 1;
+pub const _IOC_READ: ::std::os::raw::c_uint = 2;
+pub const IOC_IN: ::std::os::raw::c_uint = 1073741824;
+pub const IOC_OUT: ::std::os::raw::c_uint = 2147483648;
+pub const IOC_INOUT: ::std::os::raw::c_uint = 3221225472;
+pub const IOCSIZE_MASK: ::std::os::raw::c_uint = 1073676288;
+pub const IOCSIZE_SHIFT: ::std::os::raw::c_uint = 16;
+pub const VIRTIO_CONFIG_S_ACKNOWLEDGE: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_CONFIG_S_DRIVER: ::std::os::raw::c_uint = 2;
+pub const VIRTIO_CONFIG_S_DRIVER_OK: ::std::os::raw::c_uint = 4;
+pub const VIRTIO_CONFIG_S_FEATURES_OK: ::std::os::raw::c_uint = 8;
+pub const VIRTIO_CONFIG_S_FAILED: ::std::os::raw::c_uint = 128;
+pub const VIRTIO_TRANSPORT_F_START: ::std::os::raw::c_uint = 28;
+pub const VIRTIO_TRANSPORT_F_END: ::std::os::raw::c_uint = 33;
+pub const VIRTIO_F_NOTIFY_ON_EMPTY: ::std::os::raw::c_uint = 24;
+pub const VIRTIO_F_ANY_LAYOUT: ::std::os::raw::c_uint = 27;
+pub const VIRTIO_F_VERSION_1: ::std::os::raw::c_uint = 32;
+pub const _STDINT_H: ::std::os::raw::c_uint = 1;
+pub const _FEATURES_H: ::std::os::raw::c_uint = 1;
+pub const _DEFAULT_SOURCE: ::std::os::raw::c_uint = 1;
+pub const __USE_ISOC11: ::std::os::raw::c_uint = 1;
+pub const __USE_ISOC99: ::std::os::raw::c_uint = 1;
+pub const __USE_ISOC95: ::std::os::raw::c_uint = 1;
+pub const __USE_POSIX_IMPLICITLY: ::std::os::raw::c_uint = 1;
+pub const _POSIX_SOURCE: ::std::os::raw::c_uint = 1;
+pub const _POSIX_C_SOURCE: ::std::os::raw::c_uint = 200809;
+pub const __USE_POSIX: ::std::os::raw::c_uint = 1;
+pub const __USE_POSIX2: ::std::os::raw::c_uint = 1;
+pub const __USE_POSIX199309: ::std::os::raw::c_uint = 1;
+pub const __USE_POSIX199506: ::std::os::raw::c_uint = 1;
+pub const __USE_XOPEN2K: ::std::os::raw::c_uint = 1;
+pub const __USE_XOPEN2K8: ::std::os::raw::c_uint = 1;
+pub const _ATFILE_SOURCE: ::std::os::raw::c_uint = 1;
+pub const __USE_MISC: ::std::os::raw::c_uint = 1;
+pub const __USE_ATFILE: ::std::os::raw::c_uint = 1;
+pub const __USE_FORTIFY_LEVEL: ::std::os::raw::c_uint = 0;
+pub const _STDC_PREDEF_H: ::std::os::raw::c_uint = 1;
+pub const __STDC_IEC_559__: ::std::os::raw::c_uint = 1;
+pub const __STDC_IEC_559_COMPLEX__: ::std::os::raw::c_uint = 1;
+pub const __STDC_ISO_10646__: ::std::os::raw::c_uint = 201505;
+pub const __STDC_NO_THREADS__: ::std::os::raw::c_uint = 1;
+pub const __GNU_LIBRARY__: ::std::os::raw::c_uint = 6;
+pub const __GLIBC__: ::std::os::raw::c_uint = 2;
+pub const __GLIBC_MINOR__: ::std::os::raw::c_uint = 23;
+pub const _SYS_CDEFS_H: ::std::os::raw::c_uint = 1;
+pub const __WORDSIZE: ::std::os::raw::c_uint = 64;
+pub const __WORDSIZE_TIME64_COMPAT32: ::std::os::raw::c_uint = 1;
+pub const __SYSCALL_WORDSIZE: ::std::os::raw::c_uint = 64;
+pub const _BITS_WCHAR_H: ::std::os::raw::c_uint = 1;
+pub const INT8_MIN: ::std::os::raw::c_int = -128;
+pub const INT16_MIN: ::std::os::raw::c_int = -32768;
+pub const INT32_MIN: ::std::os::raw::c_int = -2147483648;
+pub const INT8_MAX: ::std::os::raw::c_uint = 127;
+pub const INT16_MAX: ::std::os::raw::c_uint = 32767;
+pub const INT32_MAX: ::std::os::raw::c_uint = 2147483647;
+pub const UINT8_MAX: ::std::os::raw::c_uint = 255;
+pub const UINT16_MAX: ::std::os::raw::c_uint = 65535;
+pub const UINT32_MAX: ::std::os::raw::c_uint = 4294967295;
+pub const INT_LEAST8_MIN: ::std::os::raw::c_int = -128;
+pub const INT_LEAST16_MIN: ::std::os::raw::c_int = -32768;
+pub const INT_LEAST32_MIN: ::std::os::raw::c_int = -2147483648;
+pub const INT_LEAST8_MAX: ::std::os::raw::c_uint = 127;
+pub const INT_LEAST16_MAX: ::std::os::raw::c_uint = 32767;
+pub const INT_LEAST32_MAX: ::std::os::raw::c_uint = 2147483647;
+pub const UINT_LEAST8_MAX: ::std::os::raw::c_uint = 255;
+pub const UINT_LEAST16_MAX: ::std::os::raw::c_uint = 65535;
+pub const UINT_LEAST32_MAX: ::std::os::raw::c_uint = 4294967295;
+pub const INT_FAST8_MIN: ::std::os::raw::c_int = -128;
+pub const INT_FAST16_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
+pub const INT_FAST32_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
+pub const INT_FAST8_MAX: ::std::os::raw::c_uint = 127;
+pub const INT_FAST16_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
+pub const INT_FAST32_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
+pub const UINT_FAST8_MAX: ::std::os::raw::c_uint = 255;
+pub const UINT_FAST16_MAX: ::std::os::raw::c_int = -1;
+pub const UINT_FAST32_MAX: ::std::os::raw::c_int = -1;
+pub const INTPTR_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
+pub const INTPTR_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
+pub const UINTPTR_MAX: ::std::os::raw::c_int = -1;
+pub const PTRDIFF_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
+pub const PTRDIFF_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
+pub const SIG_ATOMIC_MIN: ::std::os::raw::c_int = -2147483648;
+pub const SIG_ATOMIC_MAX: ::std::os::raw::c_uint = 2147483647;
+pub const SIZE_MAX: ::std::os::raw::c_int = -1;
+pub const WINT_MIN: ::std::os::raw::c_uint = 0;
+pub const WINT_MAX: ::std::os::raw::c_uint = 4294967295;
+pub const VRING_DESC_F_NEXT: ::std::os::raw::c_uint = 1;
+pub const VRING_DESC_F_WRITE: ::std::os::raw::c_uint = 2;
+pub const VRING_DESC_F_INDIRECT: ::std::os::raw::c_uint = 4;
+pub const VRING_USED_F_NO_NOTIFY: ::std::os::raw::c_uint = 1;
+pub const VRING_AVAIL_F_NO_INTERRUPT: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_RING_F_INDIRECT_DESC: ::std::os::raw::c_uint = 28;
+pub const VIRTIO_RING_F_EVENT_IDX: ::std::os::raw::c_uint = 29;
+pub const VRING_AVAIL_ALIGN_SIZE: ::std::os::raw::c_uint = 2;
+pub const VRING_USED_ALIGN_SIZE: ::std::os::raw::c_uint = 4;
+pub const VRING_DESC_ALIGN_SIZE: ::std::os::raw::c_uint = 16;
+pub const VHOST_VRING_F_LOG: ::std::os::raw::c_uint = 0;
+pub const VHOST_PAGE_SIZE: ::std::os::raw::c_uint = 4096;
+pub const VHOST_VIRTIO: ::std::os::raw::c_uint = 175;
+pub const VHOST_VRING_LITTLE_ENDIAN: ::std::os::raw::c_uint = 0;
+pub const VHOST_VRING_BIG_ENDIAN: ::std::os::raw::c_uint = 1;
+pub const VHOST_F_LOG_ALL: ::std::os::raw::c_uint = 26;
+pub const VHOST_NET_F_VIRTIO_NET_HDR: ::std::os::raw::c_uint = 27;
+pub const VHOST_SCSI_ABI_VERSION: ::std::os::raw::c_uint = 1;
+pub type __s8 = ::std::os::raw::c_schar;
+pub type __u8 = ::std::os::raw::c_uchar;
+pub type __s16 = ::std::os::raw::c_short;
+pub type __u16 = ::std::os::raw::c_ushort;
+pub type __s32 = ::std::os::raw::c_int;
+pub type __u32 = ::std::os::raw::c_uint;
+pub type __s64 = ::std::os::raw::c_longlong;
+pub type __u64 = ::std::os::raw::c_ulonglong;
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct __kernel_fd_set {
+    pub fds_bits: [::std::os::raw::c_ulong; 16usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fd_set() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fd_set>(),
+        128usize,
+        concat!("Size of: ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fd_set>(),
+        8usize,
+        concat!("Alignment of ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const __kernel_fd_set)).fds_bits as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(__kernel_fd_set),
+            "::",
+            stringify!(fds_bits)
+        )
+    );
+}
+impl Clone for __kernel_fd_set {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+pub type __kernel_sighandler_t =
+    ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
+pub type __kernel_key_t = ::std::os::raw::c_int;
+pub type __kernel_mqd_t = ::std::os::raw::c_int;
+pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
+pub type __kernel_long_t = ::std::os::raw::c_long;
+pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
+pub type __kernel_ino_t = __kernel_ulong_t;
+pub type __kernel_mode_t = ::std::os::raw::c_uint;
+pub type __kernel_pid_t = ::std::os::raw::c_int;
+pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
+pub type __kernel_uid_t = ::std::os::raw::c_uint;
+pub type __kernel_gid_t = ::std::os::raw::c_uint;
+pub type __kernel_suseconds_t = __kernel_long_t;
+pub type __kernel_daddr_t = ::std::os::raw::c_int;
+pub type __kernel_uid32_t = ::std::os::raw::c_uint;
+pub type __kernel_gid32_t = ::std::os::raw::c_uint;
+pub type __kernel_size_t = __kernel_ulong_t;
+pub type __kernel_ssize_t = __kernel_long_t;
+pub type __kernel_ptrdiff_t = __kernel_long_t;
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct __kernel_fsid_t {
+    pub val: [::std::os::raw::c_int; 2usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fsid_t() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fsid_t>(),
+        8usize,
+        concat!("Size of: ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fsid_t>(),
+        4usize,
+        concat!("Alignment of ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const __kernel_fsid_t)).val as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(__kernel_fsid_t),
+            "::",
+            stringify!(val)
+        )
+    );
+}
+impl Clone for __kernel_fsid_t {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+pub type __kernel_off_t = __kernel_long_t;
+pub type __kernel_loff_t = ::std::os::raw::c_longlong;
+pub type __kernel_time_t = __kernel_long_t;
+pub type __kernel_clock_t = __kernel_long_t;
+pub type __kernel_timer_t = ::std::os::raw::c_int;
+pub type __kernel_clockid_t = ::std::os::raw::c_int;
+pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
+pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
+pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
+pub type __le16 = __u16;
+pub type __be16 = __u16;
+pub type __le32 = __u32;
+pub type __be32 = __u32;
+pub type __le64 = __u64;
+pub type __be64 = __u64;
+pub type __sum16 = __u16;
+pub type __wsum = __u32;
+pub type int_least8_t = ::std::os::raw::c_schar;
+pub type int_least16_t = ::std::os::raw::c_short;
+pub type int_least32_t = ::std::os::raw::c_int;
+pub type int_least64_t = ::std::os::raw::c_long;
+pub type uint_least8_t = ::std::os::raw::c_uchar;
+pub type uint_least16_t = ::std::os::raw::c_ushort;
+pub type uint_least32_t = ::std::os::raw::c_uint;
+pub type uint_least64_t = ::std::os::raw::c_ulong;
+pub type int_fast8_t = ::std::os::raw::c_schar;
+pub type int_fast16_t = ::std::os::raw::c_long;
+pub type int_fast32_t = ::std::os::raw::c_long;
+pub type int_fast64_t = ::std::os::raw::c_long;
+pub type uint_fast8_t = ::std::os::raw::c_uchar;
+pub type uint_fast16_t = ::std::os::raw::c_ulong;
+pub type uint_fast32_t = ::std::os::raw::c_ulong;
+pub type uint_fast64_t = ::std::os::raw::c_ulong;
+pub type intmax_t = ::std::os::raw::c_long;
+pub type uintmax_t = ::std::os::raw::c_ulong;
+pub type __virtio16 = __u16;
+pub type __virtio32 = __u32;
+pub type __virtio64 = __u64;
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct vring_desc {
+    pub addr: __virtio64,
+    pub len: __virtio32,
+    pub flags: __virtio16,
+    pub next: __virtio16,
+}
+#[test]
+fn bindgen_test_layout_vring_desc() {
+    assert_eq!(
+        ::std::mem::size_of::<vring_desc>(),
+        16usize,
+        concat!("Size of: ", stringify!(vring_desc))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vring_desc>(),
+        8usize,
+        concat!("Alignment of ", stringify!(vring_desc))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring_desc)).addr as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring_desc),
+            "::",
+            stringify!(addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring_desc)).len as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring_desc),
+            "::",
+            stringify!(len)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring_desc)).flags as *const _ as usize },
+        12usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring_desc),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring_desc)).next as *const _ as usize },
+        14usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring_desc),
+            "::",
+            stringify!(next)
+        )
+    );
+}
+impl Clone for vring_desc {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct vring_avail {
+    pub flags: __virtio16,
+    pub idx: __virtio16,
+    pub ring: __IncompleteArrayField<__virtio16>,
+}
+#[test]
+fn bindgen_test_layout_vring_avail() {
+    assert_eq!(
+        ::std::mem::size_of::<vring_avail>(),
+        4usize,
+        concat!("Size of: ", stringify!(vring_avail))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vring_avail>(),
+        2usize,
+        concat!("Alignment of ", stringify!(vring_avail))
+    );
+}
+impl Clone for vring_avail {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct vring_used_elem {
+    pub id: __virtio32,
+    pub len: __virtio32,
+}
+#[test]
+fn bindgen_test_layout_vring_used_elem() {
+    assert_eq!(
+        ::std::mem::size_of::<vring_used_elem>(),
+        8usize,
+        concat!("Size of: ", stringify!(vring_used_elem))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vring_used_elem>(),
+        4usize,
+        concat!("Alignment of ", stringify!(vring_used_elem))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring_used_elem)).id as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring_used_elem),
+            "::",
+            stringify!(id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring_used_elem)).len as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring_used_elem),
+            "::",
+            stringify!(len)
+        )
+    );
+}
+impl Clone for vring_used_elem {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct vring_used {
+    pub flags: __virtio16,
+    pub idx: __virtio16,
+    pub ring: __IncompleteArrayField<vring_used_elem>,
+    pub __bindgen_align: [u32; 0usize],
+}
+#[test]
+fn bindgen_test_layout_vring_used() {
+    assert_eq!(
+        ::std::mem::size_of::<vring_used>(),
+        4usize,
+        concat!("Size of: ", stringify!(vring_used))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vring_used>(),
+        4usize,
+        concat!("Alignment of ", stringify!(vring_used))
+    );
+}
+impl Clone for vring_used {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct vring {
+    pub num: ::std::os::raw::c_uint,
+    pub desc: *mut vring_desc,
+    pub avail: *mut vring_avail,
+    pub used: *mut vring_used,
+}
+#[test]
+fn bindgen_test_layout_vring() {
+    assert_eq!(
+        ::std::mem::size_of::<vring>(),
+        32usize,
+        concat!("Size of: ", stringify!(vring))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vring>(),
+        8usize,
+        concat!("Alignment of ", stringify!(vring))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring)).num as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring),
+            "::",
+            stringify!(num)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring)).desc as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring),
+            "::",
+            stringify!(desc)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring)).avail as *const _ as usize },
+        16usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring),
+            "::",
+            stringify!(avail)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring)).used as *const _ as usize },
+        24usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring),
+            "::",
+            stringify!(used)
+        )
+    );
+}
+impl Clone for vring {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+impl Default for vring {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct vhost_vring_state {
+    pub index: ::std::os::raw::c_uint,
+    pub num: ::std::os::raw::c_uint,
+}
+#[test]
+fn bindgen_test_layout_vhost_vring_state() {
+    assert_eq!(
+        ::std::mem::size_of::<vhost_vring_state>(),
+        8usize,
+        concat!("Size of: ", stringify!(vhost_vring_state))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vhost_vring_state>(),
+        4usize,
+        concat!("Alignment of ", stringify!(vhost_vring_state))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_vring_state)).index as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_vring_state),
+            "::",
+            stringify!(index)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_vring_state)).num as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_vring_state),
+            "::",
+            stringify!(num)
+        )
+    );
+}
+impl Clone for vhost_vring_state {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct vhost_vring_file {
+    pub index: ::std::os::raw::c_uint,
+    pub fd: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_vhost_vring_file() {
+    assert_eq!(
+        ::std::mem::size_of::<vhost_vring_file>(),
+        8usize,
+        concat!("Size of: ", stringify!(vhost_vring_file))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vhost_vring_file>(),
+        4usize,
+        concat!("Alignment of ", stringify!(vhost_vring_file))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_vring_file)).index as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_vring_file),
+            "::",
+            stringify!(index)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_vring_file)).fd as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_vring_file),
+            "::",
+            stringify!(fd)
+        )
+    );
+}
+impl Clone for vhost_vring_file {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct vhost_vring_addr {
+    pub index: ::std::os::raw::c_uint,
+    pub flags: ::std::os::raw::c_uint,
+    pub desc_user_addr: __u64,
+    pub used_user_addr: __u64,
+    pub avail_user_addr: __u64,
+    pub log_guest_addr: __u64,
+}
+#[test]
+fn bindgen_test_layout_vhost_vring_addr() {
+    assert_eq!(
+        ::std::mem::size_of::<vhost_vring_addr>(),
+        40usize,
+        concat!("Size of: ", stringify!(vhost_vring_addr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vhost_vring_addr>(),
+        8usize,
+        concat!("Alignment of ", stringify!(vhost_vring_addr))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_vring_addr)).index as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_vring_addr),
+            "::",
+            stringify!(index)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_vring_addr)).flags as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_vring_addr),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_vring_addr)).desc_user_addr as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_vring_addr),
+            "::",
+            stringify!(desc_user_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_vring_addr)).used_user_addr as *const _ as usize },
+        16usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_vring_addr),
+            "::",
+            stringify!(used_user_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_vring_addr)).avail_user_addr as *const _ as usize },
+        24usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_vring_addr),
+            "::",
+            stringify!(avail_user_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_vring_addr)).log_guest_addr as *const _ as usize },
+        32usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_vring_addr),
+            "::",
+            stringify!(log_guest_addr)
+        )
+    );
+}
+impl Clone for vhost_vring_addr {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct vhost_memory_region {
+    pub guest_phys_addr: __u64,
+    pub memory_size: __u64,
+    pub userspace_addr: __u64,
+    pub flags_padding: __u64,
+}
+#[test]
+fn bindgen_test_layout_vhost_memory_region() {
+    assert_eq!(
+        ::std::mem::size_of::<vhost_memory_region>(),
+        32usize,
+        concat!("Size of: ", stringify!(vhost_memory_region))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vhost_memory_region>(),
+        8usize,
+        concat!("Alignment of ", stringify!(vhost_memory_region))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_memory_region)).guest_phys_addr as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_memory_region),
+            "::",
+            stringify!(guest_phys_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_memory_region)).memory_size as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_memory_region),
+            "::",
+            stringify!(memory_size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_memory_region)).userspace_addr as *const _ as usize },
+        16usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_memory_region),
+            "::",
+            stringify!(userspace_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_memory_region)).flags_padding as *const _ as usize },
+        24usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_memory_region),
+            "::",
+            stringify!(flags_padding)
+        )
+    );
+}
+impl Clone for vhost_memory_region {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct vhost_memory {
+    pub nregions: __u32,
+    pub padding: __u32,
+    pub regions: __IncompleteArrayField<vhost_memory_region>,
+    pub __force_alignment: [u64; 0],
+}
+#[test]
+fn bindgen_test_layout_vhost_memory() {
+    assert_eq!(
+        ::std::mem::size_of::<vhost_memory>(),
+        8usize,
+        concat!("Size of: ", stringify!(vhost_memory))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vhost_memory>(),
+        8usize,
+        concat!("Alignment of ", stringify!(vhost_memory))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_memory)).nregions as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_memory),
+            "::",
+            stringify!(nregions)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_memory)).padding as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_memory),
+            "::",
+            stringify!(padding)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_memory)).regions as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_memory),
+            "::",
+            stringify!(regions)
+        )
+    );
+}
+impl Clone for vhost_memory {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+pub struct vhost_scsi_target {
+    pub abi_version: ::std::os::raw::c_int,
+    pub vhost_wwpn: [::std::os::raw::c_char; 224usize],
+    pub vhost_tpgt: ::std::os::raw::c_ushort,
+    pub reserved: ::std::os::raw::c_ushort,
+}
+#[test]
+fn bindgen_test_layout_vhost_scsi_target() {
+    assert_eq!(
+        ::std::mem::size_of::<vhost_scsi_target>(),
+        232usize,
+        concat!("Size of: ", stringify!(vhost_scsi_target))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vhost_scsi_target>(),
+        4usize,
+        concat!("Alignment of ", stringify!(vhost_scsi_target))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_scsi_target)).abi_version as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_scsi_target),
+            "::",
+            stringify!(abi_version)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_scsi_target)).vhost_wwpn as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_scsi_target),
+            "::",
+            stringify!(vhost_wwpn)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_scsi_target)).vhost_tpgt as *const _ as usize },
+        228usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_scsi_target),
+            "::",
+            stringify!(vhost_tpgt)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vhost_scsi_target)).reserved as *const _ as usize },
+        230usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vhost_scsi_target),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+impl Default for vhost_scsi_target {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
diff --git a/virtio_sys/src/virtio_net.rs b/virtio_sys/src/virtio_net.rs
new file mode 100644
index 0000000..5cb370e
--- /dev/null
+++ b/virtio_sys/src/virtio_net.rs
@@ -0,0 +1,779 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+#[repr(C)]
+#[derive(Default)]
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
+impl<T> __IncompleteArrayField<T> {
+    #[inline]
+    pub fn new() -> Self {
+        __IncompleteArrayField(::std::marker::PhantomData)
+    }
+    #[inline]
+    pub unsafe fn as_ptr(&self) -> *const T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_slice(&self, len: usize) -> &[T] {
+        ::std::slice::from_raw_parts(self.as_ptr(), len)
+    }
+    #[inline]
+    pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
+        ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
+    }
+}
+impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        fmt.write_str("__IncompleteArrayField")
+    }
+}
+impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self::new()
+    }
+}
+impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
+pub const __BITS_PER_LONG: ::std::os::raw::c_uint = 64;
+pub const __FD_SETSIZE: ::std::os::raw::c_uint = 1024;
+pub const VIRTIO_ID_NET: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_ID_BLOCK: ::std::os::raw::c_uint = 2;
+pub const VIRTIO_ID_CONSOLE: ::std::os::raw::c_uint = 3;
+pub const VIRTIO_ID_RNG: ::std::os::raw::c_uint = 4;
+pub const VIRTIO_ID_BALLOON: ::std::os::raw::c_uint = 5;
+pub const VIRTIO_ID_RPMSG: ::std::os::raw::c_uint = 7;
+pub const VIRTIO_ID_SCSI: ::std::os::raw::c_uint = 8;
+pub const VIRTIO_ID_9P: ::std::os::raw::c_uint = 9;
+pub const VIRTIO_ID_RPROC_SERIAL: ::std::os::raw::c_uint = 11;
+pub const VIRTIO_ID_CAIF: ::std::os::raw::c_uint = 12;
+pub const VIRTIO_ID_GPU: ::std::os::raw::c_uint = 16;
+pub const VIRTIO_ID_INPUT: ::std::os::raw::c_uint = 18;
+pub const VIRTIO_CONFIG_S_ACKNOWLEDGE: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_CONFIG_S_DRIVER: ::std::os::raw::c_uint = 2;
+pub const VIRTIO_CONFIG_S_DRIVER_OK: ::std::os::raw::c_uint = 4;
+pub const VIRTIO_CONFIG_S_FEATURES_OK: ::std::os::raw::c_uint = 8;
+pub const VIRTIO_CONFIG_S_FAILED: ::std::os::raw::c_uint = 128;
+pub const VIRTIO_TRANSPORT_F_START: ::std::os::raw::c_uint = 28;
+pub const VIRTIO_TRANSPORT_F_END: ::std::os::raw::c_uint = 33;
+pub const VIRTIO_F_NOTIFY_ON_EMPTY: ::std::os::raw::c_uint = 24;
+pub const VIRTIO_F_ANY_LAYOUT: ::std::os::raw::c_uint = 27;
+pub const VIRTIO_F_VERSION_1: ::std::os::raw::c_uint = 32;
+pub const ETH_ALEN: ::std::os::raw::c_uint = 6;
+pub const ETH_HLEN: ::std::os::raw::c_uint = 14;
+pub const ETH_ZLEN: ::std::os::raw::c_uint = 60;
+pub const ETH_DATA_LEN: ::std::os::raw::c_uint = 1500;
+pub const ETH_FRAME_LEN: ::std::os::raw::c_uint = 1514;
+pub const ETH_FCS_LEN: ::std::os::raw::c_uint = 4;
+pub const ETH_P_LOOP: ::std::os::raw::c_uint = 96;
+pub const ETH_P_PUP: ::std::os::raw::c_uint = 512;
+pub const ETH_P_PUPAT: ::std::os::raw::c_uint = 513;
+pub const ETH_P_TSN: ::std::os::raw::c_uint = 8944;
+pub const ETH_P_IP: ::std::os::raw::c_uint = 2048;
+pub const ETH_P_X25: ::std::os::raw::c_uint = 2053;
+pub const ETH_P_ARP: ::std::os::raw::c_uint = 2054;
+pub const ETH_P_BPQ: ::std::os::raw::c_uint = 2303;
+pub const ETH_P_IEEEPUP: ::std::os::raw::c_uint = 2560;
+pub const ETH_P_IEEEPUPAT: ::std::os::raw::c_uint = 2561;
+pub const ETH_P_BATMAN: ::std::os::raw::c_uint = 17157;
+pub const ETH_P_DEC: ::std::os::raw::c_uint = 24576;
+pub const ETH_P_DNA_DL: ::std::os::raw::c_uint = 24577;
+pub const ETH_P_DNA_RC: ::std::os::raw::c_uint = 24578;
+pub const ETH_P_DNA_RT: ::std::os::raw::c_uint = 24579;
+pub const ETH_P_LAT: ::std::os::raw::c_uint = 24580;
+pub const ETH_P_DIAG: ::std::os::raw::c_uint = 24581;
+pub const ETH_P_CUST: ::std::os::raw::c_uint = 24582;
+pub const ETH_P_SCA: ::std::os::raw::c_uint = 24583;
+pub const ETH_P_TEB: ::std::os::raw::c_uint = 25944;
+pub const ETH_P_RARP: ::std::os::raw::c_uint = 32821;
+pub const ETH_P_ATALK: ::std::os::raw::c_uint = 32923;
+pub const ETH_P_AARP: ::std::os::raw::c_uint = 33011;
+pub const ETH_P_8021Q: ::std::os::raw::c_uint = 33024;
+pub const ETH_P_IPX: ::std::os::raw::c_uint = 33079;
+pub const ETH_P_IPV6: ::std::os::raw::c_uint = 34525;
+pub const ETH_P_PAUSE: ::std::os::raw::c_uint = 34824;
+pub const ETH_P_SLOW: ::std::os::raw::c_uint = 34825;
+pub const ETH_P_WCCP: ::std::os::raw::c_uint = 34878;
+pub const ETH_P_MPLS_UC: ::std::os::raw::c_uint = 34887;
+pub const ETH_P_MPLS_MC: ::std::os::raw::c_uint = 34888;
+pub const ETH_P_ATMMPOA: ::std::os::raw::c_uint = 34892;
+pub const ETH_P_PPP_DISC: ::std::os::raw::c_uint = 34915;
+pub const ETH_P_PPP_SES: ::std::os::raw::c_uint = 34916;
+pub const ETH_P_LINK_CTL: ::std::os::raw::c_uint = 34924;
+pub const ETH_P_ATMFATE: ::std::os::raw::c_uint = 34948;
+pub const ETH_P_PAE: ::std::os::raw::c_uint = 34958;
+pub const ETH_P_AOE: ::std::os::raw::c_uint = 34978;
+pub const ETH_P_8021AD: ::std::os::raw::c_uint = 34984;
+pub const ETH_P_802_EX1: ::std::os::raw::c_uint = 34997;
+pub const ETH_P_TIPC: ::std::os::raw::c_uint = 35018;
+pub const ETH_P_8021AH: ::std::os::raw::c_uint = 35047;
+pub const ETH_P_MVRP: ::std::os::raw::c_uint = 35061;
+pub const ETH_P_1588: ::std::os::raw::c_uint = 35063;
+pub const ETH_P_PRP: ::std::os::raw::c_uint = 35067;
+pub const ETH_P_FCOE: ::std::os::raw::c_uint = 35078;
+pub const ETH_P_TDLS: ::std::os::raw::c_uint = 35085;
+pub const ETH_P_FIP: ::std::os::raw::c_uint = 35092;
+pub const ETH_P_80221: ::std::os::raw::c_uint = 35095;
+pub const ETH_P_LOOPBACK: ::std::os::raw::c_uint = 36864;
+pub const ETH_P_QINQ1: ::std::os::raw::c_uint = 37120;
+pub const ETH_P_QINQ2: ::std::os::raw::c_uint = 37376;
+pub const ETH_P_QINQ3: ::std::os::raw::c_uint = 37632;
+pub const ETH_P_EDSA: ::std::os::raw::c_uint = 56026;
+pub const ETH_P_AF_IUCV: ::std::os::raw::c_uint = 64507;
+pub const ETH_P_802_3_MIN: ::std::os::raw::c_uint = 1536;
+pub const ETH_P_802_3: ::std::os::raw::c_uint = 1;
+pub const ETH_P_AX25: ::std::os::raw::c_uint = 2;
+pub const ETH_P_ALL: ::std::os::raw::c_uint = 3;
+pub const ETH_P_802_2: ::std::os::raw::c_uint = 4;
+pub const ETH_P_SNAP: ::std::os::raw::c_uint = 5;
+pub const ETH_P_DDCMP: ::std::os::raw::c_uint = 6;
+pub const ETH_P_WAN_PPP: ::std::os::raw::c_uint = 7;
+pub const ETH_P_PPP_MP: ::std::os::raw::c_uint = 8;
+pub const ETH_P_LOCALTALK: ::std::os::raw::c_uint = 9;
+pub const ETH_P_CAN: ::std::os::raw::c_uint = 12;
+pub const ETH_P_CANFD: ::std::os::raw::c_uint = 13;
+pub const ETH_P_PPPTALK: ::std::os::raw::c_uint = 16;
+pub const ETH_P_TR_802_2: ::std::os::raw::c_uint = 17;
+pub const ETH_P_MOBITEX: ::std::os::raw::c_uint = 21;
+pub const ETH_P_CONTROL: ::std::os::raw::c_uint = 22;
+pub const ETH_P_IRDA: ::std::os::raw::c_uint = 23;
+pub const ETH_P_ECONET: ::std::os::raw::c_uint = 24;
+pub const ETH_P_HDLC: ::std::os::raw::c_uint = 25;
+pub const ETH_P_ARCNET: ::std::os::raw::c_uint = 26;
+pub const ETH_P_DSA: ::std::os::raw::c_uint = 27;
+pub const ETH_P_TRAILER: ::std::os::raw::c_uint = 28;
+pub const ETH_P_PHONET: ::std::os::raw::c_uint = 245;
+pub const ETH_P_IEEE802154: ::std::os::raw::c_uint = 246;
+pub const ETH_P_CAIF: ::std::os::raw::c_uint = 247;
+pub const ETH_P_XDSA: ::std::os::raw::c_uint = 248;
+pub const VIRTIO_NET_F_CSUM: ::std::os::raw::c_uint = 0;
+pub const VIRTIO_NET_F_GUEST_CSUM: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_NET_F_CTRL_GUEST_OFFLOADS: ::std::os::raw::c_uint = 2;
+pub const VIRTIO_NET_F_MTU: ::std::os::raw::c_uint = 3;
+pub const VIRTIO_NET_F_MAC: ::std::os::raw::c_uint = 5;
+pub const VIRTIO_NET_F_GUEST_TSO4: ::std::os::raw::c_uint = 7;
+pub const VIRTIO_NET_F_GUEST_TSO6: ::std::os::raw::c_uint = 8;
+pub const VIRTIO_NET_F_GUEST_ECN: ::std::os::raw::c_uint = 9;
+pub const VIRTIO_NET_F_GUEST_UFO: ::std::os::raw::c_uint = 10;
+pub const VIRTIO_NET_F_HOST_TSO4: ::std::os::raw::c_uint = 11;
+pub const VIRTIO_NET_F_HOST_TSO6: ::std::os::raw::c_uint = 12;
+pub const VIRTIO_NET_F_HOST_ECN: ::std::os::raw::c_uint = 13;
+pub const VIRTIO_NET_F_HOST_UFO: ::std::os::raw::c_uint = 14;
+pub const VIRTIO_NET_F_MRG_RXBUF: ::std::os::raw::c_uint = 15;
+pub const VIRTIO_NET_F_STATUS: ::std::os::raw::c_uint = 16;
+pub const VIRTIO_NET_F_CTRL_VQ: ::std::os::raw::c_uint = 17;
+pub const VIRTIO_NET_F_CTRL_RX: ::std::os::raw::c_uint = 18;
+pub const VIRTIO_NET_F_CTRL_VLAN: ::std::os::raw::c_uint = 19;
+pub const VIRTIO_NET_F_CTRL_RX_EXTRA: ::std::os::raw::c_uint = 20;
+pub const VIRTIO_NET_F_GUEST_ANNOUNCE: ::std::os::raw::c_uint = 21;
+pub const VIRTIO_NET_F_MQ: ::std::os::raw::c_uint = 22;
+pub const VIRTIO_NET_F_CTRL_MAC_ADDR: ::std::os::raw::c_uint = 23;
+pub const VIRTIO_NET_F_GSO: ::std::os::raw::c_uint = 6;
+pub const VIRTIO_NET_S_LINK_UP: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_NET_S_ANNOUNCE: ::std::os::raw::c_uint = 2;
+pub const VIRTIO_NET_HDR_F_NEEDS_CSUM: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_NET_HDR_F_DATA_VALID: ::std::os::raw::c_uint = 2;
+pub const VIRTIO_NET_HDR_GSO_NONE: ::std::os::raw::c_uint = 0;
+pub const VIRTIO_NET_HDR_GSO_TCPV4: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_NET_HDR_GSO_UDP: ::std::os::raw::c_uint = 3;
+pub const VIRTIO_NET_HDR_GSO_TCPV6: ::std::os::raw::c_uint = 4;
+pub const VIRTIO_NET_HDR_GSO_ECN: ::std::os::raw::c_uint = 128;
+pub const VIRTIO_NET_OK: ::std::os::raw::c_uint = 0;
+pub const VIRTIO_NET_ERR: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_NET_CTRL_RX: ::std::os::raw::c_uint = 0;
+pub const VIRTIO_NET_CTRL_RX_PROMISC: ::std::os::raw::c_uint = 0;
+pub const VIRTIO_NET_CTRL_RX_ALLMULTI: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_NET_CTRL_RX_ALLUNI: ::std::os::raw::c_uint = 2;
+pub const VIRTIO_NET_CTRL_RX_NOMULTI: ::std::os::raw::c_uint = 3;
+pub const VIRTIO_NET_CTRL_RX_NOUNI: ::std::os::raw::c_uint = 4;
+pub const VIRTIO_NET_CTRL_RX_NOBCAST: ::std::os::raw::c_uint = 5;
+pub const VIRTIO_NET_CTRL_MAC: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_NET_CTRL_MAC_TABLE_SET: ::std::os::raw::c_uint = 0;
+pub const VIRTIO_NET_CTRL_MAC_ADDR_SET: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_NET_CTRL_VLAN: ::std::os::raw::c_uint = 2;
+pub const VIRTIO_NET_CTRL_VLAN_ADD: ::std::os::raw::c_uint = 0;
+pub const VIRTIO_NET_CTRL_VLAN_DEL: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_NET_CTRL_ANNOUNCE: ::std::os::raw::c_uint = 3;
+pub const VIRTIO_NET_CTRL_ANNOUNCE_ACK: ::std::os::raw::c_uint = 0;
+pub const VIRTIO_NET_CTRL_MQ: ::std::os::raw::c_uint = 4;
+pub const VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET: ::std::os::raw::c_uint = 0;
+pub const VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX: ::std::os::raw::c_uint = 32768;
+pub const VIRTIO_NET_CTRL_GUEST_OFFLOADS: ::std::os::raw::c_uint = 5;
+pub const VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET: ::std::os::raw::c_uint = 0;
+pub type __s8 = ::std::os::raw::c_schar;
+pub type __u8 = ::std::os::raw::c_uchar;
+pub type __s16 = ::std::os::raw::c_short;
+pub type __u16 = ::std::os::raw::c_ushort;
+pub type __s32 = ::std::os::raw::c_int;
+pub type __u32 = ::std::os::raw::c_uint;
+pub type __s64 = ::std::os::raw::c_longlong;
+pub type __u64 = ::std::os::raw::c_ulonglong;
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct __kernel_fd_set {
+    pub fds_bits: [::std::os::raw::c_ulong; 16usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fd_set() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fd_set>(),
+        128usize,
+        concat!("Size of: ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fd_set>(),
+        8usize,
+        concat!("Alignment of ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const __kernel_fd_set)).fds_bits as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(__kernel_fd_set),
+            "::",
+            stringify!(fds_bits)
+        )
+    );
+}
+impl Clone for __kernel_fd_set {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+pub type __kernel_sighandler_t =
+    ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
+pub type __kernel_key_t = ::std::os::raw::c_int;
+pub type __kernel_mqd_t = ::std::os::raw::c_int;
+pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
+pub type __kernel_long_t = ::std::os::raw::c_long;
+pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
+pub type __kernel_ino_t = __kernel_ulong_t;
+pub type __kernel_mode_t = ::std::os::raw::c_uint;
+pub type __kernel_pid_t = ::std::os::raw::c_int;
+pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
+pub type __kernel_uid_t = ::std::os::raw::c_uint;
+pub type __kernel_gid_t = ::std::os::raw::c_uint;
+pub type __kernel_suseconds_t = __kernel_long_t;
+pub type __kernel_daddr_t = ::std::os::raw::c_int;
+pub type __kernel_uid32_t = ::std::os::raw::c_uint;
+pub type __kernel_gid32_t = ::std::os::raw::c_uint;
+pub type __kernel_size_t = __kernel_ulong_t;
+pub type __kernel_ssize_t = __kernel_long_t;
+pub type __kernel_ptrdiff_t = __kernel_long_t;
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct __kernel_fsid_t {
+    pub val: [::std::os::raw::c_int; 2usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fsid_t() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fsid_t>(),
+        8usize,
+        concat!("Size of: ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fsid_t>(),
+        4usize,
+        concat!("Alignment of ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const __kernel_fsid_t)).val as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(__kernel_fsid_t),
+            "::",
+            stringify!(val)
+        )
+    );
+}
+impl Clone for __kernel_fsid_t {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+pub type __kernel_off_t = __kernel_long_t;
+pub type __kernel_loff_t = ::std::os::raw::c_longlong;
+pub type __kernel_time_t = __kernel_long_t;
+pub type __kernel_clock_t = __kernel_long_t;
+pub type __kernel_timer_t = ::std::os::raw::c_int;
+pub type __kernel_clockid_t = ::std::os::raw::c_int;
+pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
+pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
+pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
+pub type __le16 = __u16;
+pub type __be16 = __u16;
+pub type __le32 = __u32;
+pub type __be32 = __u32;
+pub type __le64 = __u64;
+pub type __be64 = __u64;
+pub type __sum16 = __u16;
+pub type __wsum = __u32;
+pub type __virtio16 = __u16;
+pub type __virtio32 = __u32;
+pub type __virtio64 = __u64;
+#[repr(C, packed)]
+#[derive(Debug, Copy)]
+pub struct ethhdr {
+    pub h_dest: [::std::os::raw::c_uchar; 6usize],
+    pub h_source: [::std::os::raw::c_uchar; 6usize],
+    pub h_proto: __be16,
+}
+#[test]
+fn bindgen_test_layout_ethhdr() {
+    assert_eq!(
+        ::std::mem::size_of::<ethhdr>(),
+        14usize,
+        concat!("Size of: ", stringify!(ethhdr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<ethhdr>(),
+        1usize,
+        concat!("Alignment of ", stringify!(ethhdr))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ethhdr)).h_dest as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ethhdr),
+            "::",
+            stringify!(h_dest)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ethhdr)).h_source as *const _ as usize },
+        6usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ethhdr),
+            "::",
+            stringify!(h_source)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const ethhdr)).h_proto as *const _ as usize },
+        12usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(ethhdr),
+            "::",
+            stringify!(h_proto)
+        )
+    );
+}
+impl Clone for ethhdr {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C, packed)]
+#[derive(Debug, Copy)]
+pub struct virtio_net_config {
+    pub mac: [__u8; 6usize],
+    pub status: __u16,
+    pub max_virtqueue_pairs: __u16,
+    pub mtu: __u16,
+}
+#[test]
+fn bindgen_test_layout_virtio_net_config() {
+    assert_eq!(
+        ::std::mem::size_of::<virtio_net_config>(),
+        12usize,
+        concat!("Size of: ", stringify!(virtio_net_config))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<virtio_net_config>(),
+        1usize,
+        concat!("Alignment of ", stringify!(virtio_net_config))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_config)).mac as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_config),
+            "::",
+            stringify!(mac)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_config)).status as *const _ as usize },
+        6usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_config),
+            "::",
+            stringify!(status)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_config)).max_virtqueue_pairs as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_config),
+            "::",
+            stringify!(max_virtqueue_pairs)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_config)).mtu as *const _ as usize },
+        10usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_config),
+            "::",
+            stringify!(mtu)
+        )
+    );
+}
+impl Clone for virtio_net_config {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct virtio_net_hdr_v1 {
+    pub flags: __u8,
+    pub gso_type: __u8,
+    pub hdr_len: __virtio16,
+    pub gso_size: __virtio16,
+    pub csum_start: __virtio16,
+    pub csum_offset: __virtio16,
+    pub num_buffers: __virtio16,
+}
+#[test]
+fn bindgen_test_layout_virtio_net_hdr_v1() {
+    assert_eq!(
+        ::std::mem::size_of::<virtio_net_hdr_v1>(),
+        12usize,
+        concat!("Size of: ", stringify!(virtio_net_hdr_v1))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<virtio_net_hdr_v1>(),
+        2usize,
+        concat!("Alignment of ", stringify!(virtio_net_hdr_v1))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr_v1)).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr_v1),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr_v1)).gso_type as *const _ as usize },
+        1usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr_v1),
+            "::",
+            stringify!(gso_type)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr_v1)).hdr_len as *const _ as usize },
+        2usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr_v1),
+            "::",
+            stringify!(hdr_len)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr_v1)).gso_size as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr_v1),
+            "::",
+            stringify!(gso_size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr_v1)).csum_start as *const _ as usize },
+        6usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr_v1),
+            "::",
+            stringify!(csum_start)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr_v1)).csum_offset as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr_v1),
+            "::",
+            stringify!(csum_offset)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr_v1)).num_buffers as *const _ as usize },
+        10usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr_v1),
+            "::",
+            stringify!(num_buffers)
+        )
+    );
+}
+impl Clone for virtio_net_hdr_v1 {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct virtio_net_hdr {
+    pub flags: __u8,
+    pub gso_type: __u8,
+    pub hdr_len: __virtio16,
+    pub gso_size: __virtio16,
+    pub csum_start: __virtio16,
+    pub csum_offset: __virtio16,
+}
+#[test]
+fn bindgen_test_layout_virtio_net_hdr() {
+    assert_eq!(
+        ::std::mem::size_of::<virtio_net_hdr>(),
+        10usize,
+        concat!("Size of: ", stringify!(virtio_net_hdr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<virtio_net_hdr>(),
+        2usize,
+        concat!("Alignment of ", stringify!(virtio_net_hdr))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr)).flags as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr)).gso_type as *const _ as usize },
+        1usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr),
+            "::",
+            stringify!(gso_type)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr)).hdr_len as *const _ as usize },
+        2usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr),
+            "::",
+            stringify!(hdr_len)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr)).gso_size as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr),
+            "::",
+            stringify!(gso_size)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr)).csum_start as *const _ as usize },
+        6usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr),
+            "::",
+            stringify!(csum_start)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr)).csum_offset as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr),
+            "::",
+            stringify!(csum_offset)
+        )
+    );
+}
+impl Clone for virtio_net_hdr {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct virtio_net_hdr_mrg_rxbuf {
+    pub hdr: virtio_net_hdr,
+    pub num_buffers: __virtio16,
+}
+#[test]
+fn bindgen_test_layout_virtio_net_hdr_mrg_rxbuf() {
+    assert_eq!(
+        ::std::mem::size_of::<virtio_net_hdr_mrg_rxbuf>(),
+        12usize,
+        concat!("Size of: ", stringify!(virtio_net_hdr_mrg_rxbuf))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<virtio_net_hdr_mrg_rxbuf>(),
+        2usize,
+        concat!("Alignment of ", stringify!(virtio_net_hdr_mrg_rxbuf))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr_mrg_rxbuf)).hdr as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr_mrg_rxbuf),
+            "::",
+            stringify!(hdr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_hdr_mrg_rxbuf)).num_buffers as *const _ as usize },
+        10usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_hdr_mrg_rxbuf),
+            "::",
+            stringify!(num_buffers)
+        )
+    );
+}
+impl Clone for virtio_net_hdr_mrg_rxbuf {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C, packed)]
+#[derive(Debug, Copy)]
+pub struct virtio_net_ctrl_hdr {
+    pub class: __u8,
+    pub cmd: __u8,
+}
+#[test]
+fn bindgen_test_layout_virtio_net_ctrl_hdr() {
+    assert_eq!(
+        ::std::mem::size_of::<virtio_net_ctrl_hdr>(),
+        2usize,
+        concat!("Size of: ", stringify!(virtio_net_ctrl_hdr))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<virtio_net_ctrl_hdr>(),
+        1usize,
+        concat!("Alignment of ", stringify!(virtio_net_ctrl_hdr))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_ctrl_hdr)).class as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_ctrl_hdr),
+            "::",
+            stringify!(class)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_ctrl_hdr)).cmd as *const _ as usize },
+        1usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_ctrl_hdr),
+            "::",
+            stringify!(cmd)
+        )
+    );
+}
+impl Clone for virtio_net_ctrl_hdr {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+pub type virtio_net_ctrl_ack = __u8;
+#[repr(C, packed)]
+#[derive(Debug, Copy)]
+pub struct virtio_net_ctrl_mac {
+    pub entries: __virtio32,
+    pub macs: __IncompleteArrayField<[__u8; 6usize]>,
+}
+#[test]
+fn bindgen_test_layout_virtio_net_ctrl_mac() {
+    assert_eq!(
+        ::std::mem::size_of::<virtio_net_ctrl_mac>(),
+        4usize,
+        concat!("Size of: ", stringify!(virtio_net_ctrl_mac))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<virtio_net_ctrl_mac>(),
+        1usize,
+        concat!("Alignment of ", stringify!(virtio_net_ctrl_mac))
+    );
+}
+impl Clone for virtio_net_ctrl_mac {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct virtio_net_ctrl_mq {
+    pub virtqueue_pairs: __virtio16,
+}
+#[test]
+fn bindgen_test_layout_virtio_net_ctrl_mq() {
+    assert_eq!(
+        ::std::mem::size_of::<virtio_net_ctrl_mq>(),
+        2usize,
+        concat!("Size of: ", stringify!(virtio_net_ctrl_mq))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<virtio_net_ctrl_mq>(),
+        2usize,
+        concat!("Alignment of ", stringify!(virtio_net_ctrl_mq))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const virtio_net_ctrl_mq)).virtqueue_pairs as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(virtio_net_ctrl_mq),
+            "::",
+            stringify!(virtqueue_pairs)
+        )
+    );
+}
+impl Clone for virtio_net_ctrl_mq {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
diff --git a/virtio_sys/src/virtio_ring.rs b/virtio_sys/src/virtio_ring.rs
new file mode 100644
index 0000000..c862851
--- /dev/null
+++ b/virtio_sys/src/virtio_ring.rs
@@ -0,0 +1,485 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+#[repr(C)]
+#[derive(Default)]
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
+impl<T> __IncompleteArrayField<T> {
+    #[inline]
+    pub fn new() -> Self {
+        __IncompleteArrayField(::std::marker::PhantomData)
+    }
+    #[inline]
+    pub unsafe fn as_ptr(&self) -> *const T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_slice(&self, len: usize) -> &[T] {
+        ::std::slice::from_raw_parts(self.as_ptr(), len)
+    }
+    #[inline]
+    pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
+        ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
+    }
+}
+impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        fmt.write_str("__IncompleteArrayField")
+    }
+}
+impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self::new()
+    }
+}
+impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
+pub const _STDINT_H: ::std::os::raw::c_uint = 1;
+pub const _FEATURES_H: ::std::os::raw::c_uint = 1;
+pub const _DEFAULT_SOURCE: ::std::os::raw::c_uint = 1;
+pub const __USE_ISOC11: ::std::os::raw::c_uint = 1;
+pub const __USE_ISOC99: ::std::os::raw::c_uint = 1;
+pub const __USE_ISOC95: ::std::os::raw::c_uint = 1;
+pub const __USE_POSIX_IMPLICITLY: ::std::os::raw::c_uint = 1;
+pub const _POSIX_SOURCE: ::std::os::raw::c_uint = 1;
+pub const _POSIX_C_SOURCE: ::std::os::raw::c_uint = 200809;
+pub const __USE_POSIX: ::std::os::raw::c_uint = 1;
+pub const __USE_POSIX2: ::std::os::raw::c_uint = 1;
+pub const __USE_POSIX199309: ::std::os::raw::c_uint = 1;
+pub const __USE_POSIX199506: ::std::os::raw::c_uint = 1;
+pub const __USE_XOPEN2K: ::std::os::raw::c_uint = 1;
+pub const __USE_XOPEN2K8: ::std::os::raw::c_uint = 1;
+pub const _ATFILE_SOURCE: ::std::os::raw::c_uint = 1;
+pub const __USE_MISC: ::std::os::raw::c_uint = 1;
+pub const __USE_ATFILE: ::std::os::raw::c_uint = 1;
+pub const __USE_FORTIFY_LEVEL: ::std::os::raw::c_uint = 0;
+pub const _STDC_PREDEF_H: ::std::os::raw::c_uint = 1;
+pub const __STDC_IEC_559__: ::std::os::raw::c_uint = 1;
+pub const __STDC_IEC_559_COMPLEX__: ::std::os::raw::c_uint = 1;
+pub const __STDC_ISO_10646__: ::std::os::raw::c_uint = 201505;
+pub const __STDC_NO_THREADS__: ::std::os::raw::c_uint = 1;
+pub const __GNU_LIBRARY__: ::std::os::raw::c_uint = 6;
+pub const __GLIBC__: ::std::os::raw::c_uint = 2;
+pub const __GLIBC_MINOR__: ::std::os::raw::c_uint = 23;
+pub const _SYS_CDEFS_H: ::std::os::raw::c_uint = 1;
+pub const __WORDSIZE: ::std::os::raw::c_uint = 64;
+pub const __WORDSIZE_TIME64_COMPAT32: ::std::os::raw::c_uint = 1;
+pub const __SYSCALL_WORDSIZE: ::std::os::raw::c_uint = 64;
+pub const _BITS_WCHAR_H: ::std::os::raw::c_uint = 1;
+pub const INT8_MIN: ::std::os::raw::c_int = -128;
+pub const INT16_MIN: ::std::os::raw::c_int = -32768;
+pub const INT32_MIN: ::std::os::raw::c_int = -2147483648;
+pub const INT8_MAX: ::std::os::raw::c_uint = 127;
+pub const INT16_MAX: ::std::os::raw::c_uint = 32767;
+pub const INT32_MAX: ::std::os::raw::c_uint = 2147483647;
+pub const UINT8_MAX: ::std::os::raw::c_uint = 255;
+pub const UINT16_MAX: ::std::os::raw::c_uint = 65535;
+pub const UINT32_MAX: ::std::os::raw::c_uint = 4294967295;
+pub const INT_LEAST8_MIN: ::std::os::raw::c_int = -128;
+pub const INT_LEAST16_MIN: ::std::os::raw::c_int = -32768;
+pub const INT_LEAST32_MIN: ::std::os::raw::c_int = -2147483648;
+pub const INT_LEAST8_MAX: ::std::os::raw::c_uint = 127;
+pub const INT_LEAST16_MAX: ::std::os::raw::c_uint = 32767;
+pub const INT_LEAST32_MAX: ::std::os::raw::c_uint = 2147483647;
+pub const UINT_LEAST8_MAX: ::std::os::raw::c_uint = 255;
+pub const UINT_LEAST16_MAX: ::std::os::raw::c_uint = 65535;
+pub const UINT_LEAST32_MAX: ::std::os::raw::c_uint = 4294967295;
+pub const INT_FAST8_MIN: ::std::os::raw::c_int = -128;
+pub const INT_FAST16_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
+pub const INT_FAST32_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
+pub const INT_FAST8_MAX: ::std::os::raw::c_uint = 127;
+pub const INT_FAST16_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
+pub const INT_FAST32_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
+pub const UINT_FAST8_MAX: ::std::os::raw::c_uint = 255;
+pub const UINT_FAST16_MAX: ::std::os::raw::c_int = -1;
+pub const UINT_FAST32_MAX: ::std::os::raw::c_int = -1;
+pub const INTPTR_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
+pub const INTPTR_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
+pub const UINTPTR_MAX: ::std::os::raw::c_int = -1;
+pub const PTRDIFF_MIN: ::std::os::raw::c_longlong = -9223372036854775808;
+pub const PTRDIFF_MAX: ::std::os::raw::c_ulonglong = 9223372036854775807;
+pub const SIG_ATOMIC_MIN: ::std::os::raw::c_int = -2147483648;
+pub const SIG_ATOMIC_MAX: ::std::os::raw::c_uint = 2147483647;
+pub const SIZE_MAX: ::std::os::raw::c_int = -1;
+pub const WINT_MIN: ::std::os::raw::c_uint = 0;
+pub const WINT_MAX: ::std::os::raw::c_uint = 4294967295;
+pub const __BITS_PER_LONG: ::std::os::raw::c_uint = 64;
+pub const __FD_SETSIZE: ::std::os::raw::c_uint = 1024;
+pub const VRING_DESC_F_NEXT: ::std::os::raw::c_uint = 1;
+pub const VRING_DESC_F_WRITE: ::std::os::raw::c_uint = 2;
+pub const VRING_DESC_F_INDIRECT: ::std::os::raw::c_uint = 4;
+pub const VRING_USED_F_NO_NOTIFY: ::std::os::raw::c_uint = 1;
+pub const VRING_AVAIL_F_NO_INTERRUPT: ::std::os::raw::c_uint = 1;
+pub const VIRTIO_RING_F_INDIRECT_DESC: ::std::os::raw::c_uint = 28;
+pub const VIRTIO_RING_F_EVENT_IDX: ::std::os::raw::c_uint = 29;
+pub const VRING_AVAIL_ALIGN_SIZE: ::std::os::raw::c_uint = 2;
+pub const VRING_USED_ALIGN_SIZE: ::std::os::raw::c_uint = 4;
+pub const VRING_DESC_ALIGN_SIZE: ::std::os::raw::c_uint = 16;
+pub type int_least8_t = ::std::os::raw::c_schar;
+pub type int_least16_t = ::std::os::raw::c_short;
+pub type int_least32_t = ::std::os::raw::c_int;
+pub type int_least64_t = ::std::os::raw::c_long;
+pub type uint_least8_t = ::std::os::raw::c_uchar;
+pub type uint_least16_t = ::std::os::raw::c_ushort;
+pub type uint_least32_t = ::std::os::raw::c_uint;
+pub type uint_least64_t = ::std::os::raw::c_ulong;
+pub type int_fast8_t = ::std::os::raw::c_schar;
+pub type int_fast16_t = ::std::os::raw::c_long;
+pub type int_fast32_t = ::std::os::raw::c_long;
+pub type int_fast64_t = ::std::os::raw::c_long;
+pub type uint_fast8_t = ::std::os::raw::c_uchar;
+pub type uint_fast16_t = ::std::os::raw::c_ulong;
+pub type uint_fast32_t = ::std::os::raw::c_ulong;
+pub type uint_fast64_t = ::std::os::raw::c_ulong;
+pub type intmax_t = ::std::os::raw::c_long;
+pub type uintmax_t = ::std::os::raw::c_ulong;
+pub type __s8 = ::std::os::raw::c_schar;
+pub type __u8 = ::std::os::raw::c_uchar;
+pub type __s16 = ::std::os::raw::c_short;
+pub type __u16 = ::std::os::raw::c_ushort;
+pub type __s32 = ::std::os::raw::c_int;
+pub type __u32 = ::std::os::raw::c_uint;
+pub type __s64 = ::std::os::raw::c_longlong;
+pub type __u64 = ::std::os::raw::c_ulonglong;
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct __kernel_fd_set {
+    pub fds_bits: [::std::os::raw::c_ulong; 16usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fd_set() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fd_set>(),
+        128usize,
+        concat!("Size of: ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fd_set>(),
+        8usize,
+        concat!("Alignment of ", stringify!(__kernel_fd_set))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const __kernel_fd_set)).fds_bits as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(__kernel_fd_set),
+            "::",
+            stringify!(fds_bits)
+        )
+    );
+}
+impl Clone for __kernel_fd_set {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+pub type __kernel_sighandler_t =
+    ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
+pub type __kernel_key_t = ::std::os::raw::c_int;
+pub type __kernel_mqd_t = ::std::os::raw::c_int;
+pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
+pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
+pub type __kernel_long_t = ::std::os::raw::c_long;
+pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
+pub type __kernel_ino_t = __kernel_ulong_t;
+pub type __kernel_mode_t = ::std::os::raw::c_uint;
+pub type __kernel_pid_t = ::std::os::raw::c_int;
+pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
+pub type __kernel_uid_t = ::std::os::raw::c_uint;
+pub type __kernel_gid_t = ::std::os::raw::c_uint;
+pub type __kernel_suseconds_t = __kernel_long_t;
+pub type __kernel_daddr_t = ::std::os::raw::c_int;
+pub type __kernel_uid32_t = ::std::os::raw::c_uint;
+pub type __kernel_gid32_t = ::std::os::raw::c_uint;
+pub type __kernel_size_t = __kernel_ulong_t;
+pub type __kernel_ssize_t = __kernel_long_t;
+pub type __kernel_ptrdiff_t = __kernel_long_t;
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct __kernel_fsid_t {
+    pub val: [::std::os::raw::c_int; 2usize],
+}
+#[test]
+fn bindgen_test_layout___kernel_fsid_t() {
+    assert_eq!(
+        ::std::mem::size_of::<__kernel_fsid_t>(),
+        8usize,
+        concat!("Size of: ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<__kernel_fsid_t>(),
+        4usize,
+        concat!("Alignment of ", stringify!(__kernel_fsid_t))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const __kernel_fsid_t)).val as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(__kernel_fsid_t),
+            "::",
+            stringify!(val)
+        )
+    );
+}
+impl Clone for __kernel_fsid_t {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+pub type __kernel_off_t = __kernel_long_t;
+pub type __kernel_loff_t = ::std::os::raw::c_longlong;
+pub type __kernel_time_t = __kernel_long_t;
+pub type __kernel_clock_t = __kernel_long_t;
+pub type __kernel_timer_t = ::std::os::raw::c_int;
+pub type __kernel_clockid_t = ::std::os::raw::c_int;
+pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
+pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
+pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
+pub type __le16 = __u16;
+pub type __be16 = __u16;
+pub type __le32 = __u32;
+pub type __be32 = __u32;
+pub type __le64 = __u64;
+pub type __be64 = __u64;
+pub type __sum16 = __u16;
+pub type __wsum = __u32;
+pub type __virtio16 = __u16;
+pub type __virtio32 = __u32;
+pub type __virtio64 = __u64;
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct vring_desc {
+    pub addr: __virtio64,
+    pub len: __virtio32,
+    pub flags: __virtio16,
+    pub next: __virtio16,
+}
+#[test]
+fn bindgen_test_layout_vring_desc() {
+    assert_eq!(
+        ::std::mem::size_of::<vring_desc>(),
+        16usize,
+        concat!("Size of: ", stringify!(vring_desc))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vring_desc>(),
+        8usize,
+        concat!("Alignment of ", stringify!(vring_desc))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring_desc)).addr as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring_desc),
+            "::",
+            stringify!(addr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring_desc)).len as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring_desc),
+            "::",
+            stringify!(len)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring_desc)).flags as *const _ as usize },
+        12usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring_desc),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring_desc)).next as *const _ as usize },
+        14usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring_desc),
+            "::",
+            stringify!(next)
+        )
+    );
+}
+impl Clone for vring_desc {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct vring_avail {
+    pub flags: __virtio16,
+    pub idx: __virtio16,
+    pub ring: __IncompleteArrayField<__virtio16>,
+}
+#[test]
+fn bindgen_test_layout_vring_avail() {
+    assert_eq!(
+        ::std::mem::size_of::<vring_avail>(),
+        4usize,
+        concat!("Size of: ", stringify!(vring_avail))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vring_avail>(),
+        2usize,
+        concat!("Alignment of ", stringify!(vring_avail))
+    );
+}
+impl Clone for vring_avail {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct vring_used_elem {
+    pub id: __virtio32,
+    pub len: __virtio32,
+}
+#[test]
+fn bindgen_test_layout_vring_used_elem() {
+    assert_eq!(
+        ::std::mem::size_of::<vring_used_elem>(),
+        8usize,
+        concat!("Size of: ", stringify!(vring_used_elem))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vring_used_elem>(),
+        4usize,
+        concat!("Alignment of ", stringify!(vring_used_elem))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring_used_elem)).id as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring_used_elem),
+            "::",
+            stringify!(id)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring_used_elem)).len as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring_used_elem),
+            "::",
+            stringify!(len)
+        )
+    );
+}
+impl Clone for vring_used_elem {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct vring_used {
+    pub flags: __virtio16,
+    pub idx: __virtio16,
+    pub ring: __IncompleteArrayField<vring_used_elem>,
+    pub __bindgen_align: [u32; 0usize],
+}
+#[test]
+fn bindgen_test_layout_vring_used() {
+    assert_eq!(
+        ::std::mem::size_of::<vring_used>(),
+        4usize,
+        concat!("Size of: ", stringify!(vring_used))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vring_used>(),
+        4usize,
+        concat!("Alignment of ", stringify!(vring_used))
+    );
+}
+impl Clone for vring_used {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct vring {
+    pub num: ::std::os::raw::c_uint,
+    pub desc: *mut vring_desc,
+    pub avail: *mut vring_avail,
+    pub used: *mut vring_used,
+}
+#[test]
+fn bindgen_test_layout_vring() {
+    assert_eq!(
+        ::std::mem::size_of::<vring>(),
+        32usize,
+        concat!("Size of: ", stringify!(vring))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<vring>(),
+        8usize,
+        concat!("Alignment of ", stringify!(vring))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring)).num as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring),
+            "::",
+            stringify!(num)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring)).desc as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring),
+            "::",
+            stringify!(desc)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring)).avail as *const _ as usize },
+        16usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring),
+            "::",
+            stringify!(avail)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const vring)).used as *const _ as usize },
+        24usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(vring),
+            "::",
+            stringify!(used)
+        )
+    );
+}
+impl Clone for vring {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
diff --git a/vm_control/Cargo.toml b/vm_control/Cargo.toml
new file mode 100644
index 0000000..ba70fe2
--- /dev/null
+++ b/vm_control/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "vm_control"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[features]
+sandboxed-libusb = []
+
+[dependencies]
+byteorder = "*"
+data_model = { path = "../data_model" }
+kvm = { path = "../kvm" }
+libc = "*"
+msg_socket = { path = "../msg_socket" }
+resources = { path = "../resources" }
+sys_util = { path = "../sys_util" }
diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs
new file mode 100644
index 0000000..8023abe
--- /dev/null
+++ b/vm_control/src/lib.rs
@@ -0,0 +1,456 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Handles IPC for controlling the main VM process.
+//!
+//! The VM Control IPC protocol is synchronous, meaning that each `VmRequest` sent over a connection
+//! will receive a `VmResponse` for that request next time data is received over that connection.
+//!
+//! The wire message format is a little-endian C-struct of fixed size, along with a file descriptor
+//! if the request type expects one.
+
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::io::{Seek, SeekFrom};
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+
+use libc::{EINVAL, EIO, ENODEV};
+
+use kvm::Vm;
+use msg_socket::{MsgOnSocket, MsgReceiver, MsgResult, MsgSender, MsgSocket};
+use resources::{GpuMemoryDesc, SystemAllocator};
+use sys_util::{error, Error as SysError, GuestAddress, MemoryMapping, MmapError, Result};
+
+/// A file descriptor either borrowed or owned by this.
+#[derive(Debug)]
+pub enum MaybeOwnedFd {
+    /// Owned by this enum variant, and will be destructed automatically if not moved out.
+    Owned(File),
+    /// A file descriptor borrwed by this enum.
+    Borrowed(RawFd),
+}
+
+impl AsRawFd for MaybeOwnedFd {
+    fn as_raw_fd(&self) -> RawFd {
+        match self {
+            MaybeOwnedFd::Owned(f) => f.as_raw_fd(),
+            MaybeOwnedFd::Borrowed(fd) => *fd,
+        }
+    }
+}
+
+// When sent, it could be owned or borrowed. On the receiver end, it always owned.
+impl MsgOnSocket for MaybeOwnedFd {
+    fn msg_size() -> usize {
+        0usize
+    }
+    fn max_fd_count() -> usize {
+        1usize
+    }
+    unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+        let (fd, size) = RawFd::read_from_buffer(buffer, fds)?;
+        let file = File::from_raw_fd(fd);
+        Ok((MaybeOwnedFd::Owned(file), size))
+    }
+    fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
+        let fd = self.as_raw_fd();
+        fd.write_to_buffer(buffer, fds)
+    }
+}
+
+/// Mode of execution for the VM.
+#[derive(Debug)]
+pub enum VmRunMode {
+    /// The default run mode indicating the VCPUs are running.
+    Running,
+    /// Indicates that the VCPUs are suspending execution until the `Running` mode is set.
+    Suspending,
+    /// Indicates that the VM is exiting all processes.
+    Exiting,
+}
+
+impl Display for VmRunMode {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::VmRunMode::*;
+
+        match self {
+            Running => write!(f, "running"),
+            Suspending => write!(f, "suspending"),
+            Exiting => write!(f, "exiting"),
+        }
+    }
+}
+
+impl Default for VmRunMode {
+    fn default() -> Self {
+        VmRunMode::Running
+    }
+}
+
+/// The maximum number of devices that can be listed in one `UsbControlCommand`.
+///
+/// This value was set to be equal to `xhci_regs::MAX_PORTS` for convenience, but it is not
+/// necessary for correctness. Importing that value directly would be overkill because it would
+/// require adding a big dependency for a single const.
+pub const USB_CONTROL_MAX_PORTS: usize = 16;
+
+#[derive(MsgOnSocket, Debug)]
+pub enum BalloonControlCommand {
+    /// Set the size of the VM's balloon.
+    Adjust { num_bytes: u64 },
+}
+
+#[derive(MsgOnSocket, Debug)]
+pub enum DiskControlCommand {
+    /// Resize a disk to `new_size` in bytes.
+    Resize { new_size: u64 },
+}
+
+impl Display for DiskControlCommand {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::DiskControlCommand::*;
+
+        match self {
+            Resize { new_size } => write!(f, "disk_resize {}", new_size),
+        }
+    }
+}
+
+#[derive(MsgOnSocket, Debug)]
+pub enum DiskControlResult {
+    Ok,
+    Err(SysError),
+}
+
+#[derive(MsgOnSocket, Debug)]
+pub enum UsbControlCommand {
+    AttachDevice {
+        bus: u8,
+        addr: u8,
+        vid: u16,
+        pid: u16,
+        fd: Option<MaybeOwnedFd>,
+    },
+    DetachDevice {
+        port: u8,
+    },
+    ListDevice {
+        ports: [u8; USB_CONTROL_MAX_PORTS],
+    },
+}
+
+#[derive(MsgOnSocket, Copy, Clone, Debug, Default)]
+pub struct UsbControlAttachedDevice {
+    pub port: u8,
+    pub vendor_id: u16,
+    pub product_id: u16,
+}
+
+impl UsbControlAttachedDevice {
+    fn valid(self) -> bool {
+        self.port != 0
+    }
+}
+
+#[derive(MsgOnSocket, Debug)]
+pub enum UsbControlResult {
+    Ok { port: u8 },
+    NoAvailablePort,
+    NoSuchDevice,
+    NoSuchPort,
+    FailedToOpenDevice,
+    Devices([UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS]),
+}
+
+impl Display for UsbControlResult {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::UsbControlResult::*;
+
+        match self {
+            Ok { port } => write!(f, "ok {}", port),
+            NoAvailablePort => write!(f, "no_available_port"),
+            NoSuchDevice => write!(f, "no_such_device"),
+            NoSuchPort => write!(f, "no_such_port"),
+            FailedToOpenDevice => write!(f, "failed_to_open_device"),
+            Devices(devices) => {
+                write!(f, "devices")?;
+                for d in devices.iter().filter(|d| d.valid()) {
+                    write!(f, " {} {:04x} {:04x}", d.port, d.vendor_id, d.product_id)?;
+                }
+                std::result::Result::Ok(())
+            }
+        }
+    }
+}
+
+#[derive(MsgOnSocket, Debug)]
+pub enum VmMemoryRequest {
+    /// Register shared memory represented by the given fd into guest address space. The response
+    /// variant is `VmResponse::RegisterMemory`.
+    RegisterMemory(MaybeOwnedFd, usize),
+    /// Unregister the given memory slot that was previously registereed with `RegisterMemory`.
+    UnregisterMemory(u32),
+    /// Allocate GPU buffer of a given size/format and register the memory into guest address space.
+    /// The response variant is `VmResponse::AllocateAndRegisterGpuMemory`
+    AllocateAndRegisterGpuMemory {
+        width: u32,
+        height: u32,
+        format: u32,
+    },
+}
+
+impl VmMemoryRequest {
+    /// Executes this request on the given Vm.
+    ///
+    /// # Arguments
+    /// * `vm` - The `Vm` to perform the request on.
+    /// * `allocator` - Used to allocate addresses.
+    ///
+    /// This does not return a result, instead encapsulating the success or failure in a
+    /// `VmMemoryResponse` with the intended purpose of sending the response back over the socket
+    /// that received this `VmMemoryResponse`.
+    pub fn execute(&self, vm: &mut Vm, sys_allocator: &mut SystemAllocator) -> VmMemoryResponse {
+        use self::VmMemoryRequest::*;
+        match *self {
+            RegisterMemory(ref fd, size) => match register_memory(vm, sys_allocator, fd, size) {
+                Ok((pfn, slot)) => VmMemoryResponse::RegisterMemory { pfn, slot },
+                Err(e) => VmMemoryResponse::Err(e),
+            },
+            UnregisterMemory(slot) => match vm.remove_device_memory(slot) {
+                Ok(_) => VmMemoryResponse::Ok,
+                Err(e) => VmMemoryResponse::Err(e),
+            },
+            AllocateAndRegisterGpuMemory {
+                width,
+                height,
+                format,
+            } => {
+                let (mut fd, desc) = match sys_allocator.gpu_memory_allocator() {
+                    Some(gpu_allocator) => match gpu_allocator.allocate(width, height, format) {
+                        Ok(v) => v,
+                        Err(e) => return VmMemoryResponse::Err(e),
+                    },
+                    None => return VmMemoryResponse::Err(SysError::new(ENODEV)),
+                };
+                // Determine size of buffer using 0 byte seek from end. This is preferred over
+                // `stride * height` as it's not limited to packed pixel formats.
+                let size = match fd.seek(SeekFrom::End(0)) {
+                    Ok(v) => v,
+                    Err(e) => return VmMemoryResponse::Err(SysError::from(e)),
+                };
+                match register_memory(vm, sys_allocator, &fd, size as usize) {
+                    Ok((pfn, slot)) => VmMemoryResponse::AllocateAndRegisterGpuMemory {
+                        fd: MaybeOwnedFd::Owned(fd),
+                        pfn,
+                        slot,
+                        desc,
+                    },
+                    Err(e) => VmMemoryResponse::Err(e),
+                }
+            }
+        }
+    }
+}
+
+#[derive(MsgOnSocket, Debug)]
+pub enum VmMemoryResponse {
+    /// The request to register memory into guest address space was successfully done at page frame
+    /// number `pfn` and memory slot number `slot`.
+    RegisterMemory {
+        pfn: u64,
+        slot: u32,
+    },
+    /// The request to allocate and register GPU memory into guest address space was successfully
+    /// done at page frame number `pfn` and memory slot number `slot` for buffer with `desc`.
+    AllocateAndRegisterGpuMemory {
+        fd: MaybeOwnedFd,
+        pfn: u64,
+        slot: u32,
+        desc: GpuMemoryDesc,
+    },
+    Ok,
+    Err(SysError),
+}
+
+pub type BalloonControlRequestSocket = MsgSocket<BalloonControlCommand, ()>;
+pub type BalloonControlResponseSocket = MsgSocket<(), BalloonControlCommand>;
+
+pub type DiskControlRequestSocket = MsgSocket<DiskControlCommand, DiskControlResult>;
+pub type DiskControlResponseSocket = MsgSocket<DiskControlResult, DiskControlCommand>;
+
+pub type UsbControlSocket = MsgSocket<UsbControlCommand, UsbControlResult>;
+
+pub type VmMemoryControlRequestSocket = MsgSocket<VmMemoryRequest, VmMemoryResponse>;
+pub type VmMemoryControlResponseSocket = MsgSocket<VmMemoryResponse, VmMemoryRequest>;
+
+pub type VmControlRequestSocket = MsgSocket<VmRequest, VmResponse>;
+pub type VmControlResponseSocket = MsgSocket<VmResponse, VmRequest>;
+
+/// A request to the main process to perform some operation on the VM.
+///
+/// Unless otherwise noted, each request should expect a `VmResponse::Ok` to be received on success.
+#[derive(MsgOnSocket, Debug)]
+pub enum VmRequest {
+    /// Break the VM's run loop and exit.
+    Exit,
+    /// Suspend the VM's VCPUs until resume.
+    Suspend,
+    /// Resume the VM's VCPUs that were previously suspended.
+    Resume,
+    /// Command for balloon driver.
+    BalloonCommand(BalloonControlCommand),
+    /// Send a command to a disk chosen by `disk_index`.
+    /// `disk_index` is a 0-based count of `--disk`, `--rwdisk`, and `-r` command-line options.
+    DiskCommand {
+        disk_index: usize,
+        command: DiskControlCommand,
+    },
+    /// Command to use controller.
+    UsbCommand(UsbControlCommand),
+}
+
+fn register_memory(
+    vm: &mut Vm,
+    allocator: &mut SystemAllocator,
+    fd: &dyn AsRawFd,
+    size: usize,
+) -> Result<(u64, u32)> {
+    let mmap = match MemoryMapping::from_fd(fd, size) {
+        Ok(v) => v,
+        Err(MmapError::SystemCallFailed(e)) => return Err(e),
+        _ => return Err(SysError::new(EINVAL)),
+    };
+    let alloc = allocator.get_anon_alloc();
+    let addr = match allocator.device_allocator().allocate(
+        size as u64,
+        alloc,
+        "vmcontrol_register_memory".to_string(),
+    ) {
+        Ok(a) => a,
+        Err(_) => return Err(SysError::new(EINVAL)),
+    };
+    let slot = match vm.add_device_memory(GuestAddress(addr), mmap, false, false) {
+        Ok(v) => v,
+        Err(e) => return Err(e),
+    };
+
+    Ok((addr >> 12, slot))
+}
+
+impl VmRequest {
+    /// Executes this request on the given Vm and other mutable state.
+    ///
+    /// This does not return a result, instead encapsulating the success or failure in a
+    /// `VmResponse` with the intended purpose of sending the response back over the  socket that
+    /// received this `VmRequest`.
+    pub fn execute(
+        &self,
+        run_mode: &mut Option<VmRunMode>,
+        balloon_host_socket: &BalloonControlRequestSocket,
+        disk_host_sockets: &[DiskControlRequestSocket],
+        usb_control_socket: &UsbControlSocket,
+    ) -> VmResponse {
+        match *self {
+            VmRequest::Exit => {
+                *run_mode = Some(VmRunMode::Exiting);
+                VmResponse::Ok
+            }
+            VmRequest::Suspend => {
+                *run_mode = Some(VmRunMode::Suspending);
+                VmResponse::Ok
+            }
+            VmRequest::Resume => {
+                *run_mode = Some(VmRunMode::Running);
+                VmResponse::Ok
+            }
+            VmRequest::BalloonCommand(ref command) => match balloon_host_socket.send(command) {
+                Ok(_) => VmResponse::Ok,
+                Err(_) => VmResponse::Err(SysError::last()),
+            },
+            VmRequest::DiskCommand {
+                disk_index,
+                ref command,
+            } => {
+                // Forward the request to the block device process via its control socket.
+                if let Some(sock) = disk_host_sockets.get(disk_index) {
+                    if let Err(e) = sock.send(command) {
+                        error!("disk socket send failed: {}", e);
+                        VmResponse::Err(SysError::new(EINVAL))
+                    } else {
+                        match sock.recv() {
+                            Ok(DiskControlResult::Ok) => VmResponse::Ok,
+                            Ok(DiskControlResult::Err(e)) => VmResponse::Err(e),
+                            Err(e) => {
+                                error!("disk socket recv failed: {}", e);
+                                VmResponse::Err(SysError::new(EINVAL))
+                            }
+                        }
+                    }
+                } else {
+                    VmResponse::Err(SysError::new(ENODEV))
+                }
+            }
+            VmRequest::UsbCommand(ref cmd) => {
+                let res = usb_control_socket.send(cmd);
+                if let Err(e) = res {
+                    error!("fail to send command to usb control socket: {}", e);
+                    return VmResponse::Err(SysError::new(EIO));
+                }
+                match usb_control_socket.recv() {
+                    Ok(response) => VmResponse::UsbResponse(response),
+                    Err(e) => {
+                        error!("fail to recv command from usb control socket: {}", e);
+                        VmResponse::Err(SysError::new(EIO))
+                    }
+                }
+            }
+        }
+    }
+}
+
+/// Indication of success or failure of a `VmRequest`.
+///
+/// Success is usually indicated `VmResponse::Ok` unless there is data associated with the response.
+#[derive(MsgOnSocket, Debug)]
+pub enum VmResponse {
+    /// Indicates the request was executed successfully.
+    Ok,
+    /// Indicates the request encountered some error during execution.
+    Err(SysError),
+    /// The request to register memory into guest address space was successfully done at page frame
+    /// number `pfn` and memory slot number `slot`.
+    RegisterMemory { pfn: u64, slot: u32 },
+    /// The request to allocate and register GPU memory into guest address space was successfully
+    /// done at page frame number `pfn` and memory slot number `slot` for buffer with `desc`.
+    AllocateAndRegisterGpuMemory {
+        fd: MaybeOwnedFd,
+        pfn: u64,
+        slot: u32,
+        desc: GpuMemoryDesc,
+    },
+    /// Results of usb control commands.
+    UsbResponse(UsbControlResult),
+}
+
+impl Display for VmResponse {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::VmResponse::*;
+
+        match self {
+            Ok => write!(f, "ok"),
+            Err(e) => write!(f, "error: {}", e),
+            RegisterMemory { pfn, slot } => write!(
+                f,
+                "memory registered to page frame number {:#x} and memory slot {}",
+                pfn, slot
+            ),
+            AllocateAndRegisterGpuMemory { pfn, slot, .. } => write!(
+                f,
+                "gpu memory allocated and registered to page frame number {:#x} and memory slot {}",
+                pfn, slot
+            ),
+            UsbResponse(result) => write!(f, "usb control request get result {:?}", result),
+        }
+    }
+}
diff --git a/x86_64/Cargo.toml b/x86_64/Cargo.toml
new file mode 100644
index 0000000..58d688b
--- /dev/null
+++ b/x86_64/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "x86_64"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+build = "build.rs"
+
+[dependencies]
+arch = { path = "../arch" }
+assertions = { path = "../assertions" }
+byteorder = "*"
+data_model = { path = "../data_model" }
+devices = { path = "../devices" }
+io_jail = { path = "../io_jail" }
+kernel_cmdline = { path = "../kernel_cmdline" }
+kernel_loader = { path = "../kernel_loader" }
+kvm = { path = "../kvm" }
+kvm_sys = { path = "../kvm_sys" }
+libc = "*"
+remain = "*"
+resources = { path = "../resources" }
+sync = { path = "../sync" }
+sys_util = { path = "../sys_util" }
+
+[build-dependencies]
+cc = "=1.0.25"
diff --git a/x86_64/build.rs b/x86_64/build.rs
new file mode 100644
index 0000000..5f2c1eb
--- /dev/null
+++ b/x86_64/build.rs
@@ -0,0 +1,7 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+fn main() {
+    cc::Build::new().file("host_cpuid.c").compile("host_cpuid");
+}
diff --git a/x86_64/host_cpuid.c b/x86_64/host_cpuid.c
new file mode 100644
index 0000000..3230c90
--- /dev/null
+++ b/x86_64/host_cpuid.c
@@ -0,0 +1,11 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+
+void host_cpuid(uint32_t func, uint32_t func2, uint32_t *pEax,
+                uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx) {
+    asm volatile("cpuid" : "=a"(*pEax), "=b"(*pEbx), "=c"(*pEcx), "=d"(*pEdx) :
+                 "0"(func), "2"(func2) : "cc");
+}
diff --git a/x86_64/src/bootparam.rs b/x86_64/src/bootparam.rs
new file mode 100644
index 0000000..33bd90a
--- /dev/null
+++ b/x86_64/src/bootparam.rs
@@ -0,0 +1,437 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/*
+ * automatically generated by bindgen
+ * From chromeos-linux v4.19
+ * $ bindgen \
+ *       --no-layout-tests --with-derive-default --no-doc-comments \
+ *       --whitelist-type boot_params --whitelist-type setup_data \
+ *       arch/x86/include/uapi/asm/bootparam.h
+ */
+
+#[repr(C)]
+#[derive(Default)]
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
+impl<T> __IncompleteArrayField<T> {
+    #[inline]
+    pub fn new() -> Self {
+        __IncompleteArrayField(::std::marker::PhantomData, [])
+    }
+    #[inline]
+    pub unsafe fn as_ptr(&self) -> *const T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
+        ::std::mem::transmute(self)
+    }
+    #[inline]
+    pub unsafe fn as_slice(&self, len: usize) -> &[T] {
+        ::std::slice::from_raw_parts(self.as_ptr(), len)
+    }
+    #[inline]
+    pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
+        ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
+    }
+}
+impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
+    fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        fmt.write_str("__IncompleteArrayField")
+    }
+}
+impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self::new()
+    }
+}
+pub type __u8 = ::std::os::raw::c_uchar;
+pub type __u16 = ::std::os::raw::c_ushort;
+pub type __u32 = ::std::os::raw::c_uint;
+pub type __u64 = ::std::os::raw::c_ulonglong;
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct screen_info {
+    pub orig_x: __u8,
+    pub orig_y: __u8,
+    pub ext_mem_k: __u16,
+    pub orig_video_page: __u16,
+    pub orig_video_mode: __u8,
+    pub orig_video_cols: __u8,
+    pub flags: __u8,
+    pub unused2: __u8,
+    pub orig_video_ega_bx: __u16,
+    pub unused3: __u16,
+    pub orig_video_lines: __u8,
+    pub orig_video_isVGA: __u8,
+    pub orig_video_points: __u16,
+    pub lfb_width: __u16,
+    pub lfb_height: __u16,
+    pub lfb_depth: __u16,
+    pub lfb_base: __u32,
+    pub lfb_size: __u32,
+    pub cl_magic: __u16,
+    pub cl_offset: __u16,
+    pub lfb_linelength: __u16,
+    pub red_size: __u8,
+    pub red_pos: __u8,
+    pub green_size: __u8,
+    pub green_pos: __u8,
+    pub blue_size: __u8,
+    pub blue_pos: __u8,
+    pub rsvd_size: __u8,
+    pub rsvd_pos: __u8,
+    pub vesapm_seg: __u16,
+    pub vesapm_off: __u16,
+    pub pages: __u16,
+    pub vesa_attributes: __u16,
+    pub capabilities: __u32,
+    pub ext_lfb_base: __u32,
+    pub _reserved: [__u8; 2usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct apm_bios_info {
+    pub version: __u16,
+    pub cseg: __u16,
+    pub offset: __u32,
+    pub cseg_16: __u16,
+    pub dseg: __u16,
+    pub flags: __u16,
+    pub cseg_len: __u16,
+    pub cseg_16_len: __u16,
+    pub dseg_len: __u16,
+}
+#[repr(C, packed)]
+#[derive(Copy, Clone)]
+pub struct edd_device_params {
+    pub length: __u16,
+    pub info_flags: __u16,
+    pub num_default_cylinders: __u32,
+    pub num_default_heads: __u32,
+    pub sectors_per_track: __u32,
+    pub number_of_sectors: __u64,
+    pub bytes_per_sector: __u16,
+    pub dpte_ptr: __u32,
+    pub key: __u16,
+    pub device_path_info_length: __u8,
+    pub reserved2: __u8,
+    pub reserved3: __u16,
+    pub host_bus_type: [__u8; 4usize],
+    pub interface_type: [__u8; 8usize],
+    pub interface_path: edd_device_params__bindgen_ty_1,
+    pub device_path: edd_device_params__bindgen_ty_2,
+    pub reserved4: __u8,
+    pub checksum: __u8,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union edd_device_params__bindgen_ty_1 {
+    pub isa: edd_device_params__bindgen_ty_1__bindgen_ty_1,
+    pub pci: edd_device_params__bindgen_ty_1__bindgen_ty_2,
+    pub ibnd: edd_device_params__bindgen_ty_1__bindgen_ty_3,
+    pub xprs: edd_device_params__bindgen_ty_1__bindgen_ty_4,
+    pub htpt: edd_device_params__bindgen_ty_1__bindgen_ty_5,
+    pub unknown: edd_device_params__bindgen_ty_1__bindgen_ty_6,
+    _bindgen_union_align: [u8; 8usize],
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_1__bindgen_ty_1 {
+    pub base_address: __u16,
+    pub reserved1: __u16,
+    pub reserved2: __u32,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_1__bindgen_ty_2 {
+    pub bus: __u8,
+    pub slot: __u8,
+    pub function: __u8,
+    pub channel: __u8,
+    pub reserved: __u32,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_1__bindgen_ty_3 {
+    pub reserved: __u64,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_1__bindgen_ty_4 {
+    pub reserved: __u64,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_1__bindgen_ty_5 {
+    pub reserved: __u64,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_1__bindgen_ty_6 {
+    pub reserved: __u64,
+}
+impl Default for edd_device_params__bindgen_ty_1 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union edd_device_params__bindgen_ty_2 {
+    pub ata: edd_device_params__bindgen_ty_2__bindgen_ty_1,
+    pub atapi: edd_device_params__bindgen_ty_2__bindgen_ty_2,
+    pub scsi: edd_device_params__bindgen_ty_2__bindgen_ty_3,
+    pub usb: edd_device_params__bindgen_ty_2__bindgen_ty_4,
+    pub i1394: edd_device_params__bindgen_ty_2__bindgen_ty_5,
+    pub fibre: edd_device_params__bindgen_ty_2__bindgen_ty_6,
+    pub i2o: edd_device_params__bindgen_ty_2__bindgen_ty_7,
+    pub raid: edd_device_params__bindgen_ty_2__bindgen_ty_8,
+    pub sata: edd_device_params__bindgen_ty_2__bindgen_ty_9,
+    pub unknown: edd_device_params__bindgen_ty_2__bindgen_ty_10,
+    _bindgen_union_align: [u8; 16usize],
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_2__bindgen_ty_1 {
+    pub device: __u8,
+    pub reserved1: __u8,
+    pub reserved2: __u16,
+    pub reserved3: __u32,
+    pub reserved4: __u64,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_2__bindgen_ty_2 {
+    pub device: __u8,
+    pub lun: __u8,
+    pub reserved1: __u8,
+    pub reserved2: __u8,
+    pub reserved3: __u32,
+    pub reserved4: __u64,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_2__bindgen_ty_3 {
+    pub id: __u16,
+    pub lun: __u64,
+    pub reserved1: __u16,
+    pub reserved2: __u32,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_2__bindgen_ty_4 {
+    pub serial_number: __u64,
+    pub reserved: __u64,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_2__bindgen_ty_5 {
+    pub eui: __u64,
+    pub reserved: __u64,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_2__bindgen_ty_6 {
+    pub wwid: __u64,
+    pub lun: __u64,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_2__bindgen_ty_7 {
+    pub identity_tag: __u64,
+    pub reserved: __u64,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_2__bindgen_ty_8 {
+    pub array_number: __u32,
+    pub reserved1: __u32,
+    pub reserved2: __u64,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_2__bindgen_ty_9 {
+    pub device: __u8,
+    pub reserved1: __u8,
+    pub reserved2: __u16,
+    pub reserved3: __u32,
+    pub reserved4: __u64,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct edd_device_params__bindgen_ty_2__bindgen_ty_10 {
+    pub reserved1: __u64,
+    pub reserved2: __u64,
+}
+impl Default for edd_device_params__bindgen_ty_2 {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+impl Default for edd_device_params {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C, packed)]
+#[derive(Copy, Clone)]
+pub struct edd_info {
+    pub device: __u8,
+    pub version: __u8,
+    pub interface_support: __u16,
+    pub legacy_max_cylinder: __u16,
+    pub legacy_max_head: __u8,
+    pub legacy_sectors_per_track: __u8,
+    pub params: edd_device_params,
+}
+impl Default for edd_info {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct ist_info {
+    pub signature: __u32,
+    pub command: __u32,
+    pub event: __u32,
+    pub perf_level: __u32,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct edid_info {
+    pub dummy: [::std::os::raw::c_uchar; 128usize],
+}
+impl Default for edid_info {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct setup_data {
+    pub next: __u64,
+    pub type_: __u32,
+    pub len: __u32,
+    pub data: __IncompleteArrayField<__u8>,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct setup_header {
+    pub setup_sects: __u8,
+    pub root_flags: __u16,
+    pub syssize: __u32,
+    pub ram_size: __u16,
+    pub vid_mode: __u16,
+    pub root_dev: __u16,
+    pub boot_flag: __u16,
+    pub jump: __u16,
+    pub header: __u32,
+    pub version: __u16,
+    pub realmode_swtch: __u32,
+    pub start_sys_seg: __u16,
+    pub kernel_version: __u16,
+    pub type_of_loader: __u8,
+    pub loadflags: __u8,
+    pub setup_move_size: __u16,
+    pub code32_start: __u32,
+    pub ramdisk_image: __u32,
+    pub ramdisk_size: __u32,
+    pub bootsect_kludge: __u32,
+    pub heap_end_ptr: __u16,
+    pub ext_loader_ver: __u8,
+    pub ext_loader_type: __u8,
+    pub cmd_line_ptr: __u32,
+    pub initrd_addr_max: __u32,
+    pub kernel_alignment: __u32,
+    pub relocatable_kernel: __u8,
+    pub min_alignment: __u8,
+    pub xloadflags: __u16,
+    pub cmdline_size: __u32,
+    pub hardware_subarch: __u32,
+    pub hardware_subarch_data: __u64,
+    pub payload_offset: __u32,
+    pub payload_length: __u32,
+    pub setup_data: __u64,
+    pub pref_address: __u64,
+    pub init_size: __u32,
+    pub handover_offset: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct sys_desc_table {
+    pub length: __u16,
+    pub table: [__u8; 14usize],
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct olpc_ofw_header {
+    pub ofw_magic: __u32,
+    pub ofw_version: __u32,
+    pub cif_handler: __u32,
+    pub irq_desc_table: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct efi_info {
+    pub efi_loader_signature: __u32,
+    pub efi_systab: __u32,
+    pub efi_memdesc_size: __u32,
+    pub efi_memdesc_version: __u32,
+    pub efi_memmap: __u32,
+    pub efi_memmap_size: __u32,
+    pub efi_systab_hi: __u32,
+    pub efi_memmap_hi: __u32,
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct boot_e820_entry {
+    pub addr: __u64,
+    pub size: __u64,
+    pub type_: __u32,
+}
+#[repr(C, packed)]
+#[derive(Copy, Clone)]
+pub struct boot_params {
+    pub screen_info: screen_info,
+    pub apm_bios_info: apm_bios_info,
+    pub _pad2: [__u8; 4usize],
+    pub tboot_addr: __u64,
+    pub ist_info: ist_info,
+    pub _pad3: [__u8; 16usize],
+    pub hd0_info: [__u8; 16usize],
+    pub hd1_info: [__u8; 16usize],
+    pub sys_desc_table: sys_desc_table,
+    pub olpc_ofw_header: olpc_ofw_header,
+    pub ext_ramdisk_image: __u32,
+    pub ext_ramdisk_size: __u32,
+    pub ext_cmd_line_ptr: __u32,
+    pub _pad4: [__u8; 116usize],
+    pub edid_info: edid_info,
+    pub efi_info: efi_info,
+    pub alt_mem_k: __u32,
+    pub scratch: __u32,
+    pub e820_entries: __u8,
+    pub eddbuf_entries: __u8,
+    pub edd_mbr_sig_buf_entries: __u8,
+    pub kbd_status: __u8,
+    pub secure_boot: __u8,
+    pub _pad5: [__u8; 2usize],
+    pub sentinel: __u8,
+    pub _pad6: [__u8; 1usize],
+    pub hdr: setup_header,
+    pub _pad7: [__u8; 40usize],
+    pub edd_mbr_sig_buffer: [__u32; 16usize],
+    pub e820_table: [boot_e820_entry; 128usize],
+    pub _pad8: [__u8; 48usize],
+    pub eddbuf: [edd_info; 6usize],
+    pub _pad9: [__u8; 276usize],
+}
+impl Default for boot_params {
+    fn default() -> Self {
+        unsafe { ::std::mem::zeroed() }
+    }
+}
diff --git a/x86_64/src/bzimage.rs b/x86_64/src/bzimage.rs
new file mode 100644
index 0000000..d43d405
--- /dev/null
+++ b/x86_64/src/bzimage.rs
@@ -0,0 +1,102 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Loader for bzImage-format Linux kernels as described in
+// https://www.kernel.org/doc/Documentation/x86/boot.txt
+
+use std::fmt::{self, Display};
+use std::io::{Read, Seek, SeekFrom};
+use std::os::unix::io::AsRawFd;
+
+use sys_util::{GuestAddress, GuestMemory};
+
+use crate::bootparam::boot_params;
+
+#[derive(Debug, PartialEq)]
+pub enum Error {
+    BadSignature,
+    InvalidSetupSects,
+    InvalidSysSize,
+    ReadBootParams,
+    ReadKernelImage,
+    SeekBootParams,
+    SeekKernelStart,
+}
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        let description = match self {
+            BadSignature => "bad kernel header signature",
+            InvalidSetupSects => "invalid setup_sects value",
+            InvalidSysSize => "invalid syssize value",
+            ReadBootParams => "unable to read boot_params",
+            ReadKernelImage => "unable to read kernel image",
+            SeekBootParams => "unable to seek to boot_params",
+            SeekKernelStart => "unable to seek to kernel start",
+        };
+
+        write!(f, "bzImage loader: {}", description)
+    }
+}
+
+/// Loads a kernel from a bzImage to a slice
+///
+/// # Arguments
+///
+/// * `guest_mem` - The guest memory region the kernel is written to.
+/// * `kernel_start` - The offset into `guest_mem` at which to load the kernel.
+/// * `kernel_image` - Input bzImage.
+pub fn load_bzimage<F>(
+    guest_mem: &GuestMemory,
+    kernel_start: GuestAddress,
+    kernel_image: &mut F,
+) -> Result<(boot_params, u64)>
+where
+    F: Read + Seek + AsRawFd,
+{
+    let mut params: boot_params = Default::default();
+    kernel_image
+        .seek(SeekFrom::Start(0))
+        .map_err(|_| Error::SeekBootParams)?;
+    unsafe {
+        // read_struct is safe when reading a POD struct.  It can be used and dropped without issue.
+        sys_util::read_struct(kernel_image, &mut params).map_err(|_| Error::ReadBootParams)?;
+    }
+
+    // bzImage header signature "HdrS"
+    if params.hdr.header != 0x53726448 {
+        return Err(Error::BadSignature);
+    }
+
+    let setup_sects = if params.hdr.setup_sects == 0 {
+        4u64
+    } else {
+        params.hdr.setup_sects as u64
+    };
+
+    let kernel_offset = setup_sects
+        .checked_add(1)
+        .ok_or(Error::InvalidSetupSects)?
+        .checked_mul(512)
+        .ok_or(Error::InvalidSetupSects)?;
+    let kernel_size = (params.hdr.syssize as usize)
+        .checked_mul(16)
+        .ok_or(Error::InvalidSysSize)?;
+
+    kernel_image
+        .seek(SeekFrom::Start(kernel_offset))
+        .map_err(|_| Error::SeekKernelStart)?;
+
+    // Load the whole kernel image to kernel_start
+    guest_mem
+        .read_to_memory(kernel_start, kernel_image, kernel_size)
+        .map_err(|_| Error::ReadKernelImage)?;
+
+    Ok((params, kernel_start.offset() + kernel_size as u64))
+}
diff --git a/x86_64/src/cpuid.rs b/x86_64/src/cpuid.rs
new file mode 100644
index 0000000..9f76550
--- /dev/null
+++ b/x86_64/src/cpuid.rs
@@ -0,0 +1,150 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fmt::{self, Display};
+use std::result;
+
+use kvm;
+use sys_util;
+
+#[derive(Debug, PartialEq)]
+pub enum Error {
+    GetSupportedCpusFailed(sys_util::Error),
+    SetSupportedCpusFailed(sys_util::Error),
+}
+pub type Result<T> = result::Result<T, Error>;
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            GetSupportedCpusFailed(e) => write!(f, "GetSupportedCpus ioctl failed: {}", e),
+            SetSupportedCpusFailed(e) => write!(f, "SetSupportedCpus ioctl failed: {}", e),
+        }
+    }
+}
+
+// This function is implemented in C because stable rustc does not
+// support inline assembly.
+extern "C" {
+    fn host_cpuid(
+        func: u32,
+        func2: u32,
+        rEax: *mut u32,
+        rEbx: *mut u32,
+        rEcx: *mut u32,
+        rEdx: *mut u32,
+    ) -> ();
+}
+
+// CPUID bits in ebx, ecx, and edx.
+const EBX_CLFLUSH_CACHELINE: u32 = 8; // Flush a cache line size.
+const EBX_CLFLUSH_SIZE_SHIFT: u32 = 8; // Bytes flushed when executing CLFLUSH.
+const EBX_CPU_COUNT_SHIFT: u32 = 16; // Index of this CPU.
+const EBX_CPUID_SHIFT: u32 = 24; // Index of this CPU.
+const ECX_EPB_SHIFT: u32 = 3; // "Energy Performance Bias" bit.
+const ECX_HYPERVISOR_SHIFT: u32 = 31; // Flag to be set when the cpu is running on a hypervisor.
+const EDX_HTT_SHIFT: u32 = 28; // Hyper Threading Enabled.
+
+fn filter_cpuid(cpu_id: u64, cpu_count: u64, kvm_cpuid: &mut kvm::CpuId) -> Result<()> {
+    let entries = kvm_cpuid.mut_entries_slice();
+
+    for entry in entries {
+        match entry.function {
+            1 => {
+                // X86 hypervisor feature
+                if entry.index == 0 {
+                    entry.ecx |= 1 << ECX_HYPERVISOR_SHIFT;
+                }
+                entry.ebx = (cpu_id << EBX_CPUID_SHIFT) as u32
+                    | (EBX_CLFLUSH_CACHELINE << EBX_CLFLUSH_SIZE_SHIFT);
+                if cpu_count > 1 {
+                    entry.ebx |= (cpu_count as u32) << EBX_CPU_COUNT_SHIFT;
+                    entry.edx |= 1 << EDX_HTT_SHIFT;
+                }
+            }
+            2 | 0x80000005 | 0x80000006 => unsafe {
+                host_cpuid(
+                    entry.function,
+                    0,
+                    &mut entry.eax as *mut u32,
+                    &mut entry.ebx as *mut u32,
+                    &mut entry.ecx as *mut u32,
+                    &mut entry.edx as *mut u32,
+                );
+            },
+            4 => {
+                unsafe {
+                    host_cpuid(
+                        entry.function,
+                        entry.index,
+                        &mut entry.eax as *mut u32,
+                        &mut entry.ebx as *mut u32,
+                        &mut entry.ecx as *mut u32,
+                        &mut entry.edx as *mut u32,
+                    );
+                }
+                entry.eax &= !0xFC000000;
+            }
+            6 => {
+                // Clear X86 EPB feature.  No frequency selection in the hypervisor.
+                entry.ecx &= !(1 << ECX_EPB_SHIFT);
+            }
+            _ => (),
+        }
+    }
+
+    Ok(())
+}
+
+/// Sets up the cpuid entries for the given vcpu.  Can fail if there are too many CPUs specified or
+/// if an ioctl returns an error.
+///
+/// # Arguments
+///
+/// * `kvm` - `Kvm` structure created with KVM_CREATE_VM ioctl.
+/// * `vcpu` - `Vcpu` for setting CPU ID.
+/// * `cpu_id` - The index of the CPU `vcpu` is for.
+/// * `nrcpus` - The number of vcpus being used by this VM.
+pub fn setup_cpuid(kvm: &kvm::Kvm, vcpu: &kvm::Vcpu, cpu_id: u64, nrcpus: u64) -> Result<()> {
+    let mut kvm_cpuid = kvm
+        .get_supported_cpuid()
+        .map_err(Error::GetSupportedCpusFailed)?;
+
+    filter_cpuid(cpu_id, nrcpus, &mut kvm_cpuid)?;
+
+    vcpu.set_cpuid2(&kvm_cpuid)
+        .map_err(Error::SetSupportedCpusFailed)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn feature_and_vendor_name() {
+        let mut cpuid = kvm::CpuId::new(2);
+
+        let entries = cpuid.mut_entries_slice();
+        entries[0].function = 0;
+        entries[1].function = 1;
+        entries[1].ecx = 0x10;
+        entries[1].edx = 0;
+        assert_eq!(Ok(()), filter_cpuid(1, 2, &mut cpuid));
+
+        let entries = cpuid.mut_entries_slice();
+        assert_eq!(entries[0].function, 0);
+        assert_eq!(1, (entries[1].ebx >> EBX_CPUID_SHIFT) & 0x000000ff);
+        assert_eq!(2, (entries[1].ebx >> EBX_CPU_COUNT_SHIFT) & 0x000000ff);
+        assert_eq!(
+            EBX_CLFLUSH_CACHELINE,
+            (entries[1].ebx >> EBX_CLFLUSH_SIZE_SHIFT) & 0x000000ff
+        );
+        assert_ne!(0, entries[1].ecx & (1 << ECX_HYPERVISOR_SHIFT));
+        assert_ne!(0, entries[1].edx & (1 << EDX_HTT_SHIFT));
+    }
+}
diff --git a/x86_64/src/fdt.rs b/x86_64/src/fdt.rs
new file mode 100644
index 0000000..655a812
--- /dev/null
+++ b/x86_64/src/fdt.rs
@@ -0,0 +1,84 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use arch::android::create_android_fdt;
+use arch::fdt::{begin_node, end_node, finish_fdt, start_fdt, Error};
+use data_model::DataInit;
+use std::fs::File;
+use std::mem;
+use sys_util::{GuestAddress, GuestMemory};
+
+use crate::bootparam::setup_data;
+use crate::{SETUP_DTB, X86_64_FDT_MAX_SIZE};
+
+// Like `setup_data` without the incomplete array field at the end, which allows us to safely
+// implement Copy, Clone, and DataInit.
+#[repr(C)]
+#[derive(Copy, Clone, Default)]
+struct setup_data_hdr {
+    pub next: u64,
+    pub type_: u32,
+    pub len: u32,
+}
+
+unsafe impl DataInit for setup_data_hdr {}
+
+/// Creates a flattened device tree containing all of the parameters for the
+/// kernel and loads it into the guest memory at the specified offset.
+///
+/// # Arguments
+///
+/// * `fdt_max_size` - The amount of space reserved for the device tree
+/// * `guest_mem` - The guest memory object
+/// * `fdt_load_offset` - The offset into physical memory for the device tree
+/// * `android_fstab` - the File object for the android fstab
+pub fn create_fdt(
+    fdt_max_size: usize,
+    guest_mem: &GuestMemory,
+    fdt_load_offset: u64,
+    android_fstab: File,
+) -> Result<usize, Error> {
+    // Reserve space for the setup_data
+    let fdt_data_size = fdt_max_size - mem::size_of::<setup_data>();
+
+    let mut fdt = vec![0; fdt_data_size];
+    start_fdt(&mut fdt, fdt_data_size)?;
+
+    // The whole thing is put into one giant node with some top level properties
+    begin_node(&mut fdt, "")?;
+    create_android_fdt(&mut fdt, android_fstab)?;
+    end_node(&mut fdt)?;
+
+    // Allocate another buffer so we can format and then write fdt to guest
+    let mut fdt_final = vec![0; fdt_data_size];
+    finish_fdt(&mut fdt, &mut fdt_final, fdt_data_size)?;
+
+    assert_eq!(
+        mem::size_of::<setup_data>(),
+        mem::size_of::<setup_data_hdr>()
+    );
+    let mut hdr: setup_data_hdr = Default::default();
+    hdr.next = 0;
+    hdr.type_ = SETUP_DTB;
+    hdr.len = fdt_data_size as u32;
+
+    assert!(fdt_data_size as u64 <= X86_64_FDT_MAX_SIZE);
+
+    let fdt_address = GuestAddress(fdt_load_offset);
+    guest_mem
+        .checked_offset(fdt_address, fdt_data_size as u64)
+        .ok_or(Error::FdtGuestMemoryWriteError)?;
+    guest_mem
+        .write_obj_at_addr(hdr, fdt_address)
+        .map_err(|_| Error::FdtGuestMemoryWriteError)?;
+
+    let fdt_data_address = GuestAddress(fdt_load_offset + mem::size_of::<setup_data>() as u64);
+    let written = guest_mem
+        .write_at_addr(fdt_final.as_slice(), fdt_data_address)
+        .map_err(|_| Error::FdtGuestMemoryWriteError)?;
+    if written < fdt_data_size {
+        return Err(Error::FdtGuestMemoryWriteError);
+    }
+    Ok(fdt_data_size)
+}
diff --git a/x86_64/src/gdt.rs b/x86_64/src/gdt.rs
new file mode 100644
index 0000000..7eb1ff7
--- /dev/null
+++ b/x86_64/src/gdt.rs
@@ -0,0 +1,112 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// For GDT details see arch/x86/include/asm/segment.h
+
+use kvm_sys::kvm_segment;
+
+/// Constructor for a conventional segment GDT (or LDT) entry. Derived from the kernel's segment.h.
+pub fn gdt_entry(flags: u16, base: u32, limit: u32) -> u64 {
+    ((((base as u64) & 0xff000000u64) << (56 - 24))
+        | (((flags as u64) & 0x0000f0ffu64) << 40)
+        | (((limit as u64) & 0x000f0000u64) << (48 - 16))
+        | (((base as u64) & 0x00ffffffu64) << 16)
+        | ((limit as u64) & 0x0000ffffu64))
+}
+
+fn get_base(entry: u64) -> u64 {
+    ((((entry) & 0xFF00000000000000) >> 32)
+        | (((entry) & 0x000000FF00000000) >> 16)
+        | (((entry) & 0x00000000FFFF0000) >> 16))
+}
+
+fn get_limit(entry: u64) -> u32 {
+    ((((entry) & 0x000F000000000000) >> 32) | ((entry) & 0x000000000000FFFF)) as u32
+}
+
+fn get_g(entry: u64) -> u8 {
+    ((entry & 0x0080000000000000) >> 55) as u8
+}
+
+fn get_db(entry: u64) -> u8 {
+    ((entry & 0x0040000000000000) >> 54) as u8
+}
+
+fn get_l(entry: u64) -> u8 {
+    ((entry & 0x0020000000000000) >> 53) as u8
+}
+
+fn get_avl(entry: u64) -> u8 {
+    ((entry & 0x0010000000000000) >> 52) as u8
+}
+
+fn get_p(entry: u64) -> u8 {
+    ((entry & 0x0000800000000000) >> 47) as u8
+}
+
+fn get_dpl(entry: u64) -> u8 {
+    ((entry & 0x0000600000000000) >> 45) as u8
+}
+
+fn get_s(entry: u64) -> u8 {
+    ((entry & 0x0000100000000000) >> 44) as u8
+}
+
+fn get_type(entry: u64) -> u8 {
+    ((entry & 0x00000F0000000000) >> 40) as u8
+}
+
+/// Automatically build the kvm struct for SET_SREGS from the kernel bit fields.
+///
+/// # Arguments
+///
+/// * `entry` - The gdt entry.
+/// * `table_index` - Index of the entry in the gdt table.
+pub fn kvm_segment_from_gdt(entry: u64, table_index: u8) -> kvm_segment {
+    kvm_segment {
+        base: get_base(entry),
+        limit: get_limit(entry),
+        selector: (table_index * 8) as u16,
+        type_: get_type(entry),
+        present: get_p(entry),
+        dpl: get_dpl(entry),
+        db: get_db(entry),
+        s: get_s(entry),
+        l: get_l(entry),
+        g: get_g(entry),
+        avl: get_avl(entry),
+        padding: 0,
+        unusable: match get_p(entry) {
+            0 => 1,
+            _ => 0,
+        },
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn field_parse() {
+        let gdt = gdt_entry(0xA09B, 0x100000, 0xfffff);
+        let seg = kvm_segment_from_gdt(gdt, 0);
+        // 0xA09B
+        // 'A'
+        assert_eq!(0x1, seg.g);
+        assert_eq!(0x0, seg.db);
+        assert_eq!(0x1, seg.l);
+        assert_eq!(0x0, seg.avl);
+        // '9'
+        assert_eq!(0x1, seg.present);
+        assert_eq!(0x0, seg.dpl);
+        assert_eq!(0x1, seg.s);
+        // 'B'
+        assert_eq!(0xB, seg.type_);
+        // base and limit
+        assert_eq!(0x100000, seg.base);
+        assert_eq!(0xfffff, seg.limit);
+        assert_eq!(0x0, seg.unusable);
+    }
+}
diff --git a/x86_64/src/interrupts.rs b/x86_64/src/interrupts.rs
new file mode 100644
index 0000000..6c2ebfd
--- /dev/null
+++ b/x86_64/src/interrupts.rs
@@ -0,0 +1,89 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fmt::{self, Display};
+use std::io::Cursor;
+use std::mem;
+use std::result;
+
+use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
+
+use kvm;
+use kvm_sys::kvm_lapic_state;
+use sys_util;
+
+#[derive(Debug)]
+pub enum Error {
+    GetLapic(sys_util::Error),
+    SetLapic(sys_util::Error),
+}
+pub type Result<T> = result::Result<T, Error>;
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            GetLapic(e) => write!(f, "GetLapic ioctl failed: {}", e),
+            SetLapic(e) => write!(f, "SetLapic ioctl failed: {}", e),
+        }
+    }
+}
+
+// Defines poached from apicdef.h kernel header.
+const APIC_LVT0: usize = 0x350;
+const APIC_LVT1: usize = 0x360;
+const APIC_MODE_NMI: u32 = 0x4;
+const APIC_MODE_EXTINT: u32 = 0x7;
+
+fn get_klapic_reg(klapic: &kvm_lapic_state, reg_offset: usize) -> u32 {
+    let sliceu8 = unsafe {
+        // This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
+        // Cursors are only readable on arrays of u8, not i8(c_char).
+        mem::transmute::<&[i8], &[u8]>(&klapic.regs[reg_offset..])
+    };
+    let mut reader = Cursor::new(sliceu8);
+    // read_u32 can't fail if the offsets defined above are correct.
+    reader.read_u32::<LittleEndian>().unwrap()
+}
+
+fn set_klapic_reg(klapic: &mut kvm_lapic_state, reg_offset: usize, value: u32) {
+    let sliceu8 = unsafe {
+        // This array is only accessed as parts of a u32 word, so interpret it as a u8 array.
+        // Cursors are only readable on arrays of u8, not i8(c_char).
+        mem::transmute::<&mut [i8], &mut [u8]>(&mut klapic.regs[reg_offset..])
+    };
+    let mut writer = Cursor::new(sliceu8);
+    // read_u32 can't fail if the offsets defined above are correct.
+    writer.write_u32::<LittleEndian>(value).unwrap()
+}
+
+fn set_apic_delivery_mode(reg: u32, mode: u32) -> u32 {
+    (((reg) & !0x700) | ((mode) << 8))
+}
+
+/// Configures LAPICs.  LAPIC0 is set for external interrupts, LAPIC1 is set for NMI.
+///
+/// # Arguments
+/// * `vcpu` - The VCPU object to configure.
+pub fn set_lint(vcpu: &kvm::Vcpu) -> Result<()> {
+    let mut klapic = vcpu.get_lapic().map_err(Error::GetLapic)?;
+
+    let lvt_lint0 = get_klapic_reg(&klapic, APIC_LVT0);
+    set_klapic_reg(
+        &mut klapic,
+        APIC_LVT0,
+        set_apic_delivery_mode(lvt_lint0, APIC_MODE_EXTINT),
+    );
+    let lvt_lint1 = get_klapic_reg(&klapic, APIC_LVT1);
+    set_klapic_reg(
+        &mut klapic,
+        APIC_LVT1,
+        set_apic_delivery_mode(lvt_lint1, APIC_MODE_NMI),
+    );
+
+    vcpu.set_lapic(&klapic).map_err(Error::SetLapic)
+}
diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs
new file mode 100644
index 0000000..a047b8c
--- /dev/null
+++ b/x86_64/src/lib.rs
@@ -0,0 +1,810 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+mod fdt;
+
+const E820_RAM: u32 = 1;
+const SETUP_DTB: u32 = 2;
+const X86_64_FDT_MAX_SIZE: u64 = 0x200000;
+
+#[allow(dead_code)]
+#[allow(non_upper_case_globals)]
+#[allow(non_camel_case_types)]
+#[allow(non_snake_case)]
+mod bootparam;
+
+// boot_params is just a series of ints, it is safe to initialize it.
+unsafe impl data_model::DataInit for bootparam::boot_params {}
+
+#[allow(dead_code)]
+#[allow(non_upper_case_globals)]
+mod msr_index;
+
+#[allow(dead_code)]
+#[allow(non_upper_case_globals)]
+#[allow(non_camel_case_types)]
+#[allow(clippy::all)]
+mod mpspec;
+// These mpspec types are only data, reading them from data is a safe initialization.
+unsafe impl data_model::DataInit for mpspec::mpc_bus {}
+unsafe impl data_model::DataInit for mpspec::mpc_cpu {}
+unsafe impl data_model::DataInit for mpspec::mpc_intsrc {}
+unsafe impl data_model::DataInit for mpspec::mpc_ioapic {}
+unsafe impl data_model::DataInit for mpspec::mpc_table {}
+unsafe impl data_model::DataInit for mpspec::mpc_lintsrc {}
+unsafe impl data_model::DataInit for mpspec::mpf_intel {}
+
+mod bzimage;
+mod cpuid;
+mod gdt;
+mod interrupts;
+mod mptable;
+mod regs;
+mod smbios;
+
+use std::collections::BTreeMap;
+use std::error::Error as StdError;
+use std::ffi::{CStr, CString};
+use std::fmt::{self, Display};
+use std::fs::File;
+use std::io::{self, Seek};
+use std::mem;
+use std::sync::Arc;
+
+use crate::bootparam::boot_params;
+use arch::{RunnableLinuxVm, VmComponents, VmImage};
+use devices::{get_serial_tty_string, PciConfigIo, PciDevice, PciInterruptPin, SerialParameters};
+use io_jail::Minijail;
+use kvm::*;
+use remain::sorted;
+use resources::SystemAllocator;
+use sync::Mutex;
+use sys_util::{Clock, EventFd, GuestAddress, GuestMemory, GuestMemoryError};
+
+#[sorted]
+#[derive(Debug)]
+pub enum Error {
+    CloneEventFd(sys_util::Error),
+    Cmdline(kernel_cmdline::Error),
+    ConfigureSystem,
+    CreateDevices(Box<dyn StdError>),
+    CreateEventFd(sys_util::Error),
+    CreateFdt(arch::fdt::Error),
+    CreateIrqChip(sys_util::Error),
+    CreateKvm(sys_util::Error),
+    CreatePciRoot(arch::DeviceRegistrationError),
+    CreatePit(sys_util::Error),
+    CreatePitDevice(devices::PitError),
+    CreateSerialDevices(arch::DeviceRegistrationError),
+    CreateSocket(io::Error),
+    CreateVcpu(sys_util::Error),
+    CreateVm(sys_util::Error),
+    E820Configuration,
+    KernelOffsetPastEnd,
+    LoadBios(io::Error),
+    LoadBzImage(bzimage::Error),
+    LoadCmdline(kernel_loader::Error),
+    LoadInitrd(arch::LoadImageError),
+    LoadKernel(kernel_loader::Error),
+    RegisterIrqfd(sys_util::Error),
+    RegisterVsock(arch::DeviceRegistrationError),
+    SetLint(interrupts::Error),
+    SetTssAddr(sys_util::Error),
+    SetupCpuid(cpuid::Error),
+    SetupFpu(regs::Error),
+    SetupGuestMemory(GuestMemoryError),
+    SetupMptable(mptable::Error),
+    SetupMsrs(regs::Error),
+    SetupRegs(regs::Error),
+    SetupSmbios(smbios::Error),
+    SetupSregs(regs::Error),
+    ZeroPagePastRamEnd,
+    ZeroPageSetup,
+}
+
+impl Display for Error {
+    #[remain::check]
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        #[sorted]
+        match self {
+            CloneEventFd(e) => write!(f, "unable to clone an EventFd: {}", e),
+            Cmdline(e) => write!(f, "the given kernel command line was invalid: {}", e),
+            ConfigureSystem => write!(f, "error configuring the system"),
+            CreateDevices(e) => write!(f, "error creating devices: {}", e),
+            CreateEventFd(e) => write!(f, "unable to make an EventFd: {}", e),
+            CreateFdt(e) => write!(f, "failed to create fdt: {}", e),
+            CreateIrqChip(e) => write!(f, "failed to create irq chip: {}", e),
+            CreateKvm(e) => write!(f, "failed to open /dev/kvm: {}", e),
+            CreatePciRoot(e) => write!(f, "failed to create a PCI root hub: {}", e),
+            CreatePit(e) => write!(f, "unable to create PIT: {}", e),
+            CreatePitDevice(e) => write!(f, "unable to make PIT device: {}", e),
+            CreateSerialDevices(e) => write!(f, "unable to create serial devices: {}", e),
+            CreateSocket(e) => write!(f, "failed to create socket: {}", e),
+            CreateVcpu(e) => write!(f, "failed to create VCPU: {}", e),
+            CreateVm(e) => write!(f, "failed to create VM: {}", e),
+            E820Configuration => write!(f, "invalid e820 setup params"),
+            KernelOffsetPastEnd => write!(f, "the kernel extends past the end of RAM"),
+            LoadBios(e) => write!(f, "error loading bios: {}", e),
+            LoadBzImage(e) => write!(f, "error loading kernel bzImage: {}", e),
+            LoadCmdline(e) => write!(f, "error loading command line: {}", e),
+            LoadInitrd(e) => write!(f, "error loading initrd: {}", e),
+            LoadKernel(e) => write!(f, "error loading Kernel: {}", e),
+            RegisterIrqfd(e) => write!(f, "error registering an IrqFd: {}", e),
+            RegisterVsock(e) => write!(f, "error registering virtual socket device: {}", e),
+            SetLint(e) => write!(f, "failed to set interrupts: {}", e),
+            SetTssAddr(e) => write!(f, "failed to set tss addr: {}", e),
+            SetupCpuid(e) => write!(f, "failed to set up cpuid: {}", e),
+            SetupFpu(e) => write!(f, "failed to set up FPU: {}", e),
+            SetupGuestMemory(e) => write!(f, "failed to set up guest memory: {}", e),
+            SetupMptable(e) => write!(f, "failed to set up mptable: {}", e),
+            SetupMsrs(e) => write!(f, "failed to set up MSRs: {}", e),
+            SetupRegs(e) => write!(f, "failed to set up registers: {}", e),
+            SetupSmbios(e) => write!(f, "failed to set up SMBIOS: {}", e),
+            SetupSregs(e) => write!(f, "failed to set up sregs: {}", e),
+            ZeroPagePastRamEnd => write!(f, "the zero page extends past the end of guest_mem"),
+            ZeroPageSetup => write!(f, "error writing the zero page of guest memory"),
+        }
+    }
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl std::error::Error for Error {}
+
+pub struct X8664arch;
+
+const BOOT_STACK_POINTER: u64 = 0x8000;
+const MEM_32BIT_GAP_SIZE: u64 = (768 << 20);
+const FIRST_ADDR_PAST_32BITS: u64 = (1 << 32);
+const KERNEL_64BIT_ENTRY_OFFSET: u64 = 0x200;
+const ZERO_PAGE_OFFSET: u64 = 0x7000;
+/// The x86 reset vector for i386+ and x86_64 puts the processor into an "unreal mode" where it
+/// can access the last 1 MB of the 32-bit address space in 16-bit mode, and starts the instruction
+/// pointer at the effective physical address 0xFFFFFFF0.
+const BIOS_LEN: usize = 1 << 20;
+const BIOS_START: u64 = FIRST_ADDR_PAST_32BITS - (BIOS_LEN as u64);
+
+const KERNEL_START_OFFSET: u64 = 0x200000;
+const CMDLINE_OFFSET: u64 = 0x20000;
+const CMDLINE_MAX_SIZE: u64 = KERNEL_START_OFFSET - CMDLINE_OFFSET;
+const X86_64_SERIAL_1_3_IRQ: u32 = 4;
+const X86_64_SERIAL_2_4_IRQ: u32 = 3;
+const X86_64_IRQ_BASE: u32 = 5;
+
+fn configure_system(
+    guest_mem: &GuestMemory,
+    _mem_size: u64,
+    kernel_addr: GuestAddress,
+    cmdline_addr: GuestAddress,
+    cmdline_size: usize,
+    num_cpus: u8,
+    pci_irqs: Vec<(u32, PciInterruptPin)>,
+    setup_data: Option<GuestAddress>,
+    initrd: Option<(GuestAddress, usize)>,
+    mut params: boot_params,
+) -> Result<()> {
+    const EBDA_START: u64 = 0x0009fc00;
+    const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
+    const KERNEL_HDR_MAGIC: u32 = 0x53726448;
+    const KERNEL_LOADER_OTHER: u8 = 0xff;
+    const KERNEL_MIN_ALIGNMENT_BYTES: u32 = 0x1000000; // Must be non-zero.
+    let first_addr_past_32bits = GuestAddress(FIRST_ADDR_PAST_32BITS);
+    let end_32bit_gap_start = GuestAddress(FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE);
+
+    // Note that this puts the mptable at 0x0 in guest physical memory.
+    mptable::setup_mptable(guest_mem, num_cpus, pci_irqs).map_err(Error::SetupMptable)?;
+
+    smbios::setup_smbios(guest_mem).map_err(Error::SetupSmbios)?;
+
+    params.hdr.type_of_loader = KERNEL_LOADER_OTHER;
+    params.hdr.boot_flag = KERNEL_BOOT_FLAG_MAGIC;
+    params.hdr.header = KERNEL_HDR_MAGIC;
+    params.hdr.cmd_line_ptr = cmdline_addr.offset() as u32;
+    params.hdr.cmdline_size = cmdline_size as u32;
+    params.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES;
+    if let Some(setup_data) = setup_data {
+        params.hdr.setup_data = setup_data.offset();
+    }
+    if let Some((initrd_addr, initrd_size)) = initrd {
+        params.hdr.ramdisk_image = initrd_addr.offset() as u32;
+        params.hdr.ramdisk_size = initrd_size as u32;
+    }
+
+    add_e820_entry(&mut params, 0, EBDA_START, E820_RAM)?;
+
+    let mem_end = guest_mem.end_addr();
+    if mem_end < end_32bit_gap_start {
+        add_e820_entry(
+            &mut params,
+            kernel_addr.offset() as u64,
+            mem_end.offset_from(kernel_addr) as u64,
+            E820_RAM,
+        )?;
+    } else {
+        add_e820_entry(
+            &mut params,
+            kernel_addr.offset() as u64,
+            end_32bit_gap_start.offset_from(kernel_addr) as u64,
+            E820_RAM,
+        )?;
+        if mem_end > first_addr_past_32bits {
+            add_e820_entry(
+                &mut params,
+                first_addr_past_32bits.offset() as u64,
+                mem_end.offset_from(first_addr_past_32bits) as u64,
+                E820_RAM,
+            )?;
+        }
+    }
+
+    let zero_page_addr = GuestAddress(ZERO_PAGE_OFFSET);
+    guest_mem
+        .checked_offset(zero_page_addr, mem::size_of::<boot_params>() as u64)
+        .ok_or(Error::ZeroPagePastRamEnd)?;
+    guest_mem
+        .write_obj_at_addr(params, zero_page_addr)
+        .map_err(|_| Error::ZeroPageSetup)?;
+    Ok(())
+}
+
+/// Add an e820 region to the e820 map.
+/// Returns Ok(()) if successful, or an error if there is no space left in the map.
+fn add_e820_entry(params: &mut boot_params, addr: u64, size: u64, mem_type: u32) -> Result<()> {
+    if params.e820_entries >= params.e820_table.len() as u8 {
+        return Err(Error::E820Configuration);
+    }
+
+    params.e820_table[params.e820_entries as usize].addr = addr;
+    params.e820_table[params.e820_entries as usize].size = size;
+    params.e820_table[params.e820_entries as usize].type_ = mem_type;
+    params.e820_entries += 1;
+
+    Ok(())
+}
+
+/// Returns a Vec of the valid memory addresses.
+/// These should be used to configure the GuestMemory structure for the platform.
+/// For x86_64 all addresses are valid from the start of the kernel except a
+/// carve out at the end of 32bit address space.
+fn arch_memory_regions(size: u64, has_bios: bool) -> Vec<(GuestAddress, u64)> {
+    let mem_end = GuestAddress(size);
+    let first_addr_past_32bits = GuestAddress(FIRST_ADDR_PAST_32BITS);
+    let end_32bit_gap_start = GuestAddress(FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE);
+
+    let mut regions = Vec::new();
+    if mem_end < end_32bit_gap_start {
+        regions.push((GuestAddress(0), size));
+        if has_bios {
+            regions.push((GuestAddress(BIOS_START), BIOS_LEN as u64));
+        }
+    } else {
+        regions.push((GuestAddress(0), end_32bit_gap_start.offset()));
+        if mem_end > first_addr_past_32bits {
+            let region_start = if has_bios {
+                GuestAddress(BIOS_START)
+            } else {
+                first_addr_past_32bits
+            };
+            regions.push((region_start, mem_end.offset_from(first_addr_past_32bits)));
+        } else if has_bios {
+            regions.push((GuestAddress(BIOS_START), BIOS_LEN as u64));
+        }
+    }
+
+    regions
+}
+
+impl arch::LinuxArch for X8664arch {
+    type Error = Error;
+
+    fn build_vm<F, E>(
+        mut components: VmComponents,
+        split_irqchip: bool,
+        serial_parameters: &BTreeMap<u8, SerialParameters>,
+        create_devices: F,
+    ) -> Result<RunnableLinuxVm>
+    where
+        F: FnOnce(
+            &GuestMemory,
+            &mut Vm,
+            &mut SystemAllocator,
+            &EventFd,
+        ) -> std::result::Result<Vec<(Box<dyn PciDevice>, Option<Minijail>)>, E>,
+        E: StdError + 'static,
+    {
+        let mut resources =
+            Self::get_resource_allocator(components.memory_size, components.wayland_dmabuf);
+        let has_bios = match components.vm_image {
+            VmImage::Bios(_) => true,
+            _ => false,
+        };
+        let mem = Self::setup_memory(components.memory_size, has_bios)?;
+        let kvm = Kvm::new().map_err(Error::CreateKvm)?;
+        let mut vm = Self::create_vm(&kvm, split_irqchip, mem.clone())?;
+
+        let vcpu_count = components.vcpu_count;
+        let mut vcpus = Vec::with_capacity(vcpu_count as usize);
+        for cpu_id in 0..vcpu_count {
+            let vcpu = Vcpu::new(cpu_id as libc::c_ulong, &kvm, &vm).map_err(Error::CreateVcpu)?;
+            if let VmImage::Kernel(_) = components.vm_image {
+                Self::configure_vcpu(
+                    vm.get_memory(),
+                    &kvm,
+                    &vm,
+                    &vcpu,
+                    cpu_id as u64,
+                    vcpu_count as u64,
+                )?;
+            }
+            vcpus.push(vcpu);
+        }
+
+        let vcpu_affinity = components.vcpu_affinity;
+
+        let irq_chip = Self::create_irq_chip(&vm)?;
+
+        let mut mmio_bus = devices::Bus::new();
+
+        let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?;
+
+        let pci_devices = create_devices(&mem, &mut vm, &mut resources, &exit_evt)
+            .map_err(|e| Error::CreateDevices(Box::new(e)))?;
+        let (pci, pci_irqs, pid_debug_label_map) =
+            arch::generate_pci_root(pci_devices, &mut mmio_bus, &mut resources, &mut vm)
+                .map_err(Error::CreatePciRoot)?;
+        let pci_bus = Arc::new(Mutex::new(PciConfigIo::new(pci)));
+
+        let mut io_bus = Self::setup_io_bus(
+            &mut vm,
+            split_irqchip,
+            exit_evt.try_clone().map_err(Error::CloneEventFd)?,
+            Some(pci_bus.clone()),
+            components.memory_size,
+        )?;
+
+        let (stdio_serial_num, stdio_serial) =
+            Self::setup_serial_devices(&mut vm, &mut io_bus, &serial_parameters)?;
+
+        match components.vm_image {
+            VmImage::Bios(ref mut bios) => Self::load_bios(&mem, bios)?,
+            VmImage::Kernel(ref mut kernel_image) => {
+                let mut cmdline = Self::get_base_linux_cmdline(stdio_serial_num);
+                for param in components.extra_kernel_params {
+                    cmdline.insert_str(&param).map_err(Error::Cmdline)?;
+                }
+
+                // separate out load_kernel from other setup to get a specific error for
+                // kernel loading
+                let (params, kernel_end) = Self::load_kernel(&mem, kernel_image)?;
+
+                Self::setup_system_memory(
+                    &mem,
+                    components.memory_size,
+                    vcpu_count,
+                    &CString::new(cmdline).unwrap(),
+                    components.initrd_image,
+                    pci_irqs,
+                    components.android_fstab,
+                    kernel_end,
+                    params,
+                )?;
+            }
+        }
+        Ok(RunnableLinuxVm {
+            vm,
+            kvm,
+            resources,
+            stdio_serial,
+            exit_evt,
+            vcpus,
+            vcpu_affinity,
+            irq_chip,
+            io_bus,
+            mmio_bus,
+            pid_debug_label_map,
+        })
+    }
+}
+
+impl X8664arch {
+    /// Loads the bios from an open file.
+    ///
+    /// # Arguments
+    ///
+    /// * `mem` - The memory to be used by the guest.
+    /// * `bios_image` - the File object for the specified bios
+    fn load_bios(mem: &GuestMemory, bios_image: &mut File) -> Result<()> {
+        let bios_image_length = bios_image
+            .seek(io::SeekFrom::End(0))
+            .map_err(Error::LoadBios)?;
+        if bios_image_length != BIOS_LEN as u64 {
+            return Err(Error::LoadBios(io::Error::new(
+                io::ErrorKind::InvalidData,
+                format!(
+                    "bios was {} bytes, expected {}",
+                    bios_image_length, BIOS_LEN
+                ),
+            )));
+        }
+        bios_image
+            .seek(io::SeekFrom::Start(0))
+            .map_err(Error::LoadBios)?;
+        mem.read_to_memory(GuestAddress(BIOS_START), bios_image, BIOS_LEN)
+            .map_err(Error::SetupGuestMemory)?;
+        Ok(())
+    }
+
+    /// Loads the kernel from an open file.
+    ///
+    /// # Arguments
+    ///
+    /// * `mem` - The memory to be used by the guest.
+    /// * `kernel_image` - the File object for the specified kernel.
+    fn load_kernel(mem: &GuestMemory, kernel_image: &mut File) -> Result<(boot_params, u64)> {
+        let elf_result =
+            kernel_loader::load_kernel(mem, GuestAddress(KERNEL_START_OFFSET), kernel_image);
+        if elf_result == Err(kernel_loader::Error::InvalidElfMagicNumber) {
+            bzimage::load_bzimage(mem, GuestAddress(KERNEL_START_OFFSET), kernel_image)
+                .map_err(Error::LoadBzImage)
+        } else {
+            let kernel_end = elf_result.map_err(Error::LoadKernel)?;
+            Ok((Default::default(), kernel_end))
+        }
+    }
+
+    /// Configures the system memory space should be called once per vm before
+    /// starting vcpu threads.
+    ///
+    /// # Arguments
+    ///
+    /// * `mem` - The memory to be used by the guest.
+    /// * `vcpu_count` - Number of virtual CPUs the guest will have.
+    /// * `cmdline` - the kernel commandline
+    /// * `initrd_file` - an initial ramdisk image
+    fn setup_system_memory(
+        mem: &GuestMemory,
+        mem_size: u64,
+        vcpu_count: u32,
+        cmdline: &CStr,
+        initrd_file: Option<File>,
+        pci_irqs: Vec<(u32, PciInterruptPin)>,
+        android_fstab: Option<File>,
+        kernel_end: u64,
+        params: boot_params,
+    ) -> Result<()> {
+        kernel_loader::load_cmdline(mem, GuestAddress(CMDLINE_OFFSET), cmdline)
+            .map_err(Error::LoadCmdline)?;
+
+        // Track the first free address after the kernel - this is where extra
+        // data like the device tree blob and initrd will be loaded.
+        let mut free_addr = kernel_end;
+
+        let setup_data = if let Some(android_fstab) = android_fstab {
+            let free_addr_aligned = (((free_addr + 64 - 1) / 64) * 64) + 64;
+            let dtb_start = GuestAddress(free_addr_aligned);
+            let dtb_size = fdt::create_fdt(
+                X86_64_FDT_MAX_SIZE as usize,
+                mem,
+                dtb_start.offset(),
+                android_fstab,
+            )
+            .map_err(Error::CreateFdt)?;
+            free_addr = dtb_start.offset() + dtb_size as u64;
+            Some(dtb_start)
+        } else {
+            None
+        };
+
+        let initrd = match initrd_file {
+            Some(mut initrd_file) => {
+                let mut initrd_addr_max = u64::from(params.hdr.initrd_addr_max);
+                // Default initrd_addr_max for old kernels (see Documentation/x86/boot.txt).
+                if initrd_addr_max == 0 {
+                    initrd_addr_max = 0x37FFFFFF;
+                }
+
+                let mem_max = mem.end_addr().offset() - 1;
+                if initrd_addr_max > mem_max {
+                    initrd_addr_max = mem_max;
+                }
+
+                let (initrd_start, initrd_size) = arch::load_image_high(
+                    mem,
+                    &mut initrd_file,
+                    GuestAddress(free_addr),
+                    GuestAddress(initrd_addr_max),
+                    sys_util::pagesize() as u64,
+                )
+                .map_err(Error::LoadInitrd)?;
+                Some((initrd_start, initrd_size))
+            }
+            None => None,
+        };
+
+        configure_system(
+            mem,
+            mem_size,
+            GuestAddress(KERNEL_START_OFFSET),
+            GuestAddress(CMDLINE_OFFSET),
+            cmdline.to_bytes().len() + 1,
+            vcpu_count as u8,
+            pci_irqs,
+            setup_data,
+            initrd,
+            params,
+        )?;
+        Ok(())
+    }
+
+    /// Creates a new VM object and initializes architecture specific devices
+    ///
+    /// # Arguments
+    ///
+    /// * `kvm` - The opened /dev/kvm object.
+    /// * `split_irqchip` - Whether to use a split IRQ chip.
+    /// * `mem` - The memory to be used by the guest.
+    fn create_vm(kvm: &Kvm, split_irqchip: bool, mem: GuestMemory) -> Result<Vm> {
+        let vm = Vm::new(&kvm, mem).map_err(Error::CreateVm)?;
+        let tss_addr = GuestAddress(0xfffbd000);
+        vm.set_tss_addr(tss_addr).map_err(Error::SetTssAddr)?;
+        if !split_irqchip {
+            vm.create_pit().map_err(Error::CreatePit)?;
+            vm.create_irq_chip().map_err(Error::CreateIrqChip)?;
+        }
+        Ok(vm)
+    }
+
+    /// This creates a GuestMemory object for this VM
+    ///
+    /// * `mem_size` - Desired physical memory size in bytes for this VM
+    fn setup_memory(mem_size: u64, has_bios: bool) -> Result<GuestMemory> {
+        let arch_mem_regions = arch_memory_regions(mem_size, has_bios);
+        let mem = GuestMemory::new(&arch_mem_regions).map_err(Error::SetupGuestMemory)?;
+        Ok(mem)
+    }
+
+    /// The creates the interrupt controller device and optionally returns the fd for it.
+    /// Some architectures may not have a separate descriptor for the interrupt
+    /// controller, so they would return None even on success.
+    ///
+    /// # Arguments
+    ///
+    /// * `vm` - the vm object
+    fn create_irq_chip(_vm: &kvm::Vm) -> Result<Option<File>> {
+        // Unfortunately X86 and ARM have to do this in completely different order
+        // X86 needs to create the irq chip before creating cpus and
+        // ARM needs to do it afterwards.
+        Ok(None)
+    }
+
+    /// This returns the first page frame number for use by the balloon driver.
+    ///
+    /// # Arguments
+    ///
+    /// * `mem_size` - the size in bytes of physical ram for the guest
+    fn get_base_dev_pfn(mem_size: u64) -> u64 {
+        // Put device memory at a 2MB boundary after physical memory or 4gb, whichever is greater.
+        const MB: u64 = 1024 * 1024;
+        const GB: u64 = 1024 * MB;
+        let mem_size_round_2mb = (mem_size + 2 * MB - 1) / (2 * MB) * (2 * MB);
+        std::cmp::max(mem_size_round_2mb, 4 * GB) / sys_util::pagesize() as u64
+    }
+
+    /// This returns a minimal kernel command for this architecture
+    fn get_base_linux_cmdline(stdio_serial_num: Option<u8>) -> kernel_cmdline::Cmdline {
+        let mut cmdline = kernel_cmdline::Cmdline::new(CMDLINE_MAX_SIZE as usize);
+        if stdio_serial_num.is_some() {
+            let tty_string = get_serial_tty_string(stdio_serial_num.unwrap());
+            cmdline.insert("console", &tty_string).unwrap();
+        }
+        cmdline.insert_str("noacpi reboot=k panic=-1").unwrap();
+
+        cmdline
+    }
+
+    /// Returns a system resource allocator.
+    fn get_resource_allocator(mem_size: u64, gpu_allocation: bool) -> SystemAllocator {
+        const MMIO_BASE: u64 = 0xe0000000;
+        let device_addr_start = Self::get_base_dev_pfn(mem_size) * sys_util::pagesize() as u64;
+        SystemAllocator::builder()
+            .add_io_addresses(0xc000, 0x10000)
+            .add_mmio_addresses(MMIO_BASE, 0x100000)
+            .add_device_addresses(device_addr_start, u64::max_value() - device_addr_start)
+            .create_allocator(X86_64_IRQ_BASE, gpu_allocation)
+            .unwrap()
+    }
+
+    /// Sets up the IO bus for this platform
+    ///
+    /// # Arguments
+    ///
+    /// * - `vm` the vm object
+    /// * - `split_irqchip`: whether to use a split IRQ chip (i.e. userspace PIT/PIC/IOAPIC)
+    /// * - `exit_evt` - the event fd object which should receive exit events
+    /// * - `mem_size` - the size in bytes of physical ram for the guest
+    fn setup_io_bus(
+        vm: &mut Vm,
+        split_irqchip: bool,
+        exit_evt: EventFd,
+        pci: Option<Arc<Mutex<devices::PciConfigIo>>>,
+        mem_size: u64,
+    ) -> Result<(devices::Bus)> {
+        struct NoDevice;
+        impl devices::BusDevice for NoDevice {
+            fn debug_label(&self) -> String {
+                "no device".to_owned()
+            }
+        }
+
+        let mut io_bus = devices::Bus::new();
+
+        let mem_gap_start = FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE;
+        let mem_below_4g = std::cmp::min(mem_gap_start, mem_size);
+        let mem_above_4g = mem_size.saturating_sub(FIRST_ADDR_PAST_32BITS);
+
+        io_bus
+            .insert(
+                Arc::new(Mutex::new(devices::Cmos::new(mem_below_4g, mem_above_4g))),
+                0x70,
+                0x2,
+                false,
+            )
+            .unwrap();
+        io_bus
+            .insert(
+                Arc::new(Mutex::new(devices::I8042Device::new(
+                    exit_evt.try_clone().map_err(Error::CloneEventFd)?,
+                ))),
+                0x061,
+                0x4,
+                false,
+            )
+            .unwrap();
+
+        let nul_device = Arc::new(Mutex::new(NoDevice));
+        if split_irqchip {
+            let pit_evt = EventFd::new().map_err(Error::CreateEventFd)?;
+            let pit = Arc::new(Mutex::new(
+                devices::Pit::new(
+                    pit_evt.try_clone().map_err(Error::CloneEventFd)?,
+                    Arc::new(Mutex::new(Clock::new())),
+                )
+                .map_err(Error::CreatePitDevice)?,
+            ));
+            // Reserve from 0x40 to 0x61 (the speaker).
+            io_bus.insert(pit.clone(), 0x040, 0x22, false).unwrap();
+            vm.register_irqfd(&pit_evt, 0)
+                .map_err(Error::RegisterIrqfd)?;
+        } else {
+            io_bus
+                .insert(nul_device.clone(), 0x040, 0x8, false)
+                .unwrap(); // ignore pit
+        }
+
+        io_bus
+            .insert(nul_device.clone(), 0x0ed, 0x1, false)
+            .unwrap(); // most likely this one does nothing
+        io_bus
+            .insert(nul_device.clone(), 0x0f0, 0x2, false)
+            .unwrap(); // ignore fpu
+
+        if let Some(pci_root) = pci {
+            io_bus.insert(pci_root, 0xcf8, 0x8, false).unwrap();
+        } else {
+            // ignore pci.
+            io_bus
+                .insert(nul_device.clone(), 0xcf8, 0x8, false)
+                .unwrap();
+        }
+
+        Ok(io_bus)
+    }
+
+    /// Sets up the serial devices for this platform. Returns the serial port number and serial
+    /// device to be used for stdout
+    ///
+    /// # Arguments
+    ///
+    /// * - `vm` the vm object
+    /// * - `io_bus` the I/O bus to add the devices to
+    /// * - `serial_parmaters` - definitions for how the serial devices should be configured
+    fn setup_serial_devices(
+        vm: &mut Vm,
+        io_bus: &mut devices::Bus,
+        serial_parameters: &BTreeMap<u8, SerialParameters>,
+    ) -> Result<(Option<u8>, Option<Arc<Mutex<devices::Serial>>>)> {
+        let com_evt_1_3 = EventFd::new().map_err(Error::CreateEventFd)?;
+        let com_evt_2_4 = EventFd::new().map_err(Error::CreateEventFd)?;
+
+        let (stdio_serial_num, stdio_serial) =
+            arch::add_serial_devices(io_bus, &com_evt_1_3, &com_evt_2_4, &serial_parameters)
+                .map_err(Error::CreateSerialDevices)?;
+
+        vm.register_irqfd(&com_evt_1_3, X86_64_SERIAL_1_3_IRQ)
+            .map_err(Error::RegisterIrqfd)?;
+        vm.register_irqfd(&com_evt_2_4, X86_64_SERIAL_2_4_IRQ)
+            .map_err(Error::RegisterIrqfd)?;
+
+        Ok((stdio_serial_num, stdio_serial))
+    }
+
+    /// Configures the vcpu and should be called once per vcpu from the vcpu's thread.
+    ///
+    /// # Arguments
+    ///
+    /// * `guest_mem` - The memory to be used by the guest.
+    /// * `kernel_load_offset` - Offset in bytes from `guest_mem` at which the
+    ///                          kernel starts.
+    /// * `kvm` - The /dev/kvm object that created vcpu.
+    /// * `vm` - The VM object associated with this VCPU.
+    /// * `vcpu` - The VCPU object to configure.
+    /// * `cpu_id` - The id of the given `vcpu`.
+    /// * `num_cpus` - Number of virtual CPUs the guest will have.
+    fn configure_vcpu(
+        guest_mem: &GuestMemory,
+        kvm: &Kvm,
+        _vm: &Vm,
+        vcpu: &Vcpu,
+        cpu_id: u64,
+        num_cpus: u64,
+    ) -> Result<()> {
+        let kernel_load_addr = GuestAddress(KERNEL_START_OFFSET);
+        cpuid::setup_cpuid(kvm, vcpu, cpu_id, num_cpus).map_err(Error::SetupCpuid)?;
+        regs::setup_msrs(vcpu).map_err(Error::SetupMsrs)?;
+        let kernel_end = guest_mem
+            .checked_offset(kernel_load_addr, KERNEL_64BIT_ENTRY_OFFSET)
+            .ok_or(Error::KernelOffsetPastEnd)?;
+        regs::setup_regs(
+            vcpu,
+            (kernel_end).offset() as u64,
+            BOOT_STACK_POINTER as u64,
+            ZERO_PAGE_OFFSET as u64,
+        )
+        .map_err(Error::SetupRegs)?;
+        regs::setup_fpu(vcpu).map_err(Error::SetupFpu)?;
+        regs::setup_sregs(guest_mem, vcpu).map_err(Error::SetupSregs)?;
+        interrupts::set_lint(vcpu).map_err(Error::SetLint)?;
+        Ok(())
+    }
+}
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn regions_lt_4gb_nobios() {
+        let regions = arch_memory_regions(1u64 << 29, /* has_bios */ false);
+        assert_eq!(1, regions.len());
+        assert_eq!(GuestAddress(0), regions[0].0);
+        assert_eq!(1u64 << 29, regions[0].1);
+    }
+
+    #[test]
+    fn regions_gt_4gb_nobios() {
+        let regions = arch_memory_regions((1u64 << 32) + 0x8000, /* has_bios */ false);
+        assert_eq!(2, regions.len());
+        assert_eq!(GuestAddress(0), regions[0].0);
+        assert_eq!(GuestAddress(1u64 << 32), regions[1].0);
+    }
+
+    #[test]
+    fn regions_lt_4gb_bios() {
+        let regions = arch_memory_regions(1u64 << 29, /* has_bios */ true);
+        assert_eq!(2, regions.len());
+        assert_eq!(GuestAddress(0), regions[0].0);
+        assert_eq!(1u64 << 29, regions[0].1);
+        assert_eq!(GuestAddress(BIOS_START), regions[1].0);
+        assert_eq!(BIOS_LEN as u64, regions[1].1);
+    }
+
+    #[test]
+    fn regions_gt_4gb_bios() {
+        let regions = arch_memory_regions((1u64 << 32) + 0x8000, /* has_bios */ true);
+        assert_eq!(2, regions.len());
+        assert_eq!(GuestAddress(0), regions[0].0);
+        assert_eq!(GuestAddress(BIOS_START), regions[1].0);
+    }
+}
diff --git a/x86_64/src/mpspec.rs b/x86_64/src/mpspec.rs
new file mode 100644
index 0000000..ab7af51
--- /dev/null
+++ b/x86_64/src/mpspec.rs
@@ -0,0 +1,832 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* automatically generated by rust-bindgen */
+
+pub const MPC_SIGNATURE: &'static [u8; 5usize] = b"PCMP\x00";
+pub const MP_PROCESSOR: ::std::os::raw::c_uint = 0;
+pub const MP_BUS: ::std::os::raw::c_uint = 1;
+pub const MP_IOAPIC: ::std::os::raw::c_uint = 2;
+pub const MP_INTSRC: ::std::os::raw::c_uint = 3;
+pub const MP_LINTSRC: ::std::os::raw::c_uint = 4;
+pub const MP_TRANSLATION: ::std::os::raw::c_uint = 192;
+pub const CPU_ENABLED: ::std::os::raw::c_uint = 1;
+pub const CPU_BOOTPROCESSOR: ::std::os::raw::c_uint = 2;
+pub const CPU_STEPPING_MASK: ::std::os::raw::c_uint = 15;
+pub const CPU_MODEL_MASK: ::std::os::raw::c_uint = 240;
+pub const CPU_FAMILY_MASK: ::std::os::raw::c_uint = 3840;
+pub const BUSTYPE_EISA: &'static [u8; 5usize] = b"EISA\x00";
+pub const BUSTYPE_ISA: &'static [u8; 4usize] = b"ISA\x00";
+pub const BUSTYPE_INTERN: &'static [u8; 7usize] = b"INTERN\x00";
+pub const BUSTYPE_MCA: &'static [u8; 4usize] = b"MCA\x00";
+pub const BUSTYPE_VL: &'static [u8; 3usize] = b"VL\x00";
+pub const BUSTYPE_PCI: &'static [u8; 4usize] = b"PCI\x00";
+pub const BUSTYPE_PCMCIA: &'static [u8; 7usize] = b"PCMCIA\x00";
+pub const BUSTYPE_CBUS: &'static [u8; 5usize] = b"CBUS\x00";
+pub const BUSTYPE_CBUSII: &'static [u8; 7usize] = b"CBUSII\x00";
+pub const BUSTYPE_FUTURE: &'static [u8; 7usize] = b"FUTURE\x00";
+pub const BUSTYPE_MBI: &'static [u8; 4usize] = b"MBI\x00";
+pub const BUSTYPE_MBII: &'static [u8; 5usize] = b"MBII\x00";
+pub const BUSTYPE_MPI: &'static [u8; 4usize] = b"MPI\x00";
+pub const BUSTYPE_MPSA: &'static [u8; 5usize] = b"MPSA\x00";
+pub const BUSTYPE_NUBUS: &'static [u8; 6usize] = b"NUBUS\x00";
+pub const BUSTYPE_TC: &'static [u8; 3usize] = b"TC\x00";
+pub const BUSTYPE_VME: &'static [u8; 4usize] = b"VME\x00";
+pub const BUSTYPE_XPRESS: &'static [u8; 7usize] = b"XPRESS\x00";
+pub const MPC_APIC_USABLE: ::std::os::raw::c_uint = 1;
+pub const MP_IRQDIR_DEFAULT: ::std::os::raw::c_uint = 0;
+pub const MP_IRQDIR_HIGH: ::std::os::raw::c_uint = 1;
+pub const MP_IRQDIR_LOW: ::std::os::raw::c_uint = 3;
+pub const MP_APIC_ALL: ::std::os::raw::c_uint = 255;
+pub const MPC_OEM_SIGNATURE: &'static [u8; 5usize] = b"_OEM\x00";
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct mpf_intel {
+    pub signature: [::std::os::raw::c_char; 4usize],
+    pub physptr: ::std::os::raw::c_uint,
+    pub length: ::std::os::raw::c_uchar,
+    pub specification: ::std::os::raw::c_uchar,
+    pub checksum: ::std::os::raw::c_uchar,
+    pub feature1: ::std::os::raw::c_uchar,
+    pub feature2: ::std::os::raw::c_uchar,
+    pub feature3: ::std::os::raw::c_uchar,
+    pub feature4: ::std::os::raw::c_uchar,
+    pub feature5: ::std::os::raw::c_uchar,
+}
+#[test]
+fn bindgen_test_layout_mpf_intel() {
+    assert_eq!(
+        ::std::mem::size_of::<mpf_intel>(),
+        16usize,
+        concat!("Size of: ", stringify!(mpf_intel))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<mpf_intel>(),
+        4usize,
+        concat!("Alignment of ", stringify!(mpf_intel))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpf_intel)).signature as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpf_intel),
+            "::",
+            stringify!(signature)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpf_intel)).physptr as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpf_intel),
+            "::",
+            stringify!(physptr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpf_intel)).length as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpf_intel),
+            "::",
+            stringify!(length)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpf_intel)).specification as *const _ as usize },
+        9usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpf_intel),
+            "::",
+            stringify!(specification)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpf_intel)).checksum as *const _ as usize },
+        10usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpf_intel),
+            "::",
+            stringify!(checksum)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpf_intel)).feature1 as *const _ as usize },
+        11usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpf_intel),
+            "::",
+            stringify!(feature1)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpf_intel)).feature2 as *const _ as usize },
+        12usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpf_intel),
+            "::",
+            stringify!(feature2)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpf_intel)).feature3 as *const _ as usize },
+        13usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpf_intel),
+            "::",
+            stringify!(feature3)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpf_intel)).feature4 as *const _ as usize },
+        14usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpf_intel),
+            "::",
+            stringify!(feature4)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpf_intel)).feature5 as *const _ as usize },
+        15usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpf_intel),
+            "::",
+            stringify!(feature5)
+        )
+    );
+}
+impl Clone for mpf_intel {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct mpc_table {
+    pub signature: [::std::os::raw::c_char; 4usize],
+    pub length: ::std::os::raw::c_ushort,
+    pub spec: ::std::os::raw::c_char,
+    pub checksum: ::std::os::raw::c_char,
+    pub oem: [::std::os::raw::c_char; 8usize],
+    pub productid: [::std::os::raw::c_char; 12usize],
+    pub oemptr: ::std::os::raw::c_uint,
+    pub oemsize: ::std::os::raw::c_ushort,
+    pub oemcount: ::std::os::raw::c_ushort,
+    pub lapic: ::std::os::raw::c_uint,
+    pub reserved: ::std::os::raw::c_uint,
+}
+#[test]
+fn bindgen_test_layout_mpc_table() {
+    assert_eq!(
+        ::std::mem::size_of::<mpc_table>(),
+        44usize,
+        concat!("Size of: ", stringify!(mpc_table))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<mpc_table>(),
+        4usize,
+        concat!("Alignment of ", stringify!(mpc_table))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_table)).signature as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_table),
+            "::",
+            stringify!(signature)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_table)).length as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_table),
+            "::",
+            stringify!(length)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_table)).spec as *const _ as usize },
+        6usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_table),
+            "::",
+            stringify!(spec)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_table)).checksum as *const _ as usize },
+        7usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_table),
+            "::",
+            stringify!(checksum)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_table)).oem as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_table),
+            "::",
+            stringify!(oem)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_table)).productid as *const _ as usize },
+        16usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_table),
+            "::",
+            stringify!(productid)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_table)).oemptr as *const _ as usize },
+        28usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_table),
+            "::",
+            stringify!(oemptr)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_table)).oemsize as *const _ as usize },
+        32usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_table),
+            "::",
+            stringify!(oemsize)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_table)).oemcount as *const _ as usize },
+        34usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_table),
+            "::",
+            stringify!(oemcount)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_table)).lapic as *const _ as usize },
+        36usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_table),
+            "::",
+            stringify!(lapic)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_table)).reserved as *const _ as usize },
+        40usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_table),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+impl Clone for mpc_table {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct mpc_cpu {
+    pub type_: ::std::os::raw::c_uchar,
+    pub apicid: ::std::os::raw::c_uchar,
+    pub apicver: ::std::os::raw::c_uchar,
+    pub cpuflag: ::std::os::raw::c_uchar,
+    pub cpufeature: ::std::os::raw::c_uint,
+    pub featureflag: ::std::os::raw::c_uint,
+    pub reserved: [::std::os::raw::c_uint; 2usize],
+}
+#[test]
+fn bindgen_test_layout_mpc_cpu() {
+    assert_eq!(
+        ::std::mem::size_of::<mpc_cpu>(),
+        20usize,
+        concat!("Size of: ", stringify!(mpc_cpu))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<mpc_cpu>(),
+        4usize,
+        concat!("Alignment of ", stringify!(mpc_cpu))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_cpu)).type_ as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_cpu),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_cpu)).apicid as *const _ as usize },
+        1usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_cpu),
+            "::",
+            stringify!(apicid)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_cpu)).apicver as *const _ as usize },
+        2usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_cpu),
+            "::",
+            stringify!(apicver)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_cpu)).cpuflag as *const _ as usize },
+        3usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_cpu),
+            "::",
+            stringify!(cpuflag)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_cpu)).cpufeature as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_cpu),
+            "::",
+            stringify!(cpufeature)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_cpu)).featureflag as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_cpu),
+            "::",
+            stringify!(featureflag)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_cpu)).reserved as *const _ as usize },
+        12usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_cpu),
+            "::",
+            stringify!(reserved)
+        )
+    );
+}
+impl Clone for mpc_cpu {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct mpc_bus {
+    pub type_: ::std::os::raw::c_uchar,
+    pub busid: ::std::os::raw::c_uchar,
+    pub bustype: [::std::os::raw::c_uchar; 6usize],
+}
+#[test]
+fn bindgen_test_layout_mpc_bus() {
+    assert_eq!(
+        ::std::mem::size_of::<mpc_bus>(),
+        8usize,
+        concat!("Size of: ", stringify!(mpc_bus))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<mpc_bus>(),
+        1usize,
+        concat!("Alignment of ", stringify!(mpc_bus))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_bus)).type_ as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_bus),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_bus)).busid as *const _ as usize },
+        1usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_bus),
+            "::",
+            stringify!(busid)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_bus)).bustype as *const _ as usize },
+        2usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_bus),
+            "::",
+            stringify!(bustype)
+        )
+    );
+}
+impl Clone for mpc_bus {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct mpc_ioapic {
+    pub type_: ::std::os::raw::c_uchar,
+    pub apicid: ::std::os::raw::c_uchar,
+    pub apicver: ::std::os::raw::c_uchar,
+    pub flags: ::std::os::raw::c_uchar,
+    pub apicaddr: ::std::os::raw::c_uint,
+}
+#[test]
+fn bindgen_test_layout_mpc_ioapic() {
+    assert_eq!(
+        ::std::mem::size_of::<mpc_ioapic>(),
+        8usize,
+        concat!("Size of: ", stringify!(mpc_ioapic))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<mpc_ioapic>(),
+        4usize,
+        concat!("Alignment of ", stringify!(mpc_ioapic))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_ioapic)).type_ as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_ioapic),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_ioapic)).apicid as *const _ as usize },
+        1usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_ioapic),
+            "::",
+            stringify!(apicid)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_ioapic)).apicver as *const _ as usize },
+        2usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_ioapic),
+            "::",
+            stringify!(apicver)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_ioapic)).flags as *const _ as usize },
+        3usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_ioapic),
+            "::",
+            stringify!(flags)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_ioapic)).apicaddr as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_ioapic),
+            "::",
+            stringify!(apicaddr)
+        )
+    );
+}
+impl Clone for mpc_ioapic {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct mpc_intsrc {
+    pub type_: ::std::os::raw::c_uchar,
+    pub irqtype: ::std::os::raw::c_uchar,
+    pub irqflag: ::std::os::raw::c_ushort,
+    pub srcbus: ::std::os::raw::c_uchar,
+    pub srcbusirq: ::std::os::raw::c_uchar,
+    pub dstapic: ::std::os::raw::c_uchar,
+    pub dstirq: ::std::os::raw::c_uchar,
+}
+#[test]
+fn bindgen_test_layout_mpc_intsrc() {
+    assert_eq!(
+        ::std::mem::size_of::<mpc_intsrc>(),
+        8usize,
+        concat!("Size of: ", stringify!(mpc_intsrc))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<mpc_intsrc>(),
+        2usize,
+        concat!("Alignment of ", stringify!(mpc_intsrc))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_intsrc)).type_ as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_intsrc),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_intsrc)).irqtype as *const _ as usize },
+        1usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_intsrc),
+            "::",
+            stringify!(irqtype)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_intsrc)).irqflag as *const _ as usize },
+        2usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_intsrc),
+            "::",
+            stringify!(irqflag)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_intsrc)).srcbus as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_intsrc),
+            "::",
+            stringify!(srcbus)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_intsrc)).srcbusirq as *const _ as usize },
+        5usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_intsrc),
+            "::",
+            stringify!(srcbusirq)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_intsrc)).dstapic as *const _ as usize },
+        6usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_intsrc),
+            "::",
+            stringify!(dstapic)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_intsrc)).dstirq as *const _ as usize },
+        7usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_intsrc),
+            "::",
+            stringify!(dstirq)
+        )
+    );
+}
+impl Clone for mpc_intsrc {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+pub const mp_irq_source_types_mp_INT: mp_irq_source_types = 0;
+pub const mp_irq_source_types_mp_NMI: mp_irq_source_types = 1;
+pub const mp_irq_source_types_mp_SMI: mp_irq_source_types = 2;
+pub const mp_irq_source_types_mp_ExtINT: mp_irq_source_types = 3;
+pub type mp_irq_source_types = ::std::os::raw::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct mpc_lintsrc {
+    pub type_: ::std::os::raw::c_uchar,
+    pub irqtype: ::std::os::raw::c_uchar,
+    pub irqflag: ::std::os::raw::c_ushort,
+    pub srcbusid: ::std::os::raw::c_uchar,
+    pub srcbusirq: ::std::os::raw::c_uchar,
+    pub destapic: ::std::os::raw::c_uchar,
+    pub destapiclint: ::std::os::raw::c_uchar,
+}
+#[test]
+fn bindgen_test_layout_mpc_lintsrc() {
+    assert_eq!(
+        ::std::mem::size_of::<mpc_lintsrc>(),
+        8usize,
+        concat!("Size of: ", stringify!(mpc_lintsrc))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<mpc_lintsrc>(),
+        2usize,
+        concat!("Alignment of ", stringify!(mpc_lintsrc))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_lintsrc)).type_ as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_lintsrc),
+            "::",
+            stringify!(type_)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_lintsrc)).irqtype as *const _ as usize },
+        1usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_lintsrc),
+            "::",
+            stringify!(irqtype)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_lintsrc)).irqflag as *const _ as usize },
+        2usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_lintsrc),
+            "::",
+            stringify!(irqflag)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_lintsrc)).srcbusid as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_lintsrc),
+            "::",
+            stringify!(srcbusid)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_lintsrc)).srcbusirq as *const _ as usize },
+        5usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_lintsrc),
+            "::",
+            stringify!(srcbusirq)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_lintsrc)).destapic as *const _ as usize },
+        6usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_lintsrc),
+            "::",
+            stringify!(destapic)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_lintsrc)).destapiclint as *const _ as usize },
+        7usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_lintsrc),
+            "::",
+            stringify!(destapiclint)
+        )
+    );
+}
+impl Clone for mpc_lintsrc {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct mpc_oemtable {
+    pub signature: [::std::os::raw::c_char; 4usize],
+    pub length: ::std::os::raw::c_ushort,
+    pub rev: ::std::os::raw::c_char,
+    pub checksum: ::std::os::raw::c_char,
+    pub mpc: [::std::os::raw::c_char; 8usize],
+}
+#[test]
+fn bindgen_test_layout_mpc_oemtable() {
+    assert_eq!(
+        ::std::mem::size_of::<mpc_oemtable>(),
+        16usize,
+        concat!("Size of: ", stringify!(mpc_oemtable))
+    );
+    assert_eq!(
+        ::std::mem::align_of::<mpc_oemtable>(),
+        2usize,
+        concat!("Alignment of ", stringify!(mpc_oemtable))
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_oemtable)).signature as *const _ as usize },
+        0usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_oemtable),
+            "::",
+            stringify!(signature)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_oemtable)).length as *const _ as usize },
+        4usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_oemtable),
+            "::",
+            stringify!(length)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_oemtable)).rev as *const _ as usize },
+        6usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_oemtable),
+            "::",
+            stringify!(rev)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_oemtable)).checksum as *const _ as usize },
+        7usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_oemtable),
+            "::",
+            stringify!(checksum)
+        )
+    );
+    assert_eq!(
+        unsafe { &(*(0 as *const mpc_oemtable)).mpc as *const _ as usize },
+        8usize,
+        concat!(
+            "Alignment of field: ",
+            stringify!(mpc_oemtable),
+            "::",
+            stringify!(mpc)
+        )
+    );
+}
+impl Clone for mpc_oemtable {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+pub const mp_bustype_MP_BUS_ISA: mp_bustype = 1;
+pub const mp_bustype_MP_BUS_EISA: mp_bustype = 2;
+pub const mp_bustype_MP_BUS_PCI: mp_bustype = 3;
+pub type mp_bustype = ::std::os::raw::c_uint;
diff --git a/x86_64/src/mptable.rs b/x86_64/src/mptable.rs
new file mode 100644
index 0000000..8b754bd
--- /dev/null
+++ b/x86_64/src/mptable.rs
@@ -0,0 +1,448 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fmt::{self, Display};
+use std::mem;
+use std::result;
+use std::slice;
+
+use libc::c_char;
+
+use data_model::VolatileMemory;
+use devices::PciInterruptPin;
+use sys_util::{GuestAddress, GuestMemory};
+
+use crate::mpspec::*;
+
+#[derive(Debug)]
+pub enum Error {
+    /// There was too little guest memory to store the entire MP table.
+    NotEnoughMemory,
+    /// The MP table has too little address space to be stored.
+    AddressOverflow,
+    /// Failure while zeroing out the memory for the MP table.
+    Clear,
+    /// Failure to write the MP floating pointer.
+    WriteMpfIntel,
+    /// Failure to write MP CPU entry.
+    WriteMpcCpu,
+    /// Failure to write MP ioapic entry.
+    WriteMpcIoapic,
+    /// Failure to write MP bus entry.
+    WriteMpcBus,
+    /// Failure to write MP interrupt source entry.
+    WriteMpcIntsrc,
+    /// Failure to write MP local interrupt source entry.
+    WriteMpcLintsrc,
+    /// Failure to write MP table header.
+    WriteMpcTable,
+}
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        let description = match self {
+            NotEnoughMemory => "There was too little guest memory to store the MP table",
+            AddressOverflow => "The MP table has too little address space to be stored",
+            Clear => "Failure while zeroing out the memory for the MP table",
+            WriteMpfIntel => "Failure to write the MP floating pointer",
+            WriteMpcCpu => "Failure to write MP CPU entry",
+            WriteMpcIoapic => "Failure to write MP ioapic entry",
+            WriteMpcBus => "Failure to write MP bus entry",
+            WriteMpcIntsrc => "Failure to write MP interrupt source entry",
+            WriteMpcLintsrc => "Failure to write MP local interrupt source entry",
+            WriteMpcTable => "Failure to write MP table header",
+        };
+
+        write!(f, "MPTable error: {}", description)
+    }
+}
+
+pub type Result<T> = result::Result<T, Error>;
+
+// Convenience macro for making arrays of diverse character types.
+macro_rules! char_array {
+    ($t:ty; $( $c:expr ),*) => ( [ $( $c as $t ),* ] )
+}
+
+// Most of these variables are sourced from the Intel MP Spec 1.4.
+const SMP_MAGIC_IDENT: [c_char; 4] = char_array!(c_char; '_', 'M', 'P', '_');
+const MPC_SIGNATURE: [c_char; 4] = char_array!(c_char; 'P', 'C', 'M', 'P');
+const MPC_SPEC: i8 = 4;
+const MPC_OEM: [c_char; 8] = char_array!(c_char; 'C', 'R', 'O', 'S', 'V', 'M', ' ', ' ');
+const MPC_PRODUCT_ID: [c_char; 12] = ['0' as c_char; 12];
+const BUS_TYPE_ISA: [u8; 6] = char_array!(u8; 'I', 'S', 'A', ' ', ' ', ' ');
+const BUS_TYPE_PCI: [u8; 6] = char_array!(u8; 'P', 'C', 'I', ' ', ' ', ' ');
+const IO_APIC_DEFAULT_PHYS_BASE: u32 = 0xfec00000; // source: linux/arch/x86/include/asm/apicdef.h
+const APIC_DEFAULT_PHYS_BASE: u32 = 0xfee00000; // source: linux/arch/x86/include/asm/apicdef.h
+const APIC_VERSION: u8 = 0x14;
+const CPU_STEPPING: u32 = 0x600;
+const CPU_FEATURE_APIC: u32 = 0x200;
+const CPU_FEATURE_FPU: u32 = 0x001;
+const MPTABLE_START: u64 = 0x400 * 639; // Last 1k of Linux's 640k base RAM.
+
+fn compute_checksum<T: Copy>(v: &T) -> u8 {
+    // Safe because we are only reading the bytes within the size of the `T` reference `v`.
+    let v_slice = unsafe { slice::from_raw_parts(v as *const T as *const u8, mem::size_of::<T>()) };
+    let mut checksum: u8 = 0;
+    for i in v_slice {
+        checksum = checksum.wrapping_add(*i);
+    }
+    checksum
+}
+
+fn mpf_intel_compute_checksum(v: &mpf_intel) -> u8 {
+    let checksum = compute_checksum(v).wrapping_sub(v.checksum);
+    (!checksum).wrapping_add(1)
+}
+
+fn compute_mp_size(num_cpus: u8) -> usize {
+    mem::size_of::<mpf_intel>()
+        + mem::size_of::<mpc_table>()
+        + mem::size_of::<mpc_cpu>() * (num_cpus as usize)
+        + mem::size_of::<mpc_ioapic>()
+        + mem::size_of::<mpc_bus>() * 2
+        + mem::size_of::<mpc_intsrc>()
+        + mem::size_of::<mpc_intsrc>() * 16
+        + mem::size_of::<mpc_lintsrc>() * 2
+}
+
+/// Performs setup of the MP table for the given `num_cpus`.
+pub fn setup_mptable(
+    mem: &GuestMemory,
+    num_cpus: u8,
+    pci_irqs: Vec<(u32, PciInterruptPin)>,
+) -> Result<()> {
+    const PCI_BUS_ID: u8 = 0;
+    const ISA_BUS_ID: u8 = 1;
+
+    // Used to keep track of the next base pointer into the MP table.
+    let mut base_mp = GuestAddress(MPTABLE_START);
+
+    let mp_size = compute_mp_size(num_cpus);
+
+    // The checked_add here ensures the all of the following base_mp.unchecked_add's will be without
+    // overflow.
+    if let Some(end_mp) = base_mp.checked_add(mp_size as u64 - 1) {
+        if !mem.address_in_range(end_mp) {
+            return Err(Error::NotEnoughMemory);
+        }
+    } else {
+        return Err(Error::AddressOverflow);
+    }
+
+    mem.get_slice(base_mp.0, mp_size as u64)
+        .map_err(|_| Error::Clear)?
+        .write_bytes(0);
+
+    {
+        let size = mem::size_of::<mpf_intel>();
+        let mut mpf_intel = mpf_intel::default();
+        mpf_intel.signature = SMP_MAGIC_IDENT;
+        mpf_intel.length = 1;
+        mpf_intel.specification = 4;
+        mpf_intel.physptr = (base_mp.offset() + mem::size_of::<mpf_intel>() as u64) as u32;
+        mpf_intel.checksum = mpf_intel_compute_checksum(&mpf_intel);
+        mem.write_obj_at_addr(mpf_intel, base_mp)
+            .map_err(|_| Error::WriteMpfIntel)?;
+        base_mp = base_mp.unchecked_add(size as u64);
+    }
+
+    // We set the location of the mpc_table here but we can't fill it out until we have the length
+    // of the entire table later.
+    let table_base = base_mp;
+    base_mp = base_mp.unchecked_add(mem::size_of::<mpc_table>() as u64);
+
+    let mut checksum: u8 = 0;
+    let ioapicid: u8 = num_cpus + 1;
+
+    for cpu_id in 0..num_cpus {
+        let size = mem::size_of::<mpc_cpu>();
+        let mut mpc_cpu = mpc_cpu::default();
+        mpc_cpu.type_ = MP_PROCESSOR as u8;
+        mpc_cpu.apicid = cpu_id;
+        mpc_cpu.apicver = APIC_VERSION;
+        mpc_cpu.cpuflag = CPU_ENABLED as u8
+            | if cpu_id == 0 {
+                CPU_BOOTPROCESSOR as u8
+            } else {
+                0
+            };
+        mpc_cpu.cpufeature = CPU_STEPPING;
+        mpc_cpu.featureflag = CPU_FEATURE_APIC | CPU_FEATURE_FPU;
+        mem.write_obj_at_addr(mpc_cpu, base_mp)
+            .map_err(|_| Error::WriteMpcCpu)?;
+        base_mp = base_mp.unchecked_add(size as u64);
+        checksum = checksum.wrapping_add(compute_checksum(&mpc_cpu));
+    }
+    {
+        let size = mem::size_of::<mpc_ioapic>();
+        let mut mpc_ioapic = mpc_ioapic::default();
+        mpc_ioapic.type_ = MP_IOAPIC as u8;
+        mpc_ioapic.apicid = ioapicid;
+        mpc_ioapic.apicver = APIC_VERSION;
+        mpc_ioapic.flags = MPC_APIC_USABLE as u8;
+        mpc_ioapic.apicaddr = IO_APIC_DEFAULT_PHYS_BASE;
+        mem.write_obj_at_addr(mpc_ioapic, base_mp)
+            .map_err(|_| Error::WriteMpcIoapic)?;
+        base_mp = base_mp.unchecked_add(size as u64);
+        checksum = checksum.wrapping_add(compute_checksum(&mpc_ioapic));
+    }
+    {
+        let size = mem::size_of::<mpc_bus>();
+        let mut mpc_bus = mpc_bus::default();
+        mpc_bus.type_ = MP_BUS as u8;
+        mpc_bus.busid = PCI_BUS_ID;
+        mpc_bus.bustype = BUS_TYPE_PCI;
+        mem.write_obj_at_addr(mpc_bus, base_mp)
+            .map_err(|_| Error::WriteMpcBus)?;
+        base_mp = base_mp.unchecked_add(size as u64);
+        checksum = checksum.wrapping_add(compute_checksum(&mpc_bus));
+    }
+    {
+        let size = mem::size_of::<mpc_bus>();
+        let mut mpc_bus = mpc_bus::default();
+        mpc_bus.type_ = MP_BUS as u8;
+        mpc_bus.busid = ISA_BUS_ID;
+        mpc_bus.bustype = BUS_TYPE_ISA;
+        mem.write_obj_at_addr(mpc_bus, base_mp)
+            .map_err(|_| Error::WriteMpcBus)?;
+        base_mp = base_mp.unchecked_add(size as u64);
+        checksum = checksum.wrapping_add(compute_checksum(&mpc_bus));
+    }
+    {
+        let size = mem::size_of::<mpc_intsrc>();
+        let mut mpc_intsrc = mpc_intsrc::default();
+        mpc_intsrc.type_ = MP_INTSRC as u8;
+        mpc_intsrc.irqtype = mp_irq_source_types_mp_INT as u8;
+        mpc_intsrc.irqflag = MP_IRQDIR_DEFAULT as u16;
+        mpc_intsrc.srcbus = ISA_BUS_ID;
+        mpc_intsrc.srcbusirq = 0;
+        mpc_intsrc.dstapic = 0;
+        mpc_intsrc.dstirq = 0;
+        mem.write_obj_at_addr(mpc_intsrc, base_mp)
+            .map_err(|_| Error::WriteMpcIntsrc)?;
+        base_mp = base_mp.unchecked_add(size as u64);
+        checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
+    }
+    // Per kvm_setup_default_irq_routing() in kernel
+    for i in 0..5 {
+        let size = mem::size_of::<mpc_intsrc>();
+        let mut mpc_intsrc = mpc_intsrc::default();
+        mpc_intsrc.type_ = MP_INTSRC as u8;
+        mpc_intsrc.irqtype = mp_irq_source_types_mp_INT as u8;
+        mpc_intsrc.irqflag = MP_IRQDIR_DEFAULT as u16;
+        mpc_intsrc.srcbus = ISA_BUS_ID;
+        mpc_intsrc.srcbusirq = i;
+        mpc_intsrc.dstapic = ioapicid;
+        mpc_intsrc.dstirq = i;
+        mem.write_obj_at_addr(mpc_intsrc, base_mp)
+            .map_err(|_| Error::WriteMpcIntsrc)?;
+        base_mp = base_mp.unchecked_add(size as u64);
+        checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
+    }
+    // Insert PCI interrupts after platform IRQs.
+    for (i, pci_irq) in pci_irqs.iter().enumerate() {
+        let size = mem::size_of::<mpc_intsrc>();
+        let mut mpc_intsrc = mpc_intsrc::default();
+        mpc_intsrc.type_ = MP_INTSRC as u8;
+        mpc_intsrc.irqtype = mp_irq_source_types_mp_INT as u8;
+        mpc_intsrc.irqflag = MP_IRQDIR_DEFAULT as u16;
+        mpc_intsrc.srcbus = PCI_BUS_ID;
+        mpc_intsrc.srcbusirq = (pci_irq.0 as u8 + 1) << 2 | pci_irq.1.to_mask() as u8;
+        mpc_intsrc.dstapic = ioapicid;
+        mpc_intsrc.dstirq = 5 + i as u8;
+        mem.write_obj_at_addr(mpc_intsrc, base_mp)
+            .map_err(|_| Error::WriteMpcIntsrc)?;
+        base_mp = base_mp.unchecked_add(size as u64);
+        checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
+    }
+    // Finally insert ISA interrupts.
+    for i in 5 + pci_irqs.len()..16 {
+        let size = mem::size_of::<mpc_intsrc>();
+        let mut mpc_intsrc = mpc_intsrc::default();
+        mpc_intsrc.type_ = MP_INTSRC as u8;
+        mpc_intsrc.irqtype = mp_irq_source_types_mp_INT as u8;
+        mpc_intsrc.irqflag = MP_IRQDIR_DEFAULT as u16;
+        mpc_intsrc.srcbus = ISA_BUS_ID;
+        mpc_intsrc.srcbusirq = i as u8;
+        mpc_intsrc.dstapic = ioapicid;
+        mpc_intsrc.dstirq = i as u8;
+        mem.write_obj_at_addr(mpc_intsrc, base_mp)
+            .map_err(|_| Error::WriteMpcIntsrc)?;
+        base_mp = base_mp.unchecked_add(size as u64);
+        checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
+    }
+    {
+        let size = mem::size_of::<mpc_lintsrc>();
+        let mut mpc_lintsrc = mpc_lintsrc::default();
+        mpc_lintsrc.type_ = MP_LINTSRC as u8;
+        mpc_lintsrc.irqtype = mp_irq_source_types_mp_ExtINT as u8;
+        mpc_lintsrc.irqflag = MP_IRQDIR_DEFAULT as u16;
+        mpc_lintsrc.srcbusid = ISA_BUS_ID;
+        mpc_lintsrc.srcbusirq = 0;
+        mpc_lintsrc.destapic = 0;
+        mpc_lintsrc.destapiclint = 0;
+        mem.write_obj_at_addr(mpc_lintsrc, base_mp)
+            .map_err(|_| Error::WriteMpcLintsrc)?;
+        base_mp = base_mp.unchecked_add(size as u64);
+        checksum = checksum.wrapping_add(compute_checksum(&mpc_lintsrc));
+    }
+    {
+        let size = mem::size_of::<mpc_lintsrc>();
+        let mut mpc_lintsrc = mpc_lintsrc::default();
+        mpc_lintsrc.type_ = MP_LINTSRC as u8;
+        mpc_lintsrc.irqtype = mp_irq_source_types_mp_NMI as u8;
+        mpc_lintsrc.irqflag = MP_IRQDIR_DEFAULT as u16;
+        mpc_lintsrc.srcbusid = ISA_BUS_ID;
+        mpc_lintsrc.srcbusirq = 0;
+        mpc_lintsrc.destapic = 0xFF; // Per SeaBIOS
+        mpc_lintsrc.destapiclint = 1;
+        mem.write_obj_at_addr(mpc_lintsrc, base_mp)
+            .map_err(|_| Error::WriteMpcLintsrc)?;
+        base_mp = base_mp.unchecked_add(size as u64);
+        checksum = checksum.wrapping_add(compute_checksum(&mpc_lintsrc));
+    }
+
+    // At this point we know the size of the mp_table.
+    let table_end = base_mp;
+
+    {
+        let mut mpc_table = mpc_table::default();
+        mpc_table.signature = MPC_SIGNATURE;
+        mpc_table.length = table_end.offset_from(table_base) as u16;
+        mpc_table.spec = MPC_SPEC;
+        mpc_table.oem = MPC_OEM;
+        mpc_table.productid = MPC_PRODUCT_ID;
+        mpc_table.lapic = APIC_DEFAULT_PHYS_BASE;
+        checksum = checksum.wrapping_add(compute_checksum(&mpc_table));
+        mpc_table.checksum = (!checksum).wrapping_add(1) as i8;
+        mem.write_obj_at_addr(mpc_table, table_base)
+            .map_err(|_| Error::WriteMpcTable)?;
+    }
+
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use sys_util::pagesize;
+
+    fn compute_page_aligned_mp_size(num_cpus: u8) -> u64 {
+        let mp_size = compute_mp_size(num_cpus);
+        let pg_size = pagesize();
+        (mp_size + pg_size - (mp_size % pg_size)) as u64
+    }
+
+    fn table_entry_size(type_: u8) -> usize {
+        match type_ as u32 {
+            MP_PROCESSOR => mem::size_of::<mpc_cpu>(),
+            MP_BUS => mem::size_of::<mpc_bus>(),
+            MP_IOAPIC => mem::size_of::<mpc_ioapic>(),
+            MP_INTSRC => mem::size_of::<mpc_intsrc>(),
+            MP_LINTSRC => mem::size_of::<mpc_lintsrc>(),
+            _ => panic!("unrecognized mpc table entry type: {}", type_),
+        }
+    }
+
+    #[test]
+    fn bounds_check() {
+        let num_cpus = 4;
+        let mem = GuestMemory::new(&[(
+            GuestAddress(MPTABLE_START),
+            compute_page_aligned_mp_size(num_cpus),
+        )])
+        .unwrap();
+
+        setup_mptable(&mem, num_cpus, Vec::new()).unwrap();
+    }
+
+    #[test]
+    fn bounds_check_fails() {
+        let num_cpus = 255;
+        let mem = GuestMemory::new(&[(GuestAddress(MPTABLE_START), 0x1000)]).unwrap();
+
+        assert!(setup_mptable(&mem, num_cpus, Vec::new()).is_err());
+    }
+
+    #[test]
+    fn mpf_intel_checksum() {
+        let num_cpus = 1;
+        let mem = GuestMemory::new(&[(
+            GuestAddress(MPTABLE_START),
+            compute_page_aligned_mp_size(num_cpus),
+        )])
+        .unwrap();
+
+        setup_mptable(&mem, num_cpus, Vec::new()).unwrap();
+
+        let mpf_intel = mem.read_obj_from_addr(GuestAddress(MPTABLE_START)).unwrap();
+
+        assert_eq!(mpf_intel_compute_checksum(&mpf_intel), mpf_intel.checksum);
+    }
+
+    #[test]
+    fn mpc_table_checksum() {
+        let num_cpus = 4;
+        let mem = GuestMemory::new(&[(
+            GuestAddress(MPTABLE_START),
+            compute_page_aligned_mp_size(num_cpus),
+        )])
+        .unwrap();
+
+        setup_mptable(&mem, num_cpus, Vec::new()).unwrap();
+
+        let mpf_intel: mpf_intel = mem.read_obj_from_addr(GuestAddress(MPTABLE_START)).unwrap();
+        let mpc_offset = GuestAddress(mpf_intel.physptr as u64);
+        let mpc_table: mpc_table = mem.read_obj_from_addr(mpc_offset).unwrap();
+
+        let mut buf = vec![0; mpc_table.length as usize];
+        mem.read_at_addr(&mut buf[..], mpc_offset).unwrap();
+        let mut sum: u8 = 0;
+        for &v in &buf {
+            sum = sum.wrapping_add(v);
+        }
+
+        assert_eq!(sum, 0);
+    }
+
+    #[test]
+    fn cpu_entry_count() {
+        const MAX_CPUS: u8 = 0xff;
+        let mem = GuestMemory::new(&[(
+            GuestAddress(MPTABLE_START),
+            compute_page_aligned_mp_size(MAX_CPUS),
+        )])
+        .unwrap();
+
+        for i in 0..MAX_CPUS {
+            setup_mptable(&mem, i, Vec::new()).unwrap();
+
+            let mpf_intel: mpf_intel = mem.read_obj_from_addr(GuestAddress(MPTABLE_START)).unwrap();
+            let mpc_offset = GuestAddress(mpf_intel.physptr as u64);
+            let mpc_table: mpc_table = mem.read_obj_from_addr(mpc_offset).unwrap();
+            let mpc_end = mpc_offset.checked_add(mpc_table.length as u64).unwrap();
+
+            let mut entry_offset = mpc_offset
+                .checked_add(mem::size_of::<mpc_table>() as u64)
+                .unwrap();
+            let mut cpu_count = 0;
+            while entry_offset < mpc_end {
+                let entry_type: u8 = mem.read_obj_from_addr(entry_offset).unwrap();
+                entry_offset = entry_offset
+                    .checked_add(table_entry_size(entry_type) as u64)
+                    .unwrap();
+                assert!(entry_offset <= mpc_end);
+                if entry_type as u32 == MP_PROCESSOR {
+                    cpu_count += 1;
+                }
+            }
+            assert_eq!(cpu_count, i);
+        }
+    }
+}
diff --git a/x86_64/src/msr_index.rs b/x86_64/src/msr_index.rs
new file mode 100644
index 0000000..f057835
--- /dev/null
+++ b/x86_64/src/msr_index.rs
@@ -0,0 +1,543 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/*
+ * automatically generated by rust-bindgen
+ * From upstream linux msr-index.h at commit:
+ * 806276b7f07a39a1cc3f38bb1ef5c573d4594a38
+ */
+
+pub const MSR_EFER: ::std::os::raw::c_uint = 0xc0000080;
+pub const MSR_STAR: ::std::os::raw::c_uint = 0xc0000081;
+pub const MSR_LSTAR: ::std::os::raw::c_uint = 0xc0000082;
+pub const MSR_CSTAR: ::std::os::raw::c_uint = 0xc0000083;
+pub const MSR_SYSCALL_MASK: ::std::os::raw::c_uint = 0xc0000084;
+pub const MSR_FS_BASE: ::std::os::raw::c_uint = 0xc0000100;
+pub const MSR_GS_BASE: ::std::os::raw::c_uint = 0xc0000101;
+pub const MSR_KERNEL_GS_BASE: ::std::os::raw::c_uint = 0xc0000102;
+pub const MSR_TSC_AUX: ::std::os::raw::c_uint = 0xc0000103;
+pub const _EFER_SCE: ::std::os::raw::c_uint = 0x00000000;
+pub const _EFER_LME: ::std::os::raw::c_uint = 0x00000008;
+pub const _EFER_LMA: ::std::os::raw::c_uint = 0x0000000a;
+pub const _EFER_NX: ::std::os::raw::c_uint = 0x0000000b;
+pub const _EFER_SVME: ::std::os::raw::c_uint = 0x0000000c;
+pub const _EFER_LMSLE: ::std::os::raw::c_uint = 0x0000000d;
+pub const _EFER_FFXSR: ::std::os::raw::c_uint = 0x0000000e;
+pub const EFER_SCE: ::std::os::raw::c_uint = 0x00000001;
+pub const EFER_LME: ::std::os::raw::c_uint = 0x00000100;
+pub const EFER_LMA: ::std::os::raw::c_uint = 0x00000400;
+pub const EFER_NX: ::std::os::raw::c_uint = 0x00000800;
+pub const EFER_SVME: ::std::os::raw::c_uint = 0x00001000;
+pub const EFER_LMSLE: ::std::os::raw::c_uint = 0x00002000;
+pub const EFER_FFXSR: ::std::os::raw::c_uint = 0x00004000;
+pub const MSR_PPIN_CTL: ::std::os::raw::c_uint = 0x0000004e;
+pub const MSR_PPIN: ::std::os::raw::c_uint = 0x0000004f;
+pub const MSR_IA32_PERFCTR0: ::std::os::raw::c_uint = 0x000000c1;
+pub const MSR_IA32_PERFCTR1: ::std::os::raw::c_uint = 0x000000c2;
+pub const MSR_FSB_FREQ: ::std::os::raw::c_uint = 0x000000cd;
+pub const MSR_PLATFORM_INFO: ::std::os::raw::c_uint = 0x000000ce;
+pub const MSR_PKG_CST_CONFIG_CONTROL: ::std::os::raw::c_uint = 0x000000e2;
+pub const NHM_C3_AUTO_DEMOTE: ::std::os::raw::c_uint = 0x02000000;
+pub const NHM_C1_AUTO_DEMOTE: ::std::os::raw::c_uint = 0x04000000;
+pub const ATM_LNC_C6_AUTO_DEMOTE: ::std::os::raw::c_uint = 0x02000000;
+pub const SNB_C1_AUTO_UNDEMOTE: ::std::os::raw::c_uint = 0x08000000;
+pub const SNB_C3_AUTO_UNDEMOTE: ::std::os::raw::c_uint = 0x10000000;
+pub const MSR_MTRRcap: ::std::os::raw::c_uint = 0x000000fe;
+pub const MSR_IA32_BBL_CR_CTL: ::std::os::raw::c_uint = 0x00000119;
+pub const MSR_IA32_BBL_CR_CTL3: ::std::os::raw::c_uint = 0x0000011e;
+pub const MSR_IA32_SYSENTER_CS: ::std::os::raw::c_uint = 0x00000174;
+pub const MSR_IA32_SYSENTER_ESP: ::std::os::raw::c_uint = 0x00000175;
+pub const MSR_IA32_SYSENTER_EIP: ::std::os::raw::c_uint = 0x00000176;
+pub const MSR_IA32_MCG_CAP: ::std::os::raw::c_uint = 0x00000179;
+pub const MSR_IA32_MCG_STATUS: ::std::os::raw::c_uint = 0x0000017a;
+pub const MSR_IA32_MCG_CTL: ::std::os::raw::c_uint = 0x0000017b;
+pub const MSR_IA32_MCG_EXT_CTL: ::std::os::raw::c_uint = 0x000004d0;
+pub const MSR_OFFCORE_RSP_0: ::std::os::raw::c_uint = 0x000001a6;
+pub const MSR_OFFCORE_RSP_1: ::std::os::raw::c_uint = 0x000001a7;
+pub const MSR_TURBO_RATIO_LIMIT: ::std::os::raw::c_uint = 0x000001ad;
+pub const MSR_TURBO_RATIO_LIMIT1: ::std::os::raw::c_uint = 0x000001ae;
+pub const MSR_TURBO_RATIO_LIMIT2: ::std::os::raw::c_uint = 0x000001af;
+pub const MSR_LBR_SELECT: ::std::os::raw::c_uint = 0x000001c8;
+pub const MSR_LBR_TOS: ::std::os::raw::c_uint = 0x000001c9;
+pub const MSR_LBR_NHM_FROM: ::std::os::raw::c_uint = 0x00000680;
+pub const MSR_LBR_NHM_TO: ::std::os::raw::c_uint = 0x000006c0;
+pub const MSR_LBR_CORE_FROM: ::std::os::raw::c_uint = 0x00000040;
+pub const MSR_LBR_CORE_TO: ::std::os::raw::c_uint = 0x00000060;
+pub const MSR_LBR_INFO_0: ::std::os::raw::c_uint = 0x00000dc0;
+pub const LBR_INFO_CYCLES: ::std::os::raw::c_uint = 0x0000ffff;
+pub const MSR_IA32_PEBS_ENABLE: ::std::os::raw::c_uint = 0x000003f1;
+pub const MSR_IA32_DS_AREA: ::std::os::raw::c_uint = 0x00000600;
+pub const MSR_IA32_PERF_CAPABILITIES: ::std::os::raw::c_uint = 0x00000345;
+pub const MSR_PEBS_LD_LAT_THRESHOLD: ::std::os::raw::c_uint = 0x000003f6;
+pub const MSR_IA32_RTIT_CTL: ::std::os::raw::c_uint = 0x00000570;
+pub const MSR_IA32_RTIT_STATUS: ::std::os::raw::c_uint = 0x00000571;
+pub const MSR_IA32_RTIT_ADDR0_A: ::std::os::raw::c_uint = 0x00000580;
+pub const MSR_IA32_RTIT_ADDR0_B: ::std::os::raw::c_uint = 0x00000581;
+pub const MSR_IA32_RTIT_ADDR1_A: ::std::os::raw::c_uint = 0x00000582;
+pub const MSR_IA32_RTIT_ADDR1_B: ::std::os::raw::c_uint = 0x00000583;
+pub const MSR_IA32_RTIT_ADDR2_A: ::std::os::raw::c_uint = 0x00000584;
+pub const MSR_IA32_RTIT_ADDR2_B: ::std::os::raw::c_uint = 0x00000585;
+pub const MSR_IA32_RTIT_ADDR3_A: ::std::os::raw::c_uint = 0x00000586;
+pub const MSR_IA32_RTIT_ADDR3_B: ::std::os::raw::c_uint = 0x00000587;
+pub const MSR_IA32_RTIT_CR3_MATCH: ::std::os::raw::c_uint = 0x00000572;
+pub const MSR_IA32_RTIT_OUTPUT_BASE: ::std::os::raw::c_uint = 0x00000560;
+pub const MSR_IA32_RTIT_OUTPUT_MASK: ::std::os::raw::c_uint = 0x00000561;
+pub const MSR_MTRRfix64K_00000: ::std::os::raw::c_uint = 0x00000250;
+pub const MSR_MTRRfix16K_80000: ::std::os::raw::c_uint = 0x00000258;
+pub const MSR_MTRRfix16K_A0000: ::std::os::raw::c_uint = 0x00000259;
+pub const MSR_MTRRfix4K_C0000: ::std::os::raw::c_uint = 0x00000268;
+pub const MSR_MTRRfix4K_C8000: ::std::os::raw::c_uint = 0x00000269;
+pub const MSR_MTRRfix4K_D0000: ::std::os::raw::c_uint = 0x0000026a;
+pub const MSR_MTRRfix4K_D8000: ::std::os::raw::c_uint = 0x0000026b;
+pub const MSR_MTRRfix4K_E0000: ::std::os::raw::c_uint = 0x0000026c;
+pub const MSR_MTRRfix4K_E8000: ::std::os::raw::c_uint = 0x0000026d;
+pub const MSR_MTRRfix4K_F0000: ::std::os::raw::c_uint = 0x0000026e;
+pub const MSR_MTRRfix4K_F8000: ::std::os::raw::c_uint = 0x0000026f;
+pub const MSR_MTRRdefType: ::std::os::raw::c_uint = 0x000002ff;
+pub const MSR_IA32_CR_PAT: ::std::os::raw::c_uint = 0x00000277;
+pub const MSR_IA32_DEBUGCTLMSR: ::std::os::raw::c_uint = 0x000001d9;
+pub const MSR_IA32_LASTBRANCHFROMIP: ::std::os::raw::c_uint = 0x000001db;
+pub const MSR_IA32_LASTBRANCHTOIP: ::std::os::raw::c_uint = 0x000001dc;
+pub const MSR_IA32_LASTINTFROMIP: ::std::os::raw::c_uint = 0x000001dd;
+pub const MSR_IA32_LASTINTTOIP: ::std::os::raw::c_uint = 0x000001de;
+pub const DEBUGCTLMSR_LBR: ::std::os::raw::c_uint = 0x00000001;
+pub const DEBUGCTLMSR_BTF: ::std::os::raw::c_uint = 0x00000002;
+pub const DEBUGCTLMSR_TR: ::std::os::raw::c_uint = 0x00000040;
+pub const DEBUGCTLMSR_BTS: ::std::os::raw::c_uint = 0x00000080;
+pub const DEBUGCTLMSR_BTINT: ::std::os::raw::c_uint = 0x00000100;
+pub const DEBUGCTLMSR_BTS_OFF_OS: ::std::os::raw::c_uint = 0x00000200;
+pub const DEBUGCTLMSR_BTS_OFF_USR: ::std::os::raw::c_uint = 0x00000400;
+pub const DEBUGCTLMSR_FREEZE_LBRS_ON_PMI: ::std::os::raw::c_uint = 0x00000800;
+pub const MSR_PEBS_FRONTEND: ::std::os::raw::c_uint = 0x000003f7;
+pub const MSR_IA32_POWER_CTL: ::std::os::raw::c_uint = 0x000001fc;
+pub const MSR_IA32_MC0_CTL: ::std::os::raw::c_uint = 0x00000400;
+pub const MSR_IA32_MC0_STATUS: ::std::os::raw::c_uint = 0x00000401;
+pub const MSR_IA32_MC0_ADDR: ::std::os::raw::c_uint = 0x00000402;
+pub const MSR_IA32_MC0_MISC: ::std::os::raw::c_uint = 0x00000403;
+pub const MSR_PKG_C3_RESIDENCY: ::std::os::raw::c_uint = 0x000003f8;
+pub const MSR_PKG_C6_RESIDENCY: ::std::os::raw::c_uint = 0x000003f9;
+pub const MSR_ATOM_PKG_C6_RESIDENCY: ::std::os::raw::c_uint = 0x000003fa;
+pub const MSR_PKG_C7_RESIDENCY: ::std::os::raw::c_uint = 0x000003fa;
+pub const MSR_CORE_C3_RESIDENCY: ::std::os::raw::c_uint = 0x000003fc;
+pub const MSR_CORE_C6_RESIDENCY: ::std::os::raw::c_uint = 0x000003fd;
+pub const MSR_CORE_C7_RESIDENCY: ::std::os::raw::c_uint = 0x000003fe;
+pub const MSR_KNL_CORE_C6_RESIDENCY: ::std::os::raw::c_uint = 0x000003ff;
+pub const MSR_PKG_C2_RESIDENCY: ::std::os::raw::c_uint = 0x0000060d;
+pub const MSR_PKG_C8_RESIDENCY: ::std::os::raw::c_uint = 0x00000630;
+pub const MSR_PKG_C9_RESIDENCY: ::std::os::raw::c_uint = 0x00000631;
+pub const MSR_PKG_C10_RESIDENCY: ::std::os::raw::c_uint = 0x00000632;
+pub const MSR_PKGC3_IRTL: ::std::os::raw::c_uint = 0x0000060a;
+pub const MSR_PKGC6_IRTL: ::std::os::raw::c_uint = 0x0000060b;
+pub const MSR_PKGC7_IRTL: ::std::os::raw::c_uint = 0x0000060c;
+pub const MSR_PKGC8_IRTL: ::std::os::raw::c_uint = 0x00000633;
+pub const MSR_PKGC9_IRTL: ::std::os::raw::c_uint = 0x00000634;
+pub const MSR_PKGC10_IRTL: ::std::os::raw::c_uint = 0x00000635;
+pub const MSR_RAPL_POWER_UNIT: ::std::os::raw::c_uint = 0x00000606;
+pub const MSR_PKG_POWER_LIMIT: ::std::os::raw::c_uint = 0x00000610;
+pub const MSR_PKG_ENERGY_STATUS: ::std::os::raw::c_uint = 0x00000611;
+pub const MSR_PKG_PERF_STATUS: ::std::os::raw::c_uint = 0x00000613;
+pub const MSR_PKG_POWER_INFO: ::std::os::raw::c_uint = 0x00000614;
+pub const MSR_DRAM_POWER_LIMIT: ::std::os::raw::c_uint = 0x00000618;
+pub const MSR_DRAM_ENERGY_STATUS: ::std::os::raw::c_uint = 0x00000619;
+pub const MSR_DRAM_PERF_STATUS: ::std::os::raw::c_uint = 0x0000061b;
+pub const MSR_DRAM_POWER_INFO: ::std::os::raw::c_uint = 0x0000061c;
+pub const MSR_PP0_POWER_LIMIT: ::std::os::raw::c_uint = 0x00000638;
+pub const MSR_PP0_ENERGY_STATUS: ::std::os::raw::c_uint = 0x00000639;
+pub const MSR_PP0_POLICY: ::std::os::raw::c_uint = 0x0000063a;
+pub const MSR_PP0_PERF_STATUS: ::std::os::raw::c_uint = 0x0000063b;
+pub const MSR_PP1_POWER_LIMIT: ::std::os::raw::c_uint = 0x00000640;
+pub const MSR_PP1_ENERGY_STATUS: ::std::os::raw::c_uint = 0x00000641;
+pub const MSR_PP1_POLICY: ::std::os::raw::c_uint = 0x00000642;
+pub const MSR_CONFIG_TDP_NOMINAL: ::std::os::raw::c_uint = 0x00000648;
+pub const MSR_CONFIG_TDP_LEVEL_1: ::std::os::raw::c_uint = 0x00000649;
+pub const MSR_CONFIG_TDP_LEVEL_2: ::std::os::raw::c_uint = 0x0000064a;
+pub const MSR_CONFIG_TDP_CONTROL: ::std::os::raw::c_uint = 0x0000064b;
+pub const MSR_TURBO_ACTIVATION_RATIO: ::std::os::raw::c_uint = 0x0000064c;
+pub const MSR_PLATFORM_ENERGY_STATUS: ::std::os::raw::c_uint = 0x0000064d;
+pub const MSR_PKG_WEIGHTED_CORE_C0_RES: ::std::os::raw::c_uint = 0x00000658;
+pub const MSR_PKG_ANY_CORE_C0_RES: ::std::os::raw::c_uint = 0x00000659;
+pub const MSR_PKG_ANY_GFXE_C0_RES: ::std::os::raw::c_uint = 0x0000065a;
+pub const MSR_PKG_BOTH_CORE_GFXE_C0_RES: ::std::os::raw::c_uint = 0x0000065b;
+pub const MSR_CORE_C1_RES: ::std::os::raw::c_uint = 0x00000660;
+pub const MSR_MODULE_C6_RES_MS: ::std::os::raw::c_uint = 0x00000664;
+pub const MSR_CC6_DEMOTION_POLICY_CONFIG: ::std::os::raw::c_uint = 0x00000668;
+pub const MSR_MC6_DEMOTION_POLICY_CONFIG: ::std::os::raw::c_uint = 0x00000669;
+pub const MSR_ATOM_CORE_RATIOS: ::std::os::raw::c_uint = 0x0000066a;
+pub const MSR_ATOM_CORE_VIDS: ::std::os::raw::c_uint = 0x0000066b;
+pub const MSR_ATOM_CORE_TURBO_RATIOS: ::std::os::raw::c_uint = 0x0000066c;
+pub const MSR_ATOM_CORE_TURBO_VIDS: ::std::os::raw::c_uint = 0x0000066d;
+pub const MSR_CORE_PERF_LIMIT_REASONS: ::std::os::raw::c_uint = 0x00000690;
+pub const MSR_GFX_PERF_LIMIT_REASONS: ::std::os::raw::c_uint = 0x000006b0;
+pub const MSR_RING_PERF_LIMIT_REASONS: ::std::os::raw::c_uint = 0x000006b1;
+pub const MSR_PPERF: ::std::os::raw::c_uint = 0x0000064e;
+pub const MSR_PERF_LIMIT_REASONS: ::std::os::raw::c_uint = 0x0000064f;
+pub const MSR_PM_ENABLE: ::std::os::raw::c_uint = 0x00000770;
+pub const MSR_HWP_CAPABILITIES: ::std::os::raw::c_uint = 0x00000771;
+pub const MSR_HWP_REQUEST_PKG: ::std::os::raw::c_uint = 0x00000772;
+pub const MSR_HWP_INTERRUPT: ::std::os::raw::c_uint = 0x00000773;
+pub const MSR_HWP_REQUEST: ::std::os::raw::c_uint = 0x00000774;
+pub const MSR_HWP_STATUS: ::std::os::raw::c_uint = 0x00000777;
+pub const HWP_BASE_BIT: ::std::os::raw::c_uint = 0x00000080;
+pub const HWP_NOTIFICATIONS_BIT: ::std::os::raw::c_uint = 0x00000100;
+pub const HWP_ACTIVITY_WINDOW_BIT: ::std::os::raw::c_uint = 0x00000200;
+pub const HWP_ENERGY_PERF_PREFERENCE_BIT: ::std::os::raw::c_uint = 0x00000400;
+pub const HWP_PACKAGE_LEVEL_REQUEST_BIT: ::std::os::raw::c_uint = 0x00000800;
+pub const MSR_AMD64_MC0_MASK: ::std::os::raw::c_uint = 0xc0010044;
+pub const MSR_IA32_MC0_CTL2: ::std::os::raw::c_uint = 0x00000280;
+pub const MSR_P6_PERFCTR0: ::std::os::raw::c_uint = 0x000000c1;
+pub const MSR_P6_PERFCTR1: ::std::os::raw::c_uint = 0x000000c2;
+pub const MSR_P6_EVNTSEL0: ::std::os::raw::c_uint = 0x00000186;
+pub const MSR_P6_EVNTSEL1: ::std::os::raw::c_uint = 0x00000187;
+pub const MSR_KNC_PERFCTR0: ::std::os::raw::c_uint = 0x00000020;
+pub const MSR_KNC_PERFCTR1: ::std::os::raw::c_uint = 0x00000021;
+pub const MSR_KNC_EVNTSEL0: ::std::os::raw::c_uint = 0x00000028;
+pub const MSR_KNC_EVNTSEL1: ::std::os::raw::c_uint = 0x00000029;
+pub const MSR_IA32_PMC0: ::std::os::raw::c_uint = 0x000004c1;
+pub const MSR_AMD64_PATCH_LEVEL: ::std::os::raw::c_uint = 0x0000008b;
+pub const MSR_AMD64_TSC_RATIO: ::std::os::raw::c_uint = 0xc0000104;
+pub const MSR_AMD64_NB_CFG: ::std::os::raw::c_uint = 0xc001001f;
+pub const MSR_AMD64_PATCH_LOADER: ::std::os::raw::c_uint = 0xc0010020;
+pub const MSR_AMD64_OSVW_ID_LENGTH: ::std::os::raw::c_uint = 0xc0010140;
+pub const MSR_AMD64_OSVW_STATUS: ::std::os::raw::c_uint = 0xc0010141;
+pub const MSR_AMD64_LS_CFG: ::std::os::raw::c_uint = 0xc0011020;
+pub const MSR_AMD64_DC_CFG: ::std::os::raw::c_uint = 0xc0011022;
+pub const MSR_AMD64_BU_CFG2: ::std::os::raw::c_uint = 0xc001102a;
+pub const MSR_AMD64_IBSFETCHCTL: ::std::os::raw::c_uint = 0xc0011030;
+pub const MSR_AMD64_IBSFETCHLINAD: ::std::os::raw::c_uint = 0xc0011031;
+pub const MSR_AMD64_IBSFETCHPHYSAD: ::std::os::raw::c_uint = 0xc0011032;
+pub const MSR_AMD64_IBSFETCH_REG_COUNT: ::std::os::raw::c_uint = 0x00000003;
+pub const MSR_AMD64_IBSFETCH_REG_MASK: ::std::os::raw::c_uint = 0x00000007;
+pub const MSR_AMD64_IBSOPCTL: ::std::os::raw::c_uint = 0xc0011033;
+pub const MSR_AMD64_IBSOPRIP: ::std::os::raw::c_uint = 0xc0011034;
+pub const MSR_AMD64_IBSOPDATA: ::std::os::raw::c_uint = 0xc0011035;
+pub const MSR_AMD64_IBSOPDATA2: ::std::os::raw::c_uint = 0xc0011036;
+pub const MSR_AMD64_IBSOPDATA3: ::std::os::raw::c_uint = 0xc0011037;
+pub const MSR_AMD64_IBSDCLINAD: ::std::os::raw::c_uint = 0xc0011038;
+pub const MSR_AMD64_IBSDCPHYSAD: ::std::os::raw::c_uint = 0xc0011039;
+pub const MSR_AMD64_IBSOP_REG_COUNT: ::std::os::raw::c_uint = 0x00000007;
+pub const MSR_AMD64_IBSOP_REG_MASK: ::std::os::raw::c_uint = 0x0000007f;
+pub const MSR_AMD64_IBSCTL: ::std::os::raw::c_uint = 0xc001103a;
+pub const MSR_AMD64_IBSBRTARGET: ::std::os::raw::c_uint = 0xc001103b;
+pub const MSR_AMD64_IBSOPDATA4: ::std::os::raw::c_uint = 0xc001103d;
+pub const MSR_AMD64_IBS_REG_COUNT_MAX: ::std::os::raw::c_uint = 0x00000008;
+pub const MSR_F17H_IRPERF: ::std::os::raw::c_uint = 0xc00000e9;
+pub const MSR_F16H_L2I_PERF_CTL: ::std::os::raw::c_uint = 0xc0010230;
+pub const MSR_F16H_L2I_PERF_CTR: ::std::os::raw::c_uint = 0xc0010231;
+pub const MSR_F16H_DR1_ADDR_MASK: ::std::os::raw::c_uint = 0xc0011019;
+pub const MSR_F16H_DR2_ADDR_MASK: ::std::os::raw::c_uint = 0xc001101a;
+pub const MSR_F16H_DR3_ADDR_MASK: ::std::os::raw::c_uint = 0xc001101b;
+pub const MSR_F16H_DR0_ADDR_MASK: ::std::os::raw::c_uint = 0xc0011027;
+pub const MSR_F15H_PERF_CTL: ::std::os::raw::c_uint = 0xc0010200;
+pub const MSR_F15H_PERF_CTR: ::std::os::raw::c_uint = 0xc0010201;
+pub const MSR_F15H_NB_PERF_CTL: ::std::os::raw::c_uint = 0xc0010240;
+pub const MSR_F15H_NB_PERF_CTR: ::std::os::raw::c_uint = 0xc0010241;
+pub const MSR_F15H_PTSC: ::std::os::raw::c_uint = 0xc0010280;
+pub const MSR_F15H_IC_CFG: ::std::os::raw::c_uint = 0xc0011021;
+pub const MSR_FAM10H_MMIO_CONF_BASE: ::std::os::raw::c_uint = 0xc0010058;
+pub const FAM10H_MMIO_CONF_ENABLE: ::std::os::raw::c_uint = 0x00000001;
+pub const FAM10H_MMIO_CONF_BUSRANGE_MASK: ::std::os::raw::c_uint = 0x0000000f;
+pub const FAM10H_MMIO_CONF_BUSRANGE_SHIFT: ::std::os::raw::c_uint = 0x00000002;
+pub const FAM10H_MMIO_CONF_BASE_MASK: ::std::os::raw::c_uint = 0x0fffffff;
+pub const FAM10H_MMIO_CONF_BASE_SHIFT: ::std::os::raw::c_uint = 0x00000014;
+pub const MSR_FAM10H_NODE_ID: ::std::os::raw::c_uint = 0xc001100c;
+pub const MSR_K8_TOP_MEM1: ::std::os::raw::c_uint = 0xc001001a;
+pub const MSR_K8_TOP_MEM2: ::std::os::raw::c_uint = 0xc001001d;
+pub const MSR_K8_SYSCFG: ::std::os::raw::c_uint = 0xc0010010;
+pub const MSR_K8_INT_PENDING_MSG: ::std::os::raw::c_uint = 0xc0010055;
+pub const K8_INTP_C1E_ACTIVE_MASK: ::std::os::raw::c_uint = 0x18000000;
+pub const MSR_K8_TSEG_ADDR: ::std::os::raw::c_uint = 0xc0010112;
+pub const MSR_K8_TSEG_MASK: ::std::os::raw::c_uint = 0xc0010113;
+pub const K8_MTRRFIXRANGE_DRAM_ENABLE: ::std::os::raw::c_uint = 0x00040000;
+pub const K8_MTRRFIXRANGE_DRAM_MODIFY: ::std::os::raw::c_uint = 0x00080000;
+pub const K8_MTRR_RDMEM_WRMEM_MASK: ::std::os::raw::c_uint = 0x18181818;
+pub const MSR_K7_EVNTSEL0: ::std::os::raw::c_uint = 0xc0010000;
+pub const MSR_K7_PERFCTR0: ::std::os::raw::c_uint = 0xc0010004;
+pub const MSR_K7_EVNTSEL1: ::std::os::raw::c_uint = 0xc0010001;
+pub const MSR_K7_PERFCTR1: ::std::os::raw::c_uint = 0xc0010005;
+pub const MSR_K7_EVNTSEL2: ::std::os::raw::c_uint = 0xc0010002;
+pub const MSR_K7_PERFCTR2: ::std::os::raw::c_uint = 0xc0010006;
+pub const MSR_K7_EVNTSEL3: ::std::os::raw::c_uint = 0xc0010003;
+pub const MSR_K7_PERFCTR3: ::std::os::raw::c_uint = 0xc0010007;
+pub const MSR_K7_CLK_CTL: ::std::os::raw::c_uint = 0xc001001b;
+pub const MSR_K7_HWCR: ::std::os::raw::c_uint = 0xc0010015;
+pub const MSR_K7_FID_VID_CTL: ::std::os::raw::c_uint = 0xc0010041;
+pub const MSR_K7_FID_VID_STATUS: ::std::os::raw::c_uint = 0xc0010042;
+pub const MSR_K6_WHCR: ::std::os::raw::c_uint = 0xc0000082;
+pub const MSR_K6_UWCCR: ::std::os::raw::c_uint = 0xc0000085;
+pub const MSR_K6_EPMR: ::std::os::raw::c_uint = 0xc0000086;
+pub const MSR_K6_PSOR: ::std::os::raw::c_uint = 0xc0000087;
+pub const MSR_K6_PFIR: ::std::os::raw::c_uint = 0xc0000088;
+pub const MSR_IDT_FCR1: ::std::os::raw::c_uint = 0x00000107;
+pub const MSR_IDT_FCR2: ::std::os::raw::c_uint = 0x00000108;
+pub const MSR_IDT_FCR3: ::std::os::raw::c_uint = 0x00000109;
+pub const MSR_IDT_FCR4: ::std::os::raw::c_uint = 0x0000010a;
+pub const MSR_IDT_MCR0: ::std::os::raw::c_uint = 0x00000110;
+pub const MSR_IDT_MCR1: ::std::os::raw::c_uint = 0x00000111;
+pub const MSR_IDT_MCR2: ::std::os::raw::c_uint = 0x00000112;
+pub const MSR_IDT_MCR3: ::std::os::raw::c_uint = 0x00000113;
+pub const MSR_IDT_MCR4: ::std::os::raw::c_uint = 0x00000114;
+pub const MSR_IDT_MCR5: ::std::os::raw::c_uint = 0x00000115;
+pub const MSR_IDT_MCR6: ::std::os::raw::c_uint = 0x00000116;
+pub const MSR_IDT_MCR7: ::std::os::raw::c_uint = 0x00000117;
+pub const MSR_IDT_MCR_CTRL: ::std::os::raw::c_uint = 0x00000120;
+pub const MSR_VIA_FCR: ::std::os::raw::c_uint = 0x00001107;
+pub const MSR_VIA_LONGHAUL: ::std::os::raw::c_uint = 0x0000110a;
+pub const MSR_VIA_RNG: ::std::os::raw::c_uint = 0x0000110b;
+pub const MSR_VIA_BCR2: ::std::os::raw::c_uint = 0x00001147;
+pub const MSR_TMTA_LONGRUN_CTRL: ::std::os::raw::c_uint = 0x80868010;
+pub const MSR_TMTA_LONGRUN_FLAGS: ::std::os::raw::c_uint = 0x80868011;
+pub const MSR_TMTA_LRTI_READOUT: ::std::os::raw::c_uint = 0x80868018;
+pub const MSR_TMTA_LRTI_VOLT_MHZ: ::std::os::raw::c_uint = 0x8086801a;
+pub const MSR_IA32_P5_MC_ADDR: ::std::os::raw::c_uint = 0x00000000;
+pub const MSR_IA32_P5_MC_TYPE: ::std::os::raw::c_uint = 0x00000001;
+pub const MSR_IA32_TSC: ::std::os::raw::c_uint = 0x00000010;
+pub const MSR_IA32_PLATFORM_ID: ::std::os::raw::c_uint = 0x00000017;
+pub const MSR_IA32_EBL_CR_POWERON: ::std::os::raw::c_uint = 0x0000002a;
+pub const MSR_EBC_FREQUENCY_ID: ::std::os::raw::c_uint = 0x0000002c;
+pub const MSR_SMI_COUNT: ::std::os::raw::c_uint = 0x00000034;
+pub const MSR_IA32_FEATURE_CONTROL: ::std::os::raw::c_uint = 0x0000003a;
+pub const MSR_IA32_TSC_ADJUST: ::std::os::raw::c_uint = 0x0000003b;
+pub const MSR_IA32_BNDCFGS: ::std::os::raw::c_uint = 0x00000d90;
+pub const MSR_IA32_XSS: ::std::os::raw::c_uint = 0x00000da0;
+pub const FEATURE_CONTROL_LOCKED: ::std::os::raw::c_uint = 0x00000001;
+pub const FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX: ::std::os::raw::c_uint = 0x00000002;
+pub const FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX: ::std::os::raw::c_uint = 0x00000004;
+pub const FEATURE_CONTROL_LMCE: ::std::os::raw::c_uint = 0x00100000;
+pub const MSR_IA32_APICBASE: ::std::os::raw::c_uint = 0x0000001b;
+pub const MSR_IA32_APICBASE_BSP: ::std::os::raw::c_uint = 0x00000100;
+pub const MSR_IA32_APICBASE_ENABLE: ::std::os::raw::c_uint = 0x00000800;
+pub const MSR_IA32_APICBASE_BASE: ::std::os::raw::c_uint = 0xfffff000;
+pub const MSR_IA32_TSCDEADLINE: ::std::os::raw::c_uint = 0x000006e0;
+pub const MSR_IA32_UCODE_WRITE: ::std::os::raw::c_uint = 0x00000079;
+pub const MSR_IA32_UCODE_REV: ::std::os::raw::c_uint = 0x0000008b;
+pub const MSR_IA32_SMM_MONITOR_CTL: ::std::os::raw::c_uint = 0x0000009b;
+pub const MSR_IA32_SMBASE: ::std::os::raw::c_uint = 0x0000009e;
+pub const MSR_IA32_PERF_STATUS: ::std::os::raw::c_uint = 0x00000198;
+pub const MSR_IA32_PERF_CTL: ::std::os::raw::c_uint = 0x00000199;
+pub const INTEL_PERF_CTL_MASK: ::std::os::raw::c_uint = 0x0000ffff;
+pub const MSR_AMD_PSTATE_DEF_BASE: ::std::os::raw::c_uint = 0xc0010064;
+pub const MSR_AMD_PERF_STATUS: ::std::os::raw::c_uint = 0xc0010063;
+pub const MSR_AMD_PERF_CTL: ::std::os::raw::c_uint = 0xc0010062;
+pub const MSR_IA32_MPERF: ::std::os::raw::c_uint = 0x000000e7;
+pub const MSR_IA32_APERF: ::std::os::raw::c_uint = 0x000000e8;
+pub const MSR_IA32_THERM_CONTROL: ::std::os::raw::c_uint = 0x0000019a;
+pub const MSR_IA32_THERM_INTERRUPT: ::std::os::raw::c_uint = 0x0000019b;
+pub const THERM_INT_HIGH_ENABLE: ::std::os::raw::c_uint = 0x00000001;
+pub const THERM_INT_LOW_ENABLE: ::std::os::raw::c_uint = 0x00000002;
+pub const THERM_INT_PLN_ENABLE: ::std::os::raw::c_uint = 0x01000000;
+pub const MSR_IA32_THERM_STATUS: ::std::os::raw::c_uint = 0x0000019c;
+pub const THERM_STATUS_PROCHOT: ::std::os::raw::c_uint = 0x00000001;
+pub const THERM_STATUS_POWER_LIMIT: ::std::os::raw::c_uint = 0x00000400;
+pub const MSR_THERM2_CTL: ::std::os::raw::c_uint = 0x0000019d;
+pub const MSR_THERM2_CTL_TM_SELECT: ::std::os::raw::c_uint = 0x00010000;
+pub const MSR_IA32_MISC_ENABLE: ::std::os::raw::c_uint = 0x000001a0;
+pub const MSR_IA32_TEMPERATURE_TARGET: ::std::os::raw::c_uint = 0x000001a2;
+pub const MSR_MISC_FEATURE_CONTROL: ::std::os::raw::c_uint = 0x000001a4;
+pub const MSR_MISC_PWR_MGMT: ::std::os::raw::c_uint = 0x000001aa;
+pub const MSR_IA32_ENERGY_PERF_BIAS: ::std::os::raw::c_uint = 0x000001b0;
+pub const ENERGY_PERF_BIAS_PERFORMANCE: ::std::os::raw::c_uint = 0x00000000;
+pub const ENERGY_PERF_BIAS_NORMAL: ::std::os::raw::c_uint = 0x00000006;
+pub const ENERGY_PERF_BIAS_POWERSAVE: ::std::os::raw::c_uint = 0x0000000f;
+pub const MSR_IA32_PACKAGE_THERM_STATUS: ::std::os::raw::c_uint = 0x000001b1;
+pub const PACKAGE_THERM_STATUS_PROCHOT: ::std::os::raw::c_uint = 0x00000001;
+pub const PACKAGE_THERM_STATUS_POWER_LIMIT: ::std::os::raw::c_uint = 0x00000400;
+pub const MSR_IA32_PACKAGE_THERM_INTERRUPT: ::std::os::raw::c_uint = 0x000001b2;
+pub const PACKAGE_THERM_INT_HIGH_ENABLE: ::std::os::raw::c_uint = 0x00000001;
+pub const PACKAGE_THERM_INT_LOW_ENABLE: ::std::os::raw::c_uint = 0x00000002;
+pub const PACKAGE_THERM_INT_PLN_ENABLE: ::std::os::raw::c_uint = 0x01000000;
+pub const THERM_INT_THRESHOLD0_ENABLE: ::std::os::raw::c_uint = 0x00008000;
+pub const THERM_SHIFT_THRESHOLD0: ::std::os::raw::c_uint = 0x00000008;
+pub const THERM_MASK_THRESHOLD0: ::std::os::raw::c_uint = 0x00007f00;
+pub const THERM_INT_THRESHOLD1_ENABLE: ::std::os::raw::c_uint = 0x00800000;
+pub const THERM_SHIFT_THRESHOLD1: ::std::os::raw::c_uint = 0x00000010;
+pub const THERM_MASK_THRESHOLD1: ::std::os::raw::c_uint = 0x007f0000;
+pub const THERM_STATUS_THRESHOLD0: ::std::os::raw::c_uint = 0x00000040;
+pub const THERM_LOG_THRESHOLD0: ::std::os::raw::c_uint = 0x00000080;
+pub const THERM_STATUS_THRESHOLD1: ::std::os::raw::c_uint = 0x00000100;
+pub const THERM_LOG_THRESHOLD1: ::std::os::raw::c_uint = 0x00000200;
+pub const MSR_IA32_MISC_ENABLE_FAST_STRING_BIT: ::std::os::raw::c_uint = 0x00000000;
+pub const MSR_IA32_MISC_ENABLE_FAST_STRING: ::std::os::raw::c_uint = 0x00000001;
+pub const MSR_IA32_MISC_ENABLE_TCC_BIT: ::std::os::raw::c_uint = 0x00000001;
+pub const MSR_IA32_MISC_ENABLE_TCC: ::std::os::raw::c_uint = 0x00000002;
+pub const MSR_IA32_MISC_ENABLE_EMON_BIT: ::std::os::raw::c_uint = 0x00000007;
+pub const MSR_IA32_MISC_ENABLE_EMON: ::std::os::raw::c_uint = 0x00000080;
+pub const MSR_IA32_MISC_ENABLE_BTS_UNAVAIL_BIT: ::std::os::raw::c_uint = 0x0000000b;
+pub const MSR_IA32_MISC_ENABLE_BTS_UNAVAIL: ::std::os::raw::c_uint = 0x00000800;
+pub const MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL_BIT: ::std::os::raw::c_uint = 0x0000000c;
+pub const MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL: ::std::os::raw::c_uint = 0x00001000;
+pub const MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP_BIT: ::std::os::raw::c_uint = 0x00000010;
+pub const MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP: ::std::os::raw::c_uint = 0x00010000;
+pub const MSR_IA32_MISC_ENABLE_MWAIT_BIT: ::std::os::raw::c_uint = 0x00000012;
+pub const MSR_IA32_MISC_ENABLE_MWAIT: ::std::os::raw::c_uint = 0x00040000;
+pub const MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT: ::std::os::raw::c_uint = 0x00000016;
+pub const MSR_IA32_MISC_ENABLE_LIMIT_CPUID: ::std::os::raw::c_uint = 0x00400000;
+pub const MSR_IA32_MISC_ENABLE_XTPR_DISABLE_BIT: ::std::os::raw::c_uint = 0x00000017;
+pub const MSR_IA32_MISC_ENABLE_XTPR_DISABLE: ::std::os::raw::c_uint = 0x00800000;
+pub const MSR_IA32_MISC_ENABLE_XD_DISABLE_BIT: ::std::os::raw::c_uint = 0x00000022;
+pub const MSR_IA32_MISC_ENABLE_XD_DISABLE: ::std::os::raw::c_ulonglong = 0x400000000;
+pub const MSR_IA32_MISC_ENABLE_X87_COMPAT_BIT: ::std::os::raw::c_uint = 0x00000002;
+pub const MSR_IA32_MISC_ENABLE_X87_COMPAT: ::std::os::raw::c_uint = 0x00000004;
+pub const MSR_IA32_MISC_ENABLE_TM1_BIT: ::std::os::raw::c_uint = 0x00000003;
+pub const MSR_IA32_MISC_ENABLE_TM1: ::std::os::raw::c_uint = 0x00000008;
+pub const MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE_BIT: ::std::os::raw::c_uint = 0x00000004;
+pub const MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE: ::std::os::raw::c_uint = 0x00000010;
+pub const MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE_BIT: ::std::os::raw::c_uint = 0x00000006;
+pub const MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE: ::std::os::raw::c_uint = 0x00000040;
+pub const MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK_BIT: ::std::os::raw::c_uint = 0x00000008;
+pub const MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK: ::std::os::raw::c_uint = 0x00000100;
+pub const MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT: ::std::os::raw::c_uint = 0x00000009;
+pub const MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE: ::std::os::raw::c_uint = 0x00000200;
+pub const MSR_IA32_MISC_ENABLE_FERR_BIT: ::std::os::raw::c_uint = 0x0000000a;
+pub const MSR_IA32_MISC_ENABLE_FERR: ::std::os::raw::c_uint = 0x00000400;
+pub const MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX_BIT: ::std::os::raw::c_uint = 0x0000000a;
+pub const MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX: ::std::os::raw::c_uint = 0x00000400;
+pub const MSR_IA32_MISC_ENABLE_TM2_BIT: ::std::os::raw::c_uint = 0x0000000d;
+pub const MSR_IA32_MISC_ENABLE_TM2: ::std::os::raw::c_uint = 0x00002000;
+pub const MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE_BIT: ::std::os::raw::c_uint = 0x00000013;
+pub const MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE: ::std::os::raw::c_uint = 0x00080000;
+pub const MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK_BIT: ::std::os::raw::c_uint = 0x00000014;
+pub const MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK: ::std::os::raw::c_uint = 0x00100000;
+pub const MSR_IA32_MISC_ENABLE_L1D_CONTEXT_BIT: ::std::os::raw::c_uint = 0x00000018;
+pub const MSR_IA32_MISC_ENABLE_L1D_CONTEXT: ::std::os::raw::c_uint = 0x01000000;
+pub const MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE_BIT: ::std::os::raw::c_uint = 0x00000025;
+pub const MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE: ::std::os::raw::c_ulonglong = 0x2000000000;
+pub const MSR_IA32_MISC_ENABLE_TURBO_DISABLE_BIT: ::std::os::raw::c_uint = 0x00000026;
+pub const MSR_IA32_MISC_ENABLE_TURBO_DISABLE: ::std::os::raw::c_ulonglong = 0x4000000000;
+pub const MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE_BIT: ::std::os::raw::c_uint = 0x00000027;
+pub const MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE: ::std::os::raw::c_ulonglong = 0x8000000000;
+pub const MSR_MISC_FEATURE_ENABLES: ::std::os::raw::c_uint = 0x00000140;
+pub const MSR_MISC_FEATURE_ENABLES_RING3MWAIT_BIT: ::std::os::raw::c_uint = 0x00000001;
+pub const MSR_IA32_TSC_DEADLINE: ::std::os::raw::c_uint = 0x000006e0;
+pub const MSR_IA32_MCG_EAX: ::std::os::raw::c_uint = 0x00000180;
+pub const MSR_IA32_MCG_EBX: ::std::os::raw::c_uint = 0x00000181;
+pub const MSR_IA32_MCG_ECX: ::std::os::raw::c_uint = 0x00000182;
+pub const MSR_IA32_MCG_EDX: ::std::os::raw::c_uint = 0x00000183;
+pub const MSR_IA32_MCG_ESI: ::std::os::raw::c_uint = 0x00000184;
+pub const MSR_IA32_MCG_EDI: ::std::os::raw::c_uint = 0x00000185;
+pub const MSR_IA32_MCG_EBP: ::std::os::raw::c_uint = 0x00000186;
+pub const MSR_IA32_MCG_ESP: ::std::os::raw::c_uint = 0x00000187;
+pub const MSR_IA32_MCG_EFLAGS: ::std::os::raw::c_uint = 0x00000188;
+pub const MSR_IA32_MCG_EIP: ::std::os::raw::c_uint = 0x00000189;
+pub const MSR_IA32_MCG_RESERVED: ::std::os::raw::c_uint = 0x0000018a;
+pub const MSR_P4_BPU_PERFCTR0: ::std::os::raw::c_uint = 0x00000300;
+pub const MSR_P4_BPU_PERFCTR1: ::std::os::raw::c_uint = 0x00000301;
+pub const MSR_P4_BPU_PERFCTR2: ::std::os::raw::c_uint = 0x00000302;
+pub const MSR_P4_BPU_PERFCTR3: ::std::os::raw::c_uint = 0x00000303;
+pub const MSR_P4_MS_PERFCTR0: ::std::os::raw::c_uint = 0x00000304;
+pub const MSR_P4_MS_PERFCTR1: ::std::os::raw::c_uint = 0x00000305;
+pub const MSR_P4_MS_PERFCTR2: ::std::os::raw::c_uint = 0x00000306;
+pub const MSR_P4_MS_PERFCTR3: ::std::os::raw::c_uint = 0x00000307;
+pub const MSR_P4_FLAME_PERFCTR0: ::std::os::raw::c_uint = 0x00000308;
+pub const MSR_P4_FLAME_PERFCTR1: ::std::os::raw::c_uint = 0x00000309;
+pub const MSR_P4_FLAME_PERFCTR2: ::std::os::raw::c_uint = 0x0000030a;
+pub const MSR_P4_FLAME_PERFCTR3: ::std::os::raw::c_uint = 0x0000030b;
+pub const MSR_P4_IQ_PERFCTR0: ::std::os::raw::c_uint = 0x0000030c;
+pub const MSR_P4_IQ_PERFCTR1: ::std::os::raw::c_uint = 0x0000030d;
+pub const MSR_P4_IQ_PERFCTR2: ::std::os::raw::c_uint = 0x0000030e;
+pub const MSR_P4_IQ_PERFCTR3: ::std::os::raw::c_uint = 0x0000030f;
+pub const MSR_P4_IQ_PERFCTR4: ::std::os::raw::c_uint = 0x00000310;
+pub const MSR_P4_IQ_PERFCTR5: ::std::os::raw::c_uint = 0x00000311;
+pub const MSR_P4_BPU_CCCR0: ::std::os::raw::c_uint = 0x00000360;
+pub const MSR_P4_BPU_CCCR1: ::std::os::raw::c_uint = 0x00000361;
+pub const MSR_P4_BPU_CCCR2: ::std::os::raw::c_uint = 0x00000362;
+pub const MSR_P4_BPU_CCCR3: ::std::os::raw::c_uint = 0x00000363;
+pub const MSR_P4_MS_CCCR0: ::std::os::raw::c_uint = 0x00000364;
+pub const MSR_P4_MS_CCCR1: ::std::os::raw::c_uint = 0x00000365;
+pub const MSR_P4_MS_CCCR2: ::std::os::raw::c_uint = 0x00000366;
+pub const MSR_P4_MS_CCCR3: ::std::os::raw::c_uint = 0x00000367;
+pub const MSR_P4_FLAME_CCCR0: ::std::os::raw::c_uint = 0x00000368;
+pub const MSR_P4_FLAME_CCCR1: ::std::os::raw::c_uint = 0x00000369;
+pub const MSR_P4_FLAME_CCCR2: ::std::os::raw::c_uint = 0x0000036a;
+pub const MSR_P4_FLAME_CCCR3: ::std::os::raw::c_uint = 0x0000036b;
+pub const MSR_P4_IQ_CCCR0: ::std::os::raw::c_uint = 0x0000036c;
+pub const MSR_P4_IQ_CCCR1: ::std::os::raw::c_uint = 0x0000036d;
+pub const MSR_P4_IQ_CCCR2: ::std::os::raw::c_uint = 0x0000036e;
+pub const MSR_P4_IQ_CCCR3: ::std::os::raw::c_uint = 0x0000036f;
+pub const MSR_P4_IQ_CCCR4: ::std::os::raw::c_uint = 0x00000370;
+pub const MSR_P4_IQ_CCCR5: ::std::os::raw::c_uint = 0x00000371;
+pub const MSR_P4_ALF_ESCR0: ::std::os::raw::c_uint = 0x000003ca;
+pub const MSR_P4_ALF_ESCR1: ::std::os::raw::c_uint = 0x000003cb;
+pub const MSR_P4_BPU_ESCR0: ::std::os::raw::c_uint = 0x000003b2;
+pub const MSR_P4_BPU_ESCR1: ::std::os::raw::c_uint = 0x000003b3;
+pub const MSR_P4_BSU_ESCR0: ::std::os::raw::c_uint = 0x000003a0;
+pub const MSR_P4_BSU_ESCR1: ::std::os::raw::c_uint = 0x000003a1;
+pub const MSR_P4_CRU_ESCR0: ::std::os::raw::c_uint = 0x000003b8;
+pub const MSR_P4_CRU_ESCR1: ::std::os::raw::c_uint = 0x000003b9;
+pub const MSR_P4_CRU_ESCR2: ::std::os::raw::c_uint = 0x000003cc;
+pub const MSR_P4_CRU_ESCR3: ::std::os::raw::c_uint = 0x000003cd;
+pub const MSR_P4_CRU_ESCR4: ::std::os::raw::c_uint = 0x000003e0;
+pub const MSR_P4_CRU_ESCR5: ::std::os::raw::c_uint = 0x000003e1;
+pub const MSR_P4_DAC_ESCR0: ::std::os::raw::c_uint = 0x000003a8;
+pub const MSR_P4_DAC_ESCR1: ::std::os::raw::c_uint = 0x000003a9;
+pub const MSR_P4_FIRM_ESCR0: ::std::os::raw::c_uint = 0x000003a4;
+pub const MSR_P4_FIRM_ESCR1: ::std::os::raw::c_uint = 0x000003a5;
+pub const MSR_P4_FLAME_ESCR0: ::std::os::raw::c_uint = 0x000003a6;
+pub const MSR_P4_FLAME_ESCR1: ::std::os::raw::c_uint = 0x000003a7;
+pub const MSR_P4_FSB_ESCR0: ::std::os::raw::c_uint = 0x000003a2;
+pub const MSR_P4_FSB_ESCR1: ::std::os::raw::c_uint = 0x000003a3;
+pub const MSR_P4_IQ_ESCR0: ::std::os::raw::c_uint = 0x000003ba;
+pub const MSR_P4_IQ_ESCR1: ::std::os::raw::c_uint = 0x000003bb;
+pub const MSR_P4_IS_ESCR0: ::std::os::raw::c_uint = 0x000003b4;
+pub const MSR_P4_IS_ESCR1: ::std::os::raw::c_uint = 0x000003b5;
+pub const MSR_P4_ITLB_ESCR0: ::std::os::raw::c_uint = 0x000003b6;
+pub const MSR_P4_ITLB_ESCR1: ::std::os::raw::c_uint = 0x000003b7;
+pub const MSR_P4_IX_ESCR0: ::std::os::raw::c_uint = 0x000003c8;
+pub const MSR_P4_IX_ESCR1: ::std::os::raw::c_uint = 0x000003c9;
+pub const MSR_P4_MOB_ESCR0: ::std::os::raw::c_uint = 0x000003aa;
+pub const MSR_P4_MOB_ESCR1: ::std::os::raw::c_uint = 0x000003ab;
+pub const MSR_P4_MS_ESCR0: ::std::os::raw::c_uint = 0x000003c0;
+pub const MSR_P4_MS_ESCR1: ::std::os::raw::c_uint = 0x000003c1;
+pub const MSR_P4_PMH_ESCR0: ::std::os::raw::c_uint = 0x000003ac;
+pub const MSR_P4_PMH_ESCR1: ::std::os::raw::c_uint = 0x000003ad;
+pub const MSR_P4_RAT_ESCR0: ::std::os::raw::c_uint = 0x000003bc;
+pub const MSR_P4_RAT_ESCR1: ::std::os::raw::c_uint = 0x000003bd;
+pub const MSR_P4_SAAT_ESCR0: ::std::os::raw::c_uint = 0x000003ae;
+pub const MSR_P4_SAAT_ESCR1: ::std::os::raw::c_uint = 0x000003af;
+pub const MSR_P4_SSU_ESCR0: ::std::os::raw::c_uint = 0x000003be;
+pub const MSR_P4_SSU_ESCR1: ::std::os::raw::c_uint = 0x000003bf;
+pub const MSR_P4_TBPU_ESCR0: ::std::os::raw::c_uint = 0x000003c2;
+pub const MSR_P4_TBPU_ESCR1: ::std::os::raw::c_uint = 0x000003c3;
+pub const MSR_P4_TC_ESCR0: ::std::os::raw::c_uint = 0x000003c4;
+pub const MSR_P4_TC_ESCR1: ::std::os::raw::c_uint = 0x000003c5;
+pub const MSR_P4_U2L_ESCR0: ::std::os::raw::c_uint = 0x000003b0;
+pub const MSR_P4_U2L_ESCR1: ::std::os::raw::c_uint = 0x000003b1;
+pub const MSR_P4_PEBS_MATRIX_VERT: ::std::os::raw::c_uint = 0x000003f2;
+pub const MSR_CORE_PERF_FIXED_CTR0: ::std::os::raw::c_uint = 0x00000309;
+pub const MSR_CORE_PERF_FIXED_CTR1: ::std::os::raw::c_uint = 0x0000030a;
+pub const MSR_CORE_PERF_FIXED_CTR2: ::std::os::raw::c_uint = 0x0000030b;
+pub const MSR_CORE_PERF_FIXED_CTR_CTRL: ::std::os::raw::c_uint = 0x0000038d;
+pub const MSR_CORE_PERF_GLOBAL_STATUS: ::std::os::raw::c_uint = 0x0000038e;
+pub const MSR_CORE_PERF_GLOBAL_CTRL: ::std::os::raw::c_uint = 0x0000038f;
+pub const MSR_CORE_PERF_GLOBAL_OVF_CTRL: ::std::os::raw::c_uint = 0x00000390;
+pub const MSR_GEODE_BUSCONT_CONF0: ::std::os::raw::c_uint = 0x00001900;
+pub const MSR_IA32_VMX_BASIC: ::std::os::raw::c_uint = 0x00000480;
+pub const MSR_IA32_VMX_PINBASED_CTLS: ::std::os::raw::c_uint = 0x00000481;
+pub const MSR_IA32_VMX_PROCBASED_CTLS: ::std::os::raw::c_uint = 0x00000482;
+pub const MSR_IA32_VMX_EXIT_CTLS: ::std::os::raw::c_uint = 0x00000483;
+pub const MSR_IA32_VMX_ENTRY_CTLS: ::std::os::raw::c_uint = 0x00000484;
+pub const MSR_IA32_VMX_MISC: ::std::os::raw::c_uint = 0x00000485;
+pub const MSR_IA32_VMX_CR0_FIXED0: ::std::os::raw::c_uint = 0x00000486;
+pub const MSR_IA32_VMX_CR0_FIXED1: ::std::os::raw::c_uint = 0x00000487;
+pub const MSR_IA32_VMX_CR4_FIXED0: ::std::os::raw::c_uint = 0x00000488;
+pub const MSR_IA32_VMX_CR4_FIXED1: ::std::os::raw::c_uint = 0x00000489;
+pub const MSR_IA32_VMX_VMCS_ENUM: ::std::os::raw::c_uint = 0x0000048a;
+pub const MSR_IA32_VMX_PROCBASED_CTLS2: ::std::os::raw::c_uint = 0x0000048b;
+pub const MSR_IA32_VMX_EPT_VPID_CAP: ::std::os::raw::c_uint = 0x0000048c;
+pub const MSR_IA32_VMX_TRUE_PINBASED_CTLS: ::std::os::raw::c_uint = 0x0000048d;
+pub const MSR_IA32_VMX_TRUE_PROCBASED_CTLS: ::std::os::raw::c_uint = 0x0000048e;
+pub const MSR_IA32_VMX_TRUE_EXIT_CTLS: ::std::os::raw::c_uint = 0x0000048f;
+pub const MSR_IA32_VMX_TRUE_ENTRY_CTLS: ::std::os::raw::c_uint = 0x00000490;
+pub const MSR_IA32_VMX_VMFUNC: ::std::os::raw::c_uint = 0x00000491;
+pub const VMX_BASIC_VMCS_SIZE_SHIFT: ::std::os::raw::c_uint = 0x00000020;
+pub const VMX_BASIC_TRUE_CTLS: ::std::os::raw::c_ulonglong = 0x80000000000000;
+pub const VMX_BASIC_64: ::std::os::raw::c_ulonglong = 0x1000000000000;
+pub const VMX_BASIC_MEM_TYPE_SHIFT: ::std::os::raw::c_uint = 0x00000032;
+pub const VMX_BASIC_MEM_TYPE_MASK: ::std::os::raw::c_ulonglong = 0x3c000000000000;
+pub const VMX_BASIC_MEM_TYPE_WB: ::std::os::raw::c_uint = 0x00000006;
+pub const VMX_BASIC_INOUT: ::std::os::raw::c_ulonglong = 0x40000000000000;
+pub const MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS: ::std::os::raw::c_uint = 0x20000000;
+pub const MSR_IA32_VMX_MISC_PREEMPTION_TIMER_SCALE: ::std::os::raw::c_uint = 0x0000001f;
+pub const MSR_VM_CR: ::std::os::raw::c_uint = 0xc0010114;
+pub const MSR_VM_IGNNE: ::std::os::raw::c_uint = 0xc0010115;
+pub const MSR_VM_HSAVE_PA: ::std::os::raw::c_uint = 0xc0010117;
diff --git a/x86_64/src/regs.rs b/x86_64/src/regs.rs
new file mode 100644
index 0000000..8879a0c
--- /dev/null
+++ b/x86_64/src/regs.rs
@@ -0,0 +1,370 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::alloc::Layout;
+use std::fmt::{self, Display};
+use std::{mem, result};
+
+use assertions::const_assert;
+use kvm;
+use kvm_sys::kvm_fpu;
+use kvm_sys::kvm_msr_entry;
+use kvm_sys::kvm_msrs;
+use kvm_sys::kvm_regs;
+use kvm_sys::kvm_sregs;
+use sys_util::{self, GuestAddress, GuestMemory, LayoutAllocation};
+
+use crate::gdt;
+
+#[derive(Debug)]
+pub enum Error {
+    /// Setting up msrs failed.
+    MsrIoctlFailed(sys_util::Error),
+    /// Failed to configure the FPU.
+    FpuIoctlFailed(sys_util::Error),
+    /// Failed to get sregs for this cpu.
+    GetSRegsIoctlFailed(sys_util::Error),
+    /// Failed to set base registers for this cpu.
+    SettingRegistersIoctl(sys_util::Error),
+    /// Failed to set sregs for this cpu.
+    SetSRegsIoctlFailed(sys_util::Error),
+    /// Writing the GDT to RAM failed.
+    WriteGDTFailure,
+    /// Writing the IDT to RAM failed.
+    WriteIDTFailure,
+    /// Writing PML4 to RAM failed.
+    WritePML4Address,
+    /// Writing PDPTE to RAM failed.
+    WritePDPTEAddress,
+    /// Writing PDE to RAM failed.
+    WritePDEAddress,
+}
+pub type Result<T> = result::Result<T, Error>;
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            MsrIoctlFailed(e) => write!(f, "setting up msrs failed: {}", e),
+            FpuIoctlFailed(e) => write!(f, "failed to configure the FPU: {}", e),
+            GetSRegsIoctlFailed(e) => write!(f, "failed to get sregs for this cpu: {}", e),
+            SettingRegistersIoctl(e) => {
+                write!(f, "failed to set base registers for this cpu: {}", e)
+            }
+            SetSRegsIoctlFailed(e) => write!(f, "failed to set sregs for this cpu: {}", e),
+            WriteGDTFailure => write!(f, "writing the GDT to RAM failed"),
+            WriteIDTFailure => write!(f, "writing the IDT to RAM failed"),
+            WritePML4Address => write!(f, "writing PML4 to RAM failed"),
+            WritePDPTEAddress => write!(f, "writing PDPTE to RAM failed"),
+            WritePDEAddress => write!(f, "writing PDE to RAM failed"),
+        }
+    }
+}
+
+fn create_msr_entries() -> Vec<kvm_msr_entry> {
+    let mut entries = Vec::<kvm_msr_entry>::new();
+
+    entries.push(kvm_msr_entry {
+        index: crate::msr_index::MSR_IA32_SYSENTER_CS,
+        data: 0x0,
+        ..Default::default()
+    });
+    entries.push(kvm_msr_entry {
+        index: crate::msr_index::MSR_IA32_SYSENTER_ESP,
+        data: 0x0,
+        ..Default::default()
+    });
+    entries.push(kvm_msr_entry {
+        index: crate::msr_index::MSR_IA32_SYSENTER_EIP,
+        data: 0x0,
+        ..Default::default()
+    });
+    // x86_64 specific msrs, we only run on x86_64 not x86
+    entries.push(kvm_msr_entry {
+        index: crate::msr_index::MSR_STAR,
+        data: 0x0,
+        ..Default::default()
+    });
+    entries.push(kvm_msr_entry {
+        index: crate::msr_index::MSR_CSTAR,
+        data: 0x0,
+        ..Default::default()
+    });
+    entries.push(kvm_msr_entry {
+        index: crate::msr_index::MSR_KERNEL_GS_BASE,
+        data: 0x0,
+        ..Default::default()
+    });
+    entries.push(kvm_msr_entry {
+        index: crate::msr_index::MSR_SYSCALL_MASK,
+        data: 0x0,
+        ..Default::default()
+    });
+    entries.push(kvm_msr_entry {
+        index: crate::msr_index::MSR_LSTAR,
+        data: 0x0,
+        ..Default::default()
+    });
+    // end of x86_64 specific code
+    entries.push(kvm_msr_entry {
+        index: crate::msr_index::MSR_IA32_TSC,
+        data: 0x0,
+        ..Default::default()
+    });
+    entries.push(kvm_msr_entry {
+        index: crate::msr_index::MSR_IA32_MISC_ENABLE,
+        data: crate::msr_index::MSR_IA32_MISC_ENABLE_FAST_STRING as u64,
+        ..Default::default()
+    });
+
+    entries
+}
+
+/// Configure Model specific registers for x86
+///
+/// # Arguments
+///
+/// * `vcpu` - Structure for the vcpu that holds the vcpu fd.
+pub fn setup_msrs(vcpu: &kvm::Vcpu) -> Result<()> {
+    const SIZE_OF_MSRS: usize = mem::size_of::<kvm_msrs>();
+    const SIZE_OF_ENTRY: usize = mem::size_of::<kvm_msr_entry>();
+    const ALIGN_OF_MSRS: usize = mem::align_of::<kvm_msrs>();
+    const ALIGN_OF_ENTRY: usize = mem::align_of::<kvm_msr_entry>();
+    const_assert!(ALIGN_OF_MSRS >= ALIGN_OF_ENTRY);
+
+    let entry_vec = create_msr_entries();
+    let size = SIZE_OF_MSRS + entry_vec.len() * SIZE_OF_ENTRY;
+    let layout = Layout::from_size_align(size, ALIGN_OF_MSRS).expect("impossible layout");
+    let mut allocation = LayoutAllocation::zeroed(layout);
+
+    // Safe to obtain an exclusive reference because there are no other
+    // references to the allocation yet and all-zero is a valid bit pattern.
+    let msrs = unsafe { allocation.as_mut::<kvm_msrs>() };
+
+    unsafe {
+        // Mapping the unsized array to a slice is unsafe becase the length isn't known.  Providing
+        // the length used to create the struct guarantees the entire slice is valid.
+        let entries: &mut [kvm_msr_entry] = msrs.entries.as_mut_slice(entry_vec.len());
+        entries.copy_from_slice(&entry_vec);
+    }
+    msrs.nmsrs = entry_vec.len() as u32;
+
+    vcpu.set_msrs(msrs).map_err(Error::MsrIoctlFailed)?;
+
+    Ok(())
+
+    // msrs allocation is deallocated.
+}
+
+/// Configure FPU registers for x86
+///
+/// # Arguments
+///
+/// * `vcpu` - Structure for the vcpu that holds the vcpu fd.
+pub fn setup_fpu(vcpu: &kvm::Vcpu) -> Result<()> {
+    let fpu: kvm_fpu = kvm_fpu {
+        fcw: 0x37f,
+        mxcsr: 0x1f80,
+        ..Default::default()
+    };
+
+    vcpu.set_fpu(&fpu).map_err(Error::FpuIoctlFailed)?;
+
+    Ok(())
+}
+
+/// Configure base registers for x86
+///
+/// # Arguments
+///
+/// * `vcpu` - Structure for the vcpu that holds the vcpu fd.
+/// * `boot_ip` - Starting instruction pointer.
+/// * `boot_sp` - Starting stack pointer.
+/// * `boot_si` - Must point to zero page address per Linux ABI.
+pub fn setup_regs(vcpu: &kvm::Vcpu, boot_ip: u64, boot_sp: u64, boot_si: u64) -> Result<()> {
+    let regs: kvm_regs = kvm_regs {
+        rflags: 0x0000000000000002u64,
+        rip: boot_ip,
+        rsp: boot_sp,
+        rbp: boot_sp,
+        rsi: boot_si,
+        ..Default::default()
+    };
+
+    vcpu.set_regs(&regs).map_err(Error::SettingRegistersIoctl)?;
+
+    Ok(())
+}
+
+const X86_CR0_PE: u64 = 0x1;
+const X86_CR0_PG: u64 = 0x80000000;
+const X86_CR4_PAE: u64 = 0x20;
+
+const EFER_LME: u64 = 0x100;
+const EFER_LMA: u64 = 0x400;
+
+const BOOT_GDT_OFFSET: u64 = 0x500;
+const BOOT_IDT_OFFSET: u64 = 0x520;
+
+const BOOT_GDT_MAX: usize = 4;
+
+fn write_gdt_table(table: &[u64], guest_mem: &GuestMemory) -> Result<()> {
+    let boot_gdt_addr = GuestAddress(BOOT_GDT_OFFSET);
+    for (index, entry) in table.iter().enumerate() {
+        let addr = guest_mem
+            .checked_offset(boot_gdt_addr, (index * mem::size_of::<u64>()) as u64)
+            .ok_or(Error::WriteGDTFailure)?;
+        guest_mem
+            .write_obj_at_addr(*entry, addr)
+            .map_err(|_| Error::WriteGDTFailure)?;
+    }
+    Ok(())
+}
+
+fn write_idt_value(val: u64, guest_mem: &GuestMemory) -> Result<()> {
+    let boot_idt_addr = GuestAddress(BOOT_IDT_OFFSET);
+    guest_mem
+        .write_obj_at_addr(val, boot_idt_addr)
+        .map_err(|_| Error::WriteIDTFailure)
+}
+
+fn configure_segments_and_sregs(mem: &GuestMemory, sregs: &mut kvm_sregs) -> Result<()> {
+    let gdt_table: [u64; BOOT_GDT_MAX as usize] = [
+        gdt::gdt_entry(0, 0, 0),            // NULL
+        gdt::gdt_entry(0xa09b, 0, 0xfffff), // CODE
+        gdt::gdt_entry(0xc093, 0, 0xfffff), // DATA
+        gdt::gdt_entry(0x808b, 0, 0xfffff), // TSS
+    ];
+
+    let code_seg = gdt::kvm_segment_from_gdt(gdt_table[1], 1);
+    let data_seg = gdt::kvm_segment_from_gdt(gdt_table[2], 2);
+    let tss_seg = gdt::kvm_segment_from_gdt(gdt_table[3], 3);
+
+    // Write segments
+    write_gdt_table(&gdt_table[..], mem)?;
+    sregs.gdt.base = BOOT_GDT_OFFSET as u64;
+    sregs.gdt.limit = mem::size_of_val(&gdt_table) as u16 - 1;
+
+    write_idt_value(0, mem)?;
+    sregs.idt.base = BOOT_IDT_OFFSET as u64;
+    sregs.idt.limit = mem::size_of::<u64>() as u16 - 1;
+
+    sregs.cs = code_seg;
+    sregs.ds = data_seg;
+    sregs.es = data_seg;
+    sregs.fs = data_seg;
+    sregs.gs = data_seg;
+    sregs.ss = data_seg;
+    sregs.tr = tss_seg;
+
+    /* 64-bit protected mode */
+    sregs.cr0 |= X86_CR0_PE;
+    sregs.efer |= EFER_LME;
+
+    Ok(())
+}
+
+fn setup_page_tables(mem: &GuestMemory, sregs: &mut kvm_sregs) -> Result<()> {
+    // Puts PML4 right after zero page but aligned to 4k.
+    let boot_pml4_addr = GuestAddress(0x9000);
+    let boot_pdpte_addr = GuestAddress(0xa000);
+    let boot_pde_addr = GuestAddress(0xb000);
+
+    // Entry covering VA [0..512GB)
+    mem.write_obj_at_addr(boot_pdpte_addr.offset() as u64 | 0x03, boot_pml4_addr)
+        .map_err(|_| Error::WritePML4Address)?;
+
+    // Entry covering VA [0..1GB)
+    mem.write_obj_at_addr(boot_pde_addr.offset() as u64 | 0x03, boot_pdpte_addr)
+        .map_err(|_| Error::WritePDPTEAddress)?;
+
+    // 512 2MB entries together covering VA [0..1GB). Note we are assuming
+    // CPU supports 2MB pages (/proc/cpuinfo has 'pse'). All modern CPUs do.
+    for i in 0..512 {
+        mem.write_obj_at_addr((i << 21) + 0x83u64, boot_pde_addr.unchecked_add(i * 8))
+            .map_err(|_| Error::WritePDEAddress)?;
+    }
+    sregs.cr3 = boot_pml4_addr.offset() as u64;
+    sregs.cr4 |= X86_CR4_PAE;
+    sregs.cr0 |= X86_CR0_PG;
+    sregs.efer |= EFER_LMA; // Long mode is active. Must be auto-enabled with CR0_PG.
+    Ok(())
+}
+
+/// Configures the segment registers and system page tables for a given CPU.
+///
+/// # Arguments
+///
+/// * `mem` - The memory that will be passed to the guest.
+/// * `vcpu_fd` - The FD returned from the KVM_CREATE_VCPU ioctl.
+pub fn setup_sregs(mem: &GuestMemory, vcpu: &kvm::Vcpu) -> Result<()> {
+    let mut sregs: kvm_sregs = vcpu.get_sregs().map_err(Error::GetSRegsIoctlFailed)?;
+
+    configure_segments_and_sregs(mem, &mut sregs)?;
+    setup_page_tables(mem, &mut sregs)?; // TODO(dgreid) - Can this be done once per system instead?
+
+    vcpu.set_sregs(&sregs).map_err(Error::SetSRegsIoctlFailed)?;
+
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use sys_util::{GuestAddress, GuestMemory};
+
+    fn create_guest_mem() -> GuestMemory {
+        GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap()
+    }
+
+    fn read_u64(gm: &GuestMemory, offset: u64) -> u64 {
+        let read_addr = GuestAddress(offset);
+        gm.read_obj_from_addr(read_addr).unwrap()
+    }
+
+    #[test]
+    fn segments_and_sregs() {
+        let mut sregs: kvm_sregs = Default::default();
+        let gm = create_guest_mem();
+        configure_segments_and_sregs(&gm, &mut sregs).unwrap();
+
+        assert_eq!(0x0, read_u64(&gm, BOOT_GDT_OFFSET));
+        assert_eq!(0xaf9b000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 8));
+        assert_eq!(0xcf93000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 16));
+        assert_eq!(0x8f8b000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 24));
+        assert_eq!(0x0, read_u64(&gm, BOOT_IDT_OFFSET));
+
+        assert_eq!(0, sregs.cs.base);
+        assert_eq!(0xfffff, sregs.ds.limit);
+        assert_eq!(0x10, sregs.es.selector);
+        assert_eq!(1, sregs.fs.present);
+        assert_eq!(1, sregs.gs.g);
+        assert_eq!(0, sregs.ss.avl);
+        assert_eq!(0, sregs.tr.base);
+        assert_eq!(0xfffff, sregs.tr.limit);
+        assert_eq!(0, sregs.tr.avl);
+        assert_eq!(X86_CR0_PE, sregs.cr0);
+        assert_eq!(EFER_LME, sregs.efer);
+    }
+
+    #[test]
+    fn page_tables() {
+        let mut sregs: kvm_sregs = Default::default();
+        let gm = create_guest_mem();
+        setup_page_tables(&gm, &mut sregs).unwrap();
+
+        assert_eq!(0xa003, read_u64(&gm, 0x9000));
+        assert_eq!(0xb003, read_u64(&gm, 0xa000));
+        for i in 0..512 {
+            assert_eq!((i << 21) + 0x83u64, read_u64(&gm, 0xb000 + i * 8));
+        }
+
+        assert_eq!(0x9000, sregs.cr3);
+        assert_eq!(X86_CR4_PAE, sregs.cr4);
+        assert_eq!(X86_CR0_PG, sregs.cr0);
+    }
+}
diff --git a/x86_64/src/smbios.rs b/x86_64/src/smbios.rs
new file mode 100644
index 0000000..0ae3851
--- /dev/null
+++ b/x86_64/src/smbios.rs
@@ -0,0 +1,247 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fmt::{self, Display};
+use std::mem;
+use std::result;
+use std::slice;
+
+use data_model::DataInit;
+use sys_util::{GuestAddress, GuestMemory};
+
+#[derive(Debug)]
+pub enum Error {
+    /// There was too little guest memory to store the entire SMBIOS table.
+    NotEnoughMemory,
+    /// The SMBIOS table has too little address space to be stored.
+    AddressOverflow,
+    /// Failure while zeroing out the memory for the SMBIOS table.
+    Clear,
+    /// Failure to write SMBIOS entrypoint structure
+    WriteSmbiosEp,
+    /// Failure to write additional data to memory
+    WriteData,
+}
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        let description = match self {
+            NotEnoughMemory => "There was too little guest memory to store the SMBIOS table",
+            AddressOverflow => "The SMBIOS table has too little address space to be stored",
+            Clear => "Failure while zeroing out the memory for the SMBIOS table",
+            WriteSmbiosEp => "Failure to write SMBIOS entrypoint structure",
+            WriteData => "Failure to write additional data to memory",
+        };
+
+        write!(f, "SMBIOS error: {}", description)
+    }
+}
+
+pub type Result<T> = result::Result<T, Error>;
+
+const SMBIOS_START: u64 = 0xf0000; // First possible location per the spec.
+
+// Constants sourced from SMBIOS Spec 3.2.0.
+const SM3_MAGIC_IDENT: &[u8; 5usize] = b"_SM3_";
+const BIOS_INFORMATION: u8 = 0;
+const SYSTEM_INFORMATION: u8 = 1;
+const PCI_SUPPORTED: u64 = 1 << 7;
+const IS_VIRTUAL_MACHINE: u8 = 1 << 4;
+
+fn compute_checksum<T: Copy>(v: &T) -> u8 {
+    // Safe because we are only reading the bytes within the size of the `T` reference `v`.
+    let v_slice = unsafe { slice::from_raw_parts(v as *const T as *const u8, mem::size_of::<T>()) };
+    let mut checksum: u8 = 0;
+    for i in v_slice.iter() {
+        checksum = checksum.wrapping_add(*i);
+    }
+    (!checksum).wrapping_add(1)
+}
+
+#[repr(packed)]
+#[derive(Default, Copy)]
+pub struct Smbios30Entrypoint {
+    pub signature: [u8; 5usize],
+    pub checksum: u8,
+    pub length: u8,
+    pub majorver: u8,
+    pub minorver: u8,
+    pub docrev: u8,
+    pub revision: u8,
+    pub reserved: u8,
+    pub max_size: u32,
+    pub physptr: u64,
+}
+unsafe impl data_model::DataInit for Smbios30Entrypoint {}
+
+impl Clone for Smbios30Entrypoint {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+#[repr(packed)]
+#[derive(Default, Copy)]
+pub struct SmbiosBiosInfo {
+    pub typ: u8,
+    pub length: u8,
+    pub handle: u16,
+    pub vendor: u8,
+    pub version: u8,
+    pub start_addr: u16,
+    pub release_date: u8,
+    pub rom_size: u8,
+    pub characteristics: u64,
+    pub characteristics_ext1: u8,
+    pub characteristics_ext2: u8,
+}
+
+impl Clone for SmbiosBiosInfo {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+unsafe impl data_model::DataInit for SmbiosBiosInfo {}
+
+#[repr(packed)]
+#[derive(Default, Copy)]
+pub struct SmbiosSysInfo {
+    pub typ: u8,
+    pub length: u8,
+    pub handle: u16,
+    pub manufacturer: u8,
+    pub product_name: u8,
+    pub version: u8,
+    pub serial_number: u8,
+    pub uuid: [u8; 16usize],
+    pub wake_up_type: u8,
+    pub sku: u8,
+    pub family: u8,
+}
+
+impl Clone for SmbiosSysInfo {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+unsafe impl data_model::DataInit for SmbiosSysInfo {}
+
+fn write_and_incr<T: DataInit>(
+    mem: &GuestMemory,
+    val: T,
+    mut curptr: GuestAddress,
+) -> Result<GuestAddress> {
+    mem.write_obj_at_addr(val, curptr)
+        .map_err(|_| Error::WriteData)?;
+    curptr = curptr
+        .checked_add(mem::size_of::<T>() as u64)
+        .ok_or(Error::NotEnoughMemory)?;
+    Ok(curptr)
+}
+
+fn write_string(mem: &GuestMemory, val: &str, mut curptr: GuestAddress) -> Result<GuestAddress> {
+    for c in val.as_bytes().iter() {
+        curptr = write_and_incr(mem, *c, curptr)?;
+    }
+    curptr = write_and_incr(mem, 0 as u8, curptr)?;
+    Ok(curptr)
+}
+
+pub fn setup_smbios(mem: &GuestMemory) -> Result<()> {
+    let physptr = GuestAddress(SMBIOS_START)
+        .checked_add(mem::size_of::<Smbios30Entrypoint>() as u64)
+        .ok_or(Error::NotEnoughMemory)?;
+    let mut curptr = physptr;
+    let mut handle = 0;
+
+    {
+        handle += 1;
+        let mut smbios_biosinfo = SmbiosBiosInfo::default();
+        smbios_biosinfo.typ = BIOS_INFORMATION;
+        smbios_biosinfo.length = mem::size_of::<SmbiosBiosInfo>() as u8;
+        smbios_biosinfo.handle = handle;
+        smbios_biosinfo.vendor = 1; // First string written in this section
+        smbios_biosinfo.version = 2; // Second string written in this section
+        smbios_biosinfo.characteristics = PCI_SUPPORTED;
+        smbios_biosinfo.characteristics_ext2 = IS_VIRTUAL_MACHINE;
+        curptr = write_and_incr(mem, smbios_biosinfo, curptr)?;
+        curptr = write_string(mem, "crosvm", curptr)?;
+        curptr = write_string(mem, "0", curptr)?;
+        curptr = write_and_incr(mem, 0 as u8, curptr)?;
+    }
+
+    {
+        handle += 1;
+        let mut smbios_sysinfo = SmbiosSysInfo::default();
+        smbios_sysinfo.typ = SYSTEM_INFORMATION;
+        smbios_sysinfo.length = mem::size_of::<SmbiosSysInfo>() as u8;
+        smbios_sysinfo.handle = handle;
+        smbios_sysinfo.manufacturer = 1; // First string written in this section
+        smbios_sysinfo.product_name = 2; // Second string written in this section
+        curptr = write_and_incr(mem, smbios_sysinfo, curptr)?;
+        curptr = write_string(mem, "ChromiumOS", curptr)?;
+        curptr = write_string(mem, "crosvm", curptr)?;
+        curptr = write_and_incr(mem, 0 as u8, curptr)?;
+    }
+
+    {
+        let mut smbios_ep = Smbios30Entrypoint::default();
+        smbios_ep.signature = *SM3_MAGIC_IDENT;
+        smbios_ep.length = mem::size_of::<Smbios30Entrypoint>() as u8;
+        // SMBIOS rev 3.2.0
+        smbios_ep.majorver = 0x03;
+        smbios_ep.minorver = 0x02;
+        smbios_ep.docrev = 0x00;
+        smbios_ep.revision = 0x01; // SMBIOS 3.0
+        smbios_ep.max_size = curptr.offset_from(physptr) as u32;
+        smbios_ep.physptr = physptr.offset();
+        smbios_ep.checksum = compute_checksum(&smbios_ep);
+        mem.write_obj_at_addr(smbios_ep, GuestAddress(SMBIOS_START))
+            .map_err(|_| Error::WriteSmbiosEp)?;
+    }
+
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn struct_size() {
+        assert_eq!(
+            mem::size_of::<Smbios30Entrypoint>(),
+            0x18usize,
+            concat!("Size of: ", stringify!(Smbios30Entrypoint))
+        );
+        assert_eq!(
+            mem::size_of::<SmbiosBiosInfo>(),
+            0x14usize,
+            concat!("Size of: ", stringify!(SmbiosBiosInfo))
+        );
+        assert_eq!(
+            mem::size_of::<SmbiosSysInfo>(),
+            0x1busize,
+            concat!("Size of: ", stringify!(SmbiosSysInfo))
+        );
+    }
+
+    #[test]
+    fn entrypoint_checksum() {
+        let mem = GuestMemory::new(&[(GuestAddress(SMBIOS_START), 4096)]).unwrap();
+
+        setup_smbios(&mem).unwrap();
+
+        let smbios_ep: Smbios30Entrypoint =
+            mem.read_obj_from_addr(GuestAddress(SMBIOS_START)).unwrap();
+
+        assert_eq!(compute_checksum(&smbios_ep), 0);
+    }
+}