Merge "Merge commit '47996808415af4e0b7bd11db103b52d5fdd5fda7' into HEAD"
diff --git a/Android.bp b/Android.bp
index 3339be3..cc5a759 100644
--- a/Android.bp
+++ b/Android.bp
@@ -109,6 +109,7 @@
"libminijail_rust",
"libmsg_socket",
"libnet_util",
+ "libp9",
"librand_ish",
"libresources",
"libsync_rust",
@@ -158,6 +159,7 @@
"libminijail_rust",
"libmsg_socket",
"libnet_util",
+ "libp9",
"librand_ish",
"libresources",
"libsync_rust",
@@ -232,6 +234,7 @@
"libminijail_rust",
"libmsg_socket",
"libnet_util",
+ "libp9",
"librand_ish",
"libresources",
"libsync_rust",
@@ -308,6 +311,7 @@
"libminijail_rust",
"libmsg_socket",
"libnet_util",
+ "libp9",
"librand_ish",
"libresources",
"libsync_rust",
@@ -328,9 +332,11 @@
// ../adhd/cras/client/libcras/src/libcras.rs
// ../minijail/rust/minijail-sys/lib.rs
// ../minijail/rust/minijail/src/lib.rs
+// ../rust/crates/libchromeos-rs/src/lib.rs
// ../vm_tools/p9/src/lib.rs
// ../vm_tools/p9/wire_format_derive/wire_format_derive.rs
// async-trait-0.1.42
+// autocfg-1.0.1
// bitflags-1.2.1 "default"
// cfg-if-0.1.10
// downcast-rs-1.2.0 "default,std"
@@ -343,9 +349,13 @@
// futures-sink-0.3.8 "alloc,std"
// futures-task-0.3.8 "alloc,once_cell,std"
// futures-util-0.3.8 "alloc,async-await,async-await-macro,channel,futures-channel,futures-io,futures-macro,futures-sink,io,memchr,proc-macro-hack,proc-macro-nested,sink,slab,std"
+// getopts-0.2.21
// getrandom-0.1.15 "std"
+// intrusive-collections-0.9.0 "alloc,default"
// libc-0.2.80 "default,std"
+// log-0.4.11
// memchr-2.3.4 "default,std"
+// memoffset-0.5.6 "default"
// once_cell-1.5.2 "alloc,std"
// paste-1.0.3
// pin-project-1.0.2
@@ -356,6 +366,7 @@
// proc-macro-hack-0.5.19
// proc-macro-nested-0.1.6
// proc-macro2-1.0.24 "default,proc-macro"
+// protobuf-2.18.1
// quote-1.0.7 "default,proc-macro"
// rand-0.7.3 "alloc,default,getrandom,getrandom_package,libc,std"
// rand_chacha-0.2.2 "std"
@@ -363,8 +374,9 @@
// remain-0.2.2
// remove_dir_all-0.5.3
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// tempfile-3.1.0
// thiserror-1.0.22
// thiserror-impl-1.0.22
+// unicode-width-0.1.8 "default"
// unicode-xid-0.2.1 "default"
diff --git a/Cargo.lock b/Cargo.lock
index f410a02..a630236 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -41,10 +41,12 @@
"acpi_tables 0.1.0",
"base 0.1.0",
"devices 0.1.0",
+ "gdbstub 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hypervisor 0.1.0",
"kernel_cmdline 0.1.0",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"minijail 0.2.1",
+ "msg_socket 0.1.0",
"resources 0.1.0",
"sync 0.1.0",
"vm_control 0.1.0",
@@ -74,10 +76,17 @@
]
[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "base"
version = "0.1.0"
dependencies = [
+ "cros_async 0.1.0",
"data_model 0.1.0",
+ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"sync 0.1.0",
"sys_util 0.1.0",
]
@@ -110,7 +119,7 @@
[[package]]
name = "cfg-if"
-version = "0.1.5"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -126,13 +135,13 @@
version = "0.1.0"
dependencies = [
"async-trait 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
- "base 0.1.0",
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"io_uring 0.1.0",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
- "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "paste 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sys_util 0.1.0",
"syscall_defines 0.1.0",
"thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -153,6 +162,7 @@
"devices 0.1.0",
"disk 0.1.0",
"enumn 0.1.0",
+ "gdbstub 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gpu_buffer 0.1.0",
"gpu_renderer 0.1.0",
"hypervisor 0.1.0",
@@ -165,6 +175,7 @@
"minijail 0.2.1",
"msg_socket 0.1.0",
"net_util 0.1.0",
+ "p9 0.1.0",
"protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"protos 0.1.0",
"rand_ish 0.1.0",
@@ -172,6 +183,7 @@
"resources 0.1.0",
"sync 0.1.0",
"tempfile 3.0.7",
+ "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
"vhost 0.1.0",
"vm_control 0.1.0",
"vm_memory 0.1.0",
@@ -206,11 +218,11 @@
"audio_streams 0.1.0",
"base 0.1.0",
"bit_field 0.1.0",
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cros_async 0.1.0",
"data_model 0.1.0",
"disk 0.1.0",
"enumn 0.1.0",
+ "fuse 0.1.0",
"gpu_buffer 0.1.0",
"gpu_display 0.1.0",
"gpu_renderer 0.1.0",
@@ -274,6 +286,18 @@
]
[[package]]
+name = "fuse"
+version = "0.1.0"
+dependencies = [
+ "base 0.1.0",
+ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "data_model 0.1.0",
+ "enumn 0.1.0",
+ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
+ "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "futures"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -356,6 +380,18 @@
]
[[package]]
+name = "gdbstub"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "managed 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "paste 1.0.2 (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"
@@ -410,11 +446,19 @@
]
[[package]]
+name = "intrusive-collections"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "memoffset 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "io_uring"
version = "0.1.0"
dependencies = [
- "base 0.1.0",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sys_util 0.1.0",
"syscall_defines 0.1.0",
]
@@ -463,6 +507,19 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "libchromeos"
+version = "0.1.0"
+dependencies = [
+ "data_model 0.1.0",
+ "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "intrusive-collections 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "libcras"
version = "0.1.0"
dependencies = [
@@ -496,15 +553,28 @@
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)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "managed"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "memchr"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "memoffset"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "minijail"
version = "0.2.1"
dependencies = [
@@ -524,6 +594,7 @@
name = "msg_on_socket_derive"
version = "0.1.0"
dependencies = [
+ "base 0.1.0",
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -560,6 +631,14 @@
]
[[package]]
+name = "num-traits"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "num_cpus"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -572,28 +651,14 @@
version = "0.1.0"
dependencies = [
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libchromeos 0.1.0",
"wire_format_derive 0.1.0",
]
[[package]]
name = "paste"
-version = "0.1.6"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "paste-impl"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
-]
[[package]]
name = "pin-utils"
@@ -857,6 +922,7 @@
dependencies = [
"base 0.1.0",
"data_model 0.1.0",
+ "gdbstub 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hypervisor 0.1.0",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"msg_socket 0.1.0",
@@ -895,11 +961,13 @@
"base 0.1.0",
"data_model 0.1.0",
"devices 0.1.0",
+ "gdbstub 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hypervisor 0.1.0",
"kernel_cmdline 0.1.0",
"kernel_loader 0.1.0",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"minijail 0.2.1",
+ "msg_socket 0.1.0",
"remain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"resources 0.1.0",
"sync 0.1.0",
@@ -910,9 +978,10 @@
[metadata]
"checksum android_log-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85965b6739a430150bdd138e2374a98af0c3ee0d030b3bb7fc3bddff58d0102e"
"checksum async-trait 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a265e3abeffdce30b2e26b7a11b222fe37c6067404001b434101457d0385eb92"
+"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
"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 cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum downcast-rs 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
"checksum futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6f16056ecbb57525ff698bb955162d0cd03bee84e6241c27ff75c08d8ca5987"
"checksum futures-channel 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fcae98ca17d102fd8a3603727b9259fcf7fa4239b603d2142926189bc8999b86"
@@ -923,13 +992,17 @@
"checksum futures-sink 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "171be33efae63c2d59e6dbba34186fe0d6394fb378069a76dfd80fdcffd43c16"
"checksum futures-task 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0bae52d6b29cf440e298856fec3965ee6fa71b06aa7495178615953fd669e5f9"
"checksum futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d66274fb76985d3c62c886d1da7ac4c0903a8c9f754e8fe0f35a6a6cc39e76"
+"checksum gdbstub 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "347c27d24b8ac4a2bcad3ff3d0695271a0510c020bd8134b53d189e973ed58bf"
"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797"
+"checksum intrusive-collections 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4bca8c0bb831cd60d4dda79a58e3705ca6eb47efb65d665651a8d672213ec3db"
"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8"
"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f"
+"checksum managed 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223"
+"checksum memoffset 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa"
+"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
"checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238"
-"checksum paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "423a519e1c6e828f1e73b720f9d9ed2fa643dce8a7737fb43235ce0b41eeaa49"
-"checksum paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5"
+"checksum paste 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ba7ae1a2180ed02ddfdb5ab70c70d596a26dd642e097bb6fe78b1bde8588ed97"
"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
"checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f"
"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5"
diff --git a/Cargo.toml b/Cargo.toml
index 1b3e233..354e072 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -45,6 +45,7 @@
virtio-gpu-next = ["gpu_renderer/virtio-gpu-next"]
composite-disk = ["protos/composite-disk", "protobuf", "disk/composite-disk"]
gfxstream = ["devices/gfxstream"]
+gdb = ["gdbstub", "thiserror", "arch/gdb", "vm_control/gdb", "x86_64/gdb"]
[dependencies]
arch = { path = "arch" }
@@ -57,6 +58,7 @@
devices = { path = "devices" }
disk = { path = "disk" }
enumn = { path = "enumn" }
+gdbstub = { version = "0.4.0", optional = true }
gpu_buffer = { path = "gpu_buffer", optional = true }
gpu_renderer = { path = "gpu_renderer", optional = true }
hypervisor = { path = "hypervisor" }
@@ -69,6 +71,7 @@
minijail = "*" # provided by ebuild
msg_socket = { path = "msg_socket" }
net_util = { path = "net_util" }
+p9 = { path = "../vm_tools/p9" }
protobuf = { version = "2.3", optional = true }
protos = { path = "protos", optional = true }
rand_ish = { path = "rand_ish" }
@@ -76,6 +79,7 @@
resources = { path = "resources" }
sync = { path = "sync" }
tempfile = "*"
+thiserror = { version = "1.0.20", optional = true }
vhost = { path = "vhost" }
vm_control = { path = "vm_control" }
acpi_tables = { path = "acpi_tables" }
diff --git a/README.md b/README.md
index f6b8f5d..3999a5e 100644
--- a/README.md
+++ b/README.md
@@ -162,6 +162,34 @@
the path `$XDG_RUNTIME_DIR/wayland-0` points to the socket of the Wayland
compositor you would like the guest to use.
+### GDB Support
+
+crosvm supports [GDB Remote Serial Protocol] to allow developers to debug guest
+kernel via GDB.
+
+You can enable the feature by `--gdb` flag:
+
+```sh
+# Use uncompressed vmlinux
+$ crosvm run --gdb <port> ${USUAL_CROSVM_ARGS} vmlinux
+```
+
+Then, you can start GDB in another shell.
+
+```sh
+$ gdb vmlinux
+(gdb) target remote :<port>
+(gdb) hbreak start_kernel
+(gdb) c
+<start booting in the other shell>
+```
+
+For general techniques for debugging the Linux kernel via GDB, see this
+[kernel documentation].
+
+[GDB Remote Serial Protocol]: https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html
+[kernel documentation]: https://www.kernel.org/doc/html/latest/dev-tools/gdb-kernel-debugging.html
+
## Defaults
The following are crosvm's default arguments and how to override them.
diff --git a/aarch64/Android.bp b/aarch64/Android.bp
index 90a99f9..790b958 100644
--- a/aarch64/Android.bp
+++ b/aarch64/Android.bp
@@ -95,6 +95,7 @@
// ../../adhd/cras/client/libcras/src/libcras.rs
// ../../minijail/rust/minijail-sys/lib.rs
// ../../minijail/rust/minijail/src/lib.rs
+// ../../rust/crates/libchromeos-rs/src/lib.rs
// ../../vm_tools/p9/src/lib.rs
// ../../vm_tools/p9/wire_format_derive/wire_format_derive.rs
// ../acpi_tables/src/lib.rs
@@ -108,6 +109,7 @@
// ../devices/src/lib.rs
// ../disk/src/disk.rs
// ../enumn/src/lib.rs
+// ../fuse/src/lib.rs
// ../hypervisor/src/lib.rs
// ../io_uring/src/lib.rs
// ../kernel_cmdline/src/kernel_cmdline.rs
@@ -133,6 +135,8 @@
// ../vm_control/src/lib.rs
// ../vm_memory/src/lib.rs
// async-trait-0.1.42
+// autocfg-1.0.1
+// base-0.1.0
// bitflags-1.2.1 "default"
// cfg-if-0.1.10
// downcast-rs-1.2.0 "default,std"
@@ -145,9 +149,13 @@
// futures-sink-0.3.8 "alloc,std"
// futures-task-0.3.8 "alloc,once_cell,std"
// futures-util-0.3.8 "alloc,async-await,async-await-macro,channel,futures-channel,futures-io,futures-macro,futures-sink,io,memchr,proc-macro-hack,proc-macro-nested,sink,slab,std"
+// getopts-0.2.21
// getrandom-0.1.15 "std"
+// intrusive-collections-0.9.0 "alloc,default"
// libc-0.2.80 "default,std"
+// log-0.4.11
// memchr-2.3.4 "default,std"
+// memoffset-0.5.6 "default"
// once_cell-1.5.2 "alloc,std"
// paste-1.0.3
// pin-project-1.0.2
@@ -158,6 +166,7 @@
// proc-macro-hack-0.5.19
// proc-macro-nested-0.1.6
// proc-macro2-1.0.24 "default,proc-macro"
+// protobuf-2.18.1
// quote-1.0.7 "default,proc-macro"
// rand-0.7.3 "alloc,default,getrandom,getrandom_package,libc,std"
// rand_chacha-0.2.2 "std"
@@ -165,8 +174,9 @@
// remain-0.2.2
// remove_dir_all-0.5.3
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// tempfile-3.1.0
// thiserror-1.0.22
// thiserror-impl-1.0.22
+// unicode-width-0.1.8 "default"
// unicode-xid-0.2.1 "default"
diff --git a/aarch64/src/fdt.rs b/aarch64/src/fdt.rs
index cda15fa..9606982 100644
--- a/aarch64/src/fdt.rs
+++ b/aarch64/src/fdt.rs
@@ -12,6 +12,7 @@
};
use arch::SERIAL_ADDR;
use devices::{PciAddress, PciInterruptPin};
+use hypervisor::PsciVersion;
use vm_memory::{GuestAddress, GuestMemory};
// This is the start of DRAM in the physical address space.
@@ -182,18 +183,20 @@
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";
+fn create_psci_node(fdt: &mut Vec<u8>, version: &PsciVersion) -> Result<()> {
+ let compatible = if version.major == 1 {
+ // Put `psci-0.2` as well because PSCI 1.0 is compatible with PSCI 0.2.
+ format!(
+ "\"arm,psci-{}.{}\", \"arm,psci-0.2\"",
+ version.major, version.minor
+ )
+ } else {
+ format!("arm,psci-{}.{}", version.major, version.minor)
+ };
begin_node(fdt, "psci")?;
- property_string(fdt, "compatible", compatible)?;
+ 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(())
@@ -358,6 +361,7 @@
/// * `initrd` - An optional tuple of initrd guest physical address and size
/// * `android_fstab` - An optional file holding Android fstab entries
/// * `is_gicv3` - True if gicv3, false if v2
+/// * `psci_version` - the current PSCI version
pub fn create_fdt(
fdt_max_size: usize,
guest_mem: &GuestMemory,
@@ -371,6 +375,7 @@
android_fstab: Option<File>,
is_gicv3: bool,
use_pmu: bool,
+ psci_version: PsciVersion,
) -> Result<()> {
let mut fdt = vec![0; fdt_max_size];
start_fdt(&mut fdt, fdt_max_size)?;
@@ -393,7 +398,7 @@
create_pmu_node(&mut fdt, num_cpus)?;
}
create_serial_nodes(&mut fdt)?;
- create_psci_node(&mut fdt)?;
+ create_psci_node(&mut fdt, &psci_version)?;
create_pci_nodes(&mut fdt, pci_irqs, pci_device_base, pci_device_size)?;
create_rtc_node(&mut fdt)?;
// End giant node
diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs
index cb8fecf..9eb5a74 100644
--- a/aarch64/src/lib.rs
+++ b/aarch64/src/lib.rs
@@ -18,11 +18,14 @@
use devices::{
Bus, BusError, IrqChip, IrqChipAArch64, PciAddress, PciConfigMmio, PciDevice, PciInterruptPin,
};
-use hypervisor::{DeviceKind, Hypervisor, HypervisorCap, VcpuAArch64, VcpuFeature, VmAArch64};
+use hypervisor::{
+ DeviceKind, Hypervisor, HypervisorCap, PsciVersion, VcpuAArch64, VcpuFeature, VmAArch64,
+};
use minijail::Minijail;
use remain::sorted;
use resources::SystemAllocator;
use sync::Mutex;
+use vm_control::BatteryType;
use vm_memory::{GuestAddress, GuestMemory, GuestMemoryError};
mod fdt;
@@ -123,6 +126,7 @@
CreateVcpu(base::Error),
CreateVm(Box<dyn StdError>),
DowncastVcpu,
+ GetPsciVersion(base::Error),
GetSerialCmdline(GetSerialCmdlineError),
InitrdLoadFailure(arch::LoadImageError),
KernelLoadFailure(arch::LoadImageError),
@@ -156,6 +160,7 @@
CreateVcpu(e) => write!(f, "failed to create VCPU: {}", e),
CreateVm(e) => write!(f, "failed to create vm: {}", e),
DowncastVcpu => write!(f, "vm created wrong kind of vcpu"),
+ GetPsciVersion(e) => write!(f, "failed to get PSCI version: {}", e),
GetSerialCmdline(e) => write!(f, "failed to get serial cmdline: {}", e),
InitrdLoadFailure(e) => write!(f, "initrd cound not be loaded: {}", e),
KernelLoadFailure(e) => write!(f, "kernel cound not be loaded: {}", e),
@@ -197,6 +202,7 @@
mut components: VmComponents,
serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
serial_jail: Option<Minijail>,
+ _battery: (&Option<BatteryType>, Option<Minijail>),
create_devices: FD,
create_vm: FV,
create_irq_chip: FI,
@@ -290,12 +296,7 @@
.map_err(Error::RegisterIrqfd)?;
mmio_bus
- .insert(
- pci_bus.clone(),
- AARCH64_PCI_CFG_BASE,
- AARCH64_PCI_CFG_SIZE,
- false,
- )
+ .insert(pci_bus.clone(), AARCH64_PCI_CFG_BASE, AARCH64_PCI_CFG_SIZE)
.map_err(Error::RegisterPci)?;
let mut cmdline = Self::get_base_linux_cmdline();
@@ -316,6 +317,8 @@
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;
+ let psci_version = vcpus[0].get_psci_version().map_err(Error::GetPsciVersion)?;
+
Self::setup_system_memory(
&mem,
components.memory_size,
@@ -327,6 +330,7 @@
kernel_end,
irq_chip.get_vgic_version() == DeviceKind::ArmVgicV3,
use_pmu,
+ psci_version,
)?;
Ok(RunnableLinuxVm {
@@ -344,6 +348,7 @@
pid_debug_label_map,
suspend_evt,
rt_cpus: components.rt_cpus,
+ bat_control: None,
})
}
@@ -374,6 +379,7 @@
kernel_end: u64,
is_gicv3: bool,
use_pmu: bool,
+ psci_version: PsciVersion,
) -> Result<()> {
let initrd = match initrd_file {
Some(initrd_file) => {
@@ -403,6 +409,7 @@
android_fstab,
is_gicv3,
use_pmu,
+ psci_version,
)
.map_err(Error::CreateFdt)?;
Ok(())
@@ -450,7 +457,7 @@
.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)
+ bus.insert(rtc, AARCH64_RTC_ADDR, AARCH64_RTC_SIZE)
.expect("failed to add rtc device");
Ok(())
diff --git a/arch/Android.bp b/arch/Android.bp
index d67d261..e5f2ed4 100644
--- a/arch/Android.bp
+++ b/arch/Android.bp
@@ -16,6 +16,7 @@
"libkernel_cmdline",
"liblibc",
"libminijail_rust",
+ "libmsg_socket",
"libresources",
"libsync_rust",
"libvm_control",
@@ -51,6 +52,7 @@
"libkernel_cmdline",
"liblibc",
"libminijail_rust",
+ "libmsg_socket",
"libresources",
"libsync_rust",
"libvm_control",
@@ -65,6 +67,7 @@
// ../../adhd/audio_streams/src/audio_streams.rs
// ../../adhd/cras/client/cras-sys/src/lib.rs
// ../../adhd/cras/client/libcras/src/libcras.rs
+// ../../libchromeos-rs/src/lib.rs
// ../../minijail/rust/minijail-sys/lib.rs
// ../../minijail/rust/minijail/src/lib.rs
// ../../vm_tools/p9/src/lib.rs
@@ -79,6 +82,7 @@
// ../devices/src/lib.rs
// ../disk/src/disk.rs
// ../enumn/src/lib.rs
+// ../fuse/src/lib.rs
// ../hypervisor/src/lib.rs
// ../io_uring/src/lib.rs
// ../kernel_cmdline/src/kernel_cmdline.rs
@@ -104,6 +108,8 @@
// ../vm_control/src/lib.rs
// ../vm_memory/src/lib.rs
// async-trait-0.1.42
+// autocfg-1.0.1
+// base-0.1.0
// bitflags-1.2.1 "default"
// cfg-if-0.1.10
// downcast-rs-1.2.0 "default,std"
@@ -117,8 +123,11 @@
// futures-task-0.3.8 "alloc,once_cell,std"
// futures-util-0.3.8 "alloc,async-await,async-await-macro,channel,futures-channel,futures-io,futures-macro,futures-sink,io,memchr,proc-macro-hack,proc-macro-nested,sink,slab,std"
// getrandom-0.1.15 "std"
+// intrusive-collections-0.9.0 "alloc,default"
// libc-0.2.80 "default,std"
+// log-0.4.11
// memchr-2.3.4 "default,std"
+// memoffset-0.5.6 "default"
// once_cell-1.5.2 "alloc,std"
// paste-1.0.3
// pin-project-1.0.2
@@ -129,6 +138,7 @@
// proc-macro-hack-0.5.19
// proc-macro-nested-0.1.6
// proc-macro2-1.0.24 "default,proc-macro"
+// protobuf-2.18.1
// quote-1.0.7 "default,proc-macro"
// rand-0.7.3 "alloc,default,getrandom,getrandom_package,libc,std"
// rand_chacha-0.2.2 "std"
@@ -136,7 +146,7 @@
// remain-0.2.2
// remove_dir_all-0.5.3
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// tempfile-3.1.0
// thiserror-1.0.22
// thiserror-impl-1.0.22
diff --git a/arch/Cargo.toml b/arch/Cargo.toml
index dfd3eb7..38b27f5 100644
--- a/arch/Cargo.toml
+++ b/arch/Cargo.toml
@@ -4,13 +4,18 @@
authors = ["The Chromium OS Authors"]
edition = "2018"
+[features]
+gdb = ["gdbstub"]
+
[dependencies]
acpi_tables = { path = "../acpi_tables" }
devices = { path = "../devices" }
+gdbstub = { version = "0.4.0", optional = true }
hypervisor = { path = "../hypervisor" }
kernel_cmdline = { path = "../kernel_cmdline" }
libc = "*"
minijail = { path = "../../minijail/rust/minijail" } # ignored by ebuild
+msg_socket = { path = "../msg_socket" }
resources = { path = "../resources" }
sync = { path = "../sync" }
base = { path = "../base" }
diff --git a/arch/src/lib.rs b/arch/src/lib.rs
index 354a8e9..61e71f6 100644
--- a/arch/src/lib.rs
+++ b/arch/src/lib.rs
@@ -12,10 +12,10 @@
use std::fmt::{self, Display};
use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom};
-use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use std::sync::Arc;
+use acpi_tables::aml::Aml;
use acpi_tables::sdt::SDT;
use base::{syslog, AsRawDescriptor, Event};
use devices::virtio::VirtioDevice;
@@ -25,10 +25,18 @@
};
use hypervisor::{IoEventAddress, Vm};
use minijail::Minijail;
-use resources::SystemAllocator;
+use resources::{MmioType, SystemAllocator};
use sync::Mutex;
+#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+use vm_control::VmControlRequestSocket;
+use vm_control::{
+ BatControl, BatControlCommand, BatControlRequestSocket, BatControlResult, BatteryType,
+};
use vm_memory::{GuestAddress, GuestMemory, GuestMemoryError};
+#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+use gdbstub::arch::x86::reg::X86_64CoreRegs as GdbStubRegs;
+
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
use {
devices::IrqChipAArch64 as IrqChipArch,
@@ -84,6 +92,8 @@
pub acpi_sdts: Vec<SDT>,
pub rt_cpus: Vec<usize>,
pub protected_vm: bool,
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ pub gdb: Option<(u32, VmControlRequestSocket)>, // port and control socket.
}
/// Holds the elements needed to run a Linux VM. Created by `build_vm`.
@@ -104,6 +114,9 @@
pub pid_debug_label_map: BTreeMap<u32, String>,
pub suspend_evt: Event,
pub rt_cpus: Vec<usize>,
+ pub bat_control: Option<BatControl>,
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ pub gdb: Option<(u32, VmControlRequestSocket)>,
}
/// The device and optional jail.
@@ -123,6 +136,7 @@
///
/// * `components` - Parts to use to build the VM.
/// * `serial_parameters` - definitions for how the serial devices should be configured.
+ /// * `battery` - defines what battery device will be created.
/// * `create_devices` - Function to generate a list of devices.
/// * `create_vm` - Function to generate a VM.
/// * `create_irq_chip` - Function to generate an IRQ chip.
@@ -130,6 +144,7 @@
components: VmComponents,
serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
serial_jail: Option<Minijail>,
+ battery: (&Option<BatteryType>, Option<Minijail>),
create_devices: FD,
create_vm: FV,
create_irq_chip: FI,
@@ -171,6 +186,43 @@
has_bios: bool,
no_smt: bool,
) -> Result<(), Self::Error>;
+
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ /// Reads vCPU's registers.
+ fn debug_read_registers<T: VcpuArch>(vcpu: &T) -> Result<GdbStubRegs, Self::Error>;
+
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ /// Writes vCPU's registers.
+ fn debug_write_registers<T: VcpuArch>(vcpu: &T, regs: &GdbStubRegs) -> Result<(), Self::Error>;
+
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ /// Reads bytes from the guest memory.
+ fn debug_read_memory<T: VcpuArch>(
+ vcpu: &T,
+ guest_mem: &GuestMemory,
+ vaddr: GuestAddress,
+ len: usize,
+ ) -> Result<Vec<u8>, Self::Error>;
+
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ /// Writes bytes to the specified guest memory.
+ fn debug_write_memory<T: VcpuArch>(
+ vcpu: &T,
+ guest_mem: &GuestMemory,
+ vaddr: GuestAddress,
+ buf: &[u8],
+ ) -> Result<(), Self::Error>;
+
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ /// Make the next vCPU's run single-step.
+ fn debug_enable_singlestep<T: VcpuArch>(vcpu: &T) -> Result<(), Self::Error>;
+
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ /// Set hardware breakpoints at the given addresses.
+ fn debug_set_hw_breakpoints<T: VcpuArch>(
+ vcpu: &T,
+ breakpoints: &[GuestAddress],
+ ) -> Result<(), Self::Error>;
}
/// Errors for device manager.
@@ -178,6 +230,8 @@
pub enum DeviceRegistrationError {
/// Could not allocate IO space for the device.
AllocateIoAddrs(PciDeviceError),
+ /// Could not allocate MMIO or IO resource for the device.
+ AllocateIoResource(resources::Error),
/// Could not allocate device address space for the device.
AllocateDeviceAddrs(PciDeviceError),
/// Could not allocate an IRQ number.
@@ -186,6 +240,8 @@
CreatePipe(base::Error),
// Unable to create serial device from serial parameters
CreateSerialDevice(serial::Error),
+ // Unable to create socket
+ CreateSocket(io::Error),
/// Could not clone an event.
EventClone(base::Error),
/// Could not create an event.
@@ -208,6 +264,8 @@
AddrsExhausted,
/// Could not register PCI device capabilities.
RegisterDeviceCapabilities(PciDeviceError),
+ // Failed to register battery device.
+ RegisterBattery(devices::BatteryError),
}
impl Display for DeviceRegistrationError {
@@ -216,10 +274,12 @@
match self {
AllocateIoAddrs(e) => write!(f, "Allocating IO addresses: {}", e),
+ AllocateIoResource(e) => write!(f, "Allocating IO resource: {}", e),
AllocateDeviceAddrs(e) => write!(f, "Allocating device addresses: {}", e),
AllocateIrq => write!(f, "Allocating IRQ number"),
CreatePipe(e) => write!(f, "failed to create pipe: {}", e),
CreateSerialDevice(e) => write!(f, "failed to create serial device: {}", e),
+ CreateSocket(e) => write!(f, "failed to create socket: {}", e),
Cmdline(e) => write!(f, "unable to add device to kernel command line: {}", e),
EventClone(e) => write!(f, "failed to clone event: {}", e),
EventCreate(e) => write!(f, "failed to create event: {}", e),
@@ -233,6 +293,7 @@
RegisterDeviceCapabilities(e) => {
write!(f, "could not register PCI device capabilities: {}", e)
}
+ RegisterBattery(e) => write!(f, "failed to register battery device to VM: {}", e),
}
}
}
@@ -294,8 +355,8 @@
for (dev_idx, (mut device, jail)) in devices.into_iter().enumerate() {
let address = device_addrs[dev_idx];
- let mut keep_fds = device.keep_fds();
- syslog::push_fds(&mut keep_fds);
+ let mut keep_rds = device.keep_rds();
+ syslog::push_descriptors(&mut keep_rds);
let irqfd = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
let irq_resample_fd = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
@@ -320,8 +381,8 @@
.register_irq_event(irq_num, &irqfd, Some(&irq_resample_fd))
.map_err(DeviceRegistrationError::RegisterIrqfd)?;
- keep_fds.push(irqfd.as_raw_fd());
- keep_fds.push(irq_resample_fd.as_raw_fd());
+ keep_rds.push(irqfd.as_raw_descriptor());
+ keep_rds.push(irq_resample_fd.as_raw_descriptor());
device.assign_irq(irqfd, irq_resample_fd, irq_num, pci_irq_pin);
pci_irqs.push((address, irq_num, pci_irq_pin));
let ranges = io_ranges.remove(&dev_idx).unwrap_or_default();
@@ -333,10 +394,10 @@
let io_addr = IoEventAddress::Mmio(addr);
vm.register_ioevent(&event, io_addr, datamatch)
.map_err(DeviceRegistrationError::RegisterIoevent)?;
- keep_fds.push(event.as_raw_fd());
+ keep_rds.push(event.as_raw_descriptor());
}
let arced_dev: Arc<Mutex<dyn BusDevice>> = if let Some(jail) = jail {
- let proxy = ProxyDevice::new(device, &jail, keep_fds)
+ let proxy = ProxyDevice::new(device, &jail, keep_rds)
.map_err(DeviceRegistrationError::ProxyDeviceCreation)?;
pid_labels.insert(proxy.pid() as u32, proxy.debug_label());
Arc::new(Mutex::new(proxy))
@@ -347,19 +408,99 @@
root.add_device(address, arced_dev.clone());
for range in &ranges {
mmio_bus
- .insert(arced_dev.clone(), range.0, range.1, true)
+ .insert(arced_dev.clone(), range.0, range.1)
.map_err(DeviceRegistrationError::MmioInsert)?;
}
for range in &device_ranges {
mmio_bus
- .insert(arced_dev.clone(), range.0, range.1, true)
+ .insert(arced_dev.clone(), range.0, range.1)
.map_err(DeviceRegistrationError::MmioInsert)?;
}
}
Ok((root, pci_irqs, pid_labels))
}
+/// Adds goldfish battery
+/// return the platform needed resouces include its AML data, irq number
+///
+/// # Arguments
+///
+/// * `amls` - the vector to put the goldfish battery AML
+/// * `battery_jail` - used when sandbox is enabled
+/// * `mmio_bus` - bus to add the devices to
+/// * `irq_chip` - the IrqChip object for registering irq events
+/// * `irq_num` - assigned interrupt to use
+/// * `resources` - the SystemAllocator to allocate IO and MMIO for acpi
+pub fn add_goldfish_battery(
+ amls: &mut Vec<u8>,
+ battery_jail: Option<Minijail>,
+ mmio_bus: &mut Bus,
+ irq_chip: &mut impl IrqChip,
+ irq_num: u32,
+ resources: &mut SystemAllocator,
+) -> Result<BatControlRequestSocket, DeviceRegistrationError> {
+ let alloc = resources.get_anon_alloc();
+ let mmio_base = resources
+ .mmio_allocator(MmioType::Low)
+ .allocate_with_align(
+ devices::bat::GOLDFISHBAT_MMIO_LEN,
+ alloc,
+ "GoldfishBattery".to_string(),
+ devices::bat::GOLDFISHBAT_MMIO_LEN,
+ )
+ .map_err(DeviceRegistrationError::AllocateIoResource)?;
+
+ let irq_evt = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
+ let irq_resample_evt = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
+
+ irq_chip
+ .register_irq_event(irq_num, &irq_evt, Some(&irq_resample_evt))
+ .map_err(DeviceRegistrationError::RegisterIrqfd)?;
+
+ let (control_socket, response_socket) =
+ msg_socket::pair::<BatControlCommand, BatControlResult>()
+ .map_err(DeviceRegistrationError::CreateSocket)?;
+
+ let goldfish_bat = devices::GoldfishBattery::new(
+ mmio_base,
+ irq_num,
+ irq_evt,
+ irq_resample_evt,
+ response_socket,
+ )
+ .map_err(DeviceRegistrationError::RegisterBattery)?;
+ Aml::to_aml_bytes(&goldfish_bat, amls);
+
+ match battery_jail.as_ref() {
+ Some(jail) => {
+ let mut keep_fds = goldfish_bat.keep_fds();
+ syslog::push_fds(&mut keep_fds);
+ mmio_bus
+ .insert(
+ Arc::new(Mutex::new(
+ ProxyDevice::new(goldfish_bat, &jail, keep_fds)
+ .map_err(DeviceRegistrationError::ProxyDeviceCreation)?,
+ )),
+ mmio_base,
+ devices::bat::GOLDFISHBAT_MMIO_LEN,
+ )
+ .map_err(DeviceRegistrationError::MmioInsert)?;
+ }
+ None => {
+ mmio_bus
+ .insert(
+ Arc::new(Mutex::new(goldfish_bat)),
+ mmio_base,
+ devices::bat::GOLDFISHBAT_MMIO_LEN,
+ )
+ .map_err(DeviceRegistrationError::MmioInsert)?;
+ }
+ }
+
+ Ok(control_socket)
+}
+
/// Errors for image loading.
#[derive(Debug)]
pub enum LoadImageError {
diff --git a/arch/src/serial.rs b/arch/src/serial.rs
index 3ebb84b..cf7d7b0 100644
--- a/arch/src/serial.rs
+++ b/arch/src/serial.rs
@@ -2,17 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+use std::borrow::Cow;
use std::collections::BTreeMap;
use std::fmt::{self, Display};
use std::fs::{File, OpenOptions};
use std::io::{self, stdin, stdout, ErrorKind};
-use std::os::unix::io::{AsRawFd, RawFd};
+use std::os::unix::io::AsRawFd;
use std::os::unix::net::UnixDatagram;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::sync::Arc;
+use std::thread;
+use std::time::Duration;
-use base::{error, info, read_raw_stdin, syslog, Event};
+use base::{error, info, read_raw_stdin, syslog, AsRawDescriptor, Event, RawDescriptor};
use devices::{Bus, ProxyDevice, Serial, SerialDevice};
use minijail::Minijail;
use sync::Mutex;
@@ -25,6 +28,7 @@
FileError(std::io::Error),
InvalidSerialHardware(String),
InvalidSerialType(String),
+ InvalidPath,
PathRequired,
SocketCreateFailed,
Unimplemented(SerialType),
@@ -39,6 +43,7 @@
FileError(e) => write!(f, "unable to open/create file: {}", e),
InvalidSerialHardware(e) => write!(f, "invalid serial hardware: {}", e),
InvalidSerialType(e) => write!(f, "invalid serial type: {}", e),
+ InvalidPath => write!(f, "serial device path is invalid"),
PathRequired => write!(f, "serial device type file requires a path"),
SocketCreateFailed => write!(f, "failed to create unbound socket"),
Unimplemented(e) => write!(f, "serial device type {} not implemented", e.to_string()),
@@ -115,27 +120,20 @@
struct WriteSocket {
sock: UnixDatagram,
- path: PathBuf,
buf: String,
}
const BUF_CAPACITY: usize = 1024;
impl WriteSocket {
- pub fn new(s: UnixDatagram, p: PathBuf) -> WriteSocket {
+ pub fn new(s: UnixDatagram) -> WriteSocket {
WriteSocket {
sock: s,
- path: p,
buf: String::with_capacity(BUF_CAPACITY),
}
}
- // |send_buf| uses an immutable |self|, even though its |sock| is possibly
- // going be modified. This is needed to allow the mutating of |buf| between
- // calls to |send_buf| in the io::Write impl.
pub fn send_buf(&self, buf: &[u8]) -> io::Result<usize> {
- // It's possible we aren't yet connected to the socket. Always try once
- // to reconnect if sending fails.
const SEND_RETRY: usize = 2;
let mut sent = 0;
for _ in 0..SEND_RETRY {
@@ -144,22 +142,7 @@
sent = bytes_sent;
break;
}
- Err(e) => match e.kind() {
- ErrorKind::ConnectionRefused
- | ErrorKind::ConnectionReset
- | ErrorKind::ConnectionAborted
- | ErrorKind::NotConnected
- | ErrorKind::Other => match self.sock.connect(self.path.as_path()) {
- Ok(_) => {}
- Err(e) => {
- info!("Couldn't connect {:?}", e);
- break;
- }
- },
- _ => {
- info!("Send error: {:?}", e);
- }
- },
+ Err(e) => info!("Send error: {:?}", e),
}
}
Ok(sent)
@@ -215,27 +198,32 @@
pub stdin: bool,
}
+// The maximum length of a path that can be used as the address of a
+// unix socket. Note that this includes the null-terminator.
+const MAX_SOCKET_PATH_LENGTH: usize = 108;
+
impl SerialParameters {
/// Helper function to create a serial device from the defined parameters.
///
/// # Arguments
/// * `evt` - event used for interrupt events
- /// * `keep_fds` - Vector of FDs required by this device if it were sandboxed in a child
- /// process. `evt` will always be added to this vector by this function.
+ /// * `keep_rds` - Vector of descriptors required by this device if it were sandboxed
+ /// in a child process. `evt` will always be added to this vector by
+ /// this function.
pub fn create_serial_device<T: SerialDevice>(
&self,
protected_vm: bool,
evt: &Event,
- keep_fds: &mut Vec<RawFd>,
+ keep_rds: &mut Vec<RawDescriptor>,
) -> std::result::Result<T, Error> {
let evt = evt.try_clone().map_err(Error::CloneEvent)?;
- keep_fds.push(evt.as_raw_fd());
+ keep_rds.push(evt.as_raw_descriptor());
let input: Option<Box<dyn io::Read + Send>> = if let Some(input_path) = &self.input {
let input_file = File::open(input_path.as_path()).map_err(Error::FileError)?;
- keep_fds.push(input_file.as_raw_fd());
+ keep_rds.push(input_file.as_raw_descriptor());
Some(Box::new(input_file))
} else if self.stdin {
- keep_fds.push(stdin().as_raw_fd());
+ keep_rds.push(stdin().as_raw_descriptor());
// This wrapper is used in place of the libstd native version because we don't want
// buffering for stdin.
struct StdinWrapper;
@@ -250,12 +238,12 @@
};
let output: Option<Box<dyn io::Write + Send>> = match self.type_ {
SerialType::Stdout => {
- keep_fds.push(stdout().as_raw_fd());
+ keep_rds.push(stdout().as_raw_descriptor());
Some(Box::new(stdout()))
}
SerialType::Sink => None,
SerialType::Syslog => {
- syslog::push_fds(keep_fds);
+ syslog::push_descriptors(keep_rds);
Some(Box::new(syslog::Syslogger::new(
syslog::Priority::Info,
syslog::Facility::Daemon,
@@ -268,36 +256,80 @@
.create(true)
.open(path.as_path())
.map_err(Error::FileError)?;
- keep_fds.push(file.as_raw_fd());
+ keep_rds.push(file.as_raw_descriptor());
Some(Box::new(file))
}
None => return Err(Error::PathRequired),
},
- SerialType::UnixSocket => match &self.path {
- Some(path) => {
- let sock = match UnixDatagram::bind(path) {
- Ok(sock) => sock,
- Err(e) => {
- if e.kind() == ErrorKind::AddrInUse {
- // In most cases vmlog_forwarder will
- // have already bound this address and
- // this error is expected. This
- // unbound socket will be connected on
- // first write.
- UnixDatagram::unbound().map_err(Error::FileError)?
- } else {
- error!("Couldn't bind: {:?}", e);
- return Err(Error::FileError(e));
- }
+ SerialType::UnixSocket => {
+ match &self.path {
+ Some(path) => {
+ // If the path is longer than 107 characters,
+ // then we won't be able to connect directly
+ // to it. Instead we can shorten the path by
+ // opening the containing directory and using
+ // /proc/self/fd/*/ to access it via a shorter
+ // path.
+ let mut path_cow = Cow::<Path>::Borrowed(path);
+ let mut _dir_fd = None;
+ if path.as_os_str().len() >= MAX_SOCKET_PATH_LENGTH {
+ let mut short_path = PathBuf::with_capacity(MAX_SOCKET_PATH_LENGTH);
+ short_path.push("/proc/self/fd/");
+
+ // We don't actually want to open this
+ // directory for reading, but the stdlib
+ // requires all files be opened as at
+ // least one of readable, writeable, or
+ // appeandable.
+ let dir = OpenOptions::new()
+ .read(true)
+ .open(path.parent().ok_or(Error::InvalidPath)?)
+ .map_err(Error::FileError)?;
+
+ short_path.push(dir.as_raw_fd().to_string());
+ short_path.push(path.file_name().ok_or(Error::InvalidPath)?);
+ path_cow = Cow::Owned(short_path);
+ _dir_fd = Some(dir);
}
- };
- keep_fds.push(sock.as_raw_fd());
- Some(Box::new(WriteSocket::new(sock, path.to_path_buf())))
+
+ // The shortened path may still be too long,
+ // in which case we must give up here.
+ if path_cow.as_os_str().len() >= MAX_SOCKET_PATH_LENGTH {
+ return Err(Error::InvalidPath);
+ }
+
+ // There's a race condition between
+ // vmlog_forwarder making the logging socket and
+ // crosvm starting up, so we loop here until it's
+ // available.
+ let sock = UnixDatagram::unbound().map_err(Error::FileError)?;
+ loop {
+ match sock.connect(&path_cow) {
+ Ok(_) => break,
+ Err(e) => {
+ match e.kind() {
+ ErrorKind::NotFound | ErrorKind::ConnectionRefused => {
+ // logging socket doesn't
+ // exist yet, sleep for 10 ms
+ // and try again.
+ thread::sleep(Duration::from_millis(10))
+ }
+ _ => {
+ error!("Unexpected error connecting to logging socket: {:?}", e);
+ return Err(Error::FileError(e));
+ }
+ }
+ }
+ };
+ }
+ keep_rds.push(sock.as_raw_descriptor());
+ Some(Box::new(WriteSocket::new(sock)))
+ }
+ None => return Err(Error::PathRequired),
}
- None => return Err(Error::PathRequired),
- },
+ }
};
- Ok(T::new(protected_vm, evt, input, output, keep_fds.to_vec()))
+ Ok(T::new(protected_vm, evt, input, output, keep_rds.to_vec()))
}
pub fn add_bind_mounts(&self, jail: &mut Minijail) -> Result<(), minijail::Error> {
@@ -413,13 +445,13 @@
.map_err(DeviceRegistrationError::ProxyDeviceCreation)?,
));
io_bus
- .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8, false)
+ .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8)
.unwrap();
}
None => {
let com = Arc::new(Mutex::new(com));
io_bus
- .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8, false)
+ .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8)
.unwrap();
}
}
diff --git a/base/Android.bp b/base/Android.bp
index 4c6365c..abfd267 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -9,7 +9,9 @@
auto_gen_config: true,
edition: "2018",
rustlibs: [
+ "libcros_async",
"libdata_model",
+ "liblibc",
"libsync_rust",
"libsys_util",
],
@@ -34,7 +36,9 @@
srcs: ["src/lib.rs"],
edition: "2018",
rustlibs: [
+ "libcros_async",
"libdata_model",
+ "liblibc",
"libsync_rust",
"libsys_util",
],
@@ -42,14 +46,31 @@
// dependent_library ["feature_list"]
// ../assertions/src/lib.rs
+// ../cros_async/src/lib.rs
// ../data_model/src/lib.rs
+// ../io_uring/src/lib.rs
// ../sync/src/lib.rs
// ../sys_util/poll_token_derive/poll_token_derive.rs
// ../sys_util/src/lib.rs
// ../syscall_defines/src/lib.rs
// ../tempfile/src/lib.rs
+// async-trait-0.1.42
+// futures-0.3.8 "alloc"
+// futures-channel-0.3.8 "alloc,futures-sink,sink"
+// futures-core-0.3.8 "alloc"
+// futures-io-0.3.8
+// futures-sink-0.3.8 "alloc"
+// futures-task-0.3.8 "alloc"
+// futures-util-0.3.8 "alloc,futures-sink,sink"
// libc-0.2.80 "default,std"
+// paste-1.0.3
+// pin-project-1.0.2
+// pin-project-internal-1.0.2
+// pin-utils-0.1.0
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// slab-0.4.2
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// thiserror-1.0.22
+// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/base/Cargo.toml b/base/Cargo.toml
index 1b9afc1..2520d42 100644
--- a/base/Cargo.toml
+++ b/base/Cargo.toml
@@ -8,6 +8,8 @@
chromeos = ["sys_util/chromeos"]
[dependencies]
+cros_async = { path = "../cros_async" }
data_model = { path = "../data_model" }
+libc = "*"
sync = { path = "../sync" }
sys_util = { path = "../sys_util" }
diff --git a/base/src/async_types.rs b/base/src/async_types.rs
new file mode 100644
index 0000000..4fbe53e
--- /dev/null
+++ b/base/src/async_types.rs
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium OS 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::AsRawDescriptor;
+use cros_async::IntoAsync;
+use std::os::unix::io::{AsRawFd, RawFd};
+
+/// Like `cros_async::IntoAsync`, except for use with crosvm's AsRawDescriptor
+/// trait object family.
+pub trait DescriptorIntoAsync: AsRawDescriptor {}
+
+/// To use an IO struct with cros_async, the type must be marked with
+/// DescriptorIntoAsync (to signify it is suitable for use with async
+/// operations), and then wrapped with this type.
+pub struct DescriptorAdapter<T: DescriptorIntoAsync>(pub T);
+impl<T> AsRawFd for DescriptorAdapter<T>
+where
+ T: DescriptorIntoAsync,
+{
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_raw_descriptor()
+ }
+}
+impl<T> IntoAsync for DescriptorAdapter<T> where T: DescriptorIntoAsync {}
diff --git a/base/src/event.rs b/base/src/event.rs
index 2e8a2c2..abd9433 100644
--- a/base/src/event.rs
+++ b/base/src/event.rs
@@ -4,7 +4,7 @@
use std::mem;
use std::ops::Deref;
-use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
use std::ptr;
use std::time::Duration;
@@ -15,7 +15,7 @@
/// See [EventFd](sys_util::EventFd) for struct- and method-level
/// documentation.
#[derive(Debug, PartialEq, Eq)]
-pub struct Event(pub(self) EventFd);
+pub struct Event(pub EventFd);
impl Event {
pub fn new() -> Result<Event> {
EventFd::new().map(|eventfd| Event(eventfd))
@@ -56,26 +56,6 @@
}
}
-// TODO(mikehoyle): Remove Fd-related trait impls once the rest
-// of base is complete to accomodate it.
-impl AsRawFd for Event {
- fn as_raw_fd(&self) -> RawFd {
- self.0.as_raw_fd()
- }
-}
-
-impl FromRawFd for Event {
- unsafe fn from_raw_fd(descriptor: RawFd) -> Self {
- Event(EventFd::from_raw_fd(descriptor))
- }
-}
-
-impl IntoRawFd for Event {
- fn into_raw_fd(self) -> RawFd {
- self.0.into_raw_fd()
- }
-}
-
/// See [ScopedEvent](sys_util::ScopedEvent) for struct- and method-level
/// documentation.
pub struct ScopedEvent(Event);
diff --git a/base/src/ioctl.rs b/base/src/ioctl.rs
new file mode 100644
index 0000000..a50f689
--- /dev/null
+++ b/base/src/ioctl.rs
@@ -0,0 +1,60 @@
+// Copyright 2020 The Chromium OS 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::{AsRawDescriptor, IoctlNr};
+use std::os::raw::{c_int, c_ulong, c_void};
+
+/// Run an ioctl with no arguments.
+pub unsafe fn ioctl<F: AsRawDescriptor>(descriptor: &F, nr: IoctlNr) -> c_int {
+ libc::ioctl(descriptor.as_raw_descriptor(), nr, 0)
+}
+
+/// Run an ioctl with a single value argument.
+pub unsafe fn ioctl_with_val<F: AsRawDescriptor>(
+ descriptor: &F,
+ nr: IoctlNr,
+ arg: c_ulong,
+) -> c_int {
+ libc::ioctl(descriptor.as_raw_descriptor(), nr, arg)
+}
+
+/// Run an ioctl with an immutable reference.
+pub unsafe fn ioctl_with_ref<F: AsRawDescriptor, T>(descriptor: &F, nr: IoctlNr, arg: &T) -> c_int {
+ libc::ioctl(
+ descriptor.as_raw_descriptor(),
+ nr,
+ arg as *const T as *const c_void,
+ )
+}
+
+/// Run an ioctl with a mutable reference.
+pub unsafe fn ioctl_with_mut_ref<F: AsRawDescriptor, T>(
+ descriptor: &F,
+ nr: IoctlNr,
+ arg: &mut T,
+) -> c_int {
+ libc::ioctl(
+ descriptor.as_raw_descriptor(),
+ nr,
+ arg as *mut T as *mut c_void,
+ )
+}
+
+/// Run an ioctl with a raw pointer.
+pub unsafe fn ioctl_with_ptr<F: AsRawDescriptor, T>(
+ descriptor: &F,
+ nr: IoctlNr,
+ arg: *const T,
+) -> c_int {
+ libc::ioctl(descriptor.as_raw_descriptor(), nr, arg as *const c_void)
+}
+
+/// Run an ioctl with a mutable raw pointer.
+pub unsafe fn ioctl_with_mut_ptr<F: AsRawDescriptor, T>(
+ descriptor: &F,
+ nr: IoctlNr,
+ arg: *mut T,
+) -> c_int {
+ libc::ioctl(descriptor.as_raw_descriptor(), nr, arg as *mut c_void)
+}
diff --git a/base/src/lib.rs b/base/src/lib.rs
index bf40664..7f88632 100644
--- a/base/src/lib.rs
+++ b/base/src/lib.rs
@@ -4,12 +4,19 @@
pub use sys_util::*;
+mod async_types;
mod event;
+mod ioctl;
mod mmap;
mod shm;
mod timer;
+mod wait_context;
+pub use async_types::*;
pub use event::{Event, EventReadResult, ScopedEvent};
+pub use ioctl::{
+ ioctl, ioctl_with_mut_ptr, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref, ioctl_with_val,
+};
pub use mmap::{MemoryMapping, MemoryMappingBuilder};
pub use shm::{SharedMemory, Unix as SharedMemoryUnix};
pub use sys_util::ioctl::*;
@@ -20,13 +27,20 @@
};
pub use sys_util::{SeekHole, WriteZeroesAt};
pub use timer::{FakeTimer, Timer};
+pub use wait_context::{EventToken, EventType, TriggeredEvent, WaitContext};
/// Wraps an AsRawDescriptor in the simple Descriptor struct, which
/// has AsRawFd methods for interfacing with sys_util
-fn wrap_descriptor(descriptor: &dyn AsRawDescriptor) -> Descriptor {
+pub fn wrap_descriptor(descriptor: &dyn AsRawDescriptor) -> Descriptor {
Descriptor(descriptor.as_raw_descriptor())
}
+/// Verifies that |raw_descriptor| is actually owned by this process and duplicates it
+/// to ensure that we have a unique handle to it.
+pub fn validate_raw_descriptor(raw_descriptor: RawDescriptor) -> Result<RawDescriptor> {
+ validate_raw_fd(raw_descriptor)
+}
+
/// A trait similar to `AsRawDescriptor` but supports an arbitrary number of descriptors.
pub trait AsRawDescriptors {
fn as_raw_descriptors(&self) -> Vec<RawDescriptor>;
diff --git a/base/src/shm.rs b/base/src/shm.rs
index 59594f6..f22e96f 100644
--- a/base/src/shm.rs
+++ b/base/src/shm.rs
@@ -8,7 +8,7 @@
};
use std::ffi::CStr;
use std::fs::File;
-use std::os::unix::io::{AsRawFd, RawFd};
+use std::os::unix::io::AsRawFd;
use sys_util::SharedMemory as SysUtilSharedMemory;
/// See [SharedMemory](sys_util::SharedMemory) for struct- and method-level
@@ -71,14 +71,6 @@
}
}
-// TODO(mikehoyle): Remove this in favor of just AsRawDescriptor
-// when the rest of the codebase is ready.
-impl AsRawFd for SharedMemory {
- fn as_raw_fd(&self) -> RawFd {
- self.0.as_raw_fd()
- }
-}
-
impl AsRawDescriptor for SharedMemory {
fn as_raw_descriptor(&self) -> RawDescriptor {
self.0.as_raw_fd()
diff --git a/base/src/timer.rs b/base/src/timer.rs
index 7a95846..e3bfc0f 100644
--- a/base/src/timer.rs
+++ b/base/src/timer.rs
@@ -6,7 +6,7 @@
AsRawDescriptor, FakeClock, FromRawDescriptor, IntoRawDescriptor, RawDescriptor, Result,
};
-use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
use std::sync::Arc;
use std::time::Duration;
use sync::Mutex;
@@ -54,14 +54,6 @@
}
}
- // TODO(mikehoyle): Remove this in favor of AsRawDescriptor
- // when PollContext is updated
- impl AsRawFd for $timer {
- fn as_raw_fd(&self) -> RawFd {
- self.0.as_raw_fd()
- }
- }
-
impl AsRawDescriptor for $timer {
fn as_raw_descriptor(&self) -> RawDescriptor {
self.0.as_raw_fd()
diff --git a/base/src/wait_context.rs b/base/src/wait_context.rs
new file mode 100644
index 0000000..86a0488
--- /dev/null
+++ b/base/src/wait_context.rs
@@ -0,0 +1,160 @@
+// Copyright 2020 The Chromium OS 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 std::time::Duration;
+
+use crate::{wrap_descriptor, AsRawDescriptor, RawDescriptor, Result};
+use sys_util::{PollContext, PollToken, WatchingEvents};
+
+// Typedef PollToken as EventToken for better adherance to base naming.
+// As actual typdefing is experimental, define a new trait with the mirrored
+// attributes.
+pub trait EventToken: PollToken {}
+impl<T: PollToken> EventToken for T {}
+
+/// Represents an event that has been signaled and waited for via a wait function.
+#[derive(Copy, Clone, Debug)]
+pub struct TriggeredEvent<T: EventToken> {
+ pub token: T,
+ pub is_readable: bool,
+ pub is_writable: bool,
+ pub is_hungup: bool,
+}
+
+/// Represents types of events to watch for.
+pub enum EventType {
+ // Used to to temporarily stop waiting for events without
+ // removing the associated descriptor from the WaitContext.
+ // In most cases if a descriptor no longer needs to be
+ // waited on, prefer removing it entirely with
+ // WaitContext#delete
+ None,
+ Read,
+ Write,
+ ReadWrite,
+}
+
+/// Used to wait for multiple objects which are eligible for waiting.
+///
+/// # Example
+///
+/// ```
+/// # use base::{
+/// Result, Event, WaitContext,
+/// };
+/// # fn test() -> Result<()> {
+/// let evt1 = Event::new()?;
+/// let evt2 = Event::new()?;
+/// evt2.write(1)?;
+///
+/// let ctx: WaitContext<u32> = WaitContext::new()?;
+/// ctx.add(&evt1, 1)?;
+/// ctx.add(&evt2, 2)?;
+///
+/// let events = ctx.wait()?;
+/// let tokens: Vec<u32> = events.iter().filter(|e| e.is_readable)
+/// .map(|e| e.token).collect();
+/// assert_eq!(tokens, [2]);
+/// # Ok(())
+/// # }
+/// ```
+pub struct WaitContext<T: EventToken>(PollContext<T>);
+
+impl<T: EventToken> WaitContext<T> {
+ /// Creates a new WaitContext.
+ pub fn new() -> Result<WaitContext<T>> {
+ PollContext::new().map(|poll_ctx| WaitContext(poll_ctx))
+ }
+
+ /// Creates a new WaitContext with the the associated triggers.
+ pub fn build_with(triggers: &[(&dyn AsRawDescriptor, T)]) -> Result<WaitContext<T>> {
+ let ctx = WaitContext::new()?;
+ ctx.add_many(triggers)?;
+ Ok(ctx)
+ }
+
+ /// Adds a trigger to the WaitContext.
+ pub fn add(&self, descriptor: &dyn AsRawDescriptor, token: T) -> Result<()> {
+ self.add_for_event(descriptor, EventType::Read, token)
+ }
+
+ /// Adds a trigger to the WaitContext watching for a specific type of event
+ pub fn add_for_event(
+ &self,
+ descriptor: &dyn AsRawDescriptor,
+ event_type: EventType,
+ token: T,
+ ) -> Result<()> {
+ self.0.add_fd_with_events(
+ &wrap_descriptor(descriptor),
+ convert_to_watching_events(event_type),
+ token,
+ )
+ }
+
+ /// Adds multiple triggers to the WaitContext.
+ pub fn add_many(&self, triggers: &[(&dyn AsRawDescriptor, T)]) -> Result<()> {
+ for trigger in triggers {
+ self.add(trigger.0, T::from_raw_token(trigger.1.as_raw_token()))?
+ }
+ Ok(())
+ }
+
+ /// Modifies a trigger already added to the WaitContext. If the descriptor is
+ /// already registered, its associated token will be updated.
+ pub fn modify(
+ &self,
+ descriptor: &dyn AsRawDescriptor,
+ event_type: EventType,
+ token: T,
+ ) -> Result<()> {
+ self.0.modify(
+ &wrap_descriptor(descriptor),
+ convert_to_watching_events(event_type),
+ token,
+ )
+ }
+
+ /// Removes the given handle from triggers registered in the WaitContext if
+ /// present.
+ pub fn delete(&self, descriptor: &dyn AsRawDescriptor) -> Result<()> {
+ self.0.delete(&wrap_descriptor(descriptor))
+ }
+
+ /// Waits for one or more of the registered triggers to become signaled.
+ pub fn wait(&self) -> Result<Vec<TriggeredEvent<T>>> {
+ self.wait_timeout(Duration::new(i64::MAX as u64, 0))
+ }
+ /// Waits for one or more of the registered triggers to become signaled, failing if no triggers
+ /// are signaled before the designated timeout has elapsed.
+ pub fn wait_timeout(&self, timeout: Duration) -> Result<Vec<TriggeredEvent<T>>> {
+ let events = self.0.wait_timeout(timeout)?;
+ let mut return_vec: Vec<TriggeredEvent<T>> = vec![];
+ for event in events.iter() {
+ return_vec.push(TriggeredEvent {
+ token: event.token(),
+ is_readable: event.readable(),
+ is_writable: event.writable(),
+ is_hungup: event.hungup(),
+ });
+ }
+ Ok(return_vec)
+ }
+}
+
+impl<T: PollToken> AsRawDescriptor for WaitContext<T> {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.0.as_raw_fd()
+ }
+}
+
+fn convert_to_watching_events(event_type: EventType) -> WatchingEvents {
+ match event_type {
+ EventType::None => WatchingEvents::empty(),
+ EventType::Read => WatchingEvents::empty().set_read(),
+ EventType::Write => WatchingEvents::empty().set_write(),
+ EventType::ReadWrite => WatchingEvents::empty().set_read().set_write(),
+ }
+}
diff --git a/bit_field/Android.bp b/bit_field/Android.bp
index 0b48897..7bb0d73 100644
--- a/bit_field/Android.bp
+++ b/bit_field/Android.bp
@@ -71,5 +71,5 @@
// dependent_library ["feature_list"]
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// syn-1.0.53 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
// unicode-xid-0.2.1 "default"
diff --git a/bit_field/bit_field_derive/Android.bp b/bit_field/bit_field_derive/Android.bp
index 92c63e8..056064c 100644
--- a/bit_field/bit_field_derive/Android.bp
+++ b/bit_field/bit_field_derive/Android.bp
@@ -31,5 +31,5 @@
// dependent_library ["feature_list"]
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// syn-1.0.53 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
// unicode-xid-0.2.1 "default"
diff --git a/cros_async/Android.bp b/cros_async/Android.bp
index c4717d0..db62c8f 100644
--- a/cros_async/Android.bp
+++ b/cros_async/Android.bp
@@ -9,12 +9,12 @@
auto_gen_config: true,
edition: "2018",
rustlibs: [
- "libbase_rust",
"libfutures",
"libio_uring",
"liblibc",
"libpin_utils",
"libslab",
+ "libsys_util",
"libsyscall_defines",
"libtempfile",
"libthiserror",
@@ -44,12 +44,12 @@
srcs: ["src/lib.rs"],
edition: "2018",
rustlibs: [
- "libbase_rust",
"libfutures",
"libio_uring",
"liblibc",
"libpin_utils",
"libslab",
+ "libsys_util",
"libsyscall_defines",
"libthiserror",
],
@@ -86,7 +86,7 @@
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// thiserror-1.0.22
// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/cros_async/Cargo.toml b/cros_async/Cargo.toml
index b502d24..08dc04f 100644
--- a/cros_async/Cargo.toml
+++ b/cros_async/Cargo.toml
@@ -8,9 +8,9 @@
async-trait = "0.1.36"
io_uring = { path = "../io_uring" }
libc = "*"
-paste = "*"
+paste = "1.0"
pin-utils = "0.1.0-alpha.4"
-base = { path = "../base" }
+sys_util = { path = "../sys_util" }
syscall_defines = { path = "../syscall_defines" }
slab = "0.4"
thiserror = "1.0.20"
@@ -21,6 +21,5 @@
features = ["alloc"]
[dev-dependencies]
-base = { path = "../base" }
tempfile = { path = "../tempfile" }
vm_memory = { path = "../vm_memory" }
diff --git a/cros_async/src/event.rs b/cros_async/src/event.rs
index ad03d77..8105210 100644
--- a/cros_async/src/event.rs
+++ b/cros_async/src/event.rs
@@ -2,26 +2,29 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use crate::{new, AsyncResult, IoSourceExt};
-use std::os::unix::io::AsRawFd;
+use crate::io_ext::async_from;
+use crate::{AsyncError, AsyncResult, IntoAsync, IoSourceExt};
+use std::convert::TryFrom;
+use sys_util::EventFd;
-/// An async version of sys_util::EventFd.
-pub struct EventAsync<F: AsRawFd + 'static> {
- io_source: Box<dyn IoSourceExt<F> + 'static>,
+/// An async version of `sys_util::EventFd`.
+pub struct EventAsync {
+ io_source: Box<dyn IoSourceExt<EventFd>>,
}
-impl<F: AsRawFd + 'static> EventAsync<F> {
- /// Creates a new EventAsync wrapper around the provided eventfd.
- #[allow(dead_code)]
- pub fn new(f: F) -> AsyncResult<EventAsync<F>> {
- Ok(EventAsync { io_source: new(f)? })
+impl EventAsync {
+ #[cfg(test)]
+ pub(crate) fn new_poll(event: EventFd) -> AsyncResult<EventAsync> {
+ Ok(EventAsync {
+ io_source: crate::io_ext::async_poll_from(event)?,
+ })
}
- /// Like new, but allows the source to be constructed directly. Used for
- /// testing only.
#[cfg(test)]
- pub(crate) fn new_from_source(io_source: Box<dyn IoSourceExt<F> + 'static>) -> EventAsync<F> {
- EventAsync { io_source }
+ pub(crate) fn new_uring(event: EventFd) -> AsyncResult<EventAsync> {
+ Ok(EventAsync {
+ io_source: crate::io_ext::async_uring_from(event)?,
+ })
}
/// Gets the next value from the eventfd.
@@ -31,21 +34,33 @@
}
}
+impl TryFrom<EventFd> for EventAsync {
+ type Error = AsyncError;
+
+ /// Creates a new EventAsync wrapper around the provided eventfd.
+ fn try_from(event: EventFd) -> AsyncResult<Self> {
+ Ok(EventAsync {
+ io_source: async_from(event)?,
+ })
+ }
+}
+
+impl IntoAsync for EventFd {}
+
#[cfg(test)]
mod tests {
use super::*;
- use crate::io_ext::{new_poll, new_uring};
- use base::Event;
use futures::pin_mut;
+ use std::convert::TryInto;
#[test]
fn next_val_reads_value() {
- async fn go(event: Event) -> u64 {
- let event_async = EventAsync::new(event).unwrap();
+ async fn go(event: EventFd) -> u64 {
+ let event_async: EventAsync = event.try_into().unwrap();
event_async.next_val().await.unwrap()
}
- let eventfd = Event::new().unwrap();
+ let eventfd = EventFd::new().unwrap();
eventfd.write(0xaa).unwrap();
let fut = go(eventfd);
pin_mut!(fut);
@@ -55,23 +70,22 @@
#[test]
fn next_val_reads_value_poll_and_ring() {
- async fn go(source: Box<dyn IoSourceExt<Event> + 'static>) -> u64 {
- let event_async = EventAsync::new_from_source(source);
+ async fn go(event_async: EventAsync) -> u64 {
event_async.next_val().await.unwrap()
}
- let eventfd = Event::new().unwrap();
+ let eventfd = EventFd::new().unwrap();
eventfd.write(0xaa).unwrap();
- let fut = go(new_poll(eventfd).unwrap());
+ let fut = go(EventAsync::new_uring(eventfd).unwrap());
pin_mut!(fut);
- let val = crate::run_executor(crate::RunOne::new(fut)).unwrap();
+ let val = crate::run_one_uring(fut).unwrap();
assert_eq!(val, 0xaa);
- let eventfd = Event::new().unwrap();
+ let eventfd = EventFd::new().unwrap();
eventfd.write(0xaa).unwrap();
- let fut = go(new_uring(eventfd).unwrap());
+ let fut = go(EventAsync::new_poll(eventfd).unwrap());
pin_mut!(fut);
- let val = crate::run_executor(crate::RunOne::new(fut)).unwrap();
+ let val = crate::run_one_poll(fut).unwrap();
assert_eq!(val, 0xaa);
}
}
diff --git a/cros_async/src/fd_executor.rs b/cros_async/src/fd_executor.rs
index 4e20b2f..08ca2f4 100644
--- a/cros_async/src/fd_executor.rs
+++ b/cros_async/src/fd_executor.rs
@@ -21,7 +21,7 @@
use slab::Slab;
-use base::{PollContext, WatchingEvents};
+use sys_util::{error, PollContext, WatchingEvents};
use crate::executor::{ExecutableFuture, Executor, FutureList};
use crate::WakerToken;
@@ -31,15 +31,15 @@
/// Attempts to create two Executors on the same thread fail.
AttemptedDuplicateExecutor,
/// Failed to copy the FD for the polling context.
- DuplicatingFd(base::Error),
+ DuplicatingFd(sys_util::Error),
/// Failed accessing the thread local storage for wakers.
InvalidContext,
/// Creating a context to wait on FDs failed.
- CreatingContext(base::Error),
+ CreatingContext(sys_util::Error),
/// PollContext failure.
- PollContextError(base::Error),
+ PollContextError(sys_util::Error),
/// Failed to submit the waker to the polling context.
- SubmittingWaker(base::Error),
+ SubmittingWaker(sys_util::Error),
/// A Waker was canceled, but the operation isn't running.
UnknownWaker,
}
@@ -150,7 +150,7 @@
// Tracks active wakers and associates wakers with the futures that registered them.
struct FdWakerState {
poll_ctx: PollContext<usize>,
- tokens: Slab<(File, Waker)>,
+ tokens: Slab<(File, Option<Waker>)>,
new_futures: VecDeque<ExecutableFuture<()>>,
}
@@ -175,7 +175,7 @@
self.poll_ctx
.add_fd_with_events(&duped_fd, events, next_token)
.map_err(Error::SubmittingWaker)?;
- entry.insert((duped_fd, waker));
+ entry.insert((duped_fd, Some(waker)));
Ok(WakerToken(next_token))
}
@@ -184,9 +184,16 @@
let events = self.poll_ctx.wait().map_err(Error::PollContextError)?;
for e in events.iter() {
let token = e.token();
- let (fd, waker) = self.tokens.remove(token);
- self.poll_ctx.delete(&fd).map_err(Error::PollContextError)?;
- waker.wake();
+ if let Some((fd, waker)) = self.tokens.get_mut(token) {
+ self.poll_ctx.delete(fd).map_err(Error::PollContextError)?;
+ if let Some(waker) = waker.take() {
+ waker.wake();
+ } else {
+ error!("Woken twice");
+ }
+ } else {
+ error!("Unknown waker");
+ }
}
Ok(())
}
@@ -274,7 +281,7 @@
unsafe fn dup_fd(fd: RawFd) -> Result<RawFd> {
let ret = libc::dup(fd);
if ret < 0 {
- Err(Error::DuplicatingFd(base::Error::last()))
+ Err(Error::DuplicatingFd(sys_util::Error::last()))
} else {
Ok(ret)
}
@@ -338,7 +345,7 @@
#[test]
fn test_it() {
async fn do_test() {
- let (r, _w) = base::pipe(true).unwrap();
+ let (r, _w) = sys_util::pipe(true).unwrap();
let done = Box::pin(async { 5usize });
let pending = Box::pin(TestFut::new(r));
match futures::future::select(pending, done).await {
diff --git a/cros_async/src/io_ext.rs b/cros_async/src/io_ext.rs
index 0a946e3..5743d3d 100644
--- a/cros_async/src/io_ext.rs
+++ b/cros_async/src/io_ext.rs
@@ -18,11 +18,13 @@
use crate::poll_source::PollSource;
use crate::UringSource;
use async_trait::async_trait;
+use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::rc::Rc;
use thiserror::Error as ThisError;
use crate::uring_mem::{BackingMemory, MemRegion};
+use sys_util::net::UnixSeqpacket;
#[derive(ThisError, Debug)]
pub enum Error {
@@ -94,27 +96,41 @@
fn as_source(&self) -> &F;
}
+/// Marker trait signifying that the implementor is suitable for use with
+/// cros_async. Examples of this include File, and sys_util::net::UnixSeqpacket.
+///
+/// (Note: it'd be really nice to implement a TryFrom for any implementors, and
+/// remove our factory functions. Unfortunately
+/// https://github.com/rust-lang/rust/issues/50133 makes that too painful.)
+pub trait IntoAsync: AsRawFd {}
+
+impl IntoAsync for File {}
+impl IntoAsync for UnixSeqpacket {}
+impl IntoAsync for &UnixSeqpacket {}
+
/// Creates a concrete `IoSourceExt` that uses uring if available or falls back to the fd_executor if not.
/// Note that on older kernels (pre 5.6) FDs such as event or timer FDs are unreliable when
/// having readvwritev performed through io_uring. To deal with EventFd or TimerFd, use
/// `IoSourceExt::read_u64`.
-pub fn new<'a, F: AsRawFd + 'a>(f: F) -> Result<Box<dyn IoSourceExt<F> + 'a>> {
+pub fn async_from<'a, F: IntoAsync + 'a>(f: F) -> Result<Box<dyn IoSourceExt<F> + 'a>> {
if crate::uring_executor::use_uring() {
- new_uring(f)
+ async_uring_from(f)
} else {
- new_poll(f)
+ async_poll_from(f)
}
}
/// Creates a concrete `IoSourceExt` using Uring.
-pub(crate) fn new_uring<'a, F: AsRawFd + 'a>(f: F) -> Result<Box<dyn IoSourceExt<F> + 'a>> {
+pub(crate) fn async_uring_from<'a, F: IntoAsync + 'a>(
+ f: F,
+) -> Result<Box<dyn IoSourceExt<F> + 'a>> {
UringSource::new(f)
.map(|u| Box::new(u) as Box<dyn IoSourceExt<F>>)
.map_err(Error::Uring)
}
/// Creates a concrete `IoSourceExt` using the fd_executor.
-pub(crate) fn new_poll<'a, F: AsRawFd + 'a>(f: F) -> Result<Box<dyn IoSourceExt<F> + 'a>> {
+pub(crate) fn async_poll_from<'a, F: IntoAsync + 'a>(f: F) -> Result<Box<dyn IoSourceExt<F> + 'a>> {
PollSource::new(f)
.map(|u| Box::new(u) as Box<dyn IoSourceExt<F>>)
.map_err(Error::Poll)
@@ -145,7 +161,7 @@
}
let f = File::open("/dev/zero").unwrap();
- let uring_source = new_uring(f).unwrap();
+ let uring_source = async_uring_from(f).unwrap();
let fut = go(uring_source);
pin_mut!(fut);
crate::uring_executor::URingExecutor::new(crate::RunOne::new(fut))
@@ -154,7 +170,7 @@
.unwrap();
let f = File::open("/dev/zero").unwrap();
- let poll_source = new_poll(f).unwrap();
+ let poll_source = async_poll_from(f).unwrap();
let fut = go(poll_source);
pin_mut!(fut);
crate::fd_executor::FdExecutor::new(crate::RunOne::new(fut))
@@ -175,7 +191,7 @@
}
let f = OpenOptions::new().write(true).open("/dev/null").unwrap();
- let uring_source = new_uring(f).unwrap();
+ let uring_source = async_uring_from(f).unwrap();
let fut = go(uring_source);
pin_mut!(fut);
crate::uring_executor::URingExecutor::new(crate::RunOne::new(fut))
@@ -184,7 +200,7 @@
.unwrap();
let f = OpenOptions::new().write(true).open("/dev/null").unwrap();
- let poll_source = new_poll(f).unwrap();
+ let poll_source = async_poll_from(f).unwrap();
let fut = go(poll_source);
pin_mut!(fut);
crate::fd_executor::FdExecutor::new(crate::RunOne::new(fut))
@@ -223,7 +239,7 @@
}
let f = File::open("/dev/zero").unwrap();
- let uring_source = new_uring(f).unwrap();
+ let uring_source = async_uring_from(f).unwrap();
let fut = go(uring_source);
pin_mut!(fut);
crate::uring_executor::URingExecutor::new(crate::RunOne::new(fut))
@@ -232,7 +248,7 @@
.unwrap();
let f = File::open("/dev/zero").unwrap();
- let poll_source = new_poll(f).unwrap();
+ let poll_source = async_poll_from(f).unwrap();
let fut = go(poll_source);
pin_mut!(fut);
crate::fd_executor::FdExecutor::new(crate::RunOne::new(fut))
@@ -257,7 +273,7 @@
}
let f = OpenOptions::new().write(true).open("/dev/null").unwrap();
- let uring_source = new_uring(f).unwrap();
+ let uring_source = async_uring_from(f).unwrap();
let fut = go(uring_source);
pin_mut!(fut);
crate::uring_executor::URingExecutor::new(crate::RunOne::new(fut))
@@ -266,7 +282,7 @@
.unwrap();
let f = OpenOptions::new().write(true).open("/dev/null").unwrap();
- let poll_source = new_poll(f).unwrap();
+ let poll_source = async_poll_from(f).unwrap();
let fut = go(poll_source);
pin_mut!(fut);
crate::fd_executor::FdExecutor::new(crate::RunOne::new(fut))
@@ -277,8 +293,8 @@
#[test]
fn read_u64s() {
- async fn go<F: AsRawFd + Unpin>(async_source: F) -> u64 {
- let source = new(async_source).unwrap();
+ async fn go(async_source: File) -> u64 {
+ let source = async_from(async_source).unwrap();
source.read_u64().await.unwrap()
}
@@ -294,7 +310,7 @@
#[test]
fn read_eventfds() {
- use base::EventFd;
+ use sys_util::EventFd;
async fn go<F: AsRawFd + Unpin>(source: Box<dyn IoSourceExt<F>>) -> u64 {
source.read_u64().await.unwrap()
@@ -302,7 +318,7 @@
let eventfd = EventFd::new().unwrap();
eventfd.write(0x55).unwrap();
- let fut = go(new(eventfd).unwrap());
+ let fut = go(async_uring_from(eventfd).unwrap());
pin_mut!(fut);
let val = crate::uring_executor::URingExecutor::new(crate::RunOne::new(fut))
.unwrap()
@@ -312,7 +328,7 @@
let eventfd = EventFd::new().unwrap();
eventfd.write(0xaa).unwrap();
- let fut = go(new_poll(eventfd).unwrap());
+ let fut = go(async_poll_from(eventfd).unwrap());
pin_mut!(fut);
let val = crate::fd_executor::FdExecutor::new(crate::RunOne::new(fut))
.unwrap()
@@ -334,7 +350,7 @@
}
let f = tempfile::tempfile().unwrap();
- let source = new(f).unwrap();
+ let source = async_from(f).unwrap();
let fut = go(source);
pin_mut!(fut);
diff --git a/cros_async/src/lib.rs b/cros_async/src/lib.rs
index 7438ec8..7bde511 100644
--- a/cros_async/src/lib.rs
+++ b/cros_async/src/lib.rs
@@ -74,7 +74,8 @@
pub use event::EventAsync;
pub use executor::Executor;
pub use io_ext::{
- new, Error as AsyncError, IoSourceExt, ReadAsync, Result as AsyncResult, WriteAsync,
+ async_from, Error as AsyncError, IntoAsync, IoSourceExt, ReadAsync, Result as AsyncResult,
+ WriteAsync,
};
pub use poll_source::PollSource;
pub use select::SelectResult;
diff --git a/cros_async/src/poll_source.rs b/cros_async/src/poll_source.rs
index ed9404c..f100368 100644
--- a/cros_async/src/poll_source.rs
+++ b/cros_async/src/poll_source.rs
@@ -21,7 +21,7 @@
use crate::AsyncError;
use crate::AsyncResult;
use crate::{IoSourceExt, ReadAsync, WriteAsync};
-use base::{self, add_fd_flags};
+use sys_util::{self, add_fd_flags};
use thiserror::Error as ThisError;
#[derive(ThisError, Debug)]
@@ -31,23 +31,23 @@
AddingWaker(fd_executor::Error),
/// An error occurred when executing fallocate synchronously.
#[error("An error occurred when executing fallocate synchronously: {0}")]
- Fallocate(base::Error),
+ Fallocate(sys_util::Error),
/// An error occurred when executing fsync synchronously.
#[error("An error occurred when executing fsync synchronously: {0}")]
- Fsync(base::Error),
+ Fsync(sys_util::Error),
/// An error occurred when reading the FD.
///
#[error("An error occurred when reading the FD: {0}.")]
- Read(base::Error),
+ Read(sys_util::Error),
/// Can't seek file.
#[error("An error occurred when seeking the FD: {0}.")]
- Seeking(base::Error),
+ Seeking(sys_util::Error),
/// An error occurred when setting the FD non-blocking.
#[error("An error occurred setting the FD non-blocking: {0}.")]
- SettingNonBlocking(base::Error),
+ SettingNonBlocking(sys_util::Error),
/// An error occurred when writing the FD.
#[error("An error occurred when writing the FD: {0}.")]
- Write(base::Error),
+ Write(sys_util::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
@@ -186,7 +186,7 @@
if ret == 0 {
Ok(())
} else {
- Err(AsyncError::Poll(Error::Fallocate(base::Error::last())))
+ Err(AsyncError::Poll(Error::Fallocate(sys_util::Error::last())))
}
}
@@ -196,7 +196,7 @@
if ret == 0 {
Ok(())
} else {
- Err(AsyncError::Poll(Error::Fsync(base::Error::last())))
+ Err(AsyncError::Poll(Error::Fsync(sys_util::Error::last())))
}
}
}
@@ -236,7 +236,7 @@
type Output = Result<(usize, Vec<u8>)>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
- fn do_read(fd: RawFd, file_offset: u64, buf: &mut [u8]) -> base::Result<usize> {
+ fn do_read(fd: RawFd, file_offset: u64, buf: &mut [u8]) -> sys_util::Result<usize> {
// Safe because we trust the kernel not to write past the length given and the length is
// guaranteed to be valid from the pointer by the mut slice.
let ret = unsafe {
@@ -249,7 +249,7 @@
};
match ret {
n if n >= 0 => Ok(n as usize),
- _ => base::errno_result(),
+ _ => sys_util::errno_result(),
}
}
@@ -293,13 +293,13 @@
type Output = Result<u64>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
- fn do_read(fd: RawFd, buf: &mut [u8]) -> base::Result<usize> {
+ fn do_read(fd: RawFd, buf: &mut [u8]) -> sys_util::Result<usize> {
// Safe because we trust the kernel not to write past the length given and the length is
// guaranteed to be valid from the pointer by the mut slice.
let ret = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut _, buf.len()) };
match ret {
n if n >= 0 => Ok(n as usize),
- _ => base::errno_result(),
+ _ => sys_util::errno_result(),
}
}
@@ -343,10 +343,10 @@
type Output = Result<()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
- fn do_poll(fd: RawFd) -> base::Result<usize> {
+ fn do_poll(fd: RawFd) -> sys_util::Result<usize> {
let poll_arg = libc::pollfd {
fd,
- events: base::WatchingEvents::empty().set_read().get_raw() as i16,
+ events: sys_util::WatchingEvents::empty().set_read().get_raw() as i16,
revents: 0,
};
@@ -354,7 +354,7 @@
let ret = unsafe { libc::poll(&poll_arg as *const _ as *mut _, 1, 0) };
match ret {
n if n >= 0 => Ok(n as usize),
- _ => base::errno_result(),
+ _ => sys_util::errno_result(),
}
}
@@ -390,7 +390,7 @@
type Output = Result<(usize, Vec<u8>)>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
- fn do_write(fd: RawFd, file_offset: u64, buf: &[u8]) -> base::Result<usize> {
+ fn do_write(fd: RawFd, file_offset: u64, buf: &[u8]) -> sys_util::Result<usize> {
// Safe because we trust the kernel not to write to the buffer, only read from it and
// the length is guaranteed to be valid from the pointer by the mut slice.
let ret = unsafe {
@@ -403,7 +403,7 @@
};
match ret {
n if n >= 0 => Ok(n as usize),
- _ => base::errno_result(),
+ _ => sys_util::errno_result(),
}
}
@@ -455,7 +455,7 @@
file_offset: u64,
mem: &dyn BackingMemory,
mem_offsets: &[MemRegion],
- ) -> base::Result<usize> {
+ ) -> sys_util::Result<usize> {
let mut iovecs = mem_offsets
.iter()
.filter_map(|&mem_vec| mem.get_iovec(mem_vec).ok())
@@ -472,7 +472,7 @@
};
match ret {
n if n >= 0 => Ok(n as usize),
- _ => base::errno_result(),
+ _ => sys_util::errno_result(),
}
}
@@ -523,7 +523,7 @@
file_offset: u64,
mem: &dyn BackingMemory,
mem_offsets: &[MemRegion],
- ) -> base::Result<usize> {
+ ) -> sys_util::Result<usize> {
let iovecs = mem_offsets
.iter()
.map(|&mem_vec| mem.get_iovec(mem_vec))
@@ -541,7 +541,7 @@
};
match ret {
n if n >= 0 => Ok(n as usize),
- _ => base::errno_result(),
+ _ => sys_util::errno_result(),
}
}
diff --git a/cros_async/src/uring_executor.rs b/cros_async/src/uring_executor.rs
index 3d27eda..462582f 100644
--- a/cros_async/src/uring_executor.rs
+++ b/cros_async/src/uring_executor.rs
@@ -68,8 +68,8 @@
use futures::pin_mut;
use slab::Slab;
-use base::WatchingEvents;
use io_uring::URingContext;
+use sys_util::WatchingEvents;
use crate::executor::{ExecutableFuture, Executor, FutureList};
use crate::uring_mem::{BackingMemory, MemRegion};
@@ -80,7 +80,7 @@
/// Attempts to create two Executors on the same thread fail.
AttemptedDuplicateExecutor,
/// Failed to copy the FD for the polling context.
- DuplicatingFd(base::Error),
+ DuplicatingFd(sys_util::Error),
/// Failed accessing the thread local storage for wakers.
InvalidContext,
/// Invalid offset or length given for an iovec in backing memory.
@@ -346,7 +346,7 @@
fn submit_poll(
&mut self,
source: &RegisteredSource,
- events: &base::WatchingEvents,
+ events: &sys_util::WatchingEvents,
) -> Result<WakerToken> {
let src = self
.registered_sources
@@ -679,7 +679,7 @@
unsafe fn dup_fd(fd: RawFd) -> Result<RawFd> {
let ret = libc::dup(fd);
if ret < 0 {
- Err(Error::DuplicatingFd(base::Error::last()))
+ Err(Error::DuplicatingFd(sys_util::Error::last()))
} else {
Ok(ret)
}
@@ -733,7 +733,7 @@
let bm = Rc::new(VecIoWrapper::from(vec![0u8; 4096])) as Rc<dyn BackingMemory>;
// Use pipes to create a future that will block forever.
- let (rx, mut tx) = base::pipe(true).unwrap();
+ let (rx, mut tx) = sys_util::pipe(true).unwrap();
// Set up the TLS for the uring_executor by creating one.
let _ex = URingExecutor::new(crate::executor::UnitFutures::new()).unwrap();
@@ -771,7 +771,7 @@
let bm = Rc::new(VecIoWrapper::from(vec![0u8; 4096])) as Rc<dyn BackingMemory>;
// Use pipes to create a future that will block forever.
- let (mut rx, tx) = base::new_pipe_full().expect("Pipe failed");
+ let (mut rx, tx) = sys_util::new_pipe_full().expect("Pipe failed");
// Set up the TLS for the uring_executor by creating one.
let _ex = URingExecutor::new(crate::executor::UnitFutures::new()).unwrap();
@@ -797,7 +797,7 @@
// Finishing the operation should put the Rc count back to 1.
// write to the pipe to wake the read pipe and then wait for the uring result in the
// executor.
- let mut buf = vec![0u8; base::round_up_to_page_size(1)];
+ let mut buf = vec![0u8; sys_util::round_up_to_page_size(1)];
rx.read(&mut buf).expect("read to empty failed");
RingWakerState::wait_wake_event().expect("Failed to wait for read pipe ready");
assert_eq!(Rc::strong_count(&bm), 1);
@@ -806,7 +806,7 @@
#[test]
fn registered_source_outlives_executor() {
let bm = Rc::new(VecIoWrapper::from(vec![0u8; 4096])) as Rc<dyn BackingMemory>;
- let (rx, tx) = base::pipe(true).unwrap();
+ let (rx, tx) = sys_util::pipe(true).unwrap();
// Register a source before creating the executor.
let rx_source = register_source(&rx).expect("register source failed");
@@ -854,7 +854,7 @@
let bm = Rc::new(VecIoWrapper::from(vec![0u8; 16])) as Rc<dyn BackingMemory>;
- let (rx, tx) = base::pipe(true).expect("Pipe failed");
+ let (rx, tx) = sys_util::pipe(true).expect("Pipe failed");
let mut ex = URingExecutor::new(crate::executor::UnitFutures::new()).unwrap();
diff --git a/cros_async/src/uring_futures/read_vec.rs b/cros_async/src/uring_futures/read_vec.rs
index f80472b..09d851d 100644
--- a/cros_async/src/uring_futures/read_vec.rs
+++ b/cros_async/src/uring_futures/read_vec.rs
@@ -144,9 +144,9 @@
#[test]
fn event() {
- use base::Event;
+ use sys_util::EventFd;
- async fn write_event(ev: Event, wait: Event) {
+ async fn write_event(ev: EventFd, wait: EventFd) {
let wait = UringSource::new(wait).unwrap();
ev.write(55).unwrap();
read_u64(&wait).await;
@@ -156,7 +156,7 @@
read_u64(&wait).await;
}
- async fn read_events(ev: Event, signal: Event) {
+ async fn read_events(ev: EventFd, signal: EventFd) {
let source = UringSource::new(ev).unwrap();
assert_eq!(read_u64(&source).await, 55);
signal.write(1).unwrap();
@@ -166,8 +166,8 @@
signal.write(1).unwrap();
}
- let event = Event::new().unwrap();
- let signal_wait = Event::new().unwrap();
+ let event = EventFd::new().unwrap();
+ let signal_wait = EventFd::new().unwrap();
let write_task = write_event(event.try_clone().unwrap(), signal_wait.try_clone().unwrap());
let read_task = read_events(event, signal_wait);
let joined = futures::future::join(read_task, write_task);
@@ -180,7 +180,7 @@
use futures::future::Either;
async fn do_test() {
- let (read_source, _w) = base::pipe(true).unwrap();
+ let (read_source, _w) = sys_util::pipe(true).unwrap();
let source = UringSource::new(read_source).unwrap();
let done = async { 5usize };
let pending = read_u64(&source);
diff --git a/cros_async/src/uring_futures/uring_source.rs b/cros_async/src/uring_futures/uring_source.rs
index 15b88b8..1d6a1a2 100644
--- a/cros_async/src/uring_futures/uring_source.rs
+++ b/cros_async/src/uring_futures/uring_source.rs
@@ -299,17 +299,15 @@
#[test]
fn read_to_mem() {
- use vm_memory::{GuestAddress, GuestMemory};
-
use crate::uring_mem::VecIoWrapper;
+ use std::io::Write;
+ use tempfile::tempfile;
let io_obj = Box::pin({
// Use guest memory as a test file, it implements AsRawFd.
- let source = GuestMemory::new(&[(GuestAddress(0), 8192)]).unwrap();
- source
- .get_slice_at_addr(GuestAddress(0), 8192)
- .unwrap()
- .write_bytes(0x55);
+ let mut source = tempfile().unwrap();
+ let data = vec![0x55; 8192];
+ source.write(&data).unwrap();
UringSource::new(source).unwrap()
});
diff --git a/data_model/Android.bp b/data_model/Android.bp
index 54cce1d..a35df0a 100644
--- a/data_model/Android.bp
+++ b/data_model/Android.bp
@@ -1,4 +1,4 @@
-// This file is generated by cargo2android.py --run --device --tests --dependencies --global_defaults=crosvm_defaults --add_workspace.
+// This file is generated by cargo2android.py --run --device --tests --dependencies --global_defaults=crosvm_defaults.
rust_defaults {
name: "data_model_defaults",
diff --git a/data_model/src/flexible_array.rs b/data_model/src/flexible_array.rs
index c47901e..c0689dc 100644
--- a/data_model/src/flexible_array.rs
+++ b/data_model/src/flexible_array.rs
@@ -43,11 +43,11 @@
/// A complete definition of flexible array structs is found in the ISO 9899 specification
/// (http://www.iso-9899.info/n1570.html). A flexible array struct is of the form:
///
-/// ```
+/// ```ignore
/// #[repr(C)]
/// struct T {
/// some_data: u32,
-/// nent: u32
+/// nent: u32,
/// entries: __IncompleteArrayField<S>,
/// }
/// ```
diff --git a/devices/.build_test_serial b/devices/.build_test_serial
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/devices/.build_test_serial
diff --git a/devices/Android.bp b/devices/Android.bp
index 7b0e9e5..dbb5c04 100644
--- a/devices/Android.bp
+++ b/devices/Android.bp
@@ -14,10 +14,10 @@
"libaudio_streams",
"libbase_rust",
"libbit_field",
- "libbitflags",
"libcros_async",
"libdata_model",
"libdisk",
+ "libfuse_rust",
"libhypervisor",
"libkvm_sys",
"liblibc",
@@ -109,10 +109,10 @@
"libaudio_streams",
"libbase_rust",
"libbit_field",
- "libbitflags",
"libcros_async",
"libdata_model",
"libdisk",
+ "libfuse_rust",
"libgpu_buffer", // added manually
"libgpu_display", // added manually
"libgpu_renderer", // added manually
@@ -150,6 +150,7 @@
// ../../adhd/cras/client/libcras/src/libcras.rs
// ../../minijail/rust/minijail-sys/lib.rs
// ../../minijail/rust/minijail/src/lib.rs
+// ../../rust/crates/libchromeos-rs/src/lib.rs
// ../../vm_tools/p9/src/lib.rs
// ../../vm_tools/p9/wire_format_derive/wire_format_derive.rs
// ../acpi_tables/src/lib.rs
@@ -161,6 +162,7 @@
// ../data_model/src/lib.rs
// ../disk/src/disk.rs
// ../enumn/src/lib.rs
+// ../fuse/src/lib.rs
// ../hypervisor/src/lib.rs
// ../io_uring/src/lib.rs
// ../kvm/src/lib.rs
@@ -185,6 +187,8 @@
// ../vm_control/src/lib.rs
// ../vm_memory/src/lib.rs
// async-trait-0.1.42
+// autocfg-1.0.1
+// base-0.1.0
// bitflags-1.2.1 "default"
// cfg-if-0.1.10
// downcast-rs-1.2.0 "default,std"
@@ -197,9 +201,13 @@
// futures-sink-0.3.8 "alloc,std"
// futures-task-0.3.8 "alloc,once_cell,std"
// futures-util-0.3.8 "alloc,async-await,async-await-macro,channel,futures-channel,futures-io,futures-macro,futures-sink,io,memchr,proc-macro-hack,proc-macro-nested,sink,slab,std"
+// getopts-0.2.21
// getrandom-0.1.15 "std"
+// intrusive-collections-0.9.0 "alloc,default"
// libc-0.2.80 "default,std"
+// log-0.4.11
// memchr-2.3.4 "default,std"
+// memoffset-0.5.6 "default"
// once_cell-1.5.2 "alloc,std"
// paste-1.0.3
// pin-project-1.0.2
@@ -210,6 +218,7 @@
// proc-macro-hack-0.5.19
// proc-macro-nested-0.1.6
// proc-macro2-1.0.24 "default,proc-macro"
+// protobuf-2.18.1
// quote-1.0.7 "default,proc-macro"
// rand-0.7.3 "alloc,default,getrandom,getrandom_package,libc,std"
// rand_chacha-0.2.2 "std"
@@ -217,8 +226,9 @@
// remain-0.2.2
// remove_dir_all-0.5.3
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// tempfile-3.1.0
// thiserror-1.0.22
// thiserror-impl-1.0.22
+// unicode-width-0.1.8 "default"
// unicode-xid-0.2.1 "default"
diff --git a/devices/Cargo.toml b/devices/Cargo.toml
index 2284a23..bacdc92 100644
--- a/devices/Cargo.toml
+++ b/devices/Cargo.toml
@@ -18,11 +18,11 @@
acpi_tables = {path = "../acpi_tables" }
audio_streams = { path = "../../adhd/audio_streams" } # ignored by ebuild
bit_field = { path = "../bit_field" }
-bitflags = "1"
cros_async = { path = "../cros_async" }
data_model = { path = "../data_model" }
disk = { path = "../disk" }
enumn = { path = "../enumn" }
+fuse = {path = "../fuse" }
gpu_buffer = { path = "../gpu_buffer", optional = true }
gpu_display = { path = "../gpu_display", optional = true }
gpu_renderer = { path = "../gpu_renderer", optional = true }
diff --git a/devices/src/acpi.rs b/devices/src/acpi.rs
index 780e985..80c0e95 100644
--- a/devices/src/acpi.rs
+++ b/devices/src/acpi.rs
@@ -2,13 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use crate::{BusDevice, BusResumeDevice};
+use crate::{BusAccessInfo, BusDevice, BusResumeDevice};
use acpi_tables::{aml, aml::Aml};
use base::{error, warn, Event};
/// ACPI PM resource for handling OS suspend/resume request
pub struct ACPIPMResource {
suspend_evt: Event,
+ exit_evt: Event,
pm1_status: u16,
pm1_enable: u16,
pm1_control: u16,
@@ -18,9 +19,10 @@
impl ACPIPMResource {
/// Constructs ACPI Power Management Resouce.
- pub fn new(suspend_evt: Event) -> ACPIPMResource {
+ pub fn new(suspend_evt: Event, exit_evt: Event) -> ACPIPMResource {
ACPIPMResource {
suspend_evt,
+ exit_evt,
pm1_status: 0,
pm1_enable: 0,
pm1_control: 0,
@@ -46,20 +48,23 @@
const BITMASK_PM1CNT_WAKE_STATUS: u16 = 0x8000;
const BITMASK_SLEEPCNT_WAKE_STATUS: u8 = 0x80;
+const BITMASK_PM1CNT_SLEEP_TYPE: u16 = 0x1C00;
+const SLEEP_TYPE_S5: u16 = 0;
+
impl BusDevice for ACPIPMResource {
fn debug_label(&self) -> String {
"ACPIPMResource".to_owned()
}
- fn read(&mut self, offset: u64, data: &mut [u8]) {
- let val = match offset as u16 {
+ fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
+ let val = match info.offset as u16 {
PM1_STATUS => self.pm1_status,
PM1_ENABLE => self.pm1_enable,
PM1_CONTROL => self.pm1_control,
SLEEP_CONTROL => self.sleep_control as u16,
SLEEP_STATUS => self.sleep_status as u16,
_ => {
- warn!("ACPIPM: Bad read from offset {}", offset);
+ warn!("ACPIPM: Bad read from {}", info);
return;
}
};
@@ -72,7 +77,7 @@
}
}
- fn write(&mut self, offset: u64, data: &[u8]) {
+ fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
let max_bytes = std::mem::size_of::<u16>();
// only allow maximum max_bytes to write
@@ -89,13 +94,19 @@
}
let val = u16::from_ne_bytes(val_arr);
- match offset as u16 {
+ match info.offset as u16 {
PM1_STATUS => self.pm1_status &= !val,
PM1_ENABLE => self.pm1_enable = val,
PM1_CONTROL => {
if (val & BITMASK_PM1CNT_SLEEP_ENABLE) == BITMASK_PM1CNT_SLEEP_ENABLE {
- if let Err(e) = self.suspend_evt.write(1) {
- error!("ACPIPM: failed to trigger suspend event: {}", e);
+ if val & BITMASK_PM1CNT_SLEEP_TYPE == SLEEP_TYPE_S5 {
+ if let Err(e) = self.exit_evt.write(1) {
+ error!("ACPIPM: failed to trigger exit event: {}", e);
+ }
+ } else {
+ if let Err(e) = self.suspend_evt.write(1) {
+ error!("ACPIPM: failed to trigger suspend event: {}", e);
+ }
}
}
self.pm1_control = val & !BITMASK_PM1CNT_SLEEP_ENABLE;
@@ -112,7 +123,7 @@
}
SLEEP_STATUS => self.sleep_status &= !val as u8,
_ => {
- warn!("ACPIPM: Bad write to offset {}", offset);
+ warn!("ACPIPM: Bad write to {}", info);
}
};
}
@@ -136,5 +147,12 @@
&aml::Package::new(vec![&aml::ONE, &aml::ONE, &aml::ZERO, &aml::ZERO]),
)
.to_aml_bytes(bytes);
+
+ // S5
+ aml::Name::new(
+ "_S5_".into(),
+ &aml::Package::new(vec![&aml::ZERO, &aml::ZERO, &aml::ZERO, &aml::ZERO]),
+ )
+ .to_aml_bytes(bytes);
}
}
diff --git a/devices/src/bat.rs b/devices/src/bat.rs
new file mode 100644
index 0000000..78345ee
--- /dev/null
+++ b/devices/src/bat.rs
@@ -0,0 +1,412 @@
+// Copyright 2020 The Chromium OS 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::{BusAccessInfo, BusDevice};
+use acpi_tables::{aml, aml::Aml};
+use base::{error, warn, AsRawDescriptor, Descriptor, Event, PollContext, PollToken};
+use msg_socket::{MsgReceiver, MsgSender};
+use std::fmt::{self, Display};
+use std::os::unix::io::RawFd;
+use std::sync::Arc;
+use std::thread;
+use sync::Mutex;
+use vm_control::{BatControlCommand, BatControlResponseSocket, BatControlResult};
+
+/// Errors for battery devices.
+#[derive(Debug)]
+pub enum BatteryError {
+ Non32BitMmioAddress,
+}
+
+impl Display for BatteryError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use self::BatteryError::*;
+
+ match self {
+ Non32BitMmioAddress => write!(f, "Non 32-bit mmio address space"),
+ }
+ }
+}
+
+type Result<T> = std::result::Result<T, BatteryError>;
+
+/// the GoldFish Battery MMIO length.
+pub const GOLDFISHBAT_MMIO_LEN: u64 = 0x1000;
+
+struct GoldfishBatteryState {
+ // interrupt state
+ int_status: u32,
+ int_enable: u32,
+ // AC state
+ ac_online: u32,
+ // Battery state
+ status: u32,
+ health: u32,
+ present: u32,
+ capacity: u32,
+}
+
+macro_rules! create_battery_func {
+ // $property: the battery property which is going to be modified.
+ // $int: the interrupt status which is going to be set to notify the guest.
+ ($fn:ident, $property:ident, $int:ident) => {
+ fn $fn(&mut self, value: u32) -> bool {
+ let old = std::mem::replace(&mut self.$property, value);
+ old != self.$property && self.set_int_status($int)
+ }
+ };
+}
+
+impl GoldfishBatteryState {
+ fn set_int_status(&mut self, mask: u32) -> bool {
+ if ((self.int_enable & mask) != 0) && ((self.int_status & mask) == 0) {
+ self.int_status |= mask;
+ return true;
+ }
+ false
+ }
+
+ fn int_status(&self) -> u32 {
+ self.int_status
+ }
+
+ create_battery_func!(set_ac_online, ac_online, AC_STATUS_CHANGED);
+
+ create_battery_func!(set_status, status, BATTERY_STATUS_CHANGED);
+
+ create_battery_func!(set_health, health, BATTERY_STATUS_CHANGED);
+
+ create_battery_func!(set_present, present, BATTERY_STATUS_CHANGED);
+
+ create_battery_func!(set_capacity, capacity, BATTERY_STATUS_CHANGED);
+}
+
+/// GoldFish Battery state
+pub struct GoldfishBattery {
+ state: Arc<Mutex<GoldfishBatteryState>>,
+ mmio_base: u32,
+ irq_num: u32,
+ irq_evt: Event,
+ irq_resample_evt: Event,
+ activated: bool,
+ monitor_thread: Option<thread::JoinHandle<()>>,
+ kill_evt: Option<Event>,
+ socket: Option<BatControlResponseSocket>,
+}
+
+/// Goldfish Battery MMIO offset
+const BATTERY_INT_STATUS: u32 = 0;
+const BATTERY_INT_ENABLE: u32 = 0x4;
+const BATTERY_AC_ONLINE: u32 = 0x8;
+const BATTERY_STATUS: u32 = 0xC;
+const BATTERY_HEALTH: u32 = 0x10;
+const BATTERY_PRESENT: u32 = 0x14;
+const BATTERY_CAPACITY: u32 = 0x18;
+const BATTERY_VOLTAGE: u32 = 0x1C;
+const BATTERY_TEMP: u32 = 0x20;
+const BATTERY_CHARGE_COUNTER: u32 = 0x24;
+const BATTERY_VOLTAGE_MAX: u32 = 0x28;
+const BATTERY_CURRENT_MAX: u32 = 0x2C;
+const BATTERY_CURRENT_NOW: u32 = 0x30;
+const BATTERY_CURRENT_AVG: u32 = 0x34;
+const BATTERY_CHARGE_FULL_UAH: u32 = 0x38;
+const BATTERY_CYCLE_COUNT: u32 = 0x40;
+
+/// Goldfish Battery interrupt bits
+const BATTERY_STATUS_CHANGED: u32 = 1 << 0;
+const AC_STATUS_CHANGED: u32 = 1 << 1;
+const BATTERY_INT_MASK: u32 = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED;
+
+fn command_monitor(
+ socket: BatControlResponseSocket,
+ irq_evt: Event,
+ irq_resample_evt: Event,
+ kill_evt: Event,
+ state: Arc<Mutex<GoldfishBatteryState>>,
+) {
+ #[derive(PollToken)]
+ enum Token {
+ Commands,
+ Resample,
+ Kill,
+ }
+
+ let poll_ctx: PollContext<Token> = match PollContext::build_with(&[
+ (&Descriptor(socket.as_raw_descriptor()), Token::Commands),
+ (
+ &Descriptor(irq_resample_evt.as_raw_descriptor()),
+ Token::Resample,
+ ),
+ (&Descriptor(kill_evt.as_raw_descriptor()), Token::Kill),
+ ]) {
+ Ok(pc) => pc,
+ Err(e) => {
+ error!("failed to build PollContext: {}", e);
+ return;
+ }
+ };
+
+ 'poll: loop {
+ let events = match poll_ctx.wait() {
+ Ok(v) => v,
+ Err(e) => {
+ error!("error while polling for events: {}", e);
+ break;
+ }
+ };
+
+ for event in events.iter_readable() {
+ match event.token() {
+ Token::Commands => {
+ let req = match socket.recv() {
+ Ok(req) => req,
+ Err(e) => {
+ error!("failed to receive request: {}", e);
+ continue;
+ }
+ };
+
+ let mut bat_state = state.lock();
+ let inject_irq = match req {
+ BatControlCommand::SetStatus(status) => bat_state.set_status(status.into()),
+ BatControlCommand::SetHealth(health) => bat_state.set_health(health.into()),
+ BatControlCommand::SetPresent(present) => {
+ let v = if present != 0 { 1 } else { 0 };
+ bat_state.set_present(v)
+ }
+ BatControlCommand::SetCapacity(capacity) => {
+ let v = std::cmp::min(capacity, 100);
+ bat_state.set_capacity(v)
+ }
+ BatControlCommand::SetACOnline(ac_online) => {
+ let v = if ac_online != 0 { 1 } else { 0 };
+ bat_state.set_ac_online(v)
+ }
+ };
+
+ if inject_irq {
+ let _ = irq_evt.write(1);
+ }
+
+ if let Err(e) = socket.send(&BatControlResult::Ok) {
+ error!("failed to send response: {}", e);
+ }
+ }
+ Token::Resample => {
+ let _ = irq_resample_evt.read();
+ if state.lock().int_status() != 0 {
+ let _ = irq_evt.write(1);
+ }
+ }
+ Token::Kill => break 'poll,
+ }
+ }
+ }
+}
+
+impl GoldfishBattery {
+ /// Create GoldfishBattery device model
+ ///
+ /// * `mmio_base` - The 32-bit mmio base address.
+ /// * `irq_num` - The corresponding interrupt number of the irq_evt
+ /// which will be put into the ACPI DSDT.
+ /// * `irq_evt` - The interrupt event used to notify driver about
+ /// the battery properties changing.
+ /// * `irq_resample_evt` - Resample interrupt event notified at EOI.
+ /// * `socket` - Battery control socket
+ pub fn new(
+ mmio_base: u64,
+ irq_num: u32,
+ irq_evt: Event,
+ irq_resample_evt: Event,
+ socket: BatControlResponseSocket,
+ ) -> Result<Self> {
+ if mmio_base + GOLDFISHBAT_MMIO_LEN - 1 > u32::MAX as u64 {
+ return Err(BatteryError::Non32BitMmioAddress);
+ }
+ let state = Arc::new(Mutex::new(GoldfishBatteryState {
+ capacity: 50,
+ health: 1,
+ present: 1,
+ status: 1,
+ ac_online: 1,
+ int_enable: 0,
+ int_status: 0,
+ }));
+
+ Ok(GoldfishBattery {
+ state,
+ mmio_base: mmio_base as u32,
+ irq_num,
+ irq_evt,
+ irq_resample_evt,
+ activated: false,
+ monitor_thread: None,
+ kill_evt: None,
+ socket: Some(socket),
+ })
+ }
+
+ /// return the fds used by this device
+ pub fn keep_fds(&self) -> Vec<RawFd> {
+ let mut fds = vec![
+ self.irq_evt.as_raw_descriptor(),
+ self.irq_resample_evt.as_raw_descriptor(),
+ ];
+
+ if let Some(socket) = &self.socket {
+ fds.push(socket.as_raw_descriptor());
+ }
+
+ fds
+ }
+
+ /// start a monitor thread to monitor the events from host
+ fn start_monitor(&mut self) {
+ if self.activated {
+ return;
+ }
+
+ let (self_kill_evt, kill_evt) = match Event::new().and_then(|e| Ok((e.try_clone()?, e))) {
+ Ok(v) => v,
+ Err(e) => {
+ error!(
+ "{}: failed to create kill EventFd pair: {}",
+ self.debug_label(),
+ e
+ );
+ return;
+ }
+ };
+
+ if let Some(socket) = self.socket.take() {
+ let irq_evt = self.irq_evt.try_clone().unwrap();
+ let irq_resample_evt = self.irq_resample_evt.try_clone().unwrap();
+ let bat_state = self.state.clone();
+ let monitor_result = thread::Builder::new()
+ .name(self.debug_label())
+ .spawn(move || {
+ command_monitor(socket, irq_evt, irq_resample_evt, kill_evt, bat_state);
+ });
+
+ self.monitor_thread = match monitor_result {
+ Err(e) => {
+ error!(
+ "{}: failed to spawn PowerIO monitor: {}",
+ self.debug_label(),
+ e
+ );
+ return;
+ }
+ Ok(join_handle) => Some(join_handle),
+ };
+ self.kill_evt = Some(self_kill_evt);
+ self.activated = true;
+ }
+ }
+}
+
+impl Drop for GoldfishBattery {
+ 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);
+ }
+ if let Some(thread) = self.monitor_thread.take() {
+ let _ = thread.join();
+ }
+ }
+}
+
+impl BusDevice for GoldfishBattery {
+ fn debug_label(&self) -> String {
+ "GoldfishBattery".to_owned()
+ }
+
+ fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
+ if data.len() != std::mem::size_of::<u32>() {
+ warn!(
+ "{}: unsupported read length {}, only support 4bytes read",
+ self.debug_label(),
+ data.len()
+ );
+ return;
+ }
+
+ let val = match info.offset as u32 {
+ BATTERY_INT_STATUS => {
+ // read to clear the interrupt status
+ std::mem::replace(&mut self.state.lock().int_status, 0)
+ }
+ BATTERY_INT_ENABLE => self.state.lock().int_enable,
+ BATTERY_AC_ONLINE => self.state.lock().ac_online,
+ BATTERY_STATUS => self.state.lock().status,
+ BATTERY_HEALTH => self.state.lock().health,
+ BATTERY_PRESENT => self.state.lock().present,
+ BATTERY_CAPACITY => self.state.lock().capacity,
+ BATTERY_VOLTAGE => 0,
+ BATTERY_TEMP => 0,
+ BATTERY_CHARGE_COUNTER => 0,
+ BATTERY_VOLTAGE_MAX => 0,
+ BATTERY_CURRENT_MAX => 0,
+ BATTERY_CURRENT_NOW => 0,
+ BATTERY_CURRENT_AVG => 0,
+ BATTERY_CHARGE_FULL_UAH => 0,
+ BATTERY_CYCLE_COUNT => 0,
+ _ => {
+ warn!("{}: unsupported read address {}", self.debug_label(), info);
+ return;
+ }
+ };
+
+ let val_arr = val.to_ne_bytes();
+ data.copy_from_slice(&val_arr);
+ }
+
+ fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
+ if data.len() != std::mem::size_of::<u32>() {
+ warn!(
+ "{}: unsupported write length {}, only support 4bytes write",
+ self.debug_label(),
+ data.len()
+ );
+ return;
+ }
+
+ let mut val_arr = u32::to_ne_bytes(0 as u32);
+ val_arr.copy_from_slice(data);
+ let val = u32::from_ne_bytes(val_arr);
+
+ match info.offset as u32 {
+ BATTERY_INT_ENABLE => {
+ self.state.lock().int_enable = val;
+ if (val & BATTERY_INT_MASK) != 0 && !self.activated {
+ self.start_monitor();
+ }
+ }
+ _ => {
+ warn!("{}: Bad write to address {}", self.debug_label(), info);
+ }
+ };
+ }
+}
+
+impl Aml for GoldfishBattery {
+ fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
+ aml::Device::new(
+ "GFBY".into(),
+ vec![
+ &aml::Name::new("_HID".into(), &"GFSH0001"),
+ &aml::Name::new(
+ "_CRS".into(),
+ &aml::ResourceTemplate::new(vec![
+ &aml::Memory32Fixed::new(true, self.mmio_base, GOLDFISHBAT_MMIO_LEN as u32),
+ &aml::Interrupt::new(true, false, false, true, self.irq_num),
+ ]),
+ ),
+ ],
+ )
+ .to_aml_bytes(bytes);
+ }
+}
diff --git a/devices/src/bus.rs b/devices/src/bus.rs
index 3f93974..c6e7d78 100644
--- a/devices/src/bus.rs
+++ b/devices/src/bus.rs
@@ -10,8 +10,27 @@
use std::result;
use std::sync::Arc;
+use base::RawDescriptor;
+use msg_socket::MsgOnSocket;
use sync::Mutex;
+/// Information about how a device was accessed.
+#[derive(Copy, Clone, Eq, PartialEq, Debug, MsgOnSocket)]
+pub struct BusAccessInfo {
+ /// Offset from base address that the device was accessed at.
+ pub offset: u64,
+ /// Absolute address of the device's access in its address space.
+ pub address: u64,
+ /// ID of the entity requesting a device access, usually the VCPU id.
+ pub id: usize,
+}
+
+// Implement `Display` for `MinMax`.
+impl std::fmt::Display for BusAccessInfo {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}", self)
+ }
+}
/// 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
@@ -21,9 +40,9 @@
/// 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]) {}
+ fn read(&mut self, offset: BusAccessInfo, data: &mut [u8]) {}
/// Writes at `offset` into this device
- fn write(&mut self, offset: u64, data: &[u8]) {}
+ fn write(&mut self, offset: BusAccessInfo, 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.
@@ -37,6 +56,11 @@
fn on_sandboxed(&mut self) {}
}
+pub trait BusDeviceSync: BusDevice + Sync {
+ fn read(&self, offset: BusAccessInfo, data: &mut [u8]);
+ fn write(&self, offset: BusAccessInfo, data: &[u8]);
+}
+
pub trait BusResumeDevice: Send {
/// notify the devices which are invoked
/// before the VM resumes form suspend.
@@ -65,13 +89,10 @@
///
/// * 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 {
@@ -106,6 +127,12 @@
}
}
+#[derive(Clone)]
+enum BusDeviceEntry {
+ OuterSync(Arc<Mutex<dyn BusDevice>>),
+ InnerSync(Arc<dyn BusDeviceSync>),
+}
+
/// 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
@@ -115,8 +142,9 @@
/// resume back from S3 suspended state.
#[derive(Clone)]
pub struct Bus {
- devices: BTreeMap<BusRange, Arc<Mutex<dyn BusDevice>>>,
+ devices: BTreeMap<BusRange, BusDeviceEntry>,
resume_notify_devices: Vec<Arc<Mutex<dyn BusResumeDevice>>>,
+ access_id: usize,
}
impl Bus {
@@ -125,45 +153,68 @@
Bus {
devices: BTreeMap::new(),
resume_notify_devices: Vec::new(),
+ access_id: 0,
}
}
- fn first_before(&self, addr: u64) -> Option<(BusRange, &Mutex<dyn BusDevice>)> {
+ /// Sets the id that will be used for BusAccessInfo.
+ pub fn set_access_id(&mut self, id: usize) {
+ self.access_id = id;
+ }
+
+ fn first_before(&self, addr: u64) -> Option<(BusRange, &BusDeviceEntry)> {
let (range, dev) = self
.devices
- .range(
- ..=BusRange {
- base: addr,
- len: 1,
- full_addr: false,
- },
- )
+ .range(..=BusRange { base: addr, len: 1 })
.rev()
.next()?;
Some((*range, dev))
}
- fn get_device(&self, addr: u64) -> Option<(u64, &Mutex<dyn BusDevice>)> {
+ fn get_device(&self, addr: u64) -> Option<(u64, u64, &BusDeviceEntry)> {
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));
- }
+ return Some((offset, addr, dev));
}
}
None
}
/// Puts the given device at the given address space.
- pub fn insert(
+ pub fn insert(&mut self, device: Arc<Mutex<dyn BusDevice>>, base: u64, len: u64) -> 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 }, BusDeviceEntry::OuterSync(device))
+ .is_some()
+ {
+ return Err(Error::Overlap);
+ }
+
+ Ok(())
+ }
+
+ /// Puts the given device that implements BusDeviceSync at the given address space. Devices
+ /// that implement BusDeviceSync manage thread safety internally, and thus can be written to
+ /// by multiple threads simultaneously.
+ pub fn insert_sync(
&mut self,
- device: Arc<Mutex<dyn BusDevice>>,
+ device: Arc<dyn BusDeviceSync>,
base: u64,
len: u64,
- full_addr: bool,
) -> Result<()> {
if len == 0 {
return Err(Error::Overlap);
@@ -180,14 +231,7 @@
if self
.devices
- .insert(
- BusRange {
- base,
- len,
- full_addr,
- },
- device,
- )
+ .insert(BusRange { base, len }, BusDeviceEntry::InnerSync(device))
.is_some()
{
return Err(Error::Overlap);
@@ -200,8 +244,16 @@
///
/// 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);
+ if let Some((offset, address, dev)) = self.get_device(addr) {
+ let io = BusAccessInfo {
+ address,
+ offset,
+ id: self.access_id,
+ };
+ match dev {
+ BusDeviceEntry::OuterSync(dev) => dev.lock().read(io, data),
+ BusDeviceEntry::InnerSync(dev) => dev.read(io, data),
+ }
true
} else {
false
@@ -212,8 +264,16 @@
///
/// 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);
+ if let Some((offset, address, dev)) = self.get_device(addr) {
+ let io = BusAccessInfo {
+ address,
+ offset,
+ id: self.access_id,
+ };
+ match dev {
+ BusDeviceEntry::OuterSync(dev) => dev.lock().write(io, data),
+ BusDeviceEntry::InnerSync(dev) => dev.write(io, data),
+ }
true
} else {
false
@@ -245,21 +305,34 @@
}
}
- struct ConstantDevice;
+ struct ConstantDevice {
+ uses_full_addr: bool,
+ }
+
impl BusDevice for ConstantDevice {
fn debug_label(&self) -> String {
"constant device".to_owned()
}
- fn read(&mut self, offset: u64, data: &mut [u8]) {
+ fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
+ let addr = if self.uses_full_addr {
+ info.address
+ } else {
+ info.offset
+ };
for (i, v) in data.iter_mut().enumerate() {
- *v = (offset as u8) + (i as u8);
+ *v = (addr as u8) + (i as u8);
}
}
- fn write(&mut self, offset: u64, data: &[u8]) {
+ fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
+ let addr = if self.uses_full_addr {
+ info.address
+ } else {
+ info.offset
+ };
for (i, v) in data.iter().enumerate() {
- assert_eq!(*v, (offset as u8) + (i as u8))
+ assert_eq!(*v, (addr as u8) + (i as u8))
}
}
}
@@ -268,41 +341,41 @@
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());
+ assert!(bus.insert(dummy.clone(), 0x10, 0).is_err());
+ assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
+ assert!(bus.insert(dummy.clone(), 0x0f, 0x10).is_err());
+ assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_err());
+ assert!(bus.insert(dummy.clone(), 0x10, 0x15).is_err());
+ assert!(bus.insert(dummy.clone(), 0x12, 0x15).is_err());
+ assert!(bus.insert(dummy.clone(), 0x12, 0x01).is_err());
+ assert!(bus.insert(dummy.clone(), 0x0, 0x20).is_err());
+ assert!(bus.insert(dummy.clone(), 0x20, 0x05).is_ok());
+ assert!(bus.insert(dummy.clone(), 0x25, 0x05).is_ok());
+ assert!(bus.insert(dummy.clone(), 0x0, 0x10).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());
+ assert!(bus.insert(dummy.clone(), 0x10, 0).is_err());
+ assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
+ assert!(bus.insert(dummy.clone(), 0x0f, 0x10).is_err());
+ assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_err());
+ assert!(bus.insert(dummy.clone(), 0x10, 0x15).is_err());
+ assert!(bus.insert(dummy.clone(), 0x12, 0x15).is_err());
+ assert!(bus.insert(dummy.clone(), 0x12, 0x01).is_err());
+ assert!(bus.insert(dummy.clone(), 0x0, 0x20).is_err());
+ assert!(bus.insert(dummy.clone(), 0x20, 0x05).is_ok());
+ assert!(bus.insert(dummy.clone(), 0x25, 0x05).is_ok());
+ assert!(bus.insert(dummy.clone(), 0x0, 0x10).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.insert(dummy.clone(), 0x10, 0x10).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]));
@@ -318,8 +391,10 @@
#[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 dummy = Arc::new(Mutex::new(ConstantDevice {
+ uses_full_addr: false,
+ }));
+ assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
let mut values = [0, 1, 2, 3];
assert!(bus.read(0x10, &mut values));
@@ -333,8 +408,10 @@
#[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 dummy = Arc::new(Mutex::new(ConstantDevice {
+ uses_full_addr: true,
+ }));
+ assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
let mut values = [0u8; 4];
assert!(bus.read(0x10, &mut values));
@@ -350,7 +427,6 @@
let a = BusRange {
base: 0x1000,
len: 0x400,
- full_addr: false,
};
assert!(a.contains(0x1000));
assert!(a.contains(0x13ff));
@@ -364,7 +440,6 @@
let a = BusRange {
base: 0x1000,
len: 0x400,
- full_addr: false,
};
assert!(a.overlaps(0x1000, 0x400));
assert!(a.overlaps(0xf00, 0x400));
diff --git a/devices/src/cmos.rs b/devices/src/cmos.rs
index 977b9ef..fcf0498 100644
--- a/devices/src/cmos.rs
+++ b/devices/src/cmos.rs
@@ -6,7 +6,7 @@
use std::cmp::min;
use std::mem;
-use crate::BusDevice;
+use crate::{BusAccessInfo, BusDevice};
const INDEX_MASK: u8 = 0x7f;
const INDEX_OFFSET: u64 = 0x0;
@@ -51,19 +51,19 @@
"cmos".to_owned()
}
- fn write(&mut self, offset: u64, data: &[u8]) {
+ fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
if data.len() != 1 {
return;
}
- match offset {
+ match info.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 read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
fn to_bcd(v: u8) -> u8 {
assert!(v < 100);
((v / 10) << 4) | (v % 10)
@@ -73,7 +73,7 @@
return;
}
- data[0] = match offset {
+ data[0] = match info.offset {
INDEX_OFFSET => self.index,
DATA_OFFSET => {
let seconds;
diff --git a/devices/src/i8042.rs b/devices/src/i8042.rs
index 08b54b0..6fdd978 100644
--- a/devices/src/i8042.rs
+++ b/devices/src/i8042.rs
@@ -4,7 +4,7 @@
use base::{error, Event};
-use crate::BusDevice;
+use crate::{BusAccessInfo, BusDevice};
/// A i8042 PS/2 controller that emulates just enough to shutdown the machine.
pub struct I8042Device {
@@ -25,18 +25,18 @@
"i8042".to_owned()
}
- fn read(&mut self, offset: u64, data: &mut [u8]) {
- if data.len() == 1 && offset == 0x64 {
+ fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
+ if data.len() == 1 && info.offset == 0x64 {
data[0] = 0x0;
- } else if data.len() == 1 && offset == 0x61 {
+ } else if data.len() == 1 && info.offset == 0x61 {
// 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 == 0x64 {
+ fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
+ if data.len() == 1 && data[0] == 0xfe && info.offset == 0x64 {
if let Err(e) = self.reset_evt.write(1) {
error!("failed to trigger i8042 reset event: {}", e);
}
diff --git a/devices/src/irqchip/ioapic.rs b/devices/src/irqchip/ioapic.rs
index 11d78f3..bfab4ed 100644
--- a/devices/src/irqchip/ioapic.rs
+++ b/devices/src/irqchip/ioapic.rs
@@ -5,11 +5,15 @@
// 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 std::fmt::{self, Display};
+
+use super::IrqEvent;
+use crate::bus::BusAccessInfo;
use crate::BusDevice;
-use base::{error, warn, Event, Result};
+use base::{error, warn, AsRawDescriptor, Error, Event, Result};
use hypervisor::{IoapicState, MsiAddressMessage, MsiDataMessage, TriggerMode, NUM_IOAPIC_PINS};
-use msg_socket::{MsgReceiver, MsgSender};
-use vm_control::{VmIrqRequest, VmIrqRequestSocket, VmIrqResponse};
+use msg_socket::{MsgError, MsgReceiver, MsgSender};
+use vm_control::{MaybeOwnedDescriptor, VmIrqRequest, VmIrqRequestSocket, VmIrqResponse};
const IOAPIC_VERSION_ID: u32 = 0x00170011;
pub const IOAPIC_BASE_ADDRESS: u64 = 0xfec00000;
@@ -58,10 +62,11 @@
/// 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,
- /// Irq events that are used to inject interrupts
- irq_events: Vec<Event>,
- /// Events that should be triggered on an EOI
- resample_events: Vec<Option<Event>>,
+ /// Outgoing irq events that are used to inject MSI interrupts.
+ out_events: Vec<Option<IrqEvent>>,
+ /// Events that should be triggered on an EOI. The outer Vec is indexed by GSI, and the inner
+ /// Vec is an unordered list of registered resample events for the GSI.
+ resample_events: Vec<Vec<Event>>,
/// Socket used to route MSI irqs
irq_socket: VmIrqRequestSocket,
}
@@ -71,20 +76,20 @@
"userspace IOAPIC".to_string()
}
- fn read(&mut self, offset: u64, data: &mut [u8]) {
+ fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
if data.len() > 8 || data.len() == 0 {
warn!("IOAPIC: Bad read size: {}", data.len());
return;
}
- if offset >= IOAPIC_MEM_LENGTH_BYTES {
- warn!("IOAPIC: Bad read from offset {}", offset);
+ if info.offset >= IOAPIC_MEM_LENGTH_BYTES {
+ warn!("IOAPIC: Bad read from {}", info);
}
- let out = match offset as u8 {
+ let out = match info.offset as u8 {
IOREGSEL_OFF => self.state.ioregsel.into(),
IOREGSEL_DUMMY_UPPER_32_BITS_OFF => 0,
IOWIN_OFF => self.ioapic_read(),
_ => {
- warn!("IOAPIC: Bad read from offset {}", offset);
+ warn!("IOAPIC: Bad read from {}", info);
return;
}
};
@@ -96,15 +101,15 @@
}
}
- fn write(&mut self, offset: u64, data: &[u8]) {
+ fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
if data.len() > 8 || data.len() == 0 {
warn!("IOAPIC: Bad write size: {}", data.len());
return;
}
- if offset >= IOAPIC_MEM_LENGTH_BYTES {
- warn!("IOAPIC: Bad write to offset {}", offset);
+ if info.offset >= IOAPIC_MEM_LENGTH_BYTES {
+ warn!("IOAPIC: Bad write to {}", info);
}
- match offset as u8 {
+ match info.offset as u8 {
IOREGSEL_OFF => self.state.ioregsel = data[0],
IOREGSEL_DUMMY_UPPER_32_BITS_OFF => {} // Ignored.
IOWIN_OFF => {
@@ -117,14 +122,14 @@
self.ioapic_write(val);
}
_ => {
- warn!("IOAPIC: Bad write to offset {}", offset);
+ warn!("IOAPIC: Bad write to {}", info);
}
}
}
}
impl Ioapic {
- pub fn new(irq_events: Vec<Event>, irq_socket: VmIrqRequestSocket) -> Result<Ioapic> {
+ pub fn new(irq_socket: VmIrqRequestSocket) -> Result<Ioapic> {
let mut state = IoapicState::default();
for i in 0..NUM_IOAPIC_PINS {
@@ -134,7 +139,7 @@
Ok(Ioapic {
state,
rtc_remote_irr: false,
- irq_events,
+ out_events: (0..NUM_IOAPIC_PINS).map(|_| None).collect(),
resample_events: Vec::new(),
irq_socket,
})
@@ -148,7 +153,7 @@
self.state = *state
}
- pub fn register_resample_events(&mut self, resample_events: Vec<Option<Event>>) {
+ pub fn register_resample_events(&mut self, resample_events: Vec<Vec<Event>>) {
self.resample_events = resample_events;
}
@@ -164,12 +169,18 @@
if self.state.redirect_table[i].get_vector() == vector
&& self.state.redirect_table[i].get_trigger_mode() == TriggerMode::Level
{
- if self.resample_events.get(i).map_or(false, |e| e.is_some()) {
+ if self
+ .resample_events
+ .get(i)
+ .map_or(false, |events| events.len() > 0)
+ {
self.service_irq(i, false);
}
- if let Some(Some(resample_evt)) = &self.resample_events.get(i) {
- resample_evt.write(1).unwrap();
+ if let Some(resample_events) = self.resample_events.get(i) {
+ for resample_evt in resample_events {
+ resample_evt.write(1).unwrap();
+ }
}
self.state.redirect_table[i].set_remote_irr(false);
}
@@ -216,8 +227,8 @@
return false;
}
- let injected = match self.irq_events.get(irq) {
- Some(evt) => evt.write(1).is_ok(),
+ let injected = match self.out_events.get(irq) {
+ Some(Some(evt)) => evt.event.write(1).is_ok(),
_ => false,
};
@@ -284,30 +295,85 @@
data.set_delivery_mode(entry.get_delivery_mode());
data.set_trigger(entry.get_trigger_mode());
- let request = VmIrqRequest::AddMsiRoute {
- gsi: index as u32,
- msi_address: address.get(0, 32),
- msi_data: data.get(0, 32) as u32,
- };
-
- if let Err(e) = self.irq_socket.send(&request) {
- error!("IOAPIC: failed to send AddMsiRoute request: {}", e);
- return;
- }
- match self.irq_socket.recv() {
- Ok(response) => {
- if let VmIrqResponse::Err(e) = response {
- error!("IOAPIC: failed to add msi route: {}", e);
- }
- }
- Err(e) => {
- error!("IOAPIC: failed to receive AddMsiRoute response: {}", e);
- }
+ let msi_address = address.get(0, 32);
+ let msi_data = data.get(0, 32);
+ if let Err(e) = self.setup_msi(index, msi_address, msi_data as u32) {
+ error!("IOAPIC failed to set up MSI for index {}: {}", index, e);
}
}
}
}
+ fn setup_msi(
+ &mut self,
+ index: usize,
+ msi_address: u64,
+ msi_data: u32,
+ ) -> std::result::Result<(), IoapicError> {
+ if msi_data == 0 {
+ // During boot, Linux first configures all ioapic pins with msi_data == 0; the routes
+ // aren't yet assigned to devices and aren't usable. We skip MSI setup if msi_data is
+ // 0.
+ return Ok(());
+ }
+
+ // Allocate a GSI and event for the outgoing route, if we haven't already done it.
+ // The event will be used on the "outgoing" end of the ioapic to send an interrupt to the
+ // apics: when an incoming ioapic irq line gets signalled, the ioapic writes to the
+ // corresponding outgoing event. The GSI number is used to update the routing info (MSI
+ // data and addr) for the event. The GSI and event are allocated only once for each ioapic
+ // irq line, when the guest first sets up the ioapic with a valid route. If the guest
+ // later reconfigures an ioapic irq line, the same GSI and event are reused, and we change
+ // the GSI's route to the new MSI data+addr destination.
+ let gsi = if let Some(evt) = &self.out_events[index] {
+ evt.gsi
+ } else {
+ let event = Event::new().map_err(|e| IoapicError::CreateEvent(e))?;
+ let request = VmIrqRequest::AllocateOneMsi {
+ irqfd: MaybeOwnedDescriptor::Borrowed(event.as_raw_descriptor()),
+ };
+ self.irq_socket
+ .send(&request)
+ .map_err(IoapicError::AllocateOneMsiSend)?;
+ match self
+ .irq_socket
+ .recv()
+ .map_err(IoapicError::AllocateOneMsiRecv)?
+ {
+ VmIrqResponse::AllocateOneMsi { gsi, .. } => {
+ self.out_events[index] = Some(IrqEvent {
+ gsi,
+ event,
+ resample_event: None,
+ });
+ gsi
+ }
+ VmIrqResponse::Err(e) => return Err(IoapicError::AllocateOneMsi(e)),
+ _ => unreachable!(),
+ }
+ };
+
+ // Set the MSI route for the GSI. This controls which apic(s) get the interrupt when the
+ // ioapic's outgoing event is written, and various attributes of how the interrupt is
+ // delivered.
+ let request = VmIrqRequest::AddMsiRoute {
+ gsi,
+ msi_address,
+ msi_data,
+ };
+ self.irq_socket
+ .send(&request)
+ .map_err(IoapicError::AddMsiRouteSend)?;
+ if let VmIrqResponse::Err(e) = self
+ .irq_socket
+ .recv()
+ .map_err(IoapicError::AddMsiRouteRecv)?
+ {
+ return Err(IoapicError::AddMsiRoute(e));
+ }
+ Ok(())
+ }
+
fn ioapic_read(&mut self) -> u32 {
match self.state.ioregsel {
IOAPIC_REG_VERSION => IOAPIC_VERSION_ID,
@@ -330,6 +396,35 @@
}
}
+#[derive(Debug)]
+enum IoapicError {
+ AddMsiRoute(Error),
+ AddMsiRouteRecv(MsgError),
+ AddMsiRouteSend(MsgError),
+ AllocateOneMsi(Error),
+ AllocateOneMsiRecv(MsgError),
+ AllocateOneMsiSend(MsgError),
+ CreateEvent(Error),
+}
+
+impl Display for IoapicError {
+ #[remain::check]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use self::IoapicError::*;
+
+ #[sorted]
+ match self {
+ AddMsiRoute(e) => write!(f, "AddMsiRoute failed: {}", e),
+ AddMsiRouteRecv(e) => write!(f, "failed to receive AddMsiRoute response: {}", e),
+ AddMsiRouteSend(e) => write!(f, "failed to send AddMsiRoute request: {}", e),
+ AllocateOneMsi(e) => write!(f, "AllocateOneMsi failed: {}", e),
+ AllocateOneMsiRecv(e) => write!(f, "failed to receive AllocateOneMsi response: {}", e),
+ AllocateOneMsiSend(e) => write!(f, "failed to send AllocateOneMsi request: {}", e),
+ CreateEvent(e) => write!(f, "failed to create event object: {}", e),
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -340,11 +435,20 @@
fn new() -> Ioapic {
let (_, device_socket) = msg_socket::pair::<VmIrqResponse, VmIrqRequest>().unwrap();
- Ioapic::new(Vec::new(), device_socket).unwrap()
+ Ioapic::new(device_socket).unwrap()
+ }
+
+ fn ioapic_bus_address(offset: u8) -> BusAccessInfo {
+ let offset = offset as u64;
+ BusAccessInfo {
+ offset,
+ address: IOAPIC_BASE_ADDRESS + offset,
+ id: 0,
+ }
}
fn set_up(trigger: TriggerMode) -> (Ioapic, usize) {
- let irq = hypervisor::NUM_IOAPIC_PINS - 1;
+ let irq = NUM_IOAPIC_PINS - 1;
let ioapic = set_up_with_irq(irq, trigger);
(ioapic, irq)
}
@@ -352,19 +456,24 @@
fn set_up_with_irq(irq: usize, trigger: TriggerMode) -> Ioapic {
let mut ioapic = self::new();
set_up_redirection_table_entry(&mut ioapic, irq, trigger);
+ ioapic.out_events[irq] = Some(IrqEvent {
+ gsi: NUM_IOAPIC_PINS as u32,
+ event: Event::new().unwrap(),
+ resample_event: None,
+ });
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);
+ ioapic.write(ioapic_bus_address(IOREGSEL_OFF), &[selector]);
+ ioapic.read(ioapic_bus_address(IOWIN_OFF), &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());
+ ioapic.write(ioapic_bus_address(IOREGSEL_OFF), &[selector]);
+ ioapic.write(ioapic_bus_address(IOWIN_OFF), &value.to_ne_bytes());
}
fn read_entry(ioapic: &mut Ioapic, irq: usize) -> IoapicRedirectionTableEntry {
@@ -418,8 +527,8 @@
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]);
+ ioapic.write(ioapic_bus_address(IOREGSEL_OFF), &data_write[i..i + 1]);
+ ioapic.read(ioapic_bus_address(IOREGSEL_OFF), &mut data_read[i..i + 1]);
assert_eq!(data_write[i], data_read[i]);
}
}
@@ -473,7 +582,7 @@
#[should_panic(expected = "index out of bounds: the len is 24 but the index is 24")]
fn service_invalid_irq() {
let mut ioapic = self::new();
- ioapic.service_irq(hypervisor::NUM_IOAPIC_PINS, false);
+ ioapic.service_irq(NUM_IOAPIC_PINS, false);
}
// Test a level triggered IRQ interrupt.
diff --git a/devices/src/irqchip/kvm/mod.rs b/devices/src/irqchip/kvm/mod.rs
index 3da840e..21b0a99 100644
--- a/devices/src/irqchip/kvm/mod.rs
+++ b/devices/src/irqchip/kvm/mod.rs
@@ -5,7 +5,11 @@
use crate::Bus;
use base::{error, Error, Event, Result};
use hypervisor::kvm::KvmVcpu;
-use hypervisor::{IrqRoute, MPState, Vcpu};
+#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+use hypervisor::VmAArch64;
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+use hypervisor::VmX86_64;
+use hypervisor::{HypervisorCap, IrqRoute, MPState, Vcpu};
use kvm_sys::kvm_mp_state;
use resources::SystemAllocator;
@@ -19,7 +23,7 @@
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
pub use aarch64::*;
-use crate::IrqChip;
+use crate::{IrqChip, IrqChipCap, IrqEventIndex, VcpuRunState};
/// This IrqChip only works with Kvm so we only implement it for KvmVcpu.
impl IrqChip for KvmKernelIrqChip {
@@ -38,8 +42,9 @@
irq: u32,
irq_event: &Event,
resample_event: Option<&Event>,
- ) -> Result<()> {
- self.vm.register_irqfd(irq, irq_event, resample_event)
+ ) -> Result<Option<IrqEventIndex>> {
+ self.vm.register_irqfd(irq, irq_event, resample_event)?;
+ Ok(None)
}
/// Unregister an event for a particular GSI.
@@ -65,11 +70,11 @@
self.vm.set_gsi_routing(&*current_routes)
}
- /// Return a vector of all registered irq numbers and their associated events. To be used by
- /// the main thread to wait for irq events to be triggered.
+ /// Return a vector of all registered irq numbers and their associated events and event
+ /// indices. These should be used by the main thread to wait for irq events.
/// For the KvmKernelIrqChip, the kernel handles listening to irq events being triggered by
/// devices, so this function always returns an empty Vec.
- fn irq_event_tokens(&self) -> Result<Vec<(u32, Event)>> {
+ fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, u32, Event)>> {
Ok(Vec::new())
}
@@ -85,7 +90,7 @@
/// Event, then the deassert will only happen after an EOI is broadcast for a vector
/// associated with the irq line.
/// This function should never be called on KvmKernelIrqChip.
- fn service_irq_event(&mut self, _irq: u32) -> Result<()> {
+ fn service_irq_event(&mut self, _event_index: IrqEventIndex) -> Result<()> {
error!("service_irq_event should never be called for KvmKernelIrqChip");
Ok(())
}
@@ -93,26 +98,35 @@
/// Broadcast an end of interrupt.
/// This should never be called on a KvmKernelIrqChip because a KVM vcpu should never exit
/// with the KVM_EXIT_EOI_BROADCAST reason when an in-kernel irqchip exists.
- fn broadcast_eoi(&mut self, _vector: u8) -> Result<()> {
+ fn broadcast_eoi(&self, _vector: u8) -> Result<()> {
error!("broadcast_eoi should never be called for KvmKernelIrqChip");
Ok(())
}
- /// Return true if there is a pending interrupt for the specified vcpu.
- /// For the KvmKernelIrqChip this should always return false because KVM is responsible for
- /// injecting all interrupts.
- fn interrupt_requested(&self, _vcpu_id: usize) -> bool {
- false
+ /// Injects any pending interrupts for `vcpu`.
+ /// For KvmKernelIrqChip this is a no-op because KVM is responsible for injecting all
+ /// interrupts.
+ fn inject_interrupts(&self, _vcpu: &dyn Vcpu) -> Result<()> {
+ Ok(())
}
- /// Check if the specified vcpu has any pending interrupts. Returns None for no interrupts,
- /// otherwise Some(u32) should be the injected interrupt vector.
- /// For the KvmKernelIrqChip this should always return None because KVM is responsible for
- /// injecting all interrupts.
- fn get_external_interrupt(&mut self, _vcpu_id: usize) -> Result<Option<u32>> {
- Ok(None)
+ /// Notifies the irq chip that the specified VCPU has executed a halt instruction.
+ /// For KvmKernelIrqChip this is a no-op because KVM handles VCPU blocking.
+ fn halted(&self, _vcpu_id: usize) {}
+
+ /// Blocks until `vcpu` is in a runnable state or until interrupted by
+ /// `IrqChip::kick_halted_vcpus`. Returns `VcpuRunState::Runnable if vcpu is runnable, or
+ /// `VcpuRunState::Interrupted` if the wait was interrupted.
+ /// For KvmKernelIrqChip this is a no-op and always returns Runnable because KVM handles VCPU
+ /// blocking.
+ fn wait_until_runnable(&self, _vcpu: &dyn Vcpu) -> Result<VcpuRunState> {
+ Ok(VcpuRunState::Runnable)
}
+ /// Makes unrunnable VCPUs return immediately from `wait_until_runnable`.
+ /// For KvmKernelIrqChip this is a no-op because KVM handles VCPU blocking.
+ fn kick_halted_vcpus(&self) {}
+
/// Get the current MP state of the specified VCPU.
fn get_mp_state(&self, vcpu_id: usize) -> Result<MPState> {
match self.vcpus.lock().get(vcpu_id) {
@@ -152,6 +166,16 @@
fn process_delayed_irq_events(&mut self) -> Result<()> {
Ok(())
}
+
+ fn check_capability(&self, c: IrqChipCap) -> bool {
+ match c {
+ IrqChipCap::TscDeadlineTimer => self
+ .vm
+ .get_hypervisor()
+ .check_capability(&HypervisorCap::TscDeadlineTimer),
+ IrqChipCap::X2Apic => true,
+ }
+ }
}
#[cfg(test)]
diff --git a/devices/src/irqchip/kvm/x86_64.rs b/devices/src/irqchip/kvm/x86_64.rs
index c199302..1964f39 100644
--- a/devices/src/irqchip/kvm/x86_64.rs
+++ b/devices/src/irqchip/kvm/x86_64.rs
@@ -12,8 +12,8 @@
use base::FakeClock as Clock;
use hypervisor::kvm::{KvmVcpu, KvmVm};
use hypervisor::{
- IoapicState, IrqRoute, IrqSource, IrqSourceChip, LapicState, MPState, PicSelect, PicState,
- PitState, Vcpu, Vm, NUM_IOAPIC_PINS,
+ HypervisorCap, IoapicState, IrqRoute, IrqSource, IrqSourceChip, LapicState, MPState, PicSelect,
+ PicState, PitState, Vcpu, VcpuX86_64, Vm, VmX86_64, NUM_IOAPIC_PINS,
};
use kvm_sys::*;
use resources::SystemAllocator;
@@ -21,8 +21,11 @@
use base::{error, Error, Event, Result};
use vm_control::VmIrqRequestSocket;
-use crate::irqchip::{Ioapic, Pic, IOAPIC_BASE_ADDRESS, IOAPIC_MEM_LENGTH_BYTES};
-use crate::{Bus, IrqChip, IrqChipX86_64, Pit, PitError};
+use crate::irqchip::{
+ Ioapic, IrqEvent, IrqEventIndex, Pic, VcpuRunState, IOAPIC_BASE_ADDRESS,
+ IOAPIC_MEM_LENGTH_BYTES,
+};
+use crate::{Bus, IrqChip, IrqChipCap, IrqChipX86_64, Pit, PitError};
/// PIT channel 0 timer is connected to IRQ 0
const PIT_CHANNEL0_IRQ: u32 = 0;
@@ -148,14 +151,8 @@
/// locked the ioapic and the ioapic sends a AddMsiRoute signal to the main thread (which
/// itself may be busy trying to call service_irq).
delayed_ioapic_irq_events: Arc<Mutex<Vec<usize>>>,
- /// Vec of Events that the ioapic will use to trigger interrupts in KVM. This is not
- /// wrapped in an Arc<Mutex<>> because the Events themselves can be cloned and they will
- /// not change after the IrqChip is created.
- irqfds: Vec<Event>,
/// Array of Events that devices will use to assert ioapic pins.
- irq_events: Arc<Mutex<[Option<Event>; NUM_IOAPIC_PINS]>>,
- /// Array of Events that should be asserted when the ioapic receives an EOI.
- resample_events: Arc<Mutex<[Option<Event>; NUM_IOAPIC_PINS]>>,
+ irq_events: Arc<Mutex<Vec<Option<IrqEvent>>>>,
}
fn kvm_dummy_msi_routes() -> Vec<IrqRoute> {
@@ -174,6 +171,7 @@
}
routes
}
+
impl KvmSplitIrqChip {
/// Construct a new KvmSplitIrqChip.
pub fn new(vm: KvmVm, num_vcpus: usize, irq_socket: VmIrqRequestSocket) -> Result<Self> {
@@ -185,22 +183,13 @@
|e| match e {
PitError::CloneEvent(err) => err,
PitError::CreateEvent(err) => err,
- PitError::CreatePollContext(err) => err,
- PitError::PollError(err) => err,
+ PitError::CreateWaitContext(err) => err,
+ PitError::WaitError(err) => err,
PitError::TimerCreateError(err) => err,
PitError::SpawnThread(_) => Error::new(libc::EIO),
},
)?,
));
- let mut irqfds: Vec<Event> = Vec::with_capacity(NUM_IOAPIC_PINS);
- let mut irqfds_for_ioapic: Vec<Event> = Vec::with_capacity(NUM_IOAPIC_PINS);
-
- for i in 0..NUM_IOAPIC_PINS {
- let evt = Event::new()?;
- vm.register_irqfd(i as u32, &evt, None)?;
- irqfds_for_ioapic.push(evt.try_clone()?);
- irqfds.push(evt);
- }
let mut chip = KvmSplitIrqChip {
vm,
@@ -208,11 +197,9 @@
routes: Arc::new(Mutex::new(Vec::new())),
pit,
pic: Arc::new(Mutex::new(Pic::new())),
- ioapic: Arc::new(Mutex::new(Ioapic::new(irqfds_for_ioapic, irq_socket)?)),
+ ioapic: Arc::new(Mutex::new(Ioapic::new(irq_socket)?)),
delayed_ioapic_irq_events: Arc::new(Mutex::new(Vec::new())),
- irqfds,
irq_events: Arc::new(Mutex::new(Default::default())),
- resample_events: Arc::new(Mutex::new(Default::default())),
};
// Setup standard x86 irq routes
@@ -251,6 +238,31 @@
}
chips
}
+
+ /// Return true if there is a pending interrupt for the specified vcpu. For KvmSplitIrqChip
+ /// this calls interrupt_requested on the pic.
+ fn interrupt_requested(&self, vcpu_id: usize) -> bool {
+ // Pic interrupts for the split irqchip only go to vcpu 0
+ if vcpu_id != 0 {
+ return false;
+ }
+ self.pic.lock().interrupt_requested()
+ }
+
+ /// Check if the specified vcpu has any pending interrupts. Returns None for no interrupts,
+ /// otherwise Some(u32) should be the injected interrupt vector. For KvmSplitIrqChip
+ /// this calls get_external_interrupt on the pic.
+ fn get_external_interrupt(&self, vcpu_id: usize) -> Result<Option<u32>> {
+ // Pic interrupts for the split irqchip only go to vcpu 0
+ if vcpu_id != 0 {
+ return Ok(None);
+ }
+ if let Some(vector) = self.pic.lock().get_external_interrupt() {
+ Ok(Some(vector as u32))
+ } else {
+ Ok(None)
+ }
+ }
}
/// Convenience function for determining whether or not two irq routes conflict.
@@ -300,33 +312,41 @@
irq: u32,
irq_event: &Event,
resample_event: Option<&Event>,
- ) -> Result<()> {
+ ) -> Result<Option<IrqEventIndex>> {
if irq < NUM_IOAPIC_PINS as u32 {
- // safe to index here because irq_events is NUM_IOAPIC_PINS long
- self.irq_events.lock()[irq as usize] = Some(irq_event.try_clone()?);
- if let Some(evt) = resample_event {
- self.resample_events.lock()[irq as usize] = Some(evt.try_clone()?);
+ let mut evt = IrqEvent {
+ gsi: irq,
+ event: irq_event.try_clone()?,
+ resample_event: None,
+ };
+
+ if let Some(resample_event) = resample_event {
+ evt.resample_event = Some(resample_event.try_clone()?);
}
- Ok(())
+ let mut irq_events = self.irq_events.lock();
+ let index = irq_events.len();
+ irq_events.push(Some(evt));
+ Ok(Some(index))
} else {
- self.vm.register_irqfd(irq, irq_event, resample_event)
+ self.vm.register_irqfd(irq, irq_event, resample_event)?;
+ Ok(None)
}
}
/// Unregister an event for a particular GSI.
fn unregister_irq_event(&mut self, irq: u32, irq_event: &Event) -> Result<()> {
if irq < NUM_IOAPIC_PINS as u32 {
- match &self.irq_events.lock()[irq as usize] {
- // We only do something if irq_event is the same as our existing event
- Some(evt) if evt == irq_event => {
- // safe to index here because irq_events is NUM_IOAPIC_PINS long
- self.irq_events.lock()[irq as usize] = None;
- self.resample_events.lock()[irq as usize] = None;
- Ok(())
+ let mut irq_events = self.irq_events.lock();
+ for (index, evt) in irq_events.iter().enumerate() {
+ if let Some(evt) = evt {
+ if evt.gsi == irq && irq_event.eq(&evt.event) {
+ irq_events[index] = None;
+ break;
+ }
}
- _ => Ok(()),
}
+ Ok(())
} else {
self.vm.unregister_irqfd(irq, irq_event)
}
@@ -341,10 +361,7 @@
// We only call set_gsi_routing with the msi routes
let mut msi_routes = routes.clone();
- msi_routes.retain(|r| match r.source {
- IrqSource::Msi { .. } => true,
- _ => false,
- });
+ msi_routes.retain(|r| matches!(r.source, IrqSource::Msi { .. }));
self.vm.set_gsi_routing(&*msi_routes)
}
@@ -356,21 +373,18 @@
// We only call set_gsi_routing with the msi routes
let mut msi_routes = routes.to_vec().clone();
- msi_routes.retain(|r| match r.source {
- IrqSource::Msi { .. } => true,
- _ => false,
- });
+ msi_routes.retain(|r| matches!(r.source, IrqSource::Msi { .. }));
self.vm.set_gsi_routing(&*msi_routes)
}
- /// Return a vector of all registered irq numbers and their associated events. To be used by
- /// the main thread to wait for irq events to be triggered.
- fn irq_event_tokens(&self) -> Result<Vec<(u32, Event)>> {
- let mut tokens: Vec<(u32, Event)> = Vec::new();
- for i in 0..NUM_IOAPIC_PINS {
- if let Some(evt) = &self.irq_events.lock()[i] {
- tokens.push((i as u32, evt.try_clone()?));
+ /// Return a vector of all registered irq numbers and their associated events and event
+ /// indices. These should be used by the main thread to wait for irq events.
+ fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, u32, Event)>> {
+ let mut tokens: Vec<(IrqEventIndex, u32, Event)> = Vec::new();
+ for (index, evt) in self.irq_events.lock().iter().enumerate() {
+ if let Some(evt) = evt {
+ tokens.push((index, evt.gsi, evt.event.try_clone()?));
}
}
Ok(tokens)
@@ -402,36 +416,36 @@
/// attempts to call service_irq on those chips. If the ioapic is unable to be immediately
/// locked, we add the irq to the delayed_ioapic_irq_events Vec (though we still read
/// from the Event that triggered the irq event).
- fn service_irq_event(&mut self, irq: u32) -> Result<()> {
- if let Some(evt) = &self.irq_events.lock()[irq as usize] {
- evt.read()?;
- }
- let chips = self.routes_to_chips(irq);
+ fn service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()> {
+ if let Some(evt) = &self.irq_events.lock()[event_index] {
+ evt.event.read()?;
+ let chips = self.routes_to_chips(evt.gsi);
- for (chip, pin) in chips {
- match chip {
- IrqSourceChip::PicPrimary | IrqSourceChip::PicSecondary => {
- let mut pic = self.pic.lock();
- if self.resample_events.lock()[pin as usize].is_some() {
- pic.service_irq(pin as u8, true);
- } else {
- pic.service_irq(pin as u8, true);
- pic.service_irq(pin as u8, false);
- }
- }
- IrqSourceChip::Ioapic => {
- if let Ok(mut ioapic) = self.ioapic.try_lock() {
- if self.resample_events.lock()[pin as usize].is_some() {
- ioapic.service_irq(pin as usize, true);
+ for (chip, pin) in chips {
+ match chip {
+ IrqSourceChip::PicPrimary | IrqSourceChip::PicSecondary => {
+ let mut pic = self.pic.lock();
+ if evt.resample_event.is_some() {
+ pic.service_irq(pin as u8, true);
} else {
- ioapic.service_irq(pin as usize, true);
- ioapic.service_irq(pin as usize, false);
+ pic.service_irq(pin as u8, true);
+ pic.service_irq(pin as u8, false);
}
- } else {
- self.delayed_ioapic_irq_events.lock().push(pin as usize);
}
+ IrqSourceChip::Ioapic => {
+ if let Ok(mut ioapic) = self.ioapic.try_lock() {
+ if evt.resample_event.is_some() {
+ ioapic.service_irq(pin as usize, true);
+ } else {
+ ioapic.service_irq(pin as usize, true);
+ ioapic.service_irq(pin as usize, false);
+ }
+ } else {
+ self.delayed_ioapic_irq_events.lock().push(event_index);
+ }
+ }
+ _ => {}
}
- _ => {}
}
}
@@ -439,36 +453,52 @@
}
/// Broadcast an end of interrupt. For KvmSplitIrqChip this sends the EOI to the ioapic
- fn broadcast_eoi(&mut self, vector: u8) -> Result<()> {
+ fn broadcast_eoi(&self, vector: u8) -> Result<()> {
self.ioapic.lock().end_of_interrupt(vector);
Ok(())
}
- /// Return true if there is a pending interrupt for the specified vcpu. For KvmSplitIrqChip
- /// this calls interrupt_requested on the pic.
- fn interrupt_requested(&self, vcpu_id: usize) -> bool {
- // Pic interrupts for the split irqchip only go to vcpu 0
- if vcpu_id != 0 {
- return false;
+ /// Injects any pending interrupts for `vcpu`.
+ /// For KvmSplitIrqChip this injects any PIC interrupts on vcpu_id 0.
+ fn inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()> {
+ let vcpu: &KvmVcpu = vcpu
+ .downcast_ref()
+ .expect("KvmSplitIrqChip::add_vcpu called with non-KvmVcpu");
+
+ let vcpu_id = vcpu.id();
+ if !self.interrupt_requested(vcpu_id) || !vcpu.ready_for_interrupt() {
+ return Ok(());
}
- self.pic.lock().interrupt_requested()
+
+ if let Some(vector) = self.get_external_interrupt(vcpu_id)? {
+ vcpu.interrupt(vector as u32)?;
+ }
+
+ // The second interrupt request should be handled immediately, so ask vCPU to exit as soon as
+ // possible.
+ if self.interrupt_requested(vcpu_id) {
+ vcpu.set_interrupt_window_requested(true);
+ }
+ Ok(())
}
- /// Check if the specified vcpu has any pending interrupts. Returns None for no interrupts,
- /// otherwise Some(u32) should be the injected interrupt vector. For KvmSplitIrqChip
- /// this calls get_external_interrupt on the pic.
- fn get_external_interrupt(&mut self, vcpu_id: usize) -> Result<Option<u32>> {
- // Pic interrupts for the split irqchip only go to vcpu 0
- if vcpu_id != 0 {
- return Ok(None);
- }
- if let Some(vector) = self.pic.lock().get_external_interrupt() {
- Ok(Some(vector as u32))
- } else {
- Ok(None)
- }
+ /// Notifies the irq chip that the specified VCPU has executed a halt instruction.
+ /// For KvmSplitIrqChip this is a no-op because KVM handles VCPU blocking.
+ fn halted(&self, _vcpu_id: usize) {}
+
+ /// Blocks until `vcpu` is in a runnable state or until interrupted by
+ /// `IrqChip::kick_halted_vcpus`. Returns `VcpuRunState::Runnable if vcpu is runnable, or
+ /// `VcpuRunState::Interrupted` if the wait was interrupted.
+ /// For KvmSplitIrqChip this is a no-op and always returns Runnable because KVM handles VCPU
+ /// blocking.
+ fn wait_until_runnable(&self, _vcpu: &dyn Vcpu) -> Result<VcpuRunState> {
+ Ok(VcpuRunState::Runnable)
}
+ /// Makes unrunnable VCPUs return immediately from `wait_until_runnable`.
+ /// For KvmSplitIrqChip this is a no-op because KVM handles VCPU blocking.
+ fn kick_halted_vcpus(&self) {}
+
/// Get the current MP state of the specified VCPU.
fn get_mp_state(&self, vcpu_id: usize) -> Result<MPState> {
match self.vcpus.lock().get(vcpu_id) {
@@ -487,10 +517,6 @@
/// Attempt to clone this IrqChip instance.
fn try_clone(&self) -> Result<Self> {
- let mut new_irqfds: Vec<Event> = Vec::with_capacity(NUM_IOAPIC_PINS);
- for i in 0..NUM_IOAPIC_PINS {
- new_irqfds.push(self.irqfds[i].try_clone()?);
- }
Ok(KvmSplitIrqChip {
vm: self.vm.try_clone()?,
vcpus: self.vcpus.clone(),
@@ -499,9 +525,7 @@
pic: self.pic.clone(),
ioapic: self.ioapic.clone(),
delayed_ioapic_irq_events: self.delayed_ioapic_irq_events.clone(),
- irqfds: new_irqfds,
irq_events: self.irq_events.clone(),
- resample_events: self.resample_events.clone(),
})
}
@@ -514,13 +538,13 @@
mmio_bus: &mut Bus,
) -> Result<()> {
// Insert pit into io_bus
- io_bus.insert(self.pit.clone(), 0x040, 0x8, true).unwrap();
- io_bus.insert(self.pit.clone(), 0x061, 0x1, true).unwrap();
+ io_bus.insert(self.pit.clone(), 0x040, 0x8).unwrap();
+ io_bus.insert(self.pit.clone(), 0x061, 0x1).unwrap();
// Insert pic into io_bus
- io_bus.insert(self.pic.clone(), 0x20, 0x2, true).unwrap();
- io_bus.insert(self.pic.clone(), 0xa0, 0x2, true).unwrap();
- io_bus.insert(self.pic.clone(), 0x4d0, 0x2, true).unwrap();
+ io_bus.insert(self.pic.clone(), 0x20, 0x2).unwrap();
+ io_bus.insert(self.pic.clone(), 0xa0, 0x2).unwrap();
+ io_bus.insert(self.pic.clone(), 0x4d0, 0x2).unwrap();
// Insert ioapic into mmio_bus
mmio_bus
@@ -528,26 +552,26 @@
self.ioapic.clone(),
IOAPIC_BASE_ADDRESS,
IOAPIC_MEM_LENGTH_BYTES,
- false,
)
.unwrap();
// At this point, all of our devices have been created and they have registered their
// irq events, so we can clone our resample events
- let mut ioapic_resample_events: Vec<Option<Event>> = Vec::with_capacity(NUM_IOAPIC_PINS);
- let mut pic_resample_events: Vec<Option<Event>> = Vec::with_capacity(NUM_IOAPIC_PINS);
+ let mut ioapic_resample_events: Vec<Vec<Event>> =
+ (0..NUM_IOAPIC_PINS).map(|_| Vec::new()).collect();
+ let mut pic_resample_events: Vec<Vec<Event>> =
+ (0..NUM_IOAPIC_PINS).map(|_| Vec::new()).collect();
- for i in 0..NUM_IOAPIC_PINS {
- match &self.resample_events.lock()[i] {
- Some(e) => {
- ioapic_resample_events.push(Some(e.try_clone()?));
- pic_resample_events.push(Some(e.try_clone()?));
+ for evt in self.irq_events.lock().iter() {
+ if let Some(evt) = evt {
+ if (evt.gsi as usize) >= NUM_IOAPIC_PINS {
+ continue;
}
- None => {
- ioapic_resample_events.push(None);
- pic_resample_events.push(None);
+ if let Some(resample_evt) = &evt.resample_event {
+ ioapic_resample_events[evt.gsi as usize].push(resample_evt.try_clone()?);
+ pic_resample_events[evt.gsi as usize].push(resample_evt.try_clone()?);
}
- };
+ }
}
// Register resample events with the ioapic
@@ -576,22 +600,39 @@
/// processes each delayed event in the vec each time it's called. If the ioapic is still
/// locked, we keep the queued irqs for the next time this function is called.
fn process_delayed_irq_events(&mut self) -> Result<()> {
- self.delayed_ioapic_irq_events.lock().retain(|&irq| {
- if let Ok(mut ioapic) = self.ioapic.try_lock() {
- if self.resample_events.lock()[irq].is_some() {
- ioapic.service_irq(irq, true);
+ self.delayed_ioapic_irq_events
+ .lock()
+ .retain(|&event_index| {
+ if let Some(evt) = &self.irq_events.lock()[event_index] {
+ if let Ok(mut ioapic) = self.ioapic.try_lock() {
+ if evt.resample_event.is_some() {
+ ioapic.service_irq(evt.gsi as usize, true);
+ } else {
+ ioapic.service_irq(evt.gsi as usize, true);
+ ioapic.service_irq(evt.gsi as usize, false);
+ }
+
+ false
+ } else {
+ true
+ }
} else {
- ioapic.service_irq(irq, true);
- ioapic.service_irq(irq, false);
+ true
}
- false
- } else {
- true
- }
- });
+ });
Ok(())
}
+
+ fn check_capability(&self, c: IrqChipCap) -> bool {
+ match c {
+ IrqChipCap::TscDeadlineTimer => self
+ .vm
+ .get_hypervisor()
+ .check_capability(&HypervisorCap::TscDeadlineTimer),
+ IrqChipCap::X2Apic => true,
+ }
+ }
}
impl IrqChipX86_64 for KvmSplitIrqChip {
@@ -814,7 +855,7 @@
// there should be one token on a fresh split irqchip, for the pit
assert_eq!(tokens.len(), 1);
- assert_eq!(tokens[0].0, 0);
+ assert_eq!(tokens[0].1, 0);
// register another irq event
let evt = Event::new().expect("failed to create event");
@@ -827,9 +868,9 @@
// now there should be two tokens
assert_eq!(tokens.len(), 2);
- assert_eq!(tokens[0].0, 0);
- assert_eq!(tokens[1].0, 6);
- assert_eq!(tokens[1].1, evt);
+ assert_eq!(tokens[0].1, 0);
+ assert_eq!(tokens[1].1, 6);
+ assert_eq!(tokens[1].2, evt);
}
#[test]
@@ -849,8 +890,10 @@
let evt = Event::new().expect("failed to create event");
let mut resample_evt = Event::new().expect("failed to create event");
- chip.register_irq_event(1, &evt, Some(&resample_evt))
- .expect("failed to register_irq_event");
+ let evt_index = chip
+ .register_irq_event(1, &evt, Some(&resample_evt))
+ .expect("failed to register_irq_event")
+ .expect("register_irq_event should not return None");
// Once we finalize devices, the pic/pit/ioapic should be attached to io and mmio busses
chip.finalize_devices(&mut resources, &mut io_bus, &mut mmio_bus)
@@ -888,7 +931,8 @@
// if we assert irq line one, and then get the resulting interrupt, an auto-eoi should
// occur and cause the resample_event to be written to
- chip.service_irq_event(1).expect("failed to service irq");
+ chip.service_irq_event(evt_index)
+ .expect("failed to service irq");
assert!(chip.interrupt_requested(0));
assert_eq!(
diff --git a/devices/src/irqchip/mod.rs b/devices/src/irqchip/mod.rs
index 636e26a..d431360 100644
--- a/devices/src/irqchip/mod.rs
+++ b/devices/src/irqchip/mod.rs
@@ -40,6 +40,14 @@
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub use ioapic::*;
+pub type IrqEventIndex = usize;
+
+struct IrqEvent {
+ event: Event,
+ gsi: u32,
+ resample_event: Option<Event>,
+}
+
/// Trait that abstracts interactions with interrupt controllers.
///
/// Each VM will have one IrqChip instance which is responsible for routing IRQ lines and
@@ -58,7 +66,7 @@
irq: u32,
irq_event: &Event,
resample_event: Option<&Event>,
- ) -> Result<()>;
+ ) -> Result<Option<IrqEventIndex>>;
/// Unregister an event for a particular GSI.
fn unregister_irq_event(&mut self, irq: u32, irq_event: &Event) -> Result<()>;
@@ -69,9 +77,9 @@
/// Replace all irq routes with the supplied routes
fn set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()>;
- /// Return a vector of all registered irq numbers and their associated events. To be used by
- /// the main thread to wait for irq events to be triggered.
- fn irq_event_tokens(&self) -> Result<Vec<(u32, Event)>>;
+ /// Return a vector of all registered irq numbers and their associated events and event
+ /// indices. These should be used by the main thread to wait for irq events.
+ fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, u32, Event)>>;
/// Either assert or deassert an IRQ line. Sends to either an interrupt controller, or does
/// a send_msi if the irq is associated with an MSI.
@@ -81,17 +89,27 @@
/// that triggered the irq event will be read from. If the irq is associated with a resample
/// Event, then the deassert will only happen after an EOI is broadcast for a vector
/// associated with the irq line.
- fn service_irq_event(&mut self, irq: u32) -> Result<()>;
+ fn service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()>;
/// Broadcast an end of interrupt.
- fn broadcast_eoi(&mut self, vector: u8) -> Result<()>;
+ fn broadcast_eoi(&self, vector: u8) -> Result<()>;
- /// Return true if there is a pending interrupt for the specified vcpu.
- fn interrupt_requested(&self, vcpu_id: usize) -> bool;
+ /// Injects any pending interrupts for `vcpu`.
+ fn inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()>;
- /// Check if the specified vcpu has any pending interrupts. Returns None for no interrupts,
- /// otherwise Some(u32) should be the injected interrupt vector.
- fn get_external_interrupt(&mut self, vcpu_id: usize) -> Result<Option<u32>>;
+ /// Notifies the irq chip that the specified VCPU has executed a halt instruction.
+ fn halted(&self, vcpu_id: usize);
+
+ /// Blocks until `vcpu` is in a runnable state or until interrupted by
+ /// `IrqChip::kick_halted_vcpus`. Returns `VcpuRunState::Runnable if vcpu is runnable, or
+ /// `VcpuRunState::Interrupted` if the wait was interrupted.
+ fn wait_until_runnable(&self, vcpu: &dyn Vcpu) -> Result<VcpuRunState>;
+
+ /// Makes unrunnable VCPUs return immediately from `wait_until_runnable`.
+ /// For UserspaceIrqChip, every vcpu gets kicked so its current or next call to
+ /// `wait_until_runnable` will immediately return false. After that one kick, subsequent
+ /// `wait_until_runnable` calls go back to waiting for runnability normally.
+ fn kick_halted_vcpus(&self);
/// Get the current MP state of the specified VCPU.
fn get_mp_state(&self, vcpu_id: usize) -> Result<MPState>;
@@ -115,4 +133,23 @@
/// Process any irqs events that were delayed because of any locking issues.
fn process_delayed_irq_events(&mut self) -> Result<()>;
+
+ /// Checks if a particular `IrqChipCap` is available.
+ fn check_capability(&self, c: IrqChipCap) -> bool;
+}
+
+/// A capability the `IrqChip` can possibly expose.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum IrqChipCap {
+ /// APIC TSC-deadline timer mode.
+ TscDeadlineTimer,
+ /// Extended xAPIC (x2APIC) standard.
+ X2Apic,
+}
+
+/// A capability the `IrqChip` can possibly expose.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum VcpuRunState {
+ Runnable,
+ Interrupted,
}
diff --git a/devices/src/irqchip/pic.rs b/devices/src/irqchip/pic.rs
index 679f58c..4cca6a2 100644
--- a/devices/src/irqchip/pic.rs
+++ b/devices/src/irqchip/pic.rs
@@ -12,6 +12,7 @@
// 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" PICs.
+use crate::bus::BusAccessInfo;
use crate::BusDevice;
use base::{debug, warn, Event};
use hypervisor::{PicInitState, PicSelect, PicState};
@@ -19,8 +20,9 @@
pub struct Pic {
// Indicates a pending INTR signal to LINT0 of vCPU, checked by vCPU thread.
interrupt_request: bool,
- // Events that need to be triggered when an ISR is cleared
- resample_events: Vec<Option<Event>>,
+ // Events that need to be triggered when an ISR is cleared. The outer Vec is indexed by GSI,
+ // and the inner Vec is an unordered list of registered resample events for the GSI.
+ resample_events: Vec<Vec<Event>>,
// Index 0 (aka PicSelect::Primary) is the primary pic, the rest are secondary.
pics: [PicState; 2],
}
@@ -86,28 +88,28 @@
"userspace PIC".to_string()
}
- fn write(&mut self, offset: u64, data: &[u8]) {
+ fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
if data.len() != 1 {
warn!("PIC: Bad write size: {}", data.len());
return;
}
- match offset {
+ match info.address {
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),
+ _ => warn!("PIC: Invalid write to {}", info),
}
}
- fn read(&mut self, offset: u64, data: &mut [u8]) {
+ fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
if data.len() != 1 {
warn!("PIC: Bad read size: {}", data.len());
return;
}
- data[0] = match offset {
+ data[0] = match info.address {
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),
@@ -115,7 +117,7 @@
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);
+ warn!("PIC: Invalid read from {}", info);
return;
}
};
@@ -154,7 +156,7 @@
self.pics[select as usize] = *state;
}
- pub fn register_resample_events(&mut self, resample_events: Vec<Option<Event>>) {
+ pub fn register_resample_events(&mut self, resample_events: Vec<Vec<Event>>) {
self.resample_events = resample_events;
}
@@ -370,8 +372,10 @@
} else {
irq + 8
};
- if let Some(Some(resample_evt)) = self.resample_events.get(irq as usize) {
- resample_evt.write(1).unwrap();
+ if let Some(resample_events) = self.resample_events.get(irq as usize) {
+ for resample_evt in resample_events {
+ resample_evt.write(1).unwrap();
+ }
}
}
@@ -540,11 +544,29 @@
pic: Pic,
}
+ fn pic_bus_address(address: u64) -> BusAccessInfo {
+ // The PIC is added to the io_bus in three locations, so the offset depends on which
+ // address range the address is in. The PIC implementation currently does not use the
+ // offset, but we're setting it accurately here in case it does in the future.
+ let offset = match address {
+ x if x >= PIC_PRIMARY && x < PIC_PRIMARY + 0x2 => address - PIC_PRIMARY,
+ x if x >= PIC_SECONDARY && x < PIC_SECONDARY + 0x2 => address - PIC_SECONDARY,
+ x if x >= PIC_PRIMARY_ELCR && x < PIC_PRIMARY_ELCR + 0x2 => address - PIC_PRIMARY_ELCR,
+ _ => panic!("invalid PIC address: {:#x}", address),
+ };
+
+ BusAccessInfo {
+ offset,
+ address,
+ id: 0,
+ }
+ }
+
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]);
+ pic.write(pic_bus_address(PIC_PRIMARY_ELCR), &[0]);
+ pic.write(pic_bus_address(PIC_SECONDARY_ELCR), &[0]);
TestData { pic }
}
@@ -559,10 +581,10 @@
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]);
+ pic.write(pic_bus_address(command_offset), &[icw1]);
+ pic.write(pic_bus_address(data_offset), &[icw2]);
+ pic.write(pic_bus_address(data_offset), &[icw3]);
+ pic.write(pic_bus_address(data_offset), &[icw4]);
}
/// Convenience function for primary ICW init.
@@ -607,12 +629,16 @@
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);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_ELCR), &data_write);
+ data.pic
+ .read(pic_bus_address(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);
+ data.pic
+ .write(pic_bus_address(PIC_SECONDARY_ELCR), &data_write);
+ data.pic
+ .read(pic_bus_address(PIC_SECONDARY_ELCR), &mut data_read);
assert_eq!(data_read, data_write);
}
@@ -623,13 +649,16 @@
// ICW1
let mut data_write = [0x10];
- data.pic.write(PIC_PRIMARY_COMMAND, &data_write);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_COMMAND), &data_write);
data_write[0] = 0x08;
- data.pic.write(PIC_PRIMARY_DATA, &data_write);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_DATA), &data_write);
data_write[0] = 0xff;
- data.pic.write(PIC_PRIMARY_DATA, &data_write);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_DATA), &data_write);
assert_eq!(
data.pic.pics[PicSelect::Primary as usize].init_state,
@@ -675,19 +704,23 @@
icw_init_secondary(&mut data.pic);
// OCW1: Write to IMR.
- data.pic.write(PIC_SECONDARY_DATA, &[0x5f]);
+ data.pic.write(pic_bus_address(PIC_SECONDARY_DATA), &[0x5f]);
// OCW2: Set rotate on auto EOI.
- data.pic.write(PIC_SECONDARY_COMMAND, &[0x80]);
+ data.pic
+ .write(pic_bus_address(PIC_SECONDARY_COMMAND), &[0x80]);
// OCW2: Set priority.
- data.pic.write(PIC_SECONDARY_COMMAND, &[0xc0]);
+ data.pic
+ .write(pic_bus_address(PIC_SECONDARY_COMMAND), &[0xc0]);
// OCW3: Change flags.
- data.pic.write(PIC_SECONDARY_COMMAND, &[0x6b]);
+ data.pic
+ .write(pic_bus_address(PIC_SECONDARY_COMMAND), &[0x6b]);
let mut data_read = [0];
- data.pic.read(PIC_SECONDARY_DATA, &mut data_read);
+ data.pic
+ .read(pic_bus_address(PIC_SECONDARY_DATA), &mut data_read);
assert_eq!(data_read, [0x5f]);
let secondary_pic = &data.pic.pics[PicSelect::Secondary as usize];
@@ -713,13 +746,15 @@
icw_init_secondary(&mut data.pic);
// OCW2: Set rotate on auto EOI.
- data.pic.write(PIC_SECONDARY_COMMAND, &[0x80]);
+ data.pic
+ .write(pic_bus_address(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]);
+ data.pic
+ .write(pic_bus_address(PIC_SECONDARY_COMMAND), &[0x00]);
let secondary_pic = &data.pic.pics[PicSelect::Secondary as usize];
assert!(!secondary_pic.rotate_on_auto_eoi);
@@ -807,8 +842,10 @@
// 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]);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x20]);
+ data.pic
+ .write(pic_bus_address(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));
@@ -827,7 +864,7 @@
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.write(pic_bus_address(PIC_SECONDARY_DATA), &[0x40]);
data.pic.service_irq(/*irq=*/ 14, /*level=*/ true);
assert_eq!(data.pic.get_external_interrupt(), None);
@@ -839,7 +876,7 @@
// 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]);
+ data.pic.write(pic_bus_address(PIC_SECONDARY_DATA), &[0x00]);
// Previously-masked interrupt can now be served.
assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 6));
@@ -859,8 +896,8 @@
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.write(pic_bus_address(PIC_PRIMARY_DATA), &[0xff]);
+ data.pic.write(pic_bus_address(PIC_SECONDARY_DATA), &[0xff]);
data.pic.service_irq(/*irq=*/ 14, /*level=*/ true);
data.pic.service_irq(/*irq=*/ 4, /*level=*/ true);
@@ -870,14 +907,14 @@
assert_eq!(data.pic.get_external_interrupt(), None);
// OCW2: Unmask IRQ lines on secondary.
- data.pic.write(PIC_SECONDARY_DATA, &[0x00]);
+ data.pic.write(pic_bus_address(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]);
+ data.pic.write(pic_bus_address(PIC_PRIMARY_DATA), &[0xfb]);
// Previously-masked IRQs should now be served in order of priority.
// TODO(mutexlox): Verify APIC interaction when it is implemented.
@@ -886,7 +923,7 @@
// Unmask all other IRQ lines on primary.
// TODO(mutexlox): Verify APIC interaction when it is implemented.
- data.pic.write(PIC_PRIMARY_DATA, &[0x00]);
+ data.pic.write(pic_bus_address(PIC_PRIMARY_DATA), &[0x00]);
assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
}
@@ -903,25 +940,32 @@
assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
// Read primary IRR.
- data.pic.write(PIC_PRIMARY_COMMAND, &[0x0a]);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x0a]);
let mut data_read = [0];
- data.pic.read(PIC_PRIMARY_COMMAND, &mut data_read);
+ data.pic
+ .read(pic_bus_address(PIC_PRIMARY_COMMAND), &mut data_read);
assert_eq!(data_read[0], 1 << 5);
// Read primary ISR.
- data.pic.write(PIC_PRIMARY_COMMAND, &[0x0b]);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x0b]);
data_read = [0];
- data.pic.read(PIC_PRIMARY_COMMAND, &mut data_read);
+ data.pic
+ .read(pic_bus_address(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]);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x20]);
// Poll command on primary.
- data.pic.write(PIC_PRIMARY_COMMAND, &[0x0c]);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x0c]);
data_read = [0];
- data.pic.read(PIC_PRIMARY_COMMAND, &mut data_read);
+ data.pic
+ .read(pic_bus_address(PIC_PRIMARY_COMMAND), &mut data_read);
assert_eq!(data_read[0], 5);
}
@@ -953,7 +997,8 @@
// 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]);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x20]);
}
/// Raising the same IRQ line twice in level-triggered mode should send two IRQ requests out.
@@ -963,7 +1008,7 @@
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]);
+ data.pic.write(pic_bus_address(PIC_PRIMARY_ELCR), &[0x10]);
// TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 4, /*level=*/ true);
@@ -974,7 +1019,8 @@
// 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]);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x20]);
}
/// Specific EOI command in OCW2.
@@ -989,11 +1035,13 @@
// 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]);
+ data.pic
+ .write(pic_bus_address(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]);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x64]);
assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
}
@@ -1004,7 +1052,8 @@
icw_init_both(&mut data.pic);
// OCW3: Clear rotate on auto EOI mode.
- data.pic.write(PIC_PRIMARY_COMMAND, &[0x00]);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x00]);
// TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 5, /*level=*/ true);
@@ -1018,7 +1067,8 @@
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]);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x80]);
// TODO(mutexlox): Verify APIC interaction when it is implemented.
data.pic.service_irq(/*irq=*/ 5, /*level*/ true);
@@ -1043,12 +1093,14 @@
// 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]);
+ data.pic
+ .write(pic_bus_address(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]);
+ data.pic
+ .write(pic_bus_address(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);
@@ -1066,7 +1118,8 @@
data.pic.service_irq(/*irq=*/ 5, /*level=*/ false);
// Rotate on non-specific EOI.
- data.pic.write(PIC_PRIMARY_COMMAND, &[0xa0]);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0xa0]);
// The EOI should have cleared isr.
assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
@@ -1096,9 +1149,11 @@
// - 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]);
+ data.pic
+ .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x20]);
// Rotate non-specific EOI.
- data.pic.write(PIC_SECONDARY_COMMAND, &[0xa0]);
+ data.pic
+ .write(pic_bus_address(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);
diff --git a/devices/src/lib.rs b/devices/src/lib.rs
index 83f1f1f..64de009 100644
--- a/devices/src/lib.rs
+++ b/devices/src/lib.rs
@@ -16,6 +16,7 @@
#[macro_use]
mod register_space;
pub mod acpi;
+pub mod bat;
mod serial;
mod serial_device;
pub mod usb;
@@ -24,8 +25,9 @@
pub mod virtio;
pub use self::acpi::ACPIPMResource;
+pub use self::bat::{BatteryError, GoldfishBattery};
pub use self::bus::Error as BusError;
-pub use self::bus::{Bus, BusDevice, BusRange, BusResumeDevice};
+pub use self::bus::{Bus, BusAccessInfo, BusDevice, BusRange, BusResumeDevice};
pub use self::cmos::Cmos;
pub use self::i8042::I8042Device;
pub use self::irqchip::*;
diff --git a/devices/src/pci/ac97.rs b/devices/src/pci/ac97.rs
index 35ba396..245c700 100644
--- a/devices/src/pci/ac97.rs
+++ b/devices/src/pci/ac97.rs
@@ -5,11 +5,10 @@
use std::default::Default;
use std::error;
use std::fmt::{self, Display};
-use std::os::unix::io::RawFd;
use std::str::FromStr;
use audio_streams::shm_streams::{NullShmStreamSource, ShmStreamSource};
-use base::{error, Event};
+use base::{error, Event, RawDescriptor};
use libcras::{CrasClient, CrasClientType, CrasSocketType};
use resources::{Alloc, MmioType, SystemAllocator};
use vm_memory::GuestMemory;
@@ -306,8 +305,8 @@
(&mut self.config_regs).write_reg(reg_idx, offset, data)
}
- fn keep_fds(&self) -> Vec<RawFd> {
- if let Some(server_fds) = self.bus_master.keep_fds() {
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ if let Some(server_fds) = self.bus_master.keep_rds() {
server_fds
} else {
Vec::new()
diff --git a/devices/src/pci/ac97_bus_master.rs b/devices/src/pci/ac97_bus_master.rs
index f172fd8..dc0729a 100644
--- a/devices/src/pci/ac97_bus_master.rs
+++ b/devices/src/pci/ac97_bus_master.rs
@@ -6,7 +6,6 @@
use std::convert::AsRef;
use std::convert::TryInto;
use std::fmt::{self, Display};
-use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
@@ -16,7 +15,9 @@
shm_streams::{ShmStream, ShmStreamSource},
BoxError, DummyStreamControl, SampleFormat, StreamControl, StreamDirection, StreamEffect,
};
-use base::{self, error, set_rt_prio_limit, set_rt_round_robin, warn, Event};
+use base::{
+ self, error, set_rt_prio_limit, set_rt_round_robin, warn, AsRawDescriptor, Event, RawDescriptor,
+};
use sync::{Condvar, Mutex};
use vm_memory::{GuestAddress, GuestMemory};
@@ -218,10 +219,10 @@
}
/// Returns any file descriptors that need to be kept open when entering a jail.
- pub fn keep_fds(&self) -> Option<Vec<RawFd>> {
- let mut fds = self.audio_server.keep_fds();
- fds.push(self.mem.as_raw_fd());
- Some(fds)
+ pub fn keep_rds(&self) -> Option<Vec<RawDescriptor>> {
+ let mut rds = self.audio_server.keep_fds();
+ rds.push(self.mem.as_raw_descriptor());
+ Some(rds)
}
/// Provides the events needed to raise interrupts in the guest.
diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs
index 5572916..65ed080 100644
--- a/devices/src/pci/mod.rs
+++ b/devices/src/pci/mod.rs
@@ -23,8 +23,8 @@
pub use self::msix::{MsixCap, MsixConfig, MsixStatus};
pub use self::pci_configuration::{
PciBarConfiguration, PciBarPrefetchable, PciBarRegionType, PciCapability, PciCapabilityID,
- PciClassCode, PciConfiguration, PciHeaderType, PciProgrammingInterface, PciSerialBusSubClass,
- PciSubclass,
+ PciClassCode, PciConfiguration, PciDisplaySubclass, PciHeaderType, PciProgrammingInterface,
+ PciSerialBusSubClass, PciSubclass,
};
pub use self::pci_device::Error as PciDeviceError;
pub use self::pci_device::PciDevice;
diff --git a/devices/src/pci/msix.rs b/devices/src/pci/msix.rs
index af06646..7240793 100644
--- a/devices/src/pci/msix.rs
+++ b/devices/src/pci/msix.rs
@@ -3,12 +3,11 @@
// found in the LICENSE file.
use crate::pci::{PciCapability, PciCapabilityID};
-use base::{error, Error as SysError, Event};
+use base::{error, AsRawDescriptor, Error as SysError, Event, RawDescriptor};
use msg_socket::{MsgError, MsgReceiver, MsgSender};
use std::convert::TryInto;
use std::fmt::{self, Display};
-use std::os::unix::io::{AsRawFd, RawFd};
-use vm_control::{MaybeOwnedFd, VmIrqRequest, VmIrqRequestSocket, VmIrqResponse};
+use vm_control::{MaybeOwnedDescriptor, VmIrqRequest, VmIrqRequestSocket, VmIrqResponse};
use data_model::DataInit;
@@ -238,7 +237,7 @@
let irqfd = Event::new().unwrap();
self.msi_device_socket
.send(&VmIrqRequest::AllocateOneMsi {
- irqfd: MaybeOwnedFd::Borrowed(irqfd.as_raw_fd()),
+ irqfd: MaybeOwnedDescriptor::Borrowed(irqfd.as_raw_descriptor()),
})
.map_err(MsixError::AllocateOneMsiSend)?;
let irq_num: u32;
@@ -498,8 +497,8 @@
}
/// Return the raw fd of the MSI device socket
- pub fn get_msi_socket(&self) -> RawFd {
- self.msi_device_socket.as_ref().as_raw_fd()
+ pub fn get_msi_socket(&self) -> RawDescriptor {
+ self.msi_device_socket.as_ref().as_raw_descriptor()
}
/// Return irqfd of MSI-X Table entry
@@ -514,9 +513,9 @@
}
}
-impl AsRawFd for MsixConfig {
- fn as_raw_fd(&self) -> RawFd {
- self.msi_device_socket.as_raw_fd()
+impl AsRawDescriptor for MsixConfig {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.msi_device_socket.as_raw_descriptor()
}
}
diff --git a/devices/src/pci/pci_configuration.rs b/devices/src/pci/pci_configuration.rs
index fac75ab..a1d86d4 100644
--- a/devices/src/pci/pci_configuration.rs
+++ b/devices/src/pci/pci_configuration.rs
@@ -70,6 +70,22 @@
fn get_register_value(&self) -> u8;
}
+/// Subclasses of the DisplayController class.
+#[allow(dead_code)]
+#[derive(Copy, Clone)]
+pub enum PciDisplaySubclass {
+ VgaCompatibleController = 0x00,
+ XgaCompatibleController = 0x01,
+ ThreeDController = 0x02,
+ Other = 0x80,
+}
+
+impl PciSubclass for PciDisplaySubclass {
+ fn get_register_value(&self) -> u8 {
+ *self as u8
+ }
+}
+
/// Subclasses of the MultimediaController class.
#[allow(dead_code)]
#[derive(Copy, Clone)]
diff --git a/devices/src/pci/pci_device.rs b/devices/src/pci/pci_device.rs
index c92f0b2..be336e7 100644
--- a/devices/src/pci/pci_device.rs
+++ b/devices/src/pci/pci_device.rs
@@ -3,15 +3,14 @@
// found in the LICENSE file.
use std::fmt::{self, Display};
-use std::os::unix::io::RawFd;
-use base::Event;
+use base::{Event, RawDescriptor};
use hypervisor::Datamatch;
use resources::{Error as SystemAllocatorFaliure, SystemAllocator};
use crate::pci::pci_configuration;
use crate::pci::{PciAddress, PciInterruptPin};
-use crate::BusDevice;
+use crate::{BusAccessInfo, BusDevice};
#[derive(Debug)]
pub enum Error {
@@ -54,7 +53,7 @@
fn assign_address(&mut self, _address: PciAddress) {}
/// 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>;
+ fn keep_rds(&self) -> Vec<RawDescriptor>;
/// 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.
@@ -120,12 +119,12 @@
PciDevice::debug_label(self)
}
- fn read(&mut self, offset: u64, data: &mut [u8]) {
- self.read_bar(offset, data)
+ fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
+ self.read_bar(info.address, data)
}
- fn write(&mut self, offset: u64, data: &[u8]) {
- self.write_bar(offset, data)
+ fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
+ self.write_bar(info.address, data)
}
fn config_register_write(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
@@ -153,8 +152,8 @@
fn assign_address(&mut self, address: PciAddress) {
(**self).assign_address(address)
}
- fn keep_fds(&self) -> Vec<RawFd> {
- (**self).keep_fds()
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ (**self).keep_rds()
}
fn assign_irq(
&mut self,
diff --git a/devices/src/pci/pci_root.rs b/devices/src/pci/pci_root.rs
index 91d6094..c1891be 100644
--- a/devices/src/pci/pci_root.rs
+++ b/devices/src/pci/pci_root.rs
@@ -5,16 +5,16 @@
use std::collections::BTreeMap;
use std::convert::TryInto;
use std::fmt::{self, Display};
-use std::os::unix::io::RawFd;
use std::sync::Arc;
+use base::RawDescriptor;
use sync::Mutex;
use crate::pci::pci_configuration::{
PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType,
};
use crate::pci::pci_device::PciDevice;
-use crate::BusDevice;
+use crate::{BusAccessInfo, BusDevice};
// A PciDevice that holds the root hub's configuration.
struct PciRootConfiguration {
@@ -25,7 +25,7 @@
fn debug_label(&self) -> String {
"pci root device".to_owned()
}
- fn keep_fds(&self) -> Vec<RawFd> {
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
Vec::new()
}
fn read_config_register(&self, reg_idx: usize) -> u32 {
@@ -226,16 +226,16 @@
format!("pci config io-port 0x{:03x}", self.config_address)
}
- fn read(&mut self, offset: u64, data: &mut [u8]) {
+ fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
// `offset` is relative to 0xcf8
- let value = match offset {
+ let value = match info.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 start = info.offset as usize % 4;
let end = start + data.len();
if end <= 4 {
for i in start..end {
@@ -248,9 +248,9 @@
}
}
- fn write(&mut self, offset: u64, data: &[u8]) {
+ fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
// `offset` is relative to 0xcf8
- match offset {
+ match info.offset {
o @ 0..=3 => self.set_config_address(o, data),
o @ 4..=7 => self.config_space_write(o - 4, data),
_ => (),
@@ -286,27 +286,27 @@
"pci config mmio".to_owned()
}
- fn read(&mut self, offset: u64, data: &mut [u8]) {
+ fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
// Only allow reads to the register boundary.
- let start = offset as usize % 4;
+ let start = info.offset as usize % 4;
let end = start + data.len();
- if end > 4 || offset > u32::max_value() as u64 {
+ if end > 4 || info.offset > u32::max_value() as u64 {
for d in data {
*d = 0xff;
}
return;
}
- let value = self.config_space_read(offset as u32);
+ let value = self.config_space_read(info.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 {
+ fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
+ if info.offset > u32::max_value() as u64 {
return;
}
- self.config_space_write(offset as u32, offset % 4, data)
+ self.config_space_write(info.offset as u32, info.offset % 4, data)
}
}
diff --git a/devices/src/pci/vfio_pci.rs b/devices/src/pci/vfio_pci.rs
index 88a5216..7cea8e3 100644
--- a/devices/src/pci/vfio_pci.rs
+++ b/devices/src/pci/vfio_pci.rs
@@ -2,19 +2,20 @@
// 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::Arc;
use std::u32;
-use base::{error, Event, MappedRegion, MemoryMapping, MemoryMappingBuilder};
+use base::{
+ error, AsRawDescriptor, Event, MappedRegion, MemoryMapping, MemoryMappingBuilder, RawDescriptor,
+};
use hypervisor::Datamatch;
use msg_socket::{MsgReceiver, MsgSender};
use resources::{Alloc, MmioType, SystemAllocator};
use vfio_sys::*;
use vm_control::{
- MaybeOwnedFd, VmIrqRequest, VmIrqRequestSocket, VmIrqResponse, VmMemoryControlRequestSocket,
- VmMemoryRequest, VmMemoryResponse,
+ MaybeOwnedDescriptor, VmIrqRequest, VmIrqRequestSocket, VmIrqResponse,
+ VmMemoryControlRequestSocket, VmMemoryRequest, VmMemoryResponse,
};
use crate::pci::msix::{
@@ -270,7 +271,7 @@
}
if let Err(e) = self.vm_socket_irq.send(&VmIrqRequest::AllocateOneMsi {
- irqfd: MaybeOwnedFd::Borrowed(self.irqfd.as_ref().unwrap().as_raw_fd()),
+ irqfd: MaybeOwnedDescriptor::Borrowed(self.irqfd.as_ref().unwrap().as_raw_descriptor()),
}) {
error!("failed to send AllocateOneMsi request: {:?}", e);
return;
@@ -661,8 +662,8 @@
None => return,
};
- if let Some(fds) = irqfds {
- if let Err(e) = self.device.irq_enable(fds, VfioIrqType::Msix) {
+ if let Some(descriptors) = irqfds {
+ if let Err(e) = self.device.irq_enable(descriptors, VfioIrqType::Msix) {
error!("failed to enable msix: {}", e);
self.enable_intx();
return;
@@ -709,7 +710,7 @@
if self
.vm_socket_mem
.send(&VmMemoryRequest::RegisterMmapMemory {
- fd: MaybeOwnedFd::Borrowed(self.device.as_raw_fd()),
+ descriptor: MaybeOwnedDescriptor::Borrowed(self.device.as_raw_descriptor()),
size: mmap_size as usize,
offset,
gpa: guest_map_start,
@@ -776,22 +777,22 @@
self.pci_address = Some(address);
}
- fn keep_fds(&self) -> Vec<RawFd> {
- let mut fds = self.device.keep_fds();
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ let mut rds = self.device.keep_rds();
if let Some(ref interrupt_evt) = self.interrupt_evt {
- fds.push(interrupt_evt.as_raw_fd());
+ rds.push(interrupt_evt.as_raw_descriptor());
}
if let Some(ref interrupt_resample_evt) = self.interrupt_resample_evt {
- fds.push(interrupt_resample_evt.as_raw_fd());
+ rds.push(interrupt_resample_evt.as_raw_descriptor());
}
- fds.push(self.vm_socket_mem.as_raw_fd());
+ rds.push(self.vm_socket_mem.as_raw_descriptor());
if let Some(msi_cap) = &self.msi_cap {
- fds.push(msi_cap.vm_socket_irq.as_raw_fd());
+ rds.push(msi_cap.vm_socket_irq.as_raw_descriptor());
}
if let Some(msix_cap) = &self.msix_cap {
- fds.push(msix_cap.config.as_raw_fd());
+ rds.push(msix_cap.config.as_raw_descriptor());
}
- fds
+ rds
}
fn assign_irq(
@@ -833,10 +834,7 @@
low = self.config.read_config_dword(offset);
let low_flag = low & 0xf;
- let is_64bit = match low_flag & 0x4 {
- 0x4 => true,
- _ => false,
- };
+ let is_64bit = low_flag & 0x4 == 0x4;
if (low_flag & 0x1 == 0 || i == VFIO_PCI_ROM_REGION_INDEX) && low != 0 {
let mut upper: u32 = 0xffffffff;
if is_64bit {
diff --git a/devices/src/pit.rs b/devices/src/pit.rs
index 491cf32..63fa5be 100644
--- a/devices/src/pit.rs
+++ b/devices/src/pit.rs
@@ -5,12 +5,13 @@
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 base::{error, warn, Error as SysError, Event, Fd, PollContext, PollToken};
+use base::{
+ error, warn, AsRawDescriptor, Descriptor, Error as SysError, Event, PollToken, WaitContext,
+};
use bit_field::BitField1;
use bit_field::*;
use hypervisor::{PitChannelState, PitRWMode, PitRWState, PitState};
@@ -26,6 +27,7 @@
#[cfg(not(test))]
use base::Timer;
+use crate::bus::BusAccessInfo;
use crate::BusDevice;
// Bitmask for areas of standard (non-ReadBack) Control Word Format. Constant
@@ -148,10 +150,10 @@
#[derive(Debug)]
pub enum PitError {
TimerCreateError(SysError),
- /// Creating PollContext failed.
- CreatePollContext(SysError),
- /// Error while polling for events.
- PollError(SysError),
+ /// Creating WaitContext failed.
+ CreateWaitContext(SysError),
+ /// Error while waiting for events.
+ WaitError(SysError),
/// Error while trying to create worker thread.
SpawnThread(IoError),
/// Error while creating event.
@@ -166,8 +168,8 @@
match self {
TimerCreateError(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),
+ CreateWaitContext(e) => write!(f, "failed to create poll context: {}", e),
+ WaitError(err) => write!(f, "failed to wait for events: {}", err),
SpawnThread(err) => write!(f, "failed to spawn thread: {}", err),
CreateEvent(err) => write!(f, "failed to create event: {}", err),
CloneEvent(err) => write!(f, "failed to clone event: {}", err),
@@ -213,31 +215,31 @@
"userspace PIT".to_string()
}
- fn write(&mut self, offset: u64, data: &[u8]) {
+ fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
self.ensure_started();
if data.len() != 1 {
warn!("Bad write size for Pit: {}", data.len());
return;
}
- match PortIOSpace::n(offset as i64) {
+ match PortIOSpace::n(info.address 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),
+ None => warn!("PIT: bad write to {}", info),
}
}
- fn read(&mut self, offset: u64, data: &mut [u8]) {
+ fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
self.ensure_started();
if data.len() != 1 {
warn!("Bad read size for Pit: {}", data.len());
return;
}
- data[0] = match PortIOSpace::n(offset as i64) {
+ data[0] = match PortIOSpace::n(info.address 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(),
@@ -250,7 +252,7 @@
}
Some(PortIOSpace::PortSpeaker) => self.counters[2].lock().read_speaker(),
None => {
- warn!("PIT: bad read from offset {}", offset);
+ warn!("PIT: bad read from {}", info);
return;
}
};
@@ -295,7 +297,7 @@
fn start(&mut self) -> PitResult<()> {
let mut worker = Worker {
pit_counter: self.counters[0].clone(),
- fd: Fd(self.counters[0].lock().timer.as_raw_fd()),
+ fd: Descriptor(self.counters[0].lock().timer.as_raw_descriptor()),
};
let evt = self.kill_evt.try_clone().map_err(PitError::CloneEvent)?;
@@ -550,28 +552,9 @@
// - 2 counter select bits, which aren't used by the counter/channel itself
self.command = (state.mode << 1) | ((state.rw_mode as u8) << 4);
self.gate = state.gate;
- self.latched = match state.count_latched {
- PitRWState::None => false,
- _ => true,
- };
-
- match state.read_state {
- PitRWState::Word1 => {
- self.read_low_byte = true;
- }
- _ => {
- self.read_low_byte = false;
- }
- }
-
- match state.write_state {
- PitRWState::Word1 => {
- self.wrote_low_byte = true;
- }
- _ => {
- self.wrote_low_byte = false;
- }
- }
+ self.latched = state.count_latched != PitRWState::None;
+ self.read_low_byte = state.read_state == PitRWState::Word1;
+ self.wrote_low_byte = state.write_state == PitRWState::Word1;
// To convert the count_load_time to an instant we have to convert it to a
// duration by comparing it to get_monotonic_time. Then subtract that duration from
@@ -903,7 +886,7 @@
struct Worker {
pit_counter: Arc<Mutex<PitCounter>>,
- fd: Fd,
+ fd: Descriptor,
}
impl Worker {
@@ -916,14 +899,14 @@
Kill,
}
- let poll_ctx: PollContext<Token> =
- PollContext::build_with(&[(&self.fd, Token::TimerExpire), (&kill_evt, Token::Kill)])
- .map_err(PitError::CreatePollContext)?;
+ let wait_ctx: WaitContext<Token> =
+ WaitContext::build_with(&[(&self.fd, Token::TimerExpire), (&kill_evt, Token::Kill)])
+ .map_err(PitError::CreateWaitContext)?;
loop {
- let events = poll_ctx.wait().map_err(PitError::PollError)?;
- for event in events.iter_readable() {
- match event.token() {
+ let events = wait_ctx.wait().map_err(PitError::WaitError)?;
+ for event in events.iter().filter(|e| e.is_readable) {
+ match event.token {
Token::TimerExpire => {
let mut pit = self.pit_counter.lock();
pit.timer_handler();
@@ -944,14 +927,35 @@
clock: Arc<Mutex<Clock>>,
}
+ fn pit_bus_address(address: PortIOSpace) -> BusAccessInfo {
+ // The PIT is added to the io_bus in two locations, so the offset depends on which
+ // address range the address is in. The PIT implementation currently does not use the
+ // offset, but we're setting it accurately here in case it does in the future.
+ let offset = match address as u64 {
+ x if x >= PortIOSpace::PortCounter0Data as u64
+ && x < PortIOSpace::PortCounter0Data as u64 + 0x8 =>
+ {
+ address as u64 - PortIOSpace::PortCounter0Data as u64
+ }
+ x if x == PortIOSpace::PortSpeaker as u64 => 0,
+ _ => panic!("invalid PIT address: {:#x}", address as u64),
+ };
+
+ BusAccessInfo {
+ offset,
+ address: address as u64,
+ id: 0,
+ }
+ }
+
/// 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])
+ pit.write(pit_bus_address(PortIOSpace::PortCommand), &[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])
+ pit.write(pit_bus_address(PortIOSpace::PortSpeaker), &[command])
}
/// Utility method for writing to a counter.
@@ -961,17 +965,17 @@
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]);
+ pit.write(pit_bus_address(port), &[(data & 0xff) as u8]);
}
if access_mode == CommandAccess::CommandRWMost
|| access_mode == CommandAccess::CommandRWBoth
{
- pit.write(port, &[(data >> 8) as u8]);
+ pit.write(pit_bus_address(port), &[(data >> 8) as u8]);
}
}
@@ -982,20 +986,20 @@
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);
+ pit.read(pit_bus_address(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);
+ pit.read(pit_bus_address(port), &mut buffer);
result |= u16::from(buffer[0]) << 8;
}
assert_eq!(result, expected);
@@ -1123,7 +1127,8 @@
fn read_command() {
let mut data = set_up();
let mut buf = [0];
- data.pit.read(PortIOSpace::PortCommand as u64, &mut buf);
+ data.pit
+ .read(pit_bus_address(PortIOSpace::PortCommand), &mut buf);
assert_eq!(buf, [0]);
}
@@ -1444,7 +1449,21 @@
#[test]
fn invalid_write_and_read() {
let mut data = set_up();
- data.pit.write(0x44, &[0]);
- data.pit.read(0x55, &mut [0]);
+ data.pit.write(
+ BusAccessInfo {
+ address: 0x44,
+ offset: 0x4,
+ id: 0,
+ },
+ &[0],
+ );
+ data.pit.read(
+ BusAccessInfo {
+ address: 0x55,
+ offset: 0x15,
+ id: 0,
+ },
+ &mut [0],
+ );
}
}
diff --git a/devices/src/pl030.rs b/devices/src/pl030.rs
index 9db36eb..f295b96 100644
--- a/devices/src/pl030.rs
+++ b/devices/src/pl030.rs
@@ -3,9 +3,10 @@
// found in the LICENSE file.
use base::{warn, Event};
+use std::convert::TryFrom;
use std::time::{SystemTime, UNIX_EPOCH};
-use crate::BusDevice;
+use crate::{BusAccessInfo, BusDevice};
// Register offsets
// Data register
@@ -74,17 +75,17 @@
"Pl030".to_owned()
}
- fn write(&mut self, offset: u64, data: &[u8]) {
- if data.len() != 4 {
- warn!("bad write size: {} for pl030", data.len());
- return;
- }
+ fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
+ let data_array = match <&[u8; 4]>::try_from(data) {
+ Ok(array) => array,
+ _ => {
+ 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 {
+ let reg_val = u32::from_ne_bytes(*data_array);
+ match info.offset {
RTCDR => {
warn!("invalid write to read-only RTCDR register");
}
@@ -113,17 +114,20 @@
RTCCR => {
self.counter_delta_time = get_epoch_time();
}
- o => panic!("pl030: bad write offset {}", o),
+ o => panic!("pl030: bad write {}", o),
}
}
- fn read(&mut self, offset: u64, data: &mut [u8]) {
- if data.len() != 4 {
- warn!("bad read size: {} for pl030", data.len());
- return;
- }
+ fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
+ let data_array = match <&mut [u8; 4]>::try_from(data) {
+ Ok(array) => array,
+ _ => {
+ warn!("bad write size for pl030");
+ return;
+ }
+ };
- let reg_content: u32 = match offset {
+ let reg_content: u32 = match info.offset {
RTCDR => get_epoch_time(),
RTCMR => self.match_value,
RTCSTAT => self.interrupt_active as u32,
@@ -135,11 +139,51 @@
AMBA_ID_OFFSET => PL030_AMBA_ID,
AMBA_MASK_OFFSET => PL030_AMBA_MASK,
- o => panic!("pl030: bad read offset {}", o),
+ o => panic!("pl030: bad read {}", 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;
+ *data_array = reg_content.to_ne_bytes();
+ }
+}
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ // The RTC device is placed at page 2 in the mmio bus
+ const AARCH64_RTC_ADDR: u64 = 0x2000;
+
+ fn pl030_bus_address(offset: u64) -> BusAccessInfo {
+ BusAccessInfo {
+ address: AARCH64_RTC_ADDR + offset,
+ offset,
+ id: 0,
+ }
+ }
+
+ #[test]
+ fn test_interrupt_status_register() {
+ let event = Event::new().unwrap();
+ let mut device = Pl030::new(event.try_clone().unwrap());
+ let mut register = [0, 0, 0, 0];
+
+ // set interrupt
+ device.write(pl030_bus_address(RTCEOI), &[1, 0, 0, 0]);
+ device.read(pl030_bus_address(RTCSTAT), &mut register);
+ assert_eq!(register, [1, 0, 0, 0]);
+ assert_eq!(event.read().unwrap(), 1);
+
+ // clear interrupt
+ device.write(pl030_bus_address(RTCEOI), &[0, 0, 0, 0]);
+ device.read(pl030_bus_address(RTCSTAT), &mut register);
+ assert_eq!(register, [0, 0, 0, 0]);
+ }
+
+ #[test]
+ fn test_match_register() {
+ let mut device = Pl030::new(Event::new().unwrap());
+ let mut register = [0, 0, 0, 0];
+
+ device.write(pl030_bus_address(RTCMR), &[1, 2, 3, 4]);
+ device.read(pl030_bus_address(RTCMR), &mut register);
+ assert_eq!(register, [1, 2, 3, 4]);
}
}
diff --git a/devices/src/proxy.rs b/devices/src/proxy.rs
index e07b380..383eee4 100644
--- a/devices/src/proxy.rs
+++ b/devices/src/proxy.rs
@@ -5,16 +5,15 @@
//! Runs hardware devices in child processes.
use std::fmt::{self, Display};
-use std::os::unix::io::{AsRawFd, RawFd};
use std::time::Duration;
use std::{self, io};
-use base::{error, net::UnixSeqpacket};
+use base::{error, net::UnixSeqpacket, AsRawDescriptor, RawDescriptor};
use libc::{self, pid_t};
use minijail::{self, Minijail};
use msg_socket::{MsgOnSocket, MsgReceiver, MsgSender, MsgSocket};
-use crate::BusDevice;
+use crate::{BusAccessInfo, BusDevice};
/// Errors for proxy devices.
#[derive(Debug)]
@@ -41,11 +40,11 @@
enum Command {
Read {
len: u32,
- offset: u64,
+ info: BusAccessInfo,
},
Write {
len: u32,
- offset: u64,
+ info: BusAccessInfo,
data: [u8; 8],
},
ReadConfig(u32),
@@ -79,14 +78,14 @@
};
let res = match cmd {
- Command::Read { len, offset } => {
+ Command::Read { len, info } => {
let mut buffer = [0u8; 8];
- device.read(offset, &mut buffer[0..len as usize]);
+ device.read(info, &mut buffer[0..len as usize]);
sock.send(&CommandResult::ReadResult(buffer))
}
- Command::Write { len, offset, data } => {
+ Command::Write { len, info, data } => {
let len = len as usize;
- device.write(offset, &data[0..len]);
+ device.write(info, &data[0..len]);
// Command::Write does not have a result.
Ok(())
}
@@ -135,19 +134,19 @@
/// # Arguments
/// * `device` - The device to isolate to another process.
/// * `jail` - The jail to use for isolating the given device.
- /// * `keep_fds` - File descriptors that will be kept open in the child.
+ /// * `keep_rds` - 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>,
+ mut keep_rds: Vec<RawDescriptor>,
) -> 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());
+ keep_rds.push(child_sock.as_raw_descriptor());
// 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)? {
+ match jail.fork(Some(&keep_rds)).map_err(Error::ForkingJail)? {
0 => {
device.on_sandboxed();
child_proc(child_sock, &mut device);
@@ -238,23 +237,23 @@
}
}
- fn read(&mut self, offset: u64, data: &mut [u8]) {
+ fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
let len = data.len() as u32;
if let Some(CommandResult::ReadResult(buffer)) =
- self.sync_send(&Command::Read { len, offset })
+ self.sync_send(&Command::Read { len, info })
{
let len = data.len();
data.clone_from_slice(&buffer[0..len]);
}
}
- fn write(&mut self, offset: u64, data: &[u8]) {
+ fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
let mut buffer = [0u8; 8];
let len = data.len() as u32;
buffer[0..data.len()].clone_from_slice(data);
self.send_no_result(&Command::Write {
len,
- offset,
+ info,
data: buffer,
});
}
@@ -265,3 +264,83 @@
self.sync_send(&Command::Shutdown);
}
}
+
+/// Note: These tests must be run with --test-threads=1 to allow minijail to fork
+/// the process.
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ /// A simple test echo device that outputs the same u8 that was written to it.
+ struct EchoDevice {
+ data: u8,
+ config: u8,
+ }
+ impl EchoDevice {
+ fn new() -> EchoDevice {
+ EchoDevice { data: 0, config: 0 }
+ }
+ }
+ impl BusDevice for EchoDevice {
+ fn debug_label(&self) -> String {
+ "EchoDevice".to_owned()
+ }
+
+ fn write(&mut self, _info: BusAccessInfo, data: &[u8]) {
+ assert!(data.len() == 1);
+ self.data = data[0];
+ }
+
+ fn read(&mut self, _info: BusAccessInfo, data: &mut [u8]) {
+ assert!(data.len() == 1);
+ data[0] = self.data;
+ }
+
+ fn config_register_write(&mut self, _reg_idx: usize, _offset: u64, data: &[u8]) {
+ assert!(data.len() == 1);
+ self.config = data[0];
+ }
+
+ fn config_register_read(&self, _reg_idx: usize) -> u32 {
+ self.config as u32
+ }
+ }
+
+ fn new_proxied_echo_device() -> ProxyDevice {
+ let device = EchoDevice::new();
+ let keep_fds: Vec<RawDescriptor> = Vec::new();
+ let minijail = Minijail::new().unwrap();
+ ProxyDevice::new(device, &minijail, keep_fds).unwrap()
+ }
+
+ // TODO(b/173833661): Find a way to ensure these tests are run single-threaded.
+ #[test]
+ #[ignore]
+ fn test_debug_label() {
+ let proxy_device = new_proxied_echo_device();
+ assert_eq!(proxy_device.debug_label(), "EchoDevice");
+ }
+
+ #[test]
+ #[ignore]
+ fn test_proxied_read_write() {
+ let mut proxy_device = new_proxied_echo_device();
+ let address = BusAccessInfo {
+ offset: 0,
+ address: 0,
+ id: 0,
+ };
+ proxy_device.write(address, &[42]);
+ let mut read_buffer = [0];
+ proxy_device.read(address, &mut read_buffer);
+ assert_eq!(read_buffer, [42]);
+ }
+
+ #[test]
+ #[ignore]
+ fn test_proxied_config() {
+ let mut proxy_device = new_proxied_echo_device();
+ proxy_device.config_register_write(0, 0, &[42]);
+ assert_eq!(proxy_device.config_register_read(0), 42);
+ }
+}
diff --git a/devices/src/serial.rs b/devices/src/serial.rs
index ca0dee9..d4e6d45 100644
--- a/devices/src/serial.rs
+++ b/devices/src/serial.rs
@@ -4,14 +4,14 @@
use std::collections::VecDeque;
use std::io::{self, Write};
-use std::os::unix::io::RawFd;
use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::mpsc::{channel, Receiver, TryRecvError};
use std::sync::Arc;
use std::thread::{self};
-use base::{error, Event, Result};
+use base::{error, Event, RawDescriptor, Result};
+use crate::bus::BusAccessInfo;
use crate::{BusDevice, SerialDevice};
const LOOP_SIZE: usize = 0x40;
@@ -88,7 +88,7 @@
interrupt_evt: Event,
input: Option<Box<dyn io::Read + Send>>,
out: Option<Box<dyn io::Write + Send>>,
- _keep_fds: Vec<RawFd>,
+ _keep_rds: Vec<RawDescriptor>,
) -> Serial {
Serial {
interrupt_enable: Default::default(),
@@ -311,24 +311,24 @@
"serial".to_owned()
}
- fn write(&mut self, offset: u64, data: &[u8]) {
+ fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
if data.len() != 1 {
return;
}
- if let Err(e) = self.handle_write(offset as u8, data[0]) {
+ if let Err(e) = self.handle_write(info.offset as u8, data[0]) {
error!("serial failed write: {}", e);
}
}
- fn read(&mut self, offset: u64, data: &mut [u8]) {
+ fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
if data.len() != 1 {
return;
}
self.handle_input_thread();
- data[0] = match offset as u8 {
+ data[0] = match info.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 => {
@@ -404,6 +404,15 @@
}
}
+ fn serial_bus_address(offset: u8) -> BusAccessInfo {
+ // Serial devices only use the offset of the BusAccessInfo
+ BusAccessInfo {
+ offset: offset as u64,
+ address: 0,
+ id: 0,
+ }
+ }
+
#[test]
fn serial_output() {
let intr_evt = Event::new().unwrap();
@@ -417,9 +426,9 @@
Vec::new(),
);
- serial.write(DATA as u64, &['a' as u8]);
- serial.write(DATA as u64, &['b' as u8]);
- serial.write(DATA as u64, &['c' as u8]);
+ serial.write(serial_bus_address(DATA), &['a' as u8]);
+ serial.write(serial_bus_address(DATA), &['b' as u8]);
+ serial.write(serial_bus_address(DATA), &['c' as u8]);
assert_eq!(
serial_out.buf.lock().as_slice(),
&['a' as u8, 'b' as u8, 'c' as u8]
@@ -439,18 +448,18 @@
Vec::new(),
);
- serial.write(IER as u64, &[IER_RECV_BIT]);
+ serial.write(serial_bus_address(IER), &[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[..]);
+ serial.read(serial_bus_address(DATA), &mut data[..]);
assert_eq!(data[0], 'a' as u8);
- serial.read(DATA as u64, &mut data[..]);
+ serial.read(serial_bus_address(DATA), &mut data[..]);
assert_eq!(data[0], 'b' as u8);
- serial.read(DATA as u64, &mut data[..]);
+ serial.read(serial_bus_address(DATA), &mut data[..]);
assert_eq!(data[0], 'c' as u8);
}
}
diff --git a/devices/src/serial_device.rs b/devices/src/serial_device.rs
index effa5fe..280730e 100644
--- a/devices/src/serial_device.rs
+++ b/devices/src/serial_device.rs
@@ -3,9 +3,8 @@
// found in the LICENSE file.
use std::io;
-use std::os::unix::io::RawFd;
-use base::Event;
+use base::{Event, RawDescriptor};
/// Abstraction over serial-like devices that can be created given an event and optional input and
/// output streams.
@@ -15,6 +14,6 @@
interrupt_evt: Event,
input: Option<Box<dyn io::Read + Send>>,
output: Option<Box<dyn io::Write + Send>>,
- keep_fds: Vec<RawFd>,
+ keep_rds: Vec<RawDescriptor>,
) -> Self;
}
diff --git a/devices/src/usb/host_backend/host_backend_device_provider.rs b/devices/src/usb/host_backend/host_backend_device_provider.rs
index 0f5f2a7..0af8bbf 100644
--- a/devices/src/usb/host_backend/host_backend_device_provider.rs
+++ b/devices/src/usb/host_backend/host_backend_device_provider.rs
@@ -2,6 +2,7 @@
// 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::sync::Arc;
use super::error::*;
@@ -11,17 +12,16 @@
use crate::utils::AsyncJobQueue;
use crate::utils::{EventHandler, EventLoop, FailHandle};
use base::net::UnixSeqpacket;
-use base::{error, WatchingEvents};
+use base::{error, AsRawDescriptor, FromRawDescriptor, RawDescriptor, WatchingEvents};
use msg_socket::{MsgReceiver, MsgSender, MsgSocket};
use std::collections::HashMap;
use std::mem;
-use std::os::unix::io::{AsRawFd, RawFd};
use std::time::Duration;
use sync::Mutex;
use usb_util::Device;
use vm_control::{
- MaybeOwnedFd, UsbControlAttachedDevice, UsbControlCommand, UsbControlResult, UsbControlSocket,
- USB_CONTROL_MAX_PORTS,
+ MaybeOwnedDescriptor, UsbControlAttachedDevice, UsbControlCommand, UsbControlResult,
+ UsbControlSocket, USB_CONTROL_MAX_PORTS,
};
const SOCKET_TIMEOUT_MS: u64 = 2000;
@@ -110,9 +110,9 @@
})
}
- fn keep_fds(&self) -> Vec<RawFd> {
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
match self {
- HostBackendDeviceProvider::Created { sock } => vec![sock.lock().as_raw_fd()],
+ HostBackendDeviceProvider::Created { sock } => vec![sock.lock().as_raw_descriptor()],
_ => {
error!(
"Trying to get keepfds when HostBackendDeviceProvider is not in created state"
@@ -160,17 +160,18 @@
/// Open a usbdevfs file to create a host USB device object.
/// `fd` should be an open file descriptor for a file in `/dev/bus/usb`.
- fn handle_attach_device(&self, fd: Option<MaybeOwnedFd>) -> UsbControlResult {
+ fn handle_attach_device(&self, fd: Option<MaybeOwnedDescriptor>) -> UsbControlResult {
let usb_file = match fd {
- Some(MaybeOwnedFd::Owned(file)) => file,
+ Some(MaybeOwnedDescriptor::Owned(file)) => file,
_ => {
error!("missing fd in UsbControlCommand::AttachDevice message");
return UsbControlResult::FailedToOpenDevice;
}
};
- let raw_fd = usb_file.as_raw_fd();
- let device = match Device::new(usb_file) {
+ let raw_descriptor = usb_file.as_raw_descriptor();
+ // Safe as it is valid to have multiple variables accessing the same fd.
+ let device = match Device::new(unsafe { File::from_raw_descriptor(raw_descriptor) }) {
Ok(d) => d,
Err(e) => {
error!("could not construct USB device from fd: {}", e);
@@ -185,7 +186,7 @@
});
if let Err(e) = self.event_loop.add_event(
- &MaybeOwnedFd::Borrowed(raw_fd),
+ &MaybeOwnedDescriptor::Borrowed(raw_descriptor),
WatchingEvents::empty().set_read().set_write(),
Arc::downgrade(&event_handler),
) {
@@ -230,9 +231,11 @@
let device = device_ctx.device.lock();
let fd = device.fd();
- if let Err(e) = self
- .event_loop
- .remove_event_for_fd(&MaybeOwnedFd::Borrowed(fd.as_raw_fd()))
+ if let Err(e) =
+ self.event_loop
+ .remove_event_for_fd(&MaybeOwnedDescriptor::Borrowed(
+ fd.as_raw_descriptor(),
+ ))
{
error!(
"failed to remove poll change handler from event loop: {}",
@@ -274,7 +277,9 @@
let sock = self.sock.lock();
let cmd = sock.recv().map_err(Error::ReadControlSock)?;
let result = match cmd {
- UsbControlCommand::AttachDevice { fd, .. } => self.handle_attach_device(fd),
+ UsbControlCommand::AttachDevice { descriptor, .. } => {
+ self.handle_attach_device(descriptor)
+ }
UsbControlCommand::DetachDevice { port } => self.handle_detach_device(port),
UsbControlCommand::ListDevice { ports } => self.handle_list_devices(ports),
};
diff --git a/devices/src/usb/xhci/xhci_backend_device_provider.rs b/devices/src/usb/xhci/xhci_backend_device_provider.rs
index c014d77..aefcf53 100644
--- a/devices/src/usb/xhci/xhci_backend_device_provider.rs
+++ b/devices/src/usb/xhci/xhci_backend_device_provider.rs
@@ -4,7 +4,7 @@
use super::usb_hub::UsbHub;
use crate::utils::{EventLoop, FailHandle};
-use std::os::unix::io::RawFd;
+use base::RawDescriptor;
use std::sync::Arc;
/// Xhci backend provider will run on an EventLoop and connect new devices to usb ports.
@@ -17,6 +17,6 @@
hub: Arc<UsbHub>,
) -> std::result::Result<(), ()>;
- /// Keep fds that should be kept open.
- fn keep_fds(&self) -> Vec<RawFd>;
+ /// Keep raw descriptors that should be kept open.
+ fn keep_rds(&self) -> Vec<RawDescriptor>;
}
diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs
index 67393ca..0c97c7b 100644
--- a/devices/src/usb/xhci/xhci_controller.rs
+++ b/devices/src/usb/xhci/xhci_controller.rs
@@ -12,10 +12,9 @@
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 base::{error, Event};
+use base::{error, Event, RawDescriptor};
use resources::{Alloc, MmioType, SystemAllocator};
use std::mem;
-use std::os::unix::io::RawFd;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use vm_memory::GuestMemory;
@@ -171,9 +170,9 @@
self.pci_address = Some(address);
}
- fn keep_fds(&self) -> Vec<RawFd> {
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
match &self.state {
- XhciControllerState::Created { device_provider } => device_provider.keep_fds(),
+ XhciControllerState::Created { device_provider } => device_provider.keep_rds(),
_ => {
error!("xhci controller is in a wrong state");
vec![]
diff --git a/devices/src/utils/error.rs b/devices/src/utils/error.rs
index 1d0227a..453b052 100644
--- a/devices/src/utils/error.rs
+++ b/devices/src/utils/error.rs
@@ -11,9 +11,9 @@
CreateEvent(SysError),
ReadEvent(SysError),
WriteEvent(SysError),
- CreatePollContext(SysError),
- PollContextAddFd(SysError),
- PollContextDeleteFd(SysError),
+ CreateWaitContext(SysError),
+ WaitContextAddDescriptor(SysError),
+ WaitContextDeleteDescriptor(SysError),
StartThread(std::io::Error),
}
@@ -26,9 +26,11 @@
CreateEvent(e) => write!(f, "failed to create event: {}", e),
ReadEvent(e) => write!(f, "failed to read event: {}", e),
WriteEvent(e) => write!(f, "failed to write event: {}", 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),
+ CreateWaitContext(e) => write!(f, "failed to create poll context: {}", e),
+ WaitContextAddDescriptor(e) => write!(f, "failed to add fd to poll context: {}", e),
+ WaitContextDeleteDescriptor(e) => {
+ write!(f, "failed to delete fd from poll context: {}", e)
+ }
StartThread(e) => write!(f, "failed to start thread: {}", e),
}
}
diff --git a/devices/src/utils/event_loop.rs b/devices/src/utils/event_loop.rs
index c710eb2..f99d18a 100644
--- a/devices/src/utils/event_loop.rs
+++ b/devices/src/utils/event_loop.rs
@@ -3,10 +3,12 @@
// found in the LICENSE file.
use super::error::{Error, Result};
-use base::{error, warn, EpollContext, EpollEvents, Event, PollToken, WatchingEvents};
+use base::{
+ error, warn, wrap_descriptor, AsRawDescriptor, Descriptor, EpollContext, EpollEvents, Event,
+ RawDescriptor, WatchingEvents,
+};
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;
@@ -35,31 +37,12 @@
}
}
-/// 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>>>>,
+ poll_ctx: Arc<EpollContext<Descriptor>>,
+ handlers: Arc<Mutex<BTreeMap<RawDescriptor, Weak<dyn EventHandler>>>>,
stop_evt: Event,
}
@@ -78,11 +61,17 @@
.and_then(|e| Ok((e.try_clone()?, e)))
.map_err(Error::CreateEvent)?;
- let fd_callbacks: Arc<Mutex<BTreeMap<RawFd, Weak<dyn EventHandler>>>> =
+ let fd_callbacks: Arc<Mutex<BTreeMap<RawDescriptor, 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: EpollContext<Descriptor> = EpollContext::new()
+ .and_then(|pc| {
+ pc.add(
+ &wrap_descriptor(&stop_evt),
+ Descriptor(stop_evt.as_raw_descriptor()),
+ )
+ .and(Ok(pc))
+ })
+ .map_err(Error::CreateWaitContext)?;
let poll_ctx = Arc::new(poll_ctx);
let event_loop = EventLoop {
@@ -110,10 +99,10 @@
}
};
for event in &events {
- if event.token().as_raw_fd() == stop_evt.as_raw_fd() {
+ if event.token().as_raw_descriptor() == stop_evt.as_raw_descriptor() {
return;
} else {
- let fd = event.token().as_raw_fd();
+ let fd = event.token().as_raw_descriptor();
let mut locked = fd_callbacks.lock();
let weak_handler = match locked.get(&fd) {
Some(cb) => cb.clone(),
@@ -137,7 +126,7 @@
}
// If the handler is already gone, we remove the fd.
None => {
- let _ = poll_ctx.delete(&Fd(fd));
+ let _ = poll_ctx.delete(&Descriptor(fd));
if locked.remove(&fd).is_none() {
error!("fail to remove handler for file descriptor {}", fd);
}
@@ -153,39 +142,45 @@
}
/// Add a new event to event loop. The event handler will be invoked when `event` happens on
- /// `fd`.
+ /// `descriptor`.
///
- /// If the same `fd` is added multiple times, the old handler will be replaced.
+ /// If the same `descriptor` 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,
+ descriptor: &dyn AsRawDescriptor,
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);
+ self.handlers
+ .lock()
+ .insert(descriptor.as_raw_descriptor(), 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)
+ .add_fd_with_events(
+ &wrap_descriptor(descriptor),
+ events,
+ Descriptor(descriptor.as_raw_descriptor()),
+ )
+ .map_err(Error::WaitContextAddDescriptor)
}
- /// Removes event for this `fd`. This function returns false if it fails.
+ /// Removes event for this `descriptor`. 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<()> {
+ /// EventLoop does not guarantee all events for `descriptor` is handled.
+ pub fn remove_event_for_fd(&self, descriptor: &dyn AsRawDescriptor) -> 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());
+ .delete(&wrap_descriptor(descriptor))
+ .map_err(Error::WaitContextDeleteDescriptor)?;
+ self.handlers.lock().remove(&descriptor.as_raw_descriptor());
Ok(())
}
diff --git a/devices/src/vfio.rs b/devices/src/vfio.rs
index d3a1f26..24db879 100644
--- a/devices/src/vfio.rs
+++ b/devices/src/vfio.rs
@@ -9,7 +9,6 @@
use std::fs::{File, OpenOptions};
use std::io;
use std::mem;
-use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::os::unix::prelude::FileExt;
use std::path::{Path, PathBuf};
use std::sync::Arc;
@@ -18,7 +17,7 @@
use base::{
ioctl, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref, ioctl_with_val, warn,
- AsRawDescriptor, Error, Event, RawDescriptor, SafeDescriptor,
+ AsRawDescriptor, Error, Event, FromRawDescriptor, RawDescriptor, SafeDescriptor,
};
use hypervisor::{DeviceKind, Vm};
use vm_memory::GuestMemory;
@@ -97,7 +96,7 @@
.open("/dev/vfio/vfio")
.map_err(VfioError::OpenContainer)?;
- // Safe as file is vfio container fd and ioctl is defined by kernel.
+ // Safe as file is vfio container descriptor and ioctl is defined by kernel.
let version = unsafe { ioctl(&container, VFIO_GET_API_VERSION()) };
if version as u8 != VFIO_API_VERSION {
return Err(VfioError::VfioApiVersion);
@@ -219,9 +218,9 @@
}
}
-impl AsRawFd for VfioContainer {
- fn as_raw_fd(&self) -> RawFd {
- self.container.as_raw_fd()
+impl AsRawDescriptor for VfioContainer {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.container.as_raw_descriptor()
}
}
@@ -256,10 +255,16 @@
return Err(VfioError::GroupViable);
}
- // Safe as we are the owner of group_file and container_raw_fd which are valid value,
+ // Safe as we are the owner of group_file and container_raw_descriptor which are valid value,
// and we verify the ret value
- let container_raw_fd = container.as_raw_fd();
- ret = unsafe { ioctl_with_ref(&group_file, VFIO_GROUP_SET_CONTAINER(), &container_raw_fd) };
+ let container_raw_descriptor = container.as_raw_descriptor();
+ ret = unsafe {
+ ioctl_with_ref(
+ &group_file,
+ VFIO_GROUP_SET_CONTAINER(),
+ &container_raw_descriptor,
+ )
+ };
if ret < 0 {
return Err(VfioError::GroupSetContainer(get_error()));
}
@@ -268,13 +273,13 @@
}
fn kvm_device_add_group(&self, kvm_vfio_file: &SafeDescriptor) -> Result<(), VfioError> {
- let group_fd = self.as_raw_fd();
- let group_fd_ptr = &group_fd as *const i32;
+ let group_descriptor = self.as_raw_descriptor();
+ let group_descriptor_ptr = &group_descriptor as *const i32;
let vfio_dev_attr = kvm_sys::kvm_device_attr {
flags: 0,
group: kvm_sys::KVM_DEV_VFIO_GROUP,
attr: kvm_sys::KVM_DEV_VFIO_GROUP_ADD as u64,
- addr: group_fd_ptr as u64,
+ addr: group_descriptor_ptr as u64,
};
// Safe as we are the owner of vfio_dev_fd and vfio_dev_attr which are valid value,
@@ -305,13 +310,13 @@
}
// Safe as ret is valid FD
- Ok(unsafe { File::from_raw_fd(ret) })
+ Ok(unsafe { File::from_raw_descriptor(ret) })
}
}
-impl AsRawFd for VfioGroup {
- fn as_raw_fd(&self) -> RawFd {
- self.group.as_raw_fd()
+impl AsRawDescriptor for VfioGroup {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.group.as_raw_descriptor()
}
}
@@ -326,7 +331,7 @@
// flags for this region: read/write/mmap
flags: u32,
size: u64,
- // region offset used to read/write with vfio device fd
+ // region offset used to read/write with vfio device descriptor
offset: u64,
// vectors for mmap offset and size
mmaps: Vec<vfio_region_sparse_mmap_area>,
@@ -338,7 +343,7 @@
pub struct VfioDevice {
dev: File,
container: Arc<Mutex<VfioContainer>>,
- group_fd: RawFd,
+ group_descriptor: RawDescriptor,
// vec for vfio device's regions
regions: Vec<VfioRegion>,
}
@@ -370,16 +375,20 @@
Ok(VfioDevice {
dev: new_dev,
container,
- group_fd: group.as_raw_fd(),
+ group_descriptor: group.as_raw_descriptor(),
regions: dev_regions,
})
}
/// Enable vfio device's irq and associate Irqfd Event with device.
- /// When MSIx is enabled, multi vectors will be supported, so fds is vector and the vector
+ /// When MSIx is enabled, multi vectors will be supported, so descriptors is vector and the vector
/// length is the num of MSIx vectors
- pub fn irq_enable(&self, fds: Vec<&Event>, irq_type: VfioIrqType) -> Result<(), VfioError> {
- let count = fds.len();
+ pub fn irq_enable(
+ &self,
+ descriptors: Vec<&Event>,
+ irq_type: VfioIrqType,
+ ) -> Result<(), VfioError> {
+ let count = descriptors.len();
let u32_size = mem::size_of::<u32>();
let mut irq_set = vec_with_array_field::<vfio_irq_set, u32>(count);
irq_set[0].argsz = (mem::size_of::<vfio_irq_set>() + count * u32_size) as u32;
@@ -392,14 +401,14 @@
irq_set[0].start = 0;
irq_set[0].count = count as u32;
- // irq_set.data could be none, bool or fd according to flags, so irq_set.data
- // is u8 default, here irq_set.data is fd as u32, so 4 default u8 are combined
+ // irq_set.data could be none, bool or descriptor according to flags, so irq_set.data
+ // is u8 default, here irq_set.data is descriptor as u32, so 4 default u8 are combined
// together as u32. It is safe as enough space is reserved through
// vec_with_array_field(u32)<count>.
let mut data = unsafe { irq_set[0].data.as_mut_slice(count * u32_size) };
- for fd in fds.iter().take(count) {
+ for descriptor in descriptors.iter().take(count) {
let (left, right) = data.split_at_mut(u32_size);
- left.copy_from_slice(&fd.as_raw_fd().to_ne_bytes()[..]);
+ left.copy_from_slice(&descriptor.as_raw_descriptor().to_ne_bytes()[..]);
data = right;
}
@@ -420,8 +429,8 @@
/// generate another interrupts.
/// This function enable resample irqfd and let vfio kernel could get EOI notification.
///
- /// fd: should be resample IrqFd.
- pub fn resample_virq_enable(&self, fd: &Event) -> Result<(), VfioError> {
+ /// descriptor: should be resample IrqFd.
+ pub fn resample_virq_enable(&self, descriptor: &Event) -> Result<(), VfioError> {
let mut irq_set = vec_with_array_field::<vfio_irq_set, u32>(1);
irq_set[0].argsz = (mem::size_of::<vfio_irq_set>() + mem::size_of::<u32>()) as u32;
irq_set[0].flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK;
@@ -430,12 +439,12 @@
irq_set[0].count = 1;
{
- // irq_set.data could be none, bool or fd according to flags, so irq_set.data
- // is u8 default, here irq_set.data is fd as u32, so 4 default u8 are combined
+ // irq_set.data could be none, bool or descriptor according to flags, so irq_set.data
+ // is u8 default, here irq_set.data is descriptor as u32, so 4 default u8 are combined
// together as u32. It is safe as enough space is reserved through
// vec_with_array_field(u32)<1>.
- let fds = unsafe { irq_set[0].data.as_mut_slice(4) };
- fds.copy_from_slice(&fd.as_raw_fd().to_le_bytes()[..]);
+ let descriptors = unsafe { irq_set[0].data.as_mut_slice(4) };
+ descriptors.copy_from_slice(&descriptor.as_raw_descriptor().to_le_bytes()[..]);
}
// Safe as we are the owner of self and irq_set which are valid value
@@ -675,7 +684,7 @@
}
/// get a region's offset
- /// return: Region offset from the start of vfio device fd
+ /// return: Region offset from the start of vfio device descriptor
pub fn get_region_offset(&self, index: u32) -> u64 {
match self.regions.get(index as usize) {
Some(v) => v.offset,
@@ -782,13 +791,13 @@
}
}
- /// get vfio device's fds which are passed into minijail process
- pub fn keep_fds(&self) -> Vec<RawFd> {
- let mut fds = Vec::new();
- fds.push(self.as_raw_fd());
- fds.push(self.group_fd);
- fds.push(self.container.lock().as_raw_fd());
- fds
+ /// get vfio device's descriptors which are passed into minijail process
+ pub fn keep_rds(&self) -> Vec<RawDescriptor> {
+ let mut rds = Vec::new();
+ rds.push(self.as_raw_descriptor());
+ rds.push(self.group_descriptor);
+ rds.push(self.container.lock().as_raw_descriptor());
+ rds
}
/// Add (iova, user_addr) map into vfio container iommu table
@@ -807,13 +816,6 @@
}
}
-// TODO(mikehoyle): Remove this in favor of AsRawDescriptor
-impl AsRawFd for VfioDevice {
- fn as_raw_fd(&self) -> RawFd {
- self.dev.as_raw_fd()
- }
-}
-
impl AsRawDescriptor for VfioDevice {
fn as_raw_descriptor(&self) -> RawDescriptor {
self.dev.as_raw_descriptor()
diff --git a/devices/src/virtio/balloon.rs b/devices/src/virtio/balloon.rs
index 9820dbf..83184b9 100644
--- a/devices/src/virtio/balloon.rs
+++ b/devices/src/virtio/balloon.rs
@@ -3,12 +3,13 @@
// found in the LICENSE file.
use std::fmt::{self, Display};
-use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
-use base::{self, error, info, warn, Event, PollContext, PollToken};
+use base::{
+ self, error, info, warn, AsRawDescriptor, Event, PollToken, RawDescriptor, WaitContext,
+};
use data_model::{DataInit, Le16, Le32, Le64};
use msg_socket::{MsgReceiver, MsgSender};
use vm_control::{
@@ -228,7 +229,7 @@
let deflate_queue_evt = queue_evts.remove(0);
let stats_queue_evt = queue_evts.remove(0);
- let poll_ctx: PollContext<Token> = match PollContext::build_with(&[
+ let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
(&inflate_queue_evt, Token::Inflate),
(&deflate_queue_evt, Token::Deflate),
(&stats_queue_evt, Token::Stats),
@@ -238,13 +239,13 @@
]) {
Ok(pc) => pc,
Err(e) => {
- error!("failed creating PollContext: {}", e);
+ error!("failed creating WaitContext: {}", e);
return;
}
};
- 'poll: loop {
- let events = match poll_ctx.wait() {
+ 'wait: loop {
+ let events = match wait_ctx.wait() {
Ok(v) => v,
Err(e) => {
error!("failed polling for events: {}", e);
@@ -254,26 +255,26 @@
let mut needs_interrupt_inflate = false;
let mut needs_interrupt_deflate = false;
- for event in events.iter_readable() {
- match event.token() {
+ for event in events.iter().filter(|e| e.is_readable) {
+ match event.token {
Token::Inflate => {
if let Err(e) = inflate_queue_evt.read() {
error!("failed reading inflate queue Event: {}", e);
- break 'poll;
+ break 'wait;
}
needs_interrupt_inflate |= self.process_inflate_deflate(true);
}
Token::Deflate => {
if let Err(e) = deflate_queue_evt.read() {
error!("failed reading deflate queue Event: {}", e);
- break 'poll;
+ break 'wait;
}
needs_interrupt_deflate |= self.process_inflate_deflate(false);
}
Token::Stats => {
if let Err(e) = stats_queue_evt.read() {
error!("failed reading stats queue Event: {}", e);
- break 'poll;
+ break 'wait;
}
self.process_stats();
}
@@ -297,14 +298,14 @@
Token::InterruptResample => {
self.interrupt.interrupt_resample();
}
- Token::Kill => break 'poll,
+ Token::Kill => break 'wait,
}
}
- for event in events.iter_hungup() {
- if event.token() == Token::CommandSocket && !event.readable() {
+ for event in events.iter().filter(|e| e.is_hungup) {
+ if event.token == Token::CommandSocket && !event.is_readable {
// If this call fails, the command socket was already removed from the
- // PollContext.
- let _ = poll_ctx.delete(&self.command_socket);
+ // WaitContext.
+ let _ = wait_ctx.delete(&self.command_socket);
}
}
@@ -373,8 +374,8 @@
}
impl VirtioDevice for Balloon {
- fn keep_fds(&self) -> Vec<RawFd> {
- vec![self.command_socket.as_ref().unwrap().as_raw_fd()]
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ vec![self.command_socket.as_ref().unwrap().as_raw_descriptor()]
}
fn device_type(&self) -> u32 {
diff --git a/devices/src/virtio/block.rs b/devices/src/virtio/block.rs
index 271d5f7..79e8458 100644
--- a/devices/src/virtio/block.rs
+++ b/devices/src/virtio/block.rs
@@ -6,7 +6,6 @@
use std::fmt::{self, Display};
use std::io::{self, Write};
use std::mem::size_of;
-use std::os::unix::io::{AsRawFd, RawFd};
use std::result;
use std::sync::Arc;
use std::thread;
@@ -15,7 +14,10 @@
use base::Error as SysError;
use base::Result as SysResult;
-use base::{error, info, iov_max, warn, Event, PollContext, PollToken, Timer};
+use base::{
+ error, info, iov_max, warn, AsRawDescriptor, Event, PollToken, RawDescriptor, Timer,
+ WaitContext,
+};
use data_model::{DataInit, Le16, Le32, Le64};
use disk::DiskFile;
use msg_socket::{MsgReceiver, MsgSender};
@@ -377,7 +379,7 @@
};
let mut flush_timer_armed = false;
- let poll_ctx: PollContext<Token> = match PollContext::build_with(&[
+ let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
(&flush_timer, Token::FlushTimer),
(&queue_evt, Token::QueueAvailable),
(self.interrupt.get_resample_evt(), Token::InterruptResample),
@@ -391,13 +393,13 @@
}) {
Ok(pc) => pc,
Err(e) => {
- error!("failed creating PollContext: {}", e);
+ error!("failed creating WaitContext: {}", e);
return;
}
};
- 'poll: loop {
- let events = match poll_ctx.wait() {
+ 'wait: loop {
+ let events = match wait_ctx.wait() {
Ok(v) => v,
Err(e) => {
error!("failed polling for events: {}", e);
@@ -406,22 +408,22 @@
};
let mut needs_config_interrupt = false;
- for event in events.iter_readable() {
- match event.token() {
+ for event in events.iter().filter(|e| e.is_readable) {
+ match event.token {
Token::FlushTimer => {
if let Err(e) = self.disk_image.fsync() {
error!("Failed to flush the disk: {}", e);
- break 'poll;
+ break 'wait;
}
if let Err(e) = flush_timer.wait() {
error!("Failed to clear flush timer: {}", e);
- break 'poll;
+ break 'wait;
}
}
Token::QueueAvailable => {
if let Err(e) = queue_evt.read() {
error!("failed reading queue Event: {}", e);
- break 'poll;
+ break 'wait;
}
self.process_queue(0, &mut flush_timer, &mut flush_timer_armed);
}
@@ -430,14 +432,14 @@
Some(cs) => cs,
None => {
error!("received control socket request with no control socket");
- break 'poll;
+ break 'wait;
}
};
let req = match control_socket.recv() {
Ok(req) => req,
Err(e) => {
error!("control socket failed recv: {}", e);
- break 'poll;
+ break 'wait;
}
};
@@ -454,13 +456,13 @@
// We already know there is Some control_socket used to recv a request.
if let Err(e) = self.control_socket.as_ref().unwrap().send(&resp) {
error!("control socket failed send: {}", e);
- break 'poll;
+ break 'wait;
}
}
Token::InterruptResample => {
self.interrupt.interrupt_resample();
}
- Token::Kill => break 'poll,
+ Token::Kill => break 'wait,
}
}
if needs_config_interrupt {
@@ -716,18 +718,18 @@
}
impl VirtioDevice for Block {
- fn keep_fds(&self) -> Vec<RawFd> {
- let mut keep_fds = Vec::new();
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ let mut keep_rds = Vec::new();
if let Some(disk_image) = &self.disk_image {
- keep_fds.extend(disk_image.as_raw_descriptors());
+ keep_rds.extend(disk_image.as_raw_descriptors());
}
if let Some(control_socket) = &self.control_socket {
- keep_fds.push(control_socket.as_raw_fd());
+ keep_rds.push(control_socket.as_raw_descriptor());
}
- keep_fds
+ keep_rds
}
fn features(&self) -> u64 {
diff --git a/devices/src/virtio/console.rs b/devices/src/virtio/console.rs
index bd6da3d..93945da 100644
--- a/devices/src/virtio/console.rs
+++ b/devices/src/virtio/console.rs
@@ -3,11 +3,10 @@
// found in the LICENSE file.
use std::io::{self, Read, Write};
-use std::os::unix::io::RawFd;
use std::sync::mpsc::{channel, Receiver, TryRecvError};
use std::thread;
-use base::{error, Event, PollContext, PollToken};
+use base::{error, Event, PollToken, RawDescriptor, WaitContext};
use data_model::{DataInit, Le16, Le32};
use vm_memory::GuestMemory;
@@ -236,7 +235,7 @@
// the main worker thread with an event for notification bridges this gap.
let mut in_channel = self.spawn_input_thread(&in_avail_evt);
- let poll_ctx: PollContext<Token> = match PollContext::build_with(&[
+ let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
(&transmit_evt, Token::TransmitQueueAvailable),
(&receive_evt, Token::ReceiveQueueAvailable),
(&in_avail_evt, Token::InputAvailable),
@@ -245,7 +244,7 @@
]) {
Ok(pc) => pc,
Err(e) => {
- error!("failed creating PollContext: {}", e);
+ error!("failed creating WaitContext: {}", e);
return;
}
};
@@ -255,8 +254,8 @@
None => Box::new(io::sink()),
};
- 'poll: loop {
- let events = match poll_ctx.wait() {
+ 'wait: loop {
+ let events = match wait_ctx.wait() {
Ok(v) => v,
Err(e) => {
error!("failed polling for events: {}", e);
@@ -264,33 +263,33 @@
}
};
- for event in events.iter_readable() {
- match event.token() {
+ for event in events.iter().filter(|e| e.is_readable) {
+ match event.token {
Token::TransmitQueueAvailable => {
if let Err(e) = transmit_evt.read() {
error!("failed reading transmit queue Event: {}", e);
- break 'poll;
+ break 'wait;
}
self.process_transmit_queue(&mut transmit_queue, &mut output);
}
Token::ReceiveQueueAvailable => {
if let Err(e) = receive_evt.read() {
error!("failed reading receive queue Event: {}", e);
- break 'poll;
+ break 'wait;
}
self.handle_input(&mut in_channel, &mut receive_queue);
}
Token::InputAvailable => {
if let Err(e) = in_avail_evt.read() {
error!("failed reading in_avail_evt: {}", e);
- break 'poll;
+ break 'wait;
}
self.handle_input(&mut in_channel, &mut receive_queue);
}
Token::InterruptResample => {
self.interrupt.interrupt_resample();
}
- Token::Kill => break 'poll,
+ Token::Kill => break 'wait,
}
}
}
@@ -304,7 +303,7 @@
worker_thread: Option<thread::JoinHandle<Worker>>,
input: Option<Box<dyn io::Read + Send>>,
output: Option<Box<dyn io::Write + Send>>,
- keep_fds: Vec<RawFd>,
+ keep_rds: Vec<RawDescriptor>,
}
impl SerialDevice for Console {
@@ -313,7 +312,7 @@
_evt: Event,
input: Option<Box<dyn io::Read + Send>>,
output: Option<Box<dyn io::Write + Send>>,
- keep_fds: Vec<RawFd>,
+ keep_rds: Vec<RawDescriptor>,
) -> Console {
Console {
base_features: base_features(protected_vm),
@@ -321,7 +320,7 @@
worker_thread: None,
input,
output,
- keep_fds,
+ keep_rds,
}
}
}
@@ -340,8 +339,8 @@
}
impl VirtioDevice for Console {
- fn keep_fds(&self) -> Vec<RawFd> {
- self.keep_fds.clone()
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ self.keep_rds.clone()
}
fn features(&self) -> u64 {
diff --git a/devices/src/virtio/fs/mod.rs b/devices/src/virtio/fs/mod.rs
index a877270..6c4a3b4 100644
--- a/devices/src/virtio/fs/mod.rs
+++ b/devices/src/virtio/fs/mod.rs
@@ -2,33 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use std::ffi::FromBytesWithNulError;
use std::fmt;
use std::io;
use std::mem;
-use std::os::unix::io::RawFd;
use std::sync::Arc;
use std::thread;
-use base::{error, warn, Error as SysError, Event};
+use base::{error, warn, Error as SysError, Event, RawDescriptor};
use data_model::{DataInit, Le32};
use vm_memory::GuestMemory;
use crate::virtio::{copy_config, DescriptorError, Interrupt, Queue, VirtioDevice, TYPE_FS};
-mod filesystem;
-#[allow(dead_code)]
-mod fuse;
-#[cfg(fuzzing)]
-pub mod fuzzing;
mod multikey;
pub mod passthrough;
mod read_dir;
-mod server;
mod worker;
+use fuse::Server;
use passthrough::PassthroughFs;
-use server::Server;
use worker::Worker;
// The fs device does not have a fixed number of queues.
@@ -57,10 +49,10 @@
TagTooLong(usize),
/// Failed to create the file system.
CreateFs(io::Error),
- /// Creating PollContext failed.
- CreatePollContext(SysError),
+ /// Creating WaitContext failed.
+ CreateWaitContext(SysError),
/// Error while polling for events.
- PollError(SysError),
+ WaitError(SysError),
/// Error while reading from the virtio queue's Event.
ReadQueueEvent(SysError),
/// A request is missing readable descriptors.
@@ -69,27 +61,20 @@
NoWritableDescriptors,
/// Failed to signal the virio used queue.
SignalUsedQueue(SysError),
- /// Failed to decode protocol messages.
- DecodeMessage(io::Error),
- /// Failed to encode protocol messages.
- EncodeMessage(io::Error),
- /// One or more parameters are missing.
- MissingParameter,
- /// A C string parameter is invalid.
- InvalidCString(FromBytesWithNulError),
/// The `len` field of the header is too small.
- InvalidHeaderLength,
- /// A `DescriptorChain` contains invalid data.
InvalidDescriptorChain(DescriptorError),
- /// The `size` field of the `SetxattrIn` message does not match the length
- /// of the decoded value.
- InvalidXattrSize((u32, usize)),
- /// Requested too many `iovec`s for an `ioctl` retry.
- TooManyIovecs((usize, usize)),
+ /// Error happened in FUSE.
+ FuseError(fuse::Error),
}
impl ::std::error::Error for Error {}
+impl From<fuse::Error> for Error {
+ fn from(err: fuse::Error) -> Error {
+ Error::FuseError(err)
+ }
+}
+
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
@@ -100,29 +85,14 @@
len, FS_MAX_TAG_LEN
),
CreateFs(err) => write!(f, "failed to create file system: {}", err),
- CreatePollContext(err) => write!(f, "failed to create PollContext: {}", err),
- PollError(err) => write!(f, "failed to poll events: {}", err),
+ CreateWaitContext(err) => write!(f, "failed to create WaitContext: {}", err),
+ WaitError(err) => write!(f, "failed to wait for events: {}", err),
ReadQueueEvent(err) => write!(f, "failed to read from virtio queue Event: {}", err),
NoReadableDescriptors => write!(f, "request does not have any readable descriptors"),
NoWritableDescriptors => write!(f, "request does not have any writable descriptors"),
SignalUsedQueue(err) => write!(f, "failed to signal used queue: {}", err),
- DecodeMessage(err) => write!(f, "failed to decode fuse message: {}", err),
- EncodeMessage(err) => write!(f, "failed to encode fuse message: {}", err),
- MissingParameter => write!(f, "one or more parameters are missing"),
- InvalidHeaderLength => write!(f, "the `len` field of the header is too small"),
- InvalidCString(err) => write!(f, "a c string parameter is invalid: {}", err),
InvalidDescriptorChain(err) => write!(f, "DescriptorChain is invalid: {}", err),
- InvalidXattrSize((size, len)) => write!(
- f,
- "The `size` field of the `SetxattrIn` message does not match the length of the\
- decoded value: size = {}, value.len() = {}",
- size, len
- ),
- TooManyIovecs((count, max)) => write!(
- f,
- "requested too many `iovec`s for an `ioctl` retry reply: requested {}, max: {}",
- count, max
- ),
+ FuseError(err) => write!(f, "fuse error: {}", err),
}
}
}
@@ -193,10 +163,10 @@
}
impl VirtioDevice for Fs {
- fn keep_fds(&self) -> Vec<RawFd> {
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
self.fs
.as_ref()
- .map(PassthroughFs::keep_fds)
+ .map(PassthroughFs::keep_rds)
.unwrap_or_else(Vec::new)
}
diff --git a/devices/src/virtio/fs/passthrough.rs b/devices/src/virtio/fs/passthrough.rs
index b6700b1..f4591bb 100644
--- a/devices/src/virtio/fs/passthrough.rs
+++ b/devices/src/virtio/fs/passthrough.rs
@@ -11,24 +11,25 @@
use std::io;
use std::mem::{self, size_of, MaybeUninit};
use std::os::raw::{c_int, c_long};
-use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::ptr;
use std::str::FromStr;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::Arc;
use std::time::Duration;
-use base::{error, ioctl_ior_nr, ioctl_iow_nr, ioctl_with_mut_ptr, ioctl_with_ptr, warn};
+use base::{
+ error, ioctl_ior_nr, ioctl_iow_nr, ioctl_with_mut_ptr, ioctl_with_ptr, warn, AsRawDescriptor,
+ FromRawDescriptor, RawDescriptor,
+};
use data_model::DataInit;
+use fuse::filesystem::{
+ Context, DirectoryIterator, Entry, FileSystem, FsOptions, GetxattrReply, IoctlFlags,
+ IoctlIovec, IoctlReply, ListxattrReply, OpenOptions, SetattrValid, ZeroCopyReader,
+ ZeroCopyWriter, ROOT_ID,
+};
use rand_ish::SimpleRng;
use sync::Mutex;
-use crate::virtio::fs::filesystem::{
- Context, DirectoryIterator, Entry, FileSystem, FsOptions, GetxattrReply, IoctlFlags,
- IoctlIovec, IoctlReply, ListxattrReply, OpenOptions, SetattrValid, ZeroCopyReader,
- ZeroCopyWriter,
-};
-use crate::virtio::fs::fuse;
use crate::virtio::fs::multikey::MultikeyBTreeMap;
use crate::virtio::fs::read_dir::ReadDir;
@@ -221,9 +222,9 @@
let fscreate = unsafe { CStr::from_bytes_with_nul_unchecked(b"thread-self/attr/fscreate\0") };
// Safe because this doesn't modify any memory and we check the return value.
- let fd = unsafe {
+ let raw_descriptor = unsafe {
libc::openat(
- proc.as_raw_fd(),
+ proc.as_raw_descriptor(),
fscreate.as_ptr(),
libc::O_CLOEXEC | libc::O_WRONLY,
)
@@ -231,15 +232,15 @@
// We don't expect this to fail and we're not in a position to return an error here so just
// panic.
- if fd < 0 {
+ if raw_descriptor < 0 {
panic!(
"Failed to open /proc/thread-self/attr/fscreate: {}",
io::Error::last_os_error()
);
}
- // Safe because we just opened this fd.
- unsafe { File::from_raw_fd(fd) }
+ // Safe because we just opened this descriptor.
+ unsafe { File::from_raw_descriptor(raw_descriptor) }
}
struct ScopedSecurityContext;
@@ -252,7 +253,7 @@
// Safe because this doesn't modify any memory and we check the return value.
let ret = unsafe {
libc::write(
- file.as_raw_fd(),
+ file.as_raw_descriptor(),
ctx.as_ptr() as *const libc::c_void,
ctx.to_bytes_with_nul().len(),
)
@@ -277,7 +278,7 @@
.expect("Uninitialized thread-local when dropping ScopedSecurityContext");
// Safe because this doesn't modify any memory and we check the return value.
- let ret = unsafe { libc::write(file.as_raw_fd(), ptr::null(), 0) };
+ let ret = unsafe { libc::write(file.as_raw_descriptor(), ptr::null(), 0) };
if ret < 0 {
warn!(
@@ -303,7 +304,7 @@
// value.
let res = unsafe {
libc::fstatat64(
- f.as_raw_fd(),
+ f.as_raw_descriptor(),
pathname.as_ptr(),
st.as_mut_ptr(),
libc::AT_EMPTY_PATH | libc::AT_SYMLINK_NOFOLLOW,
@@ -462,23 +463,23 @@
let proc_cstr = unsafe { CStr::from_bytes_with_nul_unchecked(PROC_CSTR) };
// Safe because this doesn't modify any memory and we check the return value.
- let fd = unsafe {
+ let raw_descriptor = unsafe {
libc::openat(
libc::AT_FDCWD,
proc_cstr.as_ptr(),
libc::O_PATH | libc::O_NOFOLLOW | libc::O_CLOEXEC,
)
};
- if fd < 0 {
+ if raw_descriptor < 0 {
return Err(io::Error::last_os_error());
}
- // Safe because we just opened this fd.
- let proc = unsafe { File::from_raw_fd(fd) };
+ // Safe because we just opened this descriptor.
+ let proc = unsafe { File::from_raw_descriptor(raw_descriptor) };
Ok(PassthroughFs {
inodes: Mutex::new(MultikeyBTreeMap::new()),
- next_inode: AtomicU64::new(fuse::ROOT_ID + 1),
+ next_inode: AtomicU64::new(ROOT_ID + 1),
handles: Mutex::new(BTreeMap::new()),
next_handle: AtomicU64::new(0),
@@ -491,8 +492,8 @@
})
}
- pub fn keep_fds(&self) -> Vec<RawFd> {
- vec![self.proc.as_raw_fd()]
+ pub fn keep_rds(&self) -> Vec<RawDescriptor> {
+ vec![self.proc.as_raw_descriptor()]
}
fn rewrite_xattr_name<'xattr>(&self, name: &'xattr CStr) -> Cow<'xattr, CStr> {
@@ -532,7 +533,7 @@
}
fn open_inode(&self, inode: &InodeData, mut flags: i32) -> io::Result<File> {
- let pathname = CString::new(format!("self/fd/{}", inode.file.as_raw_fd()))
+ let pathname = CString::new(format!("self/fd/{}", inode.file.as_raw_descriptor()))
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
// When writeback caching is enabled, the kernel may send read requests even if the
@@ -558,23 +559,23 @@
// really check `flags` because if the kernel can't handle poorly specified flags then we
// have much bigger problems. Also, clear the `O_NOFOLLOW` flag if it is set since we need
// to follow the `/proc/self/fd` symlink to get the file.
- let fd = unsafe {
+ let raw_descriptor = unsafe {
libc::openat(
- self.proc.as_raw_fd(),
+ self.proc.as_raw_descriptor(),
pathname.as_ptr(),
(flags | libc::O_CLOEXEC) & !(libc::O_NOFOLLOW | libc::O_DIRECT),
)
};
- if fd < 0 {
+ if raw_descriptor < 0 {
return Err(io::Error::last_os_error());
}
- // Safe because we just opened this fd.
- Ok(unsafe { File::from_raw_fd(fd) })
+ // Safe because we just opened this descriptor.
+ Ok(unsafe { File::from_raw_descriptor(raw_descriptor) })
}
// Performs an ascii case insensitive lookup and returns an O_PATH fd for the entry, if found.
- fn ascii_casefold_lookup(&self, dir: &InodeData, name: &[u8]) -> io::Result<RawFd> {
+ fn ascii_casefold_lookup(&self, dir: &InodeData, name: &[u8]) -> io::Result<RawDescriptor> {
let parent = self.open_inode(dir, libc::O_RDONLY | libc::O_DIRECTORY)?;
let mut buf = [0u8; 1024];
let mut offset = 0;
@@ -589,7 +590,7 @@
if name.eq_ignore_ascii_case(entry.name.to_bytes()) {
return Ok(unsafe {
libc::openat(
- parent.as_raw_fd(),
+ parent.as_raw_descriptor(),
entry.name.as_ptr(),
libc::O_PATH | libc::O_NOFOLLOW | libc::O_CLOEXEC,
)
@@ -601,30 +602,30 @@
}
fn do_lookup(&self, parent: &InodeData, name: &CStr) -> io::Result<Entry> {
- let fd = {
+ let raw_descriptor = {
// Safe because this doesn't modify any memory and we check the return value.
- let fd = unsafe {
+ let raw_descriptor = unsafe {
libc::openat(
- parent.file.as_raw_fd(),
+ parent.file.as_raw_descriptor(),
name.as_ptr(),
libc::O_PATH | libc::O_NOFOLLOW | libc::O_CLOEXEC,
)
};
- if fd < 0 && self.cfg.ascii_casefold {
+ if raw_descriptor < 0 && self.cfg.ascii_casefold {
// Ignore any errors during casefold lookup.
self.ascii_casefold_lookup(parent, name.to_bytes())
- .unwrap_or(fd)
+ .unwrap_or(raw_descriptor)
} else {
- fd
+ raw_descriptor
}
};
- if fd < 0 {
+ if raw_descriptor < 0 {
return Err(io::Error::last_os_error());
}
- // Safe because we just opened this fd.
- let f = unsafe { File::from_raw_fd(fd) };
+ // Safe because we just opened this descriptor.
+ let f = unsafe { File::from_raw_descriptor(raw_descriptor) };
let st = stat(&f)?;
@@ -722,7 +723,7 @@
fn do_unlink(&self, parent: &InodeData, name: &CStr, flags: libc::c_int) -> io::Result<()> {
// Safe because this doesn't modify any memory and we check the return value.
- let res = unsafe { libc::unlinkat(parent.file.as_raw_fd(), name.as_ptr(), flags) };
+ let res = unsafe { libc::unlinkat(parent.file.as_raw_descriptor(), name.as_ptr(), flags) };
if res == 0 {
Ok(())
} else {
@@ -738,14 +739,12 @@
where
F: FnOnce() -> T,
{
- let root = self
- .find_inode(fuse::ROOT_ID)
- .expect("failed to find root inode");
+ let root = self.find_inode(ROOT_ID).expect("failed to find root inode");
let chdir_lock = self.chdir_mutex.lock();
// Safe because this doesn't modify any memory and we check the return value. Since the
// fchdir should never fail we just use debug_asserts.
- let proc_cwd = unsafe { libc::fchdir(self.proc.as_raw_fd()) };
+ let proc_cwd = unsafe { libc::fchdir(self.proc.as_raw_descriptor()) };
debug_assert_eq!(
proc_cwd,
0,
@@ -757,7 +756,7 @@
// Safe because this doesn't modify any memory and we check the return value. Since the
// fchdir should never fail we just use debug_asserts.
- let root_cwd = unsafe { libc::fchdir(root.file.as_raw_fd()) };
+ let root_cwd = unsafe { libc::fchdir(root.file.as_raw_descriptor()) };
debug_assert_eq!(
root_cwd,
0,
@@ -774,7 +773,7 @@
// For non-regular files and directories, we cannot open the fd normally. Instead we
// emulate an _at syscall by changing the CWD to /proc, running the path based syscall,
// and then setting the CWD back to the root directory.
- let path = CString::new(format!("self/fd/{}", inode.file.as_raw_fd()))
+ let path = CString::new(format!("self/fd/{}", inode.file.as_raw_descriptor()))
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
// Safe because this will only modify `value` and we check the return value.
@@ -798,7 +797,7 @@
// Safe because this will only write to `value` and we check the return value.
unsafe {
libc::fgetxattr(
- f.as_raw_fd(),
+ f.as_raw_descriptor(),
name.as_ptr(),
value.as_mut_ptr() as *mut libc::c_void,
value.len() as libc::size_t,
@@ -1054,7 +1053,7 @@
let name = CString::new(name).expect("SimpleRng produced string with nul-bytes");
// Safe because this doesn't modify any memory and we check the return value.
- let ret = unsafe { libc::mkdirat(parent.as_raw_fd(), name.as_ptr(), mode) };
+ let ret = unsafe { libc::mkdirat(parent.as_raw_descriptor(), name.as_ptr(), mode) };
if ret == 0 {
return Ok(name);
}
@@ -1089,22 +1088,22 @@
let name = create_temp_dir(parent, mode)?;
// Safe because this doesn't modify any memory and we check the return value.
- let fd = unsafe {
+ let raw_descriptor = unsafe {
libc::openat(
- parent.as_raw_fd(),
+ parent.as_raw_descriptor(),
name.as_ptr(),
libc::O_DIRECTORY | libc::O_CLOEXEC,
)
};
- if fd < 0 {
+ if raw_descriptor < 0 {
return Err(io::Error::last_os_error());
}
Ok(TempDir {
parent,
name,
- // Safe because we just opened this fd.
- file: unsafe { File::from_raw_fd(fd) },
+ // Safe because we just opened this descriptor.
+ file: unsafe { File::from_raw_descriptor(raw_descriptor) },
})
}
@@ -1126,9 +1125,9 @@
}
}
-impl<'a> AsRawFd for TempDir<'a> {
- fn as_raw_fd(&self) -> RawFd {
- self.file.as_raw_fd()
+impl<'a> AsRawDescriptor for TempDir<'a> {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.file.as_raw_descriptor()
}
}
@@ -1137,7 +1136,7 @@
// Safe because this doesn't modify any memory and we check the return value.
let ret = unsafe {
libc::unlinkat(
- self.parent.as_raw_fd(),
+ self.parent.as_raw_descriptor(),
self.name.as_ptr(),
libc::AT_REMOVEDIR,
)
@@ -1161,19 +1160,19 @@
// Safe because this doesn't modify any memory and we check the return value.
// We use `O_PATH` because we just want this for traversing the directory tree
// and not for actually reading the contents.
- let fd = unsafe {
+ let raw_descriptor = unsafe {
libc::openat(
libc::AT_FDCWD,
root.as_ptr(),
libc::O_PATH | libc::O_NOFOLLOW | libc::O_CLOEXEC,
)
};
- if fd < 0 {
+ if raw_descriptor < 0 {
return Err(io::Error::last_os_error());
}
- // Safe because we just opened this fd above.
- let f = unsafe { File::from_raw_fd(fd) };
+ // Safe because we just opened this descriptor above.
+ let f = unsafe { File::from_raw_descriptor(raw_descriptor) };
let st = stat(&f)?;
@@ -1186,13 +1185,13 @@
// Not sure why the root inode gets a refcount of 2 but that's what libfuse does.
inodes.insert(
- fuse::ROOT_ID,
+ ROOT_ID,
InodeAltKey {
ino: st.st_ino,
dev: st.st_dev,
},
Arc::new(InodeData {
- inode: fuse::ROOT_ID,
+ inode: ROOT_ID,
file: f,
refcount: AtomicU64::new(2),
filetype: st.st_mode.into(),
@@ -1223,7 +1222,7 @@
let mut out = MaybeUninit::<libc::statvfs64>::zeroed();
// Safe because this will only modify `out` and we check the return value.
- let res = unsafe { libc::fstatvfs64(data.file.as_raw_fd(), out.as_mut_ptr()) };
+ let res = unsafe { libc::fstatvfs64(data.file.as_raw_descriptor(), out.as_mut_ptr()) };
if res == 0 {
// Safe because the kernel guarantees that `out` has been initialized.
Ok(unsafe { out.assume_init() })
@@ -1312,7 +1311,7 @@
// Set the uid and gid for the directory. Safe because this doesn't modify any memory and we
// check the return value.
- let ret = unsafe { libc::fchown(tmpdir.as_raw_fd(), ctx.uid, gid) };
+ let ret = unsafe { libc::fchown(tmpdir.as_raw_descriptor(), ctx.uid, gid) };
if ret < 0 {
return Err(io::Error::last_os_error());
}
@@ -1323,9 +1322,9 @@
let ret = unsafe {
libc::syscall(
libc::SYS_renameat2,
- data.file.as_raw_fd(),
+ data.file.as_raw_descriptor(),
tmpdir.basename().as_ptr(),
- data.file.as_raw_fd(),
+ data.file.as_raw_descriptor(),
name.as_ptr(),
libc::RENAME_NOREPLACE,
)
@@ -1434,14 +1433,20 @@
let current_dir = unsafe { CStr::from_bytes_with_nul_unchecked(b".\0") };
// Safe because this doesn't modify any memory and we check the return value.
- let fd =
- unsafe { libc::openat(data.file.as_raw_fd(), current_dir.as_ptr(), tmpflags, mode) };
- if fd < 0 {
+ let raw_descriptor = unsafe {
+ libc::openat(
+ data.file.as_raw_descriptor(),
+ current_dir.as_ptr(),
+ tmpflags,
+ mode,
+ )
+ };
+ if raw_descriptor < 0 {
return Err(io::Error::last_os_error());
}
- // Safe because we just opened this fd.
- let tmpfile = unsafe { File::from_raw_fd(fd) };
+ // Safe because we just opened this descriptor.
+ let tmpfile = unsafe { File::from_raw_descriptor(raw_descriptor) };
// We need to respect the setgid bit in the parent directory if it is set.
let st = stat(&data.file)?;
@@ -1453,21 +1458,21 @@
// Now set the uid and gid for the file. Safe because this doesn't modify any memory and we
// check the return value.
- let ret = unsafe { libc::fchown(tmpfile.as_raw_fd(), ctx.uid, gid) };
+ let ret = unsafe { libc::fchown(tmpfile.as_raw_descriptor(), ctx.uid, gid) };
if ret < 0 {
return Err(io::Error::last_os_error());
}
- let proc_path = CString::new(format!("self/fd/{}", tmpfile.as_raw_fd()))
+ let proc_path = CString::new(format!("self/fd/{}", tmpfile.as_raw_descriptor()))
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
// Finally link it into the file system tree so that it's visible to other processes. Safe
// because this doesn't modify any memory and we check the return value.
let ret = unsafe {
libc::linkat(
- self.proc.as_raw_fd(),
+ self.proc.as_raw_descriptor(),
proc_path.as_ptr(),
- data.file.as_raw_fd(),
+ data.file.as_raw_descriptor(),
name.as_ptr(),
libc::AT_SYMLINK_FOLLOW,
)
@@ -1558,7 +1563,7 @@
let inode_data = self.find_inode(inode)?;
enum Data {
- Handle(Arc<HandleData>, RawFd),
+ Handle(Arc<HandleData>, RawDescriptor),
ProcPath(CString),
}
@@ -1566,10 +1571,10 @@
let data = if let Some(handle) = handle {
let hd = self.find_handle(handle, inode)?;
- let fd = hd.file.lock().as_raw_fd();
+ let fd = hd.file.lock().as_raw_descriptor();
Data::Handle(hd, fd)
} else {
- let pathname = CString::new(format!("self/fd/{}", inode_data.file.as_raw_fd()))
+ let pathname = CString::new(format!("self/fd/{}", inode_data.file.as_raw_descriptor()))
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
Data::ProcPath(pathname)
};
@@ -1580,7 +1585,7 @@
match data {
Data::Handle(_, fd) => libc::fchmod(fd, attr.st_mode),
Data::ProcPath(ref p) => {
- libc::fchmodat(self.proc.as_raw_fd(), p.as_ptr(), attr.st_mode, 0)
+ libc::fchmodat(self.proc.as_raw_descriptor(), p.as_ptr(), attr.st_mode, 0)
}
}
};
@@ -1609,7 +1614,7 @@
// Safe because this doesn't modify any memory and we check the return value.
let res = unsafe {
libc::fchownat(
- inode_data.file.as_raw_fd(),
+ inode_data.file.as_raw_descriptor(),
empty.as_ptr(),
uid,
gid,
@@ -1628,7 +1633,7 @@
_ => {
// There is no `ftruncateat` so we need to get a new fd and truncate it.
let f = self.open_inode(&inode_data, libc::O_NONBLOCK | libc::O_RDWR)?;
- unsafe { libc::ftruncate64(f.as_raw_fd(), attr.st_size) }
+ unsafe { libc::ftruncate64(f.as_raw_descriptor(), attr.st_size) }
}
};
if res < 0 {
@@ -1666,7 +1671,7 @@
let res = match data {
Data::Handle(_, fd) => unsafe { libc::futimens(fd, tvs.as_ptr()) },
Data::ProcPath(ref p) => unsafe {
- libc::utimensat(self.proc.as_raw_fd(), p.as_ptr(), tvs.as_ptr(), 0)
+ libc::utimensat(self.proc.as_raw_descriptor(), p.as_ptr(), tvs.as_ptr(), 0)
},
};
if res < 0 {
@@ -1695,9 +1700,9 @@
let res = unsafe {
libc::syscall(
libc::SYS_renameat2,
- old_inode.file.as_raw_fd(),
+ old_inode.file.as_raw_descriptor(),
oldname.as_ptr(),
- new_inode.file.as_raw_fd(),
+ new_inode.file.as_raw_descriptor(),
newname.as_ptr(),
flags,
)
@@ -1737,7 +1742,7 @@
// Safe because this doesn't modify any memory and we check the return value.
let res = unsafe {
libc::mknodat(
- data.file.as_raw_fd(),
+ data.file.as_raw_descriptor(),
name.as_ptr(),
mode as libc::mode_t,
rdev as libc::dev_t,
@@ -1761,15 +1766,15 @@
let data = self.find_inode(inode)?;
let new_inode = self.find_inode(newparent)?;
- let path = CString::new(format!("self/fd/{}", data.file.as_raw_fd()))
+ let path = CString::new(format!("self/fd/{}", data.file.as_raw_descriptor()))
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
// Safe because this doesn't modify any memory and we check the return value.
let res = unsafe {
libc::linkat(
- self.proc.as_raw_fd(),
+ self.proc.as_raw_descriptor(),
path.as_ptr(),
- new_inode.file.as_raw_fd(),
+ new_inode.file.as_raw_descriptor(),
newname.as_ptr(),
libc::AT_SYMLINK_FOLLOW,
)
@@ -1799,8 +1804,13 @@
let (_uid, _gid) = set_creds(ctx.uid, ctx.gid)?;
// Safe because this doesn't modify any memory and we check the return value.
- let res =
- unsafe { libc::symlinkat(linkname.as_ptr(), data.file.as_raw_fd(), name.as_ptr()) };
+ let res = unsafe {
+ libc::symlinkat(
+ linkname.as_ptr(),
+ data.file.as_raw_descriptor(),
+ name.as_ptr(),
+ )
+ };
if res == 0 {
self.do_lookup(&data, name)
} else {
@@ -1820,7 +1830,7 @@
// Safe because this will only modify the contents of `buf` and we check the return value.
let res = unsafe {
libc::readlinkat(
- data.file.as_raw_fd(),
+ data.file.as_raw_descriptor(),
empty.as_ptr(),
buf.as_mut_ptr() as *mut libc::c_char,
buf.len(),
@@ -1847,7 +1857,7 @@
// behavior by doing the same thing (dup-ing the fd and then immediately closing it). Safe
// because this doesn't modify any memory and we check the return values.
unsafe {
- let newfd = libc::dup(data.file.lock().as_raw_fd());
+ let newfd = libc::dup(data.file.lock().as_raw_descriptor());
if newfd < 0 {
return Err(io::Error::last_os_error());
}
@@ -1863,7 +1873,7 @@
fn fsync(&self, _ctx: Context, inode: Inode, datasync: bool, handle: Handle) -> io::Result<()> {
let data = self.find_handle(handle, inode)?;
- let fd = data.file.lock().as_raw_fd();
+ let fd = data.file.lock().as_raw_descriptor();
// Safe because this doesn't modify any memory and we check the return value.
let res = unsafe {
@@ -1958,7 +1968,7 @@
// For non-regular files and directories, we cannot open the fd normally. Instead we
// emulate an _at syscall by changing the CWD to /proc, running the path based syscall,
// and then setting the CWD back to the root directory.
- let path = CString::new(format!("self/fd/{}", data.file.as_raw_fd()))
+ let path = CString::new(format!("self/fd/{}", data.file.as_raw_descriptor()))
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
// Safe because this doesn't modify any memory and we check the return value.
@@ -1983,7 +1993,7 @@
// Safe because this doesn't modify any memory and we check the return value.
unsafe {
libc::fsetxattr(
- f.as_raw_fd(),
+ f.as_raw_descriptor(),
name.as_ptr(),
value.as_ptr() as *const libc::c_void,
value.len() as libc::size_t,
@@ -2035,7 +2045,7 @@
// For non-regular files and directories, we cannot open the fd normally. Instead we
// emulate an _at syscall by changing the CWD to /proc, running the path based syscall,
// and then setting the CWD back to the root directory.
- let path = CString::new(format!("self/fd/{}", data.file.as_raw_fd()))
+ let path = CString::new(format!("self/fd/{}", data.file.as_raw_descriptor()))
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
// Safe because this will only modify `buf` and we check the return value.
@@ -2058,7 +2068,7 @@
// Safe because this will only write to `buf` and we check the return value.
unsafe {
libc::flistxattr(
- f.as_raw_fd(),
+ f.as_raw_descriptor(),
buf.as_mut_ptr() as *mut libc::c_char,
buf.len() as libc::size_t,
)
@@ -2095,7 +2105,7 @@
// For non-regular files and directories, we cannot open the fd normally. Instead we
// emulate an _at syscall by changing the CWD to /proc, running the path based syscall,
// and then setting the CWD back to the root directory.
- let path = CString::new(format!("self/fd/{}", data.file.as_raw_fd()))
+ let path = CString::new(format!("self/fd/{}", data.file.as_raw_descriptor()))
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
// Safe because this doesn't modify any memory and we check the return value.
@@ -2110,7 +2120,7 @@
let f = self.open_inode(&data, libc::O_RDONLY | dir)?;
// Safe because this doesn't modify any memory and we check the return value.
- unsafe { libc::fremovexattr(f.as_raw_fd(), name.as_ptr()) }
+ unsafe { libc::fremovexattr(f.as_raw_descriptor(), name.as_ptr()) }
};
if res == 0 {
@@ -2131,7 +2141,7 @@
) -> io::Result<()> {
let data = self.find_handle(handle, inode)?;
- let fd = data.file.lock().as_raw_fd();
+ let fd = data.file.lock().as_raw_descriptor();
// Safe because this doesn't modify any memory and we check the return value.
let res = unsafe {
libc::fallocate64(
@@ -2246,8 +2256,8 @@
let src_data = self.find_handle(handle_src, inode_src)?;
let dst_data = self.find_handle(handle_dst, inode_dst)?;
- let src = src_data.file.lock().as_raw_fd();
- let dst = dst_data.file.lock().as_raw_fd();
+ let src = src_data.file.lock().as_raw_descriptor();
+ let dst = dst_data.file.lock().as_raw_descriptor();
let res = unsafe {
libc::syscall(
@@ -2289,7 +2299,7 @@
)
};
assert!(fd >= 0, "Failed to open env::temp_dir()");
- let parent = unsafe { File::from_raw_fd(fd) };
+ let parent = unsafe { File::from_raw_descriptor(fd) };
let t = TempDir::new(&parent, 0o755).expect("Failed to create temporary directory");
let basename = t.basename().to_string_lossy();
@@ -2310,7 +2320,7 @@
)
};
assert!(fd >= 0, "Failed to open env::temp_dir()");
- let parent = unsafe { File::from_raw_fd(fd) };
+ let parent = unsafe { File::from_raw_descriptor(fd) };
let t = TempDir::new(&parent, 0o755).expect("Failed to create temporary directory");
let basename = t.basename().to_string_lossy();
@@ -2331,7 +2341,7 @@
)
};
assert!(fd >= 0, "Failed to open env::temp_dir()");
- let parent = unsafe { File::from_raw_fd(fd) };
+ let parent = unsafe { File::from_raw_descriptor(fd) };
let t = TempDir::new(&parent, 0o755).expect("Failed to create temporary directory");
let (basename_cstr, _) = t.into_inner();
diff --git a/devices/src/virtio/fs/read_dir.rs b/devices/src/virtio/fs/read_dir.rs
index d02960d..710943c 100644
--- a/devices/src/virtio/fs/read_dir.rs
+++ b/devices/src/virtio/fs/read_dir.rs
@@ -6,11 +6,10 @@
use std::io;
use std::mem::size_of;
use std::ops::{Deref, DerefMut};
-use std::os::unix::io::AsRawFd;
+use base::AsRawDescriptor;
use data_model::DataInit;
-
-use crate::virtio::fs::filesystem::{DirEntry, DirectoryIterator};
+use fuse::filesystem::{DirEntry, DirectoryIterator};
#[repr(C, packed)]
#[derive(Clone, Copy)]
@@ -29,9 +28,9 @@
}
impl<P: DerefMut<Target = [u8]>> ReadDir<P> {
- pub fn new<D: AsRawFd>(dir: &D, offset: libc::off64_t, mut buf: P) -> io::Result<Self> {
+ pub fn new<D: AsRawDescriptor>(dir: &D, offset: libc::off64_t, mut buf: P) -> io::Result<Self> {
// Safe because this doesn't modify any memory and we check the return value.
- let res = unsafe { libc::lseek64(dir.as_raw_fd(), offset, libc::SEEK_SET) };
+ let res = unsafe { libc::lseek64(dir.as_raw_descriptor(), offset, libc::SEEK_SET) };
if res < 0 {
return Err(io::Error::last_os_error());
}
@@ -41,7 +40,7 @@
let res = unsafe {
libc::syscall(
libc::SYS_getdents64,
- dir.as_raw_fd(),
+ dir.as_raw_descriptor(),
buf.as_mut_ptr() as *mut LinuxDirent64,
buf.len() as libc::c_int,
)
diff --git a/devices/src/virtio/fs/worker.rs b/devices/src/virtio/fs/worker.rs
index 7875ed0..9a4da6c 100644
--- a/devices/src/virtio/fs/worker.rs
+++ b/devices/src/virtio/fs/worker.rs
@@ -2,20 +2,48 @@
// 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;
use std::sync::Arc;
-use base::{error, Event, PollContext, PollToken};
+use base::{error, Event, PollToken, WaitContext};
+use fuse::filesystem::{FileSystem, ZeroCopyReader, ZeroCopyWriter};
use vm_memory::GuestMemory;
-use crate::virtio::fs::filesystem::FileSystem;
-use crate::virtio::fs::server::Server;
use crate::virtio::fs::{Error, Result};
use crate::virtio::{Interrupt, Queue, Reader, Writer};
+impl fuse::Reader for Reader {}
+
+impl fuse::Writer for Writer {
+ fn write_at<F>(&mut self, offset: usize, f: F) -> io::Result<usize>
+ where
+ F: Fn(&mut Self) -> io::Result<usize>,
+ {
+ let mut writer = Writer::split_at(self, offset);
+ f(&mut writer)
+ }
+
+ fn has_sufficient_buffer(&self, size: u32) -> bool {
+ self.available_bytes() >= size as usize
+ }
+}
+
+impl ZeroCopyReader for Reader {
+ fn read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {
+ self.read_to_at(f, count, off)
+ }
+}
+
+impl ZeroCopyWriter for Writer {
+ fn write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {
+ self.write_from_at(f, count, off)
+ }
+}
pub struct Worker<F: FileSystem + Sync> {
mem: GuestMemory,
queue: Queue,
- server: Arc<Server<F>>,
+ server: Arc<fuse::Server<F>>,
irq: Arc<Interrupt>,
}
@@ -23,7 +51,7 @@
pub fn new(
mem: GuestMemory,
queue: Queue,
- server: Arc<Server<F>>,
+ server: Arc<fuse::Server<F>>,
irq: Arc<Interrupt>,
) -> Worker<F> {
Worker {
@@ -73,20 +101,20 @@
Kill,
}
- let poll_ctx =
- PollContext::build_with(&[(&queue_evt, Token::QueueReady), (&kill_evt, Token::Kill)])
- .map_err(Error::CreatePollContext)?;
+ let wait_ctx =
+ WaitContext::build_with(&[(&queue_evt, Token::QueueReady), (&kill_evt, Token::Kill)])
+ .map_err(Error::CreateWaitContext)?;
if watch_resample_event {
- poll_ctx
+ wait_ctx
.add(self.irq.get_resample_evt(), Token::InterruptResample)
- .map_err(Error::CreatePollContext)?;
+ .map_err(Error::CreateWaitContext)?;
}
loop {
- let events = poll_ctx.wait().map_err(Error::PollError)?;
- for event in events.iter_readable() {
- match event.token() {
+ let events = wait_ctx.wait().map_err(Error::WaitError)?;
+ for event in events.iter().filter(|e| e.is_readable) {
+ match event.token {
Token::QueueReady => {
queue_evt.read().map_err(Error::ReadQueueEvent)?;
if let Err(e) = self.process_queue() {
diff --git a/devices/src/virtio/gpu/mod.rs b/devices/src/virtio/gpu/mod.rs
index 330e5a1..6fd7095 100644
--- a/devices/src/virtio/gpu/mod.rs
+++ b/devices/src/virtio/gpu/mod.rs
@@ -14,7 +14,6 @@
use std::io::Read;
use std::mem::{self, size_of};
use std::num::NonZeroU8;
-use std::os::unix::io::{AsRawFd, RawFd};
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
@@ -23,7 +22,10 @@
use data_model::*;
-use base::{debug, error, warn, Event, ExternalMapping, PollContext, PollToken};
+use base::{
+ debug, error, warn, AsRawDescriptor, Event, ExternalMapping, PollToken, RawDescriptor,
+ WaitContext,
+};
use sync::Mutex;
use vm_memory::{GuestAddress, GuestMemory};
@@ -72,6 +74,8 @@
pub renderer_use_glx: bool,
pub renderer_use_surfaceless: bool,
#[cfg(feature = "gfxstream")]
+ pub gfxstream_use_guest_angle: bool,
+ #[cfg(feature = "gfxstream")]
pub gfxstream_use_syncfd: bool,
#[cfg(feature = "gfxstream")]
pub gfxstream_support_vulkan: bool,
@@ -99,6 +103,8 @@
renderer_use_glx: false,
renderer_use_surfaceless: true,
#[cfg(feature = "gfxstream")]
+ gfxstream_use_guest_angle: false,
+ #[cfg(feature = "gfxstream")]
gfxstream_use_syncfd: true,
#[cfg(feature = "gfxstream")]
gfxstream_support_vulkan: true,
@@ -941,7 +947,7 @@
ResourceBridge { index: usize },
}
- let poll_ctx: PollContext<Token> = match PollContext::build_with(&[
+ let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
(&self.ctrl_evt, Token::CtrlQueue),
(&self.cursor_evt, Token::CursorQueue),
(&*self.state.display().borrow(), Token::Display),
@@ -950,14 +956,14 @@
]) {
Ok(pc) => pc,
Err(e) => {
- error!("failed creating PollContext: {}", e);
+ error!("failed creating WaitContext: {}", e);
return;
}
};
for (index, bridge) in self.resource_bridges.iter().enumerate() {
- if let Err(e) = poll_ctx.add(bridge, Token::ResourceBridge { index }) {
- error!("failed to add resource bridge to PollContext: {}", e);
+ if let Err(e) = wait_ctx.add(bridge, Token::ResourceBridge { index }) {
+ error!("failed to add resource bridge to WaitContext: {}", e);
}
}
@@ -971,7 +977,7 @@
// Declare this outside the loop so we don't keep allocating and freeing the vector.
let mut process_resource_bridge = Vec::with_capacity(self.resource_bridges.len());
- 'poll: loop {
+ 'wait: 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)
@@ -979,7 +985,7 @@
Duration::new(i64::MAX as u64, 0)
};
- let events = match poll_ctx.wait_timeout(duration) {
+ let events = match wait_ctx.wait_timeout(duration) {
Ok(v) => v,
Err(e) => {
error!("failed polling for events: {}", e);
@@ -996,15 +1002,15 @@
// This display isn't typically used when the virt-wl device is available and it can
// lead to hung fds (crbug.com/1027379). Disable if it's hung.
- for event in events.iter_hungup() {
- if let Token::Display = event.token() {
+ for event in events.iter().filter(|e| e.is_hungup) {
+ if let Token::Display = event.token {
error!("default display hang-up detected");
- let _ = poll_ctx.delete(&*self.state.display().borrow());
+ let _ = wait_ctx.delete(&*self.state.display().borrow());
}
}
- for event in events.iter_readable() {
- match event.token() {
+ for event in events.iter().filter(|e| e.is_readable) {
+ match event.token {
Token::CtrlQueue => {
let _ = self.ctrl_evt.read();
// Set flag that control queue is available to be read, but defer reading
@@ -1030,7 +1036,7 @@
self.interrupt.interrupt_resample();
}
Token::Kill => {
- break 'poll;
+ break 'wait;
}
}
}
@@ -1141,6 +1147,7 @@
.use_surfaceless(gpu_parameters.renderer_use_surfaceless);
#[cfg(feature = "gfxstream")]
let renderer_flags = renderer_flags
+ .use_guest_angle(gpu_parameters.gfxstream_use_guest_angle)
.use_syncfd(gpu_parameters.gfxstream_use_syncfd)
.support_vulkan(gpu_parameters.gfxstream_support_vulkan);
@@ -1200,24 +1207,24 @@
}
impl VirtioDevice for Gpu {
- fn keep_fds(&self) -> Vec<RawFd> {
- let mut keep_fds = Vec::new();
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ let mut keep_rds = 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);
+ keep_rds.push(libc::STDOUT_FILENO);
+ keep_rds.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_rds.push(gpu_device_socket.as_raw_descriptor());
}
- keep_fds.push(self.exit_evt.as_raw_fd());
+ keep_rds.push(self.exit_evt.as_raw_descriptor());
for bridge in &self.resource_bridges {
- keep_fds.push(bridge.as_raw_fd());
+ keep_rds.push(bridge.as_raw_descriptor());
}
- keep_fds
+ keep_rds
}
fn device_type(&self) -> u32 {
diff --git a/devices/src/virtio/gpu/virtio_3d_backend.rs b/devices/src/virtio/gpu/virtio_3d_backend.rs
index dc38992..383b361 100644
--- a/devices/src/virtio/gpu/virtio_3d_backend.rs
+++ b/devices/src/virtio/gpu/virtio_3d_backend.rs
@@ -8,12 +8,11 @@
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::sync::Arc;
use std::usize;
-use base::{error, warn, Error, ExternalMapping};
+use base::{error, warn, AsRawDescriptor, Error, ExternalMapping};
use data_model::*;
use msg_socket::{MsgReceiver, MsgSender};
use resources::Alloc;
@@ -38,7 +37,7 @@
use crate::virtio::resource_bridge::{PlaneInfo, ResourceInfo, ResourceResponse};
use vm_control::{
- MaybeOwnedFd, MemSlot, VmMemoryControlRequestSocket, VmMemoryRequest, VmMemoryResponse,
+ MaybeOwnedDescriptor, MemSlot, VmMemoryControlRequestSocket, VmMemoryRequest, VmMemoryResponse,
};
struct Virtio3DResource {
@@ -152,7 +151,7 @@
};
match display.borrow_mut().import_dmabuf(
- dmabuf.as_raw_fd(),
+ dmabuf.as_raw_descriptor(),
offset,
stride,
query.out_modifier,
@@ -829,7 +828,7 @@
let request = match export {
Ok(ref export) => VmMemoryRequest::RegisterFdAtPciBarOffset(
self.pci_bar,
- MaybeOwnedFd::Borrowed(export.as_raw_fd()),
+ MaybeOwnedDescriptor::Borrowed(export.as_raw_descriptor()),
resource.size as usize,
offset,
),
diff --git a/devices/src/virtio/input/evdev.rs b/devices/src/virtio/input/evdev.rs
index 128692a..c8f8f57 100644
--- a/devices/src/virtio/input/evdev.rs
+++ b/devices/src/virtio/input/evdev.rs
@@ -2,8 +2,6 @@
// 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 base::{ioctl_ior_nr, ioctl_iow_nr, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref};
use data_model::Le32;
@@ -18,6 +16,8 @@
use std::os::raw::c_uint;
use std::ptr::null;
+use base::{AsRawDescriptor, Descriptor};
+
const EVDEV: c_uint = 69;
#[repr(C)]
@@ -112,12 +112,16 @@
}
/// 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> {
+pub fn device_ids<T: AsRawDescriptor>(descriptor: &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)
+ ioctl_with_mut_ref(
+ &Descriptor(descriptor.as_raw_descriptor()),
+ EVIOCGID(),
+ &mut dev_id,
+ )
};
if len < 0 {
return Err(InputError::EvdevIdError(errno()));
@@ -131,12 +135,16 @@
}
/// Gets the name of an event device (see EVIOCGNAME ioctl for details).
-pub fn name<T: AsRawFd>(fd: &T) -> Result<Vec<u8>> {
+pub fn name<T: AsRawDescriptor>(descriptor: &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)
+ ioctl_with_mut_ref(
+ &Descriptor(descriptor.as_raw_descriptor()),
+ EVIOCGNAME(),
+ &mut name,
+ )
};
if len < 0 {
return Err(InputError::EvdevNameError(errno()));
@@ -145,12 +153,16 @@
}
/// 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>> {
+pub fn serial_name<T: AsRawDescriptor>(descriptor: &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)
+ ioctl_with_mut_ref(
+ &Descriptor(descriptor.as_raw_descriptor()),
+ EVIOCGUNIQ(),
+ &mut uniq,
+ )
};
if len < 0 {
return Err(InputError::EvdevSerialError(errno()));
@@ -159,12 +171,16 @@
}
/// Gets the properties of an event device (see EVIOCGPROP ioctl for details).
-pub fn properties<T: AsRawFd>(fd: &T) -> Result<virtio_input_bitmap> {
+pub fn properties<T: AsRawDescriptor>(descriptor: &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)
+ ioctl_with_mut_ref(
+ &Descriptor(descriptor.as_raw_descriptor()),
+ EVIOCGPROP(),
+ &mut props,
+ )
};
if len < 0 {
return Err(InputError::EvdevPropertiesError(errno()));
@@ -174,14 +190,20 @@
/// 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>> {
+pub fn supported_events<T: AsRawDescriptor>(
+ descriptor: &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)
+ ioctl_with_mut_ref(
+ &Descriptor(descriptor.as_raw_descriptor()),
+ EVIOCGBIT(0),
+ &mut evt_types,
+ )
};
if len < 0 {
return Err(InputError::EvdevEventTypesError(errno()));
@@ -198,7 +220,11 @@
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)
+ ioctl_with_mut_ref(
+ &Descriptor(descriptor.as_raw_descriptor()),
+ EVIOCGBIT(ev as c_uint),
+ &mut evt_codes,
+ )
};
if len < 0 {
return Err(InputError::EvdevEventTypesError(errno()));
@@ -209,7 +235,7 @@
}
/// 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> {
+pub fn abs_info<T: AsRawDescriptor>(descriptor: &T) -> BTreeMap<u16, virtio_input_absinfo> {
let mut ret: BTreeMap<u16, virtio_input_absinfo> = BTreeMap::new();
for abs in 0..ABS_MAX {
@@ -218,7 +244,11 @@
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)
+ ioctl_with_mut_ref(
+ &Descriptor(descriptor.as_raw_descriptor()),
+ EVIOCGABS(abs as c_uint),
+ &mut abs_info,
+ )
};
if len > 0 {
ret.insert(abs, virtio_input_absinfo::from(abs_info));
@@ -228,13 +258,17 @@
}
/// 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
+/// descriptor 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<()> {
+pub fn grab_evdev<T: AsRawDescriptor>(descriptor: &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)
+ ioctl_with_ref(
+ &Descriptor(descriptor.as_raw_descriptor()),
+ EVIOCGRAB(),
+ &val,
+ )
};
if ret == 0 {
Ok(())
@@ -243,11 +277,15 @@
}
}
-pub fn ungrab_evdev<T: AsRawFd>(fd: &mut T) -> Result<()> {
+pub fn ungrab_evdev<T: AsRawDescriptor>(descriptor: &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>())
+ ioctl_with_ptr(
+ &Descriptor(descriptor.as_raw_descriptor()),
+ EVIOCGRAB(),
+ null::<u32>(),
+ )
};
if ret == 0 {
Ok(())
diff --git a/devices/src/virtio/input/event_source.rs b/devices/src/virtio/input/event_source.rs
index cf95f4a..650b193 100644
--- a/devices/src/virtio/input/event_source.rs
+++ b/devices/src/virtio/input/event_source.rs
@@ -6,20 +6,19 @@
use super::evdev::{grab_evdev, ungrab_evdev};
use super::InputError;
use super::Result;
-use base::warn;
+use base::{warn, AsRawDescriptor, RawDescriptor};
use data_model::DataInit;
use linux_input_sys::{input_event, virtio_input_event, InputEventDecoder};
use std::collections::VecDeque;
use std::io::Read;
use std::io::Write;
-use std::os::unix::io::{AsRawFd, RawFd};
/// 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: AsRawFd {
+pub trait EventSource: AsRawDescriptor {
/// Perform any necessary initialization before receiving and sending events from/to the source.
fn init(&mut self) -> Result<()> {
Ok(())
@@ -49,9 +48,9 @@
read_idx: usize,
}
-impl<T: AsRawFd> EventSourceImpl<T> {
- fn as_raw_fd(&self) -> RawFd {
- self.source.as_raw_fd()
+impl<T: AsRawDescriptor> EventSourceImpl<T> {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.source.as_raw_descriptor()
}
}
@@ -141,7 +140,7 @@
impl<T> SocketEventSource<T>
where
- T: Read + Write + AsRawFd,
+ T: Read + Write + AsRawDescriptor,
{
pub fn new(source: T) -> SocketEventSource<T> {
SocketEventSource {
@@ -150,15 +149,15 @@
}
}
-impl<T: AsRawFd> AsRawFd for SocketEventSource<T> {
- fn as_raw_fd(&self) -> RawFd {
- self.evt_source_impl.as_raw_fd()
+impl<T: AsRawDescriptor> AsRawDescriptor for SocketEventSource<T> {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.evt_source_impl.as_raw_descriptor()
}
}
impl<T> EventSource for SocketEventSource<T>
where
- T: Read + Write + AsRawFd,
+ T: Read + Write + AsRawDescriptor,
{
fn init(&mut self) -> Result<()> {
Ok(())
@@ -193,7 +192,7 @@
impl<T> EvdevEventSource<T>
where
- T: Read + Write + AsRawFd,
+ T: Read + Write + AsRawDescriptor,
{
pub fn new(source: T) -> EvdevEventSource<T> {
EvdevEventSource {
@@ -202,15 +201,15 @@
}
}
-impl<T: AsRawFd> AsRawFd for EvdevEventSource<T> {
- fn as_raw_fd(&self) -> RawFd {
- self.evt_source_impl.as_raw_fd()
+impl<T: AsRawDescriptor> AsRawDescriptor for EvdevEventSource<T> {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.evt_source_impl.as_raw_descriptor()
}
}
impl<T> EventSource for EvdevEventSource<T>
where
- T: Read + Write + AsRawFd,
+ T: Read + Write + AsRawDescriptor,
{
fn init(&mut self) -> Result<()> {
grab_evdev(self)
diff --git a/devices/src/virtio/input/mod.rs b/devices/src/virtio/input/mod.rs
index 08ffa22..91400d7 100644
--- a/devices/src/virtio/input/mod.rs
+++ b/devices/src/virtio/input/mod.rs
@@ -10,9 +10,7 @@
use self::constants::*;
-use std::os::unix::io::{AsRawFd, RawFd};
-
-use base::{error, warn, Event, PollContext, PollToken};
+use base::{error, warn, AsRawDescriptor, Event, PollToken, RawDescriptor, WaitContext};
use data_model::{DataInit, Le16, Le32};
use vm_memory::GuestMemory;
@@ -265,7 +263,7 @@
}
}
- fn from_evdev<T: AsRawFd>(source: &T) -> Result<VirtioInputConfig> {
+ fn from_evdev<T: AsRawDescriptor>(source: &T) -> Result<VirtioInputConfig> {
Ok(VirtioInputConfig::new(
evdev::device_ids(source)?,
evdev::name(source)?,
@@ -461,23 +459,23 @@
InterruptResample,
Kill,
}
- let poll_ctx: PollContext<Token> = match PollContext::build_with(&[
+ let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
(&event_queue_evt, Token::EventQAvailable),
(&status_queue_evt, Token::StatusQAvailable),
(&self.event_source, Token::InputEventsAvailable),
(self.interrupt.get_resample_evt(), Token::InterruptResample),
(&kill_evt, Token::Kill),
]) {
- Ok(poll_ctx) => poll_ctx,
+ Ok(wait_ctx) => wait_ctx,
Err(e) => {
- error!("failed creating PollContext: {}", e);
+ error!("failed creating WaitContext: {}", e);
return;
}
};
- 'poll: loop {
- let poll_events = match poll_ctx.wait() {
- Ok(poll_events) => poll_events,
+ 'wait: loop {
+ let wait_events = match wait_ctx.wait() {
+ Ok(wait_events) => wait_events,
Err(e) => {
error!("failed polling for events: {}", e);
break;
@@ -485,19 +483,19 @@
};
let mut needs_interrupt = false;
- for poll_event in poll_events.iter_readable() {
- match poll_event.token() {
+ for wait_event in wait_events.iter().filter(|e| e.is_readable) {
+ match wait_event.token {
Token::EventQAvailable => {
if let Err(e) = event_queue_evt.read() {
error!("failed reading event queue Event: {}", e);
- break 'poll;
+ break 'wait;
}
needs_interrupt |= self.send_events();
}
Token::StatusQAvailable => {
if let Err(e) = status_queue_evt.read() {
error!("failed reading status queue Event: {}", e);
- break 'poll;
+ break 'wait;
}
match self.process_status_queue() {
Ok(b) => needs_interrupt |= b,
@@ -513,7 +511,7 @@
}
Token::Kill => {
let _ = kill_evt.read();
- break 'poll;
+ break 'wait;
}
}
}
@@ -556,9 +554,9 @@
where
T: 'static + EventSource + Send,
{
- fn keep_fds(&self) -> Vec<RawFd> {
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
if let Some(source) = &self.source {
- return vec![source.as_raw_fd()];
+ return vec![source.as_raw_descriptor()];
}
Vec::new()
}
@@ -665,7 +663,7 @@
/// Creates a new virtio input device from an event device node
pub fn new_evdev<T>(source: T, virtio_features: u64) -> Result<Input<EvdevEventSource<T>>>
where
- T: Read + Write + AsRawFd,
+ T: Read + Write + AsRawDescriptor,
{
Ok(Input {
kill_evt: None,
@@ -684,7 +682,7 @@
virtio_features: u64,
) -> Result<Input<SocketEventSource<T>>>
where
- T: Read + Write + AsRawFd,
+ T: Read + Write + AsRawDescriptor,
{
Ok(Input {
kill_evt: None,
@@ -704,7 +702,7 @@
virtio_features: u64,
) -> Result<Input<SocketEventSource<T>>>
where
- T: Read + Write + AsRawFd,
+ T: Read + Write + AsRawDescriptor,
{
Ok(Input {
kill_evt: None,
@@ -718,7 +716,7 @@
/// Creates a new virtio mouse which supports primary, secondary, wheel and REL events.
pub fn new_mouse<T>(source: T, virtio_features: u64) -> Result<Input<SocketEventSource<T>>>
where
- T: Read + Write + AsRawFd,
+ T: Read + Write + AsRawDescriptor,
{
Ok(Input {
kill_evt: None,
@@ -732,7 +730,7 @@
/// Creates a new virtio keyboard, which supports the same events as an en-us physical keyboard.
pub fn new_keyboard<T>(source: T, virtio_features: u64) -> Result<Input<SocketEventSource<T>>>
where
- T: Read + Write + AsRawFd,
+ T: Read + Write + AsRawDescriptor,
{
Ok(Input {
kill_evt: None,
diff --git a/devices/src/virtio/net.rs b/devices/src/virtio/net.rs
index 417a05c..92368c4 100644
--- a/devices/src/virtio/net.rs
+++ b/devices/src/virtio/net.rs
@@ -7,13 +7,12 @@
use std::mem;
use std::net::Ipv4Addr;
use std::os::raw::c_uint;
-use std::os::unix::io::{AsRawFd, RawFd};
use std::result;
use std::sync::Arc;
use std::thread;
use base::Error as SysError;
-use base::{error, warn, Event, PollContext, PollToken, WatchingEvents};
+use base::{error, warn, AsRawDescriptor, Event, EventType, PollToken, RawDescriptor, WaitContext};
use data_model::{DataInit, Le16, Le64};
use net_util::{Error as TapError, MacAddress, TapT};
use virtio_sys::virtio_net;
@@ -33,18 +32,18 @@
pub enum NetError {
/// Creating kill event failed.
CreateKillEvent(SysError),
- /// Creating PollContext failed.
- CreatePollContext(SysError),
+ /// Creating WaitContext failed.
+ CreateWaitContext(SysError),
/// Cloning kill event failed.
CloneKillEvent(SysError),
/// Descriptor chain was invalid.
DescriptorChain(DescriptorError),
- /// Removing EPOLLIN from the tap fd events failed.
- PollDisableTap(SysError),
- /// Adding EPOLLIN to the tap fd events failed.
- PollEnableTap(SysError),
- /// Error while polling for events.
- PollError(SysError),
+ /// Removing read event from the tap fd events failed.
+ WaitContextDisableTap(SysError),
+ /// Adding read event to the tap fd events failed.
+ WaitContextEnableTap(SysError),
+ /// Error while waiting for events.
+ WaitError(SysError),
/// Error reading data from control queue.
ReadCtrlData(io::Error),
/// Error reading header from control queue.
@@ -79,12 +78,12 @@
match self {
CreateKillEvent(e) => write!(f, "failed to create kill event: {}", e),
- CreatePollContext(e) => write!(f, "failed to create poll context: {}", e),
+ CreateWaitContext(e) => write!(f, "failed to create wait context: {}", e),
CloneKillEvent(e) => write!(f, "failed to clone kill event: {}", e),
DescriptorChain(e) => write!(f, "failed to valildate descriptor chain: {}", e),
- PollDisableTap(e) => write!(f, "failed to disable EPOLLIN on tap fd: {}", e),
- PollEnableTap(e) => write!(f, "failed to enable EPOLLIN on tap fd: {}", e),
- PollError(e) => write!(f, "error while polling for events: {}", e),
+ WaitContextDisableTap(e) => write!(f, "failed to disable EPOLLIN on tap fd: {}", e),
+ WaitContextEnableTap(e) => write!(f, "failed to enable EPOLLIN on tap fd: {}", e),
+ WaitError(e) => write!(f, "error while waiting for events: {}", e),
ReadCtrlData(e) => write!(f, "failed to read control message data: {}", e),
ReadCtrlHeader(e) => write!(f, "failed to read control message header: {}", e),
RxDescriptorsExhausted => write!(f, "no rx descriptors available"),
@@ -339,35 +338,35 @@
Kill,
}
- let poll_ctx: PollContext<Token> = PollContext::build_with(&[
+ let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
(&self.tap, Token::RxTap),
(&rx_queue_evt, Token::RxQueue),
(&tx_queue_evt, Token::TxQueue),
(&self.kill_evt, Token::Kill),
])
- .map_err(NetError::CreatePollContext)?;
+ .map_err(NetError::CreateWaitContext)?;
if let Some(ctrl_evt) = &ctrl_queue_evt {
- poll_ctx
+ wait_ctx
.add(ctrl_evt, Token::CtrlQueue)
- .map_err(NetError::CreatePollContext)?;
+ .map_err(NetError::CreateWaitContext)?;
// Let CtrlQueue's thread handle InterruptResample also.
- poll_ctx
+ wait_ctx
.add(self.interrupt.get_resample_evt(), Token::InterruptResample)
- .map_err(NetError::CreatePollContext)?;
+ .map_err(NetError::CreateWaitContext)?;
}
let mut tap_polling_enabled = true;
- 'poll: loop {
- let events = poll_ctx.wait().map_err(NetError::PollError)?;
- for event in events.iter_readable() {
- match event.token() {
+ 'wait: loop {
+ let events = wait_ctx.wait().map_err(NetError::WaitError)?;
+ for event in events.iter().filter(|e| e.is_readable) {
+ match event.token {
Token::RxTap => match self.process_rx() {
Ok(()) => {}
Err(NetError::RxDescriptorsExhausted) => {
- poll_ctx
- .modify(&self.tap, WatchingEvents::empty(), Token::RxTap)
- .map_err(NetError::PollDisableTap)?;
+ wait_ctx
+ .modify(&self.tap, EventType::None, Token::RxTap)
+ .map_err(NetError::WaitContextDisableTap)?;
tap_polling_enabled = false;
}
Err(e) => return Err(e),
@@ -375,19 +374,19 @@
Token::RxQueue => {
if let Err(e) = rx_queue_evt.read() {
error!("net: error reading rx queue Event: {}", e);
- break 'poll;
+ break 'wait;
}
if !tap_polling_enabled {
- poll_ctx
- .modify(&self.tap, WatchingEvents::empty().set_read(), Token::RxTap)
- .map_err(NetError::PollEnableTap)?;
+ wait_ctx
+ .modify(&self.tap, EventType::Read, Token::RxTap)
+ .map_err(NetError::WaitContextEnableTap)?;
tap_polling_enabled = true;
}
}
Token::TxQueue => {
if let Err(e) = tx_queue_evt.read() {
error!("net: error reading tx queue Event: {}", e);
- break 'poll;
+ break 'wait;
}
self.process_tx();
}
@@ -395,14 +394,14 @@
if let Some(ctrl_evt) = &ctrl_queue_evt {
if let Err(e) = ctrl_evt.read() {
error!("net: error reading ctrl queue Event: {}", e);
- break 'poll;
+ break 'wait;
}
} else {
- break 'poll;
+ break 'wait;
}
if let Err(e) = self.process_ctrl() {
error!("net: failed to process control message: {}", e);
- break 'poll;
+ break 'wait;
}
}
Token::InterruptResample => {
@@ -410,7 +409,7 @@
}
Token::Kill => {
let _ = self.kill_evt.read();
- break 'poll;
+ break 'wait;
}
}
}
@@ -579,21 +578,21 @@
where
T: 'static + TapT,
{
- fn keep_fds(&self) -> Vec<RawFd> {
- let mut keep_fds = Vec::new();
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ let mut keep_rds = Vec::new();
for tap in &self.taps {
- keep_fds.push(tap.as_raw_fd());
+ keep_rds.push(tap.as_raw_descriptor());
}
for worker_kill_evt in &self.workers_kill_evt {
- keep_fds.push(worker_kill_evt.as_raw_fd());
+ keep_rds.push(worker_kill_evt.as_raw_descriptor());
}
for kill_evt in &self.kill_evts {
- keep_fds.push(kill_evt.as_raw_fd());
+ keep_rds.push(kill_evt.as_raw_descriptor());
}
- keep_fds
+ keep_rds
}
fn device_type(&self) -> u32 {
diff --git a/devices/src/virtio/p9.rs b/devices/src/virtio/p9.rs
index ff8aad4..a082afa 100644
--- a/devices/src/virtio/p9.rs
+++ b/devices/src/virtio/p9.rs
@@ -5,12 +5,10 @@
use std::fmt::{self, Display};
use std::io::{self, Write};
use std::mem;
-use std::os::unix::io::RawFd;
-use std::path::{Path, PathBuf};
use std::result;
use std::thread;
-use base::{error, warn, Error as SysError, Event, PollContext, PollToken};
+use base::{error, warn, Error as SysError, Event, PollToken, RawDescriptor, WaitContext};
use vm_memory::GuestMemory;
use super::{
@@ -28,12 +26,12 @@
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),
+ /// Creating WaitContext failed.
+ CreateWaitContext(SysError),
+ /// Failed to create a 9p server.
+ CreateServer(io::Error),
/// Error while polling for events.
- PollError(SysError),
+ WaitError(SysError),
/// Error while reading from the virtio queue's Event.
ReadQueueEvent(SysError),
/// A request is missing readable descriptors.
@@ -61,13 +59,9 @@
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),
+ CreateWaitContext(err) => write!(f, "failed to create WaitContext: {}", err),
+ WaitError(err) => write!(f, "failed to wait for events: {}", err),
+ CreateServer(err) => write!(f, "failed to create 9p server: {}", err),
ReadQueueEvent(err) => write!(f, "failed to read from virtio queue Event: {}", err),
NoReadableDescriptors => write!(f, "request does not have any readable descriptors"),
NoWritableDescriptors => write!(f, "request does not have any writable descriptors"),
@@ -121,17 +115,17 @@
Kill,
}
- let poll_ctx: PollContext<Token> = PollContext::build_with(&[
+ let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
(&queue_evt, Token::QueueReady),
(self.interrupt.get_resample_evt(), Token::InterruptResample),
(&kill_evt, Token::Kill),
])
- .map_err(P9Error::CreatePollContext)?;
+ .map_err(P9Error::CreateWaitContext)?;
loop {
- let events = poll_ctx.wait().map_err(P9Error::PollError)?;
- for event in events.iter_readable() {
- match event.token() {
+ let events = wait_ctx.wait().map_err(P9Error::WaitError)?;
+ for event in events.iter().filter(|e| e.is_readable) {
+ match event.token {
Token::QueueReady => {
queue_evt.read().map_err(P9Error::ReadQueueEvent)?;
self.process_queue()?;
@@ -157,19 +151,11 @@
}
impl P9 {
- pub fn new<P: AsRef<Path> + Into<Box<Path>>>(
- base_features: u64,
- root: P,
- tag: &str,
- ) -> P9Result<P9> {
+ pub fn new(base_features: u64, tag: &str, p9_cfg: p9::Config) -> 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);
@@ -177,13 +163,10 @@
cfg.write_all(tag.as_bytes()).map_err(P9Error::Internal)?;
+ let server = p9::Server::with_config(p9_cfg).map_err(P9Error::CreateServer)?;
Ok(P9 {
config: cfg,
- server: Some(p9::Server::new(
- root,
- Default::default(),
- Default::default(),
- )),
+ server: Some(server),
kill_evt: None,
avail_features: base_features | 1 << VIRTIO_9P_MOUNT_TAG,
acked_features: 0,
@@ -193,8 +176,11 @@
}
impl VirtioDevice for P9 {
- fn keep_fds(&self) -> Vec<RawFd> {
- Vec::new()
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ self.server
+ .as_ref()
+ .map(p9::Server::keep_fds)
+ .unwrap_or_else(Vec::new)
}
fn device_type(&self) -> u32 {
diff --git a/devices/src/virtio/pmem.rs b/devices/src/virtio/pmem.rs
index b241ea6..6412268 100644
--- a/devices/src/virtio/pmem.rs
+++ b/devices/src/virtio/pmem.rs
@@ -5,10 +5,9 @@
use std::fmt::{self, Display};
use std::fs::File;
use std::io;
-use std::os::unix::io::{AsRawFd, RawFd};
use std::thread;
-use base::{error, Event, PollContext, PollToken};
+use base::{error, AsRawDescriptor, Event, PollToken, RawDescriptor, WaitContext};
use base::{Error as SysError, Result as SysResult};
use vm_memory::{GuestAddress, GuestMemory};
@@ -176,20 +175,20 @@
Kill,
}
- let poll_ctx: PollContext<Token> = match PollContext::build_with(&[
+ let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
(&queue_evt, Token::QueueAvailable),
(self.interrupt.get_resample_evt(), Token::InterruptResample),
(&kill_evt, Token::Kill),
]) {
Ok(pc) => pc,
Err(e) => {
- error!("failed creating PollContext: {}", e);
+ error!("failed creating WaitContext: {}", e);
return;
}
};
- 'poll: loop {
- let events = match poll_ctx.wait() {
+ 'wait: loop {
+ let events = match wait_ctx.wait() {
Ok(v) => v,
Err(e) => {
error!("failed polling for events: {}", e);
@@ -198,19 +197,19 @@
};
let mut needs_interrupt = false;
- for event in events.iter_readable() {
- match event.token() {
+ for event in events.iter().filter(|e| e.is_readable) {
+ match event.token {
Token::QueueAvailable => {
if let Err(e) = queue_evt.read() {
error!("failed reading queue Event: {}", e);
- break 'poll;
+ break 'wait;
}
needs_interrupt |= self.process_queue();
}
Token::InterruptResample => {
self.interrupt.interrupt_resample();
}
- Token::Kill => break 'poll,
+ Token::Kill => break 'wait,
}
}
if needs_interrupt {
@@ -271,16 +270,16 @@
}
impl VirtioDevice for Pmem {
- fn keep_fds(&self) -> Vec<RawFd> {
- let mut keep_fds = Vec::new();
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ let mut keep_rds = Vec::new();
if let Some(disk_image) = &self.disk_image {
- keep_fds.push(disk_image.as_raw_fd());
+ keep_rds.push(disk_image.as_raw_descriptor());
}
if let Some(ref pmem_device_socket) = self.pmem_device_socket {
- keep_fds.push(pmem_device_socket.as_raw_fd());
+ keep_rds.push(pmem_device_socket.as_raw_descriptor());
}
- keep_fds
+ keep_rds
}
fn device_type(&self) -> u32 {
diff --git a/devices/src/virtio/queue.rs b/devices/src/virtio/queue.rs
index 60a7fc6..ce3f51f 100644
--- a/devices/src/virtio/queue.rs
+++ b/devices/src/virtio/queue.rs
@@ -5,7 +5,6 @@
use std::cell::RefCell;
use std::cmp::min;
use std::num::Wrapping;
-use std::os::unix::io::AsRawFd;
use std::rc::Rc;
use std::sync::atomic::{fence, Ordering};
@@ -330,6 +329,84 @@
}
}
+ // Get the index of the first available descriptor chain in the available ring
+ // (the next one that the driver will fill).
+ //
+ // All available ring entries between `self.next_avail` and `get_avail_index()` are available
+ // to be processed by the device.
+ fn get_avail_index(&self, mem: &GuestMemory) -> Wrapping<u16> {
+ let avail_index_addr = self.avail_ring.unchecked_add(2);
+ let avail_index: u16 = mem.read_obj_from_addr(avail_index_addr).unwrap();
+
+ // Make sure following reads (e.g. desc_idx) don't pass the avail_index read.
+ fence(Ordering::Acquire);
+
+ Wrapping(avail_index)
+ }
+
+ // Set the `avail_event` field in the used ring.
+ //
+ // This allows the device to inform the driver that driver-to-device notification
+ // (kicking the ring) is not necessary until the driver reaches the `avail_index` descriptor.
+ //
+ // This value is only used if the `VIRTIO_F_EVENT_IDX` feature has been negotiated.
+ fn set_avail_event(&mut self, mem: &GuestMemory, avail_index: Wrapping<u16>) {
+ let avail_event_addr = self
+ .used_ring
+ .unchecked_add(4 + 8 * u64::from(self.actual_size()));
+ mem.write_obj_at_addr(avail_index.0, avail_event_addr)
+ .unwrap();
+ }
+
+ // Query the value of a single-bit flag in the available ring.
+ //
+ // Returns `true` if `flag` is currently set (by the driver) in the available ring flags.
+ fn get_avail_flag(&self, mem: &GuestMemory, flag: u16) -> bool {
+ let avail_flags: u16 = mem.read_obj_from_addr(self.avail_ring).unwrap();
+ avail_flags & flag == flag
+ }
+
+ // Get the `used_event` field in the available ring.
+ //
+ // The returned value is the index of the next descriptor chain entry for which the driver
+ // needs to be notified upon use. Entries before this index may be used without notifying
+ // the driver.
+ //
+ // This value is only valid if the `VIRTIO_F_EVENT_IDX` feature has been negotiated.
+ fn get_used_event(&self, mem: &GuestMemory) -> Wrapping<u16> {
+ let used_event_addr = self
+ .avail_ring
+ .unchecked_add(4 + 2 * u64::from(self.actual_size()));
+ let used_event: u16 = mem.read_obj_from_addr(used_event_addr).unwrap();
+ Wrapping(used_event)
+ }
+
+ // Set the `idx` field in the used ring.
+ //
+ // This indicates to the driver that all entries up to (but not including) `used_index` have
+ // been used by the device and may be processed by the driver.
+ fn set_used_index(&mut self, mem: &GuestMemory, used_index: Wrapping<u16>) {
+ // This fence ensures all descriptor writes are visible before the index update.
+ fence(Ordering::Release);
+
+ let used_index_addr = self.used_ring.unchecked_add(2);
+ mem.write_obj_at_addr(used_index.0, used_index_addr)
+ .unwrap();
+ }
+
+ // Set a single-bit flag in the used ring.
+ //
+ // Changes the bit specified by the mask in `flag` to `value`.
+ fn set_used_flag(&mut self, mem: &GuestMemory, flag: u16, value: bool) {
+ let mut used_flags: u16 = mem.read_obj_from_addr(self.used_ring).unwrap();
+ if value {
+ used_flags |= flag;
+ } else {
+ used_flags &= !flag;
+ }
+ mem.write_obj_at_addr(used_flags, self.used_ring).unwrap();
+ }
+
/// Get the first available descriptor chain without removing it from the queue.
/// Call `pop_peeked` to remove the returned descriptor chain from the queue.
pub fn peek(&mut self, mem: &GuestMemory) -> Option<DescriptorChain> {
@@ -338,13 +415,10 @@
}
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();
- // make sure desc_index read doesn't bypass avail_index read
- fence(Ordering::Acquire);
- let avail_len = Wrapping(avail_index) - self.next_avail;
+ let avail_index = self.get_avail_index(mem);
+ let avail_len = avail_index - self.next_avail;
- if avail_len.0 > queue_size || self.next_avail == Wrapping(avail_index) {
+ if avail_len.0 > queue_size || self.next_avail == avail_index {
return None;
}
@@ -362,11 +436,7 @@
pub fn pop_peeked(&mut self, mem: &GuestMemory) {
self.next_avail += Wrapping(1);
if self.features & ((1u64) << VIRTIO_RING_F_EVENT_IDX) != 0 {
- let avail_event_off = self
- .used_ring
- .unchecked_add((4 + 8 * self.actual_size()).into());
- mem.write_obj_at_addr(self.next_avail.0 as u16, avail_event_off)
- .unwrap();
+ self.set_avail_event(mem, self.next_avail);
}
}
@@ -386,10 +456,10 @@
/// Asynchronously read the next descriptor chain from the queue.
/// Returns a `DescriptorChain` when it is `await`ed.
- pub async fn next_async<F: AsRawFd + Unpin>(
+ pub async fn next_async(
&mut self,
mem: &GuestMemory,
- eventfd: &mut EventAsync<F>,
+ eventfd: &mut EventAsync,
) -> std::result::Result<DescriptorChain, AsyncError> {
loop {
// Check if there are more descriptors available.
@@ -420,12 +490,7 @@
.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();
+ self.set_used_index(mem, self.next_used);
}
/// Enable / Disable guest notify device that requests are available on
@@ -438,47 +503,27 @@
}
if self.features & ((1u64) << VIRTIO_RING_F_EVENT_IDX) != 0 {
- 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_event_off = self
- .used_ring
- .unchecked_add((4 + 8 * self.actual_size()).into());
- mem.write_obj_at_addr(avail_index, avail_event_off).unwrap();
+ self.set_avail_event(mem, self.get_avail_index(mem));
} else {
- let mut used_flags: u16 = mem.read_obj_from_addr(self.used_ring).unwrap();
- if self.notification_disable_count == 0 {
- used_flags &= !VIRTQ_USED_F_NO_NOTIFY;
- } else {
- used_flags |= VIRTQ_USED_F_NO_NOTIFY;
- }
- mem.write_obj_at_addr(used_flags, self.used_ring).unwrap();
+ self.set_used_flag(
+ mem,
+ VIRTQ_USED_F_NO_NOTIFY,
+ self.notification_disable_count > 0,
+ );
}
}
// Check Whether guest enable interrupt injection or not.
fn available_interrupt_enabled(&self, mem: &GuestMemory) -> bool {
if self.features & ((1u64) << VIRTIO_RING_F_EVENT_IDX) != 0 {
- let used_event_off = self
- .avail_ring
- .unchecked_add((4 + 2 * self.actual_size()).into());
- let used_event: u16 = mem.read_obj_from_addr(used_event_off).unwrap();
+ let used_event = self.get_used_event(mem);
// if used_event >= self.last_used, driver handle interrupt quickly enough, new
// interrupt could be injected.
// if used_event < self.last_used, driver hasn't finished the last interrupt,
// so no need to inject new interrupt.
- if self.next_used - Wrapping(used_event) - Wrapping(1) < self.next_used - self.last_used
- {
- true
- } else {
- false
- }
+ self.next_used - used_event - Wrapping(1) < self.next_used - self.last_used
} else {
- let avail_flags: u16 = mem.read_obj_from_addr(self.avail_ring).unwrap();
- if avail_flags & VIRTQ_AVAIL_F_NO_INTERRUPT == VIRTQ_AVAIL_F_NO_INTERRUPT {
- false
- } else {
- true
- }
+ !self.get_avail_flag(mem, VIRTQ_AVAIL_F_NO_INTERRUPT)
}
}
diff --git a/devices/src/virtio/resource_bridge.rs b/devices/src/virtio/resource_bridge.rs
index 2a2343f..067e832 100644
--- a/devices/src/virtio/resource_bridge.rs
+++ b/devices/src/virtio/resource_bridge.rs
@@ -8,6 +8,7 @@
use std::fmt;
use std::fs::File;
+use base::RawDescriptor;
use msg_on_socket_derive::MsgOnSocket;
use msg_socket::{MsgError, MsgReceiver, MsgSender, MsgSocket};
diff --git a/devices/src/virtio/rng.rs b/devices/src/virtio/rng.rs
index 332a616..466ffd2 100644
--- a/devices/src/virtio/rng.rs
+++ b/devices/src/virtio/rng.rs
@@ -5,10 +5,9 @@
use std::fmt::{self, Display};
use std::fs::File;
use std::io;
-use std::os::unix::io::{AsRawFd, RawFd};
use std::thread;
-use base::{error, warn, Event, PollContext, PollToken};
+use base::{error, warn, AsRawDescriptor, Event, PollToken, RawDescriptor, WaitContext};
use vm_memory::GuestMemory;
use super::{Interrupt, Queue, VirtioDevice, Writer, TYPE_RNG};
@@ -74,20 +73,20 @@
Kill,
}
- let poll_ctx: PollContext<Token> = match PollContext::build_with(&[
+ let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
(&queue_evt, Token::QueueAvailable),
(self.interrupt.get_resample_evt(), Token::InterruptResample),
(&kill_evt, Token::Kill),
]) {
Ok(pc) => pc,
Err(e) => {
- error!("failed creating PollContext: {}", e);
+ error!("failed creating WaitContext: {}", e);
return;
}
};
- 'poll: loop {
- let events = match poll_ctx.wait() {
+ 'wait: loop {
+ let events = match wait_ctx.wait() {
Ok(v) => v,
Err(e) => {
error!("failed polling for events: {}", e);
@@ -96,19 +95,19 @@
};
let mut needs_interrupt = false;
- for event in events.iter_readable() {
- match event.token() {
+ for event in events.iter().filter(|e| e.is_readable) {
+ match event.token {
Token::QueueAvailable => {
if let Err(e) = queue_evt.read() {
error!("failed reading queue Event: {}", e);
- break 'poll;
+ break 'wait;
}
needs_interrupt |= self.process_queue();
}
Token::InterruptResample => {
self.interrupt.interrupt_resample();
}
- Token::Kill => break 'poll,
+ Token::Kill => break 'wait,
}
}
if needs_interrupt {
@@ -153,14 +152,14 @@
}
impl VirtioDevice for Rng {
- fn keep_fds(&self) -> Vec<RawFd> {
- let mut keep_fds = Vec::new();
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ let mut keep_rds = Vec::new();
if let Some(random_file) = &self.random_file {
- keep_fds.push(random_file.as_raw_fd());
+ keep_rds.push(random_file.as_raw_descriptor());
}
- keep_fds
+ keep_rds
}
fn device_type(&self) -> u32 {
diff --git a/devices/src/virtio/tpm.rs b/devices/src/virtio/tpm.rs
index 9afdc69..ee68ea1 100644
--- a/devices/src/virtio/tpm.rs
+++ b/devices/src/virtio/tpm.rs
@@ -7,11 +7,10 @@
use std::fs;
use std::io::{self, Read, Write};
use std::ops::BitOrAssign;
-use std::os::unix::io::RawFd;
use std::path::PathBuf;
use std::thread;
-use base::{error, Event, PollContext, PollToken};
+use base::{error, Event, PollToken, RawDescriptor, WaitContext};
use vm_memory::GuestMemory;
use super::{
@@ -111,20 +110,20 @@
Kill,
}
- let poll_ctx = match PollContext::build_with(&[
+ let wait_ctx = match WaitContext::build_with(&[
(&self.queue_evt, Token::QueueAvailable),
(self.interrupt.get_resample_evt(), Token::InterruptResample),
(&self.kill_evt, Token::Kill),
]) {
Ok(pc) => pc,
Err(e) => {
- error!("vtpm failed creating PollContext: {}", e);
+ error!("vtpm failed creating WaitContext: {}", e);
return;
}
};
- 'poll: loop {
- let events = match poll_ctx.wait() {
+ 'wait: loop {
+ let events = match wait_ctx.wait() {
Ok(v) => v,
Err(e) => {
error!("vtpm failed polling for events: {}", e);
@@ -133,19 +132,19 @@
};
let mut needs_interrupt = NeedsInterrupt::No;
- for event in events.iter_readable() {
- match event.token() {
+ for event in events.iter().filter(|e| e.is_readable) {
+ match event.token {
Token::QueueAvailable => {
if let Err(e) = self.queue_evt.read() {
error!("vtpm failed reading queue Event: {}", e);
- break 'poll;
+ break 'wait;
}
needs_interrupt |= self.process_queue();
}
Token::InterruptResample => {
self.interrupt.interrupt_resample();
}
- Token::Kill => break 'poll,
+ Token::Kill => break 'wait,
}
}
if needs_interrupt == NeedsInterrupt::Yes {
@@ -185,7 +184,7 @@
}
impl VirtioDevice for Tpm {
- fn keep_fds(&self) -> Vec<RawFd> {
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
Vec::new()
}
diff --git a/devices/src/virtio/vhost/control_socket.rs b/devices/src/virtio/vhost/control_socket.rs
index 9edc9a9..fc1d0f3 100644
--- a/devices/src/virtio/vhost/control_socket.rs
+++ b/devices/src/virtio/vhost/control_socket.rs
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use base::Error as SysError;
+use base::{Error as SysError, RawDescriptor};
use msg_socket::{MsgOnSocket, MsgSocket};
#[derive(MsgOnSocket, Debug)]
diff --git a/devices/src/virtio/vhost/mod.rs b/devices/src/virtio/vhost/mod.rs
index 2646d54..e1cd067 100644
--- a/devices/src/virtio/vhost/mod.rs
+++ b/devices/src/virtio/vhost/mod.rs
@@ -27,10 +27,8 @@
CloneKillEvent(SysError),
/// Creating kill event failed.
CreateKillEvent(SysError),
- /// Creating poll context failed.
- CreatePollContext(SysError),
- /// Error while polling for events.
- PollError(SysError),
+ /// Creating wait context failed.
+ CreateWaitContext(SysError),
/// Enabling tap interface failed.
TapEnable(TapError),
/// Open tap device failed.
@@ -75,6 +73,8 @@
VhostVsockSetCid(VhostError),
/// Failed to start vhost-vsock driver.
VhostVsockStart(VhostError),
+ /// Error while waiting for events.
+ WaitError(SysError),
}
pub type Result<T> = std::result::Result<T, Error>;
@@ -88,8 +88,7 @@
match self {
CloneKillEvent(e) => write!(f, "failed to clone kill event: {}", e),
CreateKillEvent(e) => write!(f, "failed to create kill event: {}", e),
- CreatePollContext(e) => write!(f, "failed to create poll context: {}", e),
- PollError(e) => write!(f, "failed polling for events: {}", e),
+ CreateWaitContext(e) => write!(f, "failed to create poll context: {}", 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),
@@ -112,6 +111,7 @@
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),
+ WaitError(e) => write!(f, "failed waiting for events: {}", e),
}
}
}
diff --git a/devices/src/virtio/vhost/net.rs b/devices/src/virtio/vhost/net.rs
index 14dc852..9aede36 100644
--- a/devices/src/virtio/vhost/net.rs
+++ b/devices/src/virtio/vhost/net.rs
@@ -4,12 +4,11 @@
use std::mem;
use std::net::Ipv4Addr;
-use std::os::unix::io::{AsRawFd, RawFd};
use std::thread;
use net_util::{MacAddress, TapT};
-use base::{error, warn, Event};
+use base::{error, warn, AsRawDescriptor, Event, RawDescriptor};
use vhost::NetT as VhostNetT;
use virtio_sys::virtio_net;
use vm_memory::GuestMemory;
@@ -131,37 +130,37 @@
T: TapT + 'static,
U: VhostNetT<T> + 'static,
{
- fn keep_fds(&self) -> Vec<RawFd> {
- let mut keep_fds = Vec::new();
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ let mut keep_rds = Vec::new();
if let Some(tap) = &self.tap {
- keep_fds.push(tap.as_raw_fd());
+ keep_rds.push(tap.as_raw_descriptor());
}
if let Some(vhost_net_handle) = &self.vhost_net_handle {
- keep_fds.push(vhost_net_handle.as_raw_fd());
+ keep_rds.push(vhost_net_handle.as_raw_descriptor());
}
if let Some(vhost_interrupt) = &self.vhost_interrupt {
for vhost_int in vhost_interrupt.iter() {
- keep_fds.push(vhost_int.as_raw_fd());
+ keep_rds.push(vhost_int.as_raw_descriptor());
}
}
if let Some(workers_kill_evt) = &self.workers_kill_evt {
- keep_fds.push(workers_kill_evt.as_raw_fd());
+ keep_rds.push(workers_kill_evt.as_raw_descriptor());
}
- keep_fds.push(self.kill_evt.as_raw_fd());
+ keep_rds.push(self.kill_evt.as_raw_descriptor());
if let Some(request_socket) = &self.request_socket {
- keep_fds.push(request_socket.as_raw_fd());
+ keep_rds.push(request_socket.as_raw_descriptor());
}
if let Some(response_socket) = &self.response_socket {
- keep_fds.push(response_socket.as_raw_fd());
+ keep_rds.push(response_socket.as_raw_descriptor());
}
- keep_fds
+ keep_rds
}
fn device_type(&self) -> u32 {
@@ -381,9 +380,9 @@
}
#[test]
- fn keep_fds() {
+ fn keep_rds() {
let net = create_net_common();
- let fds = net.keep_fds();
+ let fds = net.keep_rds();
assert!(fds.len() >= 1, "We should have gotten at least one fd");
}
diff --git a/devices/src/virtio/vhost/vsock.rs b/devices/src/virtio/vhost/vsock.rs
index 9702cc9..0061181 100644
--- a/devices/src/virtio/vhost/vsock.rs
+++ b/devices/src/virtio/vhost/vsock.rs
@@ -2,12 +2,11 @@
// 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::thread;
use data_model::{DataInit, Le64};
-use base::{error, warn, Event};
+use base::{error, warn, AsRawDescriptor, Event, RawDescriptor};
use vhost::Vhost;
use vhost::Vsock as VhostVsockHandle;
use vm_memory::GuestMemory;
@@ -89,24 +88,24 @@
}
impl VirtioDevice for Vsock {
- fn keep_fds(&self) -> Vec<RawFd> {
- let mut keep_fds = Vec::new();
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ let mut keep_rds = Vec::new();
if let Some(handle) = &self.vhost_handle {
- keep_fds.push(handle.as_raw_fd());
+ keep_rds.push(handle.as_raw_descriptor());
}
if let Some(interrupt) = &self.interrupts {
for vhost_int in interrupt.iter() {
- keep_fds.push(vhost_int.as_raw_fd());
+ keep_rds.push(vhost_int.as_raw_descriptor());
}
}
if let Some(worker_kill_evt) = &self.worker_kill_evt {
- keep_fds.push(worker_kill_evt.as_raw_fd());
+ keep_rds.push(worker_kill_evt.as_raw_descriptor());
}
- keep_fds
+ keep_rds
}
fn device_type(&self) -> u32 {
diff --git a/devices/src/virtio/vhost/worker.rs b/devices/src/virtio/vhost/worker.rs
index 1c0f10b..04c933a 100644
--- a/devices/src/virtio/vhost/worker.rs
+++ b/devices/src/virtio/vhost/worker.rs
@@ -4,7 +4,7 @@
use std::os::raw::c_ulonglong;
-use base::{error, Error as SysError, Event, PollContext, PollToken};
+use base::{error, Error as SysError, Event, PollToken, WaitContext};
use vhost::Vhost;
use super::control_socket::{VhostDevRequest, VhostDevResponse, VhostDevResponseSocket};
@@ -106,28 +106,28 @@
ControlNotify,
}
- let poll_ctx: PollContext<Token> = PollContext::build_with(&[
+ let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
(self.interrupt.get_resample_evt(), Token::InterruptResample),
(&self.kill_evt, Token::Kill),
])
- .map_err(Error::CreatePollContext)?;
+ .map_err(Error::CreateWaitContext)?;
for (index, vhost_int) in self.vhost_interrupt.iter().enumerate() {
- poll_ctx
+ wait_ctx
.add(vhost_int, Token::VhostIrqi { index })
- .map_err(Error::CreatePollContext)?;
+ .map_err(Error::CreateWaitContext)?;
}
if let Some(socket) = &self.response_socket {
- poll_ctx
+ wait_ctx
.add(socket, Token::ControlNotify)
- .map_err(Error::CreatePollContext)?;
+ .map_err(Error::CreateWaitContext)?;
}
- 'poll: loop {
- let events = poll_ctx.wait().map_err(Error::PollError)?;
+ 'wait: loop {
+ let events = wait_ctx.wait().map_err(Error::WaitError)?;
- for event in events.iter_readable() {
- match event.token() {
+ for event in events.iter().filter(|e| e.is_readable) {
+ match event.token {
Token::VhostIrqi { index } => {
self.vhost_interrupt[index]
.read()
@@ -139,7 +139,7 @@
}
Token::Kill => {
let _ = self.kill_evt.read();
- break 'poll;
+ break 'wait;
}
Token::ControlNotify => {
if let Some(socket) = &self.response_socket {
diff --git a/devices/src/virtio/video/decoder/backend/mod.rs b/devices/src/virtio/video/decoder/backend/mod.rs
new file mode 100644
index 0000000..a9c1411
--- /dev/null
+++ b/devices/src/virtio/video/decoder/backend/mod.rs
@@ -0,0 +1,138 @@
+// Copyright 2020 The Chromium OS 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 interface that actual decoder devices need to
+//! implement in order to provide video decoding capability to the guest.
+
+use std::fs::File;
+
+use crate::virtio::video::{
+ error::{VideoError, VideoResult},
+ format::{Format, Rect},
+};
+use base::RawDescriptor;
+
+pub mod vda;
+
+pub struct FramePlane {
+ pub offset: i32,
+ pub stride: i32,
+}
+
+/// Contains the device's state for one playback session, i.e. one stream.
+pub trait DecoderSession {
+ /// Tell how many output buffers will be used for this session. This method
+ /// Must be called after a `ProvidePictureBuffers` event is emitted, and
+ /// before the first call to `use_output_buffers()`.
+ fn set_output_buffer_count(&self, count: usize) -> VideoResult<()>;
+
+ /// Decode the compressed stream contained in [`offset`..`offset`+`bytes_used`]
+ /// of the shared memory in `descriptor`. `bitstream_id` is the identifier for that
+ /// part of the stream (most likely, a timestamp).
+ ///
+ /// The device takes ownership of `descriptor` and is responsible for closing it
+ /// once it is not used anymore.
+ ///
+ /// The device will emit a `NotifyEndOfBitstreamBuffer` event after the input
+ /// buffer has been entirely processed.
+ ///
+ /// The device will emit a `PictureReady` event with the `bitstream_id` field
+ /// set to the same value as the argument of the same name for each picture
+ /// produced from that input buffer.
+ fn decode(
+ &self,
+ bitstream_id: i32,
+ descriptor: RawDescriptor,
+ offset: u32,
+ bytes_used: u32,
+ ) -> VideoResult<()>;
+
+ /// Flush the decoder device, i.e. finish processing of all queued decode
+ /// requests.
+ ///
+ /// The device will emit a `FlushCompleted` event once the flush is done.
+ fn flush(&self) -> VideoResult<()>;
+
+ /// Reset the decoder device, i.e. cancel all pending decoding requests.
+ ///
+ /// The device will emit a `ResetCompleted` event once the reset is done.
+ fn reset(&self) -> VideoResult<()>;
+
+ /// Returns the event pipe on which the availability of an event will be
+ /// signaled.
+ fn event_pipe(&self) -> &File;
+
+ /// Ask the device to use the memory buffer in `output_buffer` to store
+ /// decoded frames in pixel format `format`. `planes` describes how the
+ /// frame's planes should be laid out in the buffer, and `picture_buffer_id`
+ /// is the ID of the picture, that will be reproduced in `PictureReady` events
+ /// using this buffer.
+ ///
+ /// The device takes ownership of `output_buffer` and is responsible for
+ /// closing it once the buffer is not used anymore (either when the session
+ /// is closed, or a new set of buffers is provided for the session).
+ ///
+ /// The device will emit a `PictureReady` event with the `picture_buffer_id`
+ /// field set to the same value as the argument of the same name when a
+ /// frame has been decoded into that buffer.
+ fn use_output_buffer(
+ &self,
+ picture_buffer_id: i32,
+ format: Format,
+ output_buffer: RawDescriptor,
+ planes: &[FramePlane],
+ ) -> VideoResult<()>;
+
+ /// Ask the device to reuse an output buffer previously passed to
+ /// `use_output_buffer` and that has previously been returned to the decoder
+ /// in a `PictureReady` event.
+ ///
+ /// The device will emit a `PictureReady` event with the `picture_buffer_id`
+ /// field set to the same value as the argument of the same name when a
+ /// frame has been decoded into that buffer.
+ fn reuse_output_buffer(&self, picture_buffer_id: i32) -> VideoResult<()>;
+
+ /// Blocking call to read a single event from the event pipe.
+ fn read_event(&mut self) -> VideoResult<DecoderEvent>;
+}
+
+pub trait DecoderBackend {
+ type Session: DecoderSession;
+
+ /// Create a new decoding session for the passed `profile`.
+ fn new_session(&self, format: Format) -> VideoResult<Self::Session>;
+}
+
+#[derive(Debug)]
+pub enum DecoderEvent {
+ /// Emitted when the device knows the buffer format it will need to decode
+ /// frames, and how many buffers it will need. The decoder is supposed to
+ /// provide buffers of the requested dimensions using `use_output_buffer`.
+ ProvidePictureBuffers {
+ min_num_buffers: u32,
+ width: i32,
+ height: i32,
+ visible_rect: Rect,
+ },
+ /// Emitted when the decoder is done decoding a picture. `picture_buffer_id`
+ /// corresponds to the argument of the same name passed to `use_output_buffer()`
+ /// or `reuse_output_buffer()`. `bitstream_id` corresponds to the argument of
+ /// the same name passed to `decode()` and can be used to match decoded frames
+ /// to the input buffer they were produced from.
+ PictureReady {
+ picture_buffer_id: i32,
+ bitstream_id: i32,
+ visible_rect: Rect,
+ },
+ /// Emitted when an input buffer passed to `decode()` is not used by the
+ /// device anymore and can be reused by the decoder. The parameter corresponds
+ /// to the `bitstream_id` argument passed to `decode()`.
+ NotifyEndOfBitstreamBuffer(i32),
+ /// Emitted when a decoding error has occured.
+ NotifyError(VideoError),
+ /// Emitted after `flush()` has been called to signal that the flush is completed.
+ FlushCompleted(VideoResult<()>),
+ /// Emitted after `reset()` has been called to signal that the reset is completed.
+ ResetCompleted(VideoResult<()>),
+}
diff --git a/devices/src/virtio/video/decoder/backend/vda.rs b/devices/src/virtio/video/decoder/backend/vda.rs
new file mode 100644
index 0000000..716347c
--- /dev/null
+++ b/devices/src/virtio/video/decoder/backend/vda.rs
@@ -0,0 +1,192 @@
+// Copyright 2020 The Chromium OS 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 base::{error, RawDescriptor};
+use std::convert::TryFrom;
+
+use libvda::decode::Event as LibvdaEvent;
+
+use crate::virtio::video::{
+ decoder::backend::*,
+ error::{VideoError, VideoResult},
+ format::{Format, Rect},
+};
+
+impl TryFrom<Format> for libvda::Profile {
+ type Error = VideoError;
+
+ fn try_from(format: Format) -> Result<Self, Self::Error> {
+ Ok(match format {
+ Format::VP8 => libvda::Profile::VP8,
+ Format::VP9 => libvda::Profile::VP9Profile0,
+ Format::H264 => libvda::Profile::H264ProfileBaseline,
+ _ => {
+ error!("specified format {} is not supported by VDA", format);
+ return Err(VideoError::InvalidParameter);
+ }
+ })
+ }
+}
+
+impl TryFrom<Format> for libvda::PixelFormat {
+ type Error = VideoError;
+
+ fn try_from(format: Format) -> Result<Self, Self::Error> {
+ Ok(match format {
+ Format::NV12 => libvda::PixelFormat::NV12,
+ _ => {
+ error!("specified format {} is not supported by VDA", format);
+ return Err(VideoError::InvalidParameter);
+ }
+ })
+ }
+}
+
+impl From<&FramePlane> for libvda::FramePlane {
+ fn from(plane: &FramePlane) -> Self {
+ libvda::FramePlane {
+ offset: plane.offset,
+ stride: plane.stride,
+ }
+ }
+}
+
+impl From<libvda::decode::Event> for DecoderEvent {
+ fn from(event: libvda::decode::Event) -> Self {
+ // We cannot use the From trait here since neither libvda::decode::Response
+ // no std::result::Result are defined in the current crate.
+ fn vda_response_to_result(resp: libvda::decode::Response) -> VideoResult<()> {
+ match resp {
+ libvda::decode::Response::Success => Ok(()),
+ resp => Err(VideoError::VdaFailure(resp)),
+ }
+ }
+
+ match event {
+ LibvdaEvent::ProvidePictureBuffers {
+ min_num_buffers,
+ width,
+ height,
+ visible_rect_left,
+ visible_rect_top,
+ visible_rect_right,
+ visible_rect_bottom,
+ } => DecoderEvent::ProvidePictureBuffers {
+ min_num_buffers,
+ width,
+ height,
+ visible_rect: Rect {
+ left: visible_rect_left,
+ top: visible_rect_top,
+ right: visible_rect_right,
+ bottom: visible_rect_bottom,
+ },
+ },
+ LibvdaEvent::PictureReady {
+ buffer_id,
+ bitstream_id,
+ left,
+ top,
+ right,
+ bottom,
+ } => DecoderEvent::PictureReady {
+ picture_buffer_id: buffer_id,
+ bitstream_id,
+ visible_rect: Rect {
+ left,
+ top,
+ right,
+ bottom,
+ },
+ },
+ LibvdaEvent::NotifyEndOfBitstreamBuffer { bitstream_id } => {
+ DecoderEvent::NotifyEndOfBitstreamBuffer(bitstream_id)
+ }
+ LibvdaEvent::NotifyError(resp) => {
+ DecoderEvent::NotifyError(VideoError::VdaFailure(resp))
+ }
+ LibvdaEvent::ResetResponse(resp) => {
+ DecoderEvent::ResetCompleted(vda_response_to_result(resp))
+ }
+ LibvdaEvent::FlushResponse(resp) => {
+ DecoderEvent::FlushCompleted(vda_response_to_result(resp))
+ }
+ }
+ }
+}
+
+pub struct LibvdaSession<'a> {
+ session: libvda::decode::Session<'a>,
+}
+
+impl<'a> DecoderSession for LibvdaSession<'a> {
+ fn set_output_buffer_count(&self, count: usize) -> VideoResult<()> {
+ Ok(self.session.set_output_buffer_count(count)?)
+ }
+
+ fn decode(
+ &self,
+ bitstream_id: i32,
+ descriptor: RawDescriptor,
+ offset: u32,
+ bytes_used: u32,
+ ) -> VideoResult<()> {
+ Ok(self
+ .session
+ .decode(bitstream_id, descriptor, offset, bytes_used)?)
+ }
+
+ fn flush(&self) -> VideoResult<()> {
+ Ok(self.session.flush()?)
+ }
+
+ fn reset(&self) -> VideoResult<()> {
+ Ok(self.session.reset()?)
+ }
+
+ fn event_pipe(&self) -> &std::fs::File {
+ self.session.pipe()
+ }
+
+ fn use_output_buffer(
+ &self,
+ picture_buffer_id: i32,
+ format: Format,
+ output_buffer: RawDescriptor,
+ planes: &[FramePlane],
+ ) -> VideoResult<()> {
+ let vda_planes: Vec<libvda::FramePlane> = planes.into_iter().map(Into::into).collect();
+ Ok(self.session.use_output_buffer(
+ picture_buffer_id,
+ libvda::PixelFormat::try_from(format)?,
+ output_buffer,
+ &vda_planes,
+ )?)
+ }
+
+ fn reuse_output_buffer(&self, picture_buffer_id: i32) -> VideoResult<()> {
+ Ok(self.session.reuse_output_buffer(picture_buffer_id)?)
+ }
+
+ fn read_event(&mut self) -> VideoResult<DecoderEvent> {
+ self.session
+ .read_event()
+ .map(Into::into)
+ .map_err(Into::into)
+ }
+}
+
+impl<'a> DecoderBackend for &'a libvda::decode::VdaInstance {
+ type Session = LibvdaSession<'a>;
+
+ fn new_session(&self, format: Format) -> VideoResult<Self::Session> {
+ let profile = libvda::Profile::try_from(format)?;
+ let session = self.open_session(profile).map_err(|e| {
+ error!("failed to open a session for {:?}: {}", format, e);
+ VideoError::InvalidOperation
+ })?;
+
+ Ok(LibvdaSession { session })
+ }
+}
diff --git a/devices/src/virtio/video/decoder/mod.rs b/devices/src/virtio/video/decoder/mod.rs
index 52c8594..c1cb84e 100644
--- a/devices/src/virtio/video/decoder/mod.rs
+++ b/devices/src/virtio/video/decoder/mod.rs
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-//! Implementation of a virtio video decoder device backed by LibVDA.
+//! Implementation of a virtio video decoder backed by a device.
use std::collections::btree_map::Entry;
use std::collections::{BTreeMap, BTreeSet};
use std::convert::TryInto;
-use std::os::unix::io::IntoRawFd;
-use base::{error, PollContext};
+use backend::*;
+use base::{error, IntoRawDescriptor, WaitContext};
use crate::virtio::resource_bridge::{self, ResourceInfo, ResourceRequestSocket};
use crate::virtio::video::async_cmd_desc_map::AsyncCmdDescMap;
@@ -23,7 +23,9 @@
use crate::virtio::video::protocol;
use crate::virtio::video::response::CmdResponse;
+mod backend;
mod capability;
+
use capability::*;
type StreamId = u32;
@@ -74,7 +76,7 @@
// destroyed.
eos_resource_id: Option<OutputResourceId>,
- // This is a flag that shows whether libvda's set_output_buffer_count is called.
+ // This is a flag that shows whether the device's set_output_buffer_count is called.
// This will be set to true when ResourceCreate for OutputBuffer is called for the first time.
//
// TODO(b/1518105): This field is added as a hack because the current virtio-video v3 spec
@@ -154,10 +156,10 @@
}
}
-// Context is associated with one `libvda::Session`, which corresponds to one stream from the
+// Context is associated with one `DecoderSession`, which corresponds to one stream from the
// virtio-video's point of view.
#[derive(Default)]
-struct Context {
+struct Context<S: DecoderSession> {
stream_id: StreamId,
in_params: Params,
@@ -165,9 +167,14 @@
in_res: InputResources,
out_res: OutputResources,
+
+ // Set the flag if we need to clear output resource when the output queue is cleared next time.
+ is_clear_out_res_needed: bool,
+
+ session: Option<S>,
}
-impl Context {
+impl<S: DecoderSession> Context<S> {
fn new(stream_id: StreamId, format: Format) -> Self {
Context {
stream_id,
@@ -179,7 +186,10 @@
..Default::default()
},
out_params: Default::default(),
- ..Default::default()
+ in_res: Default::default(),
+ out_res: Default::default(),
+ is_clear_out_res_needed: false,
+ session: None,
}
}
@@ -217,7 +227,7 @@
}
/*
- * Functions handling libvda events.
+ * Functions handling decoder events.
*/
fn handle_provide_picture_buffers(
@@ -225,16 +235,13 @@
min_num_buffers: u32,
width: i32,
height: i32,
- visible_rect_left: i32,
- visible_rect_top: i32,
- visible_rect_right: i32,
- visible_rect_bottom: i32,
+ visible_rect: Rect,
) {
// We only support NV12.
let format = Some(Format::NV12);
- let rect_width: u32 = (visible_rect_right - visible_rect_left) as u32;
- let rect_height: u32 = (visible_rect_bottom - visible_rect_top) as u32;
+ let rect_width: u32 = (visible_rect.right - visible_rect.left) as u32;
+ let rect_height: u32 = (visible_rect.bottom - visible_rect.top) as u32;
let plane_size = rect_width * rect_height;
let stride = rect_width;
@@ -252,8 +259,8 @@
min_buffers: min_num_buffers + 1,
max_buffers: 32,
crop: Crop {
- left: visible_rect_left as u32,
- top: visible_rect_top as u32,
+ left: visible_rect.left as u32,
+ top: visible_rect.top as u32,
width: rect_width,
height: rect_height,
},
@@ -261,6 +268,12 @@
// No need to set `frame_rate`, as it's only for the encoder.
..Default::default()
};
+
+ // That eos_resource_id has value means there are previous output resources.
+ // Clear the output resources when the output queue is cleared next time.
+ if self.out_res.eos_resource_id.is_some() {
+ self.is_clear_out_res_needed = true;
+ }
}
fn handle_picture_ready(
@@ -295,13 +308,18 @@
}
/// A thin wrapper of a map of contexts with error handlings.
-#[derive(Default)]
-struct ContextMap {
- map: BTreeMap<StreamId, Context>,
+struct ContextMap<S: DecoderSession> {
+ map: BTreeMap<StreamId, Context<S>>,
}
-impl ContextMap {
- fn insert(&mut self, ctx: Context) -> VideoResult<()> {
+impl<S: DecoderSession> ContextMap<S> {
+ fn new() -> Self {
+ ContextMap {
+ map: Default::default(),
+ }
+ }
+
+ fn insert(&mut self, ctx: Context<S>) -> VideoResult<()> {
match self.map.entry(ctx.stream_id) {
Entry::Vacant(e) => {
e.insert(ctx);
@@ -314,14 +332,14 @@
}
}
- fn get(&self, stream_id: &StreamId) -> VideoResult<&Context> {
+ fn get(&self, stream_id: &StreamId) -> VideoResult<&Context<S>> {
self.map.get(stream_id).ok_or_else(|| {
error!("failed to get context of stream {}", *stream_id);
VideoError::InvalidStreamId(*stream_id)
})
}
- fn get_mut(&mut self, stream_id: &StreamId) -> VideoResult<&mut Context> {
+ fn get_mut(&mut self, stream_id: &StreamId) -> VideoResult<&mut Context<S>> {
self.map.get_mut(stream_id).ok_or_else(|| {
error!("failed to get context of stream {}", *stream_id);
VideoError::InvalidStreamId(*stream_id)
@@ -329,59 +347,14 @@
}
}
-/// A thin wrapper of a map of libvda sesssions with error handlings.
-#[derive(Default)]
-struct SessionMap<'a> {
- map: BTreeMap<u32, libvda::decode::Session<'a>>,
-}
-
-impl<'a> SessionMap<'a> {
- fn contains_key(&self, stream_id: StreamId) -> bool {
- self.map.contains_key(&stream_id)
- }
-
- fn get(&self, stream_id: &StreamId) -> VideoResult<&libvda::decode::Session<'a>> {
- self.map.get(&stream_id).ok_or_else(|| {
- error!("failed to get libvda session {}", *stream_id);
- VideoError::InvalidStreamId(*stream_id)
- })
- }
-
- fn get_mut(&mut self, stream_id: &StreamId) -> VideoResult<&mut libvda::decode::Session<'a>> {
- self.map.get_mut(&stream_id).ok_or_else(|| {
- error!("failed to get libvda session {}", *stream_id);
- VideoError::InvalidStreamId(*stream_id)
- })
- }
-
- fn insert(
- &mut self,
- stream_id: StreamId,
- session: libvda::decode::Session<'a>,
- ) -> Option<libvda::decode::Session<'a>> {
- self.map.insert(stream_id, session)
- }
-}
-
-/// Represents information of a decoder backed with `libvda`.
-pub struct Decoder<'a> {
- vda: &'a libvda::decode::VdaInstance,
+/// Represents information of a decoder backed by a `DecoderBackend`.
+pub struct Decoder<D: DecoderBackend> {
+ decoder: D,
capability: Capability,
- contexts: ContextMap,
- sessions: SessionMap<'a>,
+ contexts: ContextMap<D::Session>,
}
-impl<'a> Decoder<'a> {
- pub fn new(vda: &'a libvda::decode::VdaInstance) -> Self {
- let capability = Capability::new(vda.get_capabilities());
- Decoder {
- vda,
- capability,
- contexts: Default::default(),
- sessions: Default::default(),
- }
- }
-
+impl<'a, D: DecoderBackend> Decoder<D> {
/*
* Functions processing virtio-video commands.
*/
@@ -397,7 +370,7 @@
fn create_stream(&mut self, stream_id: StreamId, coded_format: Format) -> VideoResult<()> {
// Create an instance of `Context`.
- // Note that `libvda::Session` will be created not here but at the first call of
+ // Note that the `DecoderSession` will be created not here but at the first call of
// `ResourceCreate`. This is because we need to fix a coded format for it, which
// will be set by `SetParams`.
self.contexts.insert(Context::new(stream_id, coded_format))
@@ -407,43 +380,26 @@
if self.contexts.map.remove(&stream_id).is_none() {
error!("Tried to destroy an invalid stream context {}", stream_id);
}
-
- // Close a libVDA session, as closing will be done in `Drop` for `session`.
- // Note that `sessions` doesn't have an instance for `stream_id` if the
- // first `ResourceCreate` haven't been called yet.
- self.sessions.map.remove(&stream_id);
}
fn create_session(
- vda: &'a libvda::decode::VdaInstance,
- poll_ctx: &PollContext<Token>,
- ctx: &Context,
+ decoder: &D,
+ wait_ctx: &WaitContext<Token>,
+ ctx: &Context<D::Session>,
stream_id: StreamId,
- ) -> VideoResult<libvda::decode::Session<'a>> {
- let profile = match ctx.in_params.format {
- Some(Format::VP8) => Ok(libvda::Profile::VP8),
- Some(Format::VP9) => Ok(libvda::Profile::VP9Profile0),
- Some(Format::H264) => Ok(libvda::Profile::H264ProfileBaseline),
- Some(f) => {
- error!("specified format is invalid for bitstream: {}", f);
- Err(VideoError::InvalidParameter)
- }
+ ) -> VideoResult<D::Session> {
+ let format = match ctx.in_params.format {
+ Some(f) => f,
None => {
error!("bitstream format is not specified");
- Err(VideoError::InvalidParameter)
+ return Err(VideoError::InvalidParameter);
}
- }?;
+ };
- let session = vda.open_session(profile).map_err(|e| {
- error!(
- "failed to open a session {} for {:?}: {}",
- stream_id, profile, e
- );
- VideoError::InvalidOperation
- })?;
+ let session = decoder.new_session(format)?;
- poll_ctx
- .add(session.pipe(), Token::Event { id: stream_id })
+ wait_ctx
+ .add(session.event_pipe(), Token::Event { id: stream_id })
.map_err(|e| {
error!(
"failed to add FD to poll context for session {}: {}",
@@ -457,7 +413,7 @@
fn create_resource(
&mut self,
- poll_ctx: &PollContext<Token>,
+ wait_ctx: &WaitContext<Token>,
stream_id: StreamId,
queue_type: QueueType,
resource_id: ResourceId,
@@ -465,11 +421,15 @@
) -> VideoResult<()> {
let ctx = self.contexts.get_mut(&stream_id)?;
- // Create a instance of `libvda::Session` at the first time `ResourceCreate` is
+ // Create a instance of `DecoderSession` at the first time `ResourceCreate` is
// called here.
- if !self.sessions.contains_key(stream_id) {
- let session = Self::create_session(self.vda, poll_ctx, ctx, stream_id)?;
- self.sessions.insert(stream_id, session);
+ if ctx.session.is_none() {
+ ctx.session = Some(Self::create_session(
+ &self.decoder,
+ wait_ctx,
+ ctx,
+ stream_id,
+ )?);
}
ctx.register_buffer(queue_type, resource_id, &uuid);
@@ -521,19 +481,20 @@
timestamp: u64,
data_sizes: Vec<u32>,
) -> VideoResult<()> {
- let session = self.sessions.get(&stream_id)?;
let ctx = self.contexts.get_mut(&stream_id)?;
+ let session = ctx.session.as_ref().ok_or(VideoError::InvalidOperation)?;
if data_sizes.len() != 1 {
error!("num_data_sizes must be 1 but {}", data_sizes.len());
return Err(VideoError::InvalidOperation);
}
- // Take an ownership of this file by `into_raw_fd()` as this file will be closed by libvda.
+ // Take an ownership of this file by `into_raw_descriptor()` as this file will be closed
+ // by the `DecoderBackend`.
let fd = ctx
.get_resource_info(QueueType::Input, resource_bridge, resource_id)?
.file
- .into_raw_fd();
+ .into_raw_descriptor();
// Register a mapping of timestamp to resource_id
if let Some(old_resource_id) = ctx
@@ -554,16 +515,12 @@
// a guest passes to a driver as a 32-bit integer in our implementation.
// So, overflow must not happen in this conversion.
let ts_sec: i32 = (timestamp / 1_000_000_000) as i32;
- session
- .decode(
- ts_sec,
- fd, // fd
- 0, // offset is always 0 due to the driver implementation.
- data_sizes[0], // bytes_used
- )
- .map_err(VideoError::VdaError)?;
-
- Ok(())
+ session.decode(
+ ts_sec,
+ fd, // fd
+ 0, // offset is always 0 due to the driver implementation.
+ data_sizes[0], // bytes_used
+ )
}
fn queue_output_resource(
@@ -572,8 +529,8 @@
stream_id: StreamId,
resource_id: ResourceId,
) -> VideoResult<()> {
- let session = self.sessions.get(&stream_id)?;
let ctx = self.contexts.get_mut(&stream_id)?;
+ let session = ctx.session.as_ref().ok_or(VideoError::InvalidOperation)?;
// Check if the current pixel format is set to NV12.
match ctx.out_params.format {
@@ -596,18 +553,16 @@
// Don't enqueue this resource to the host.
Ok(())
}
- QueueOutputResourceResult::Reused(buffer_id) => session
- .reuse_output_buffer(buffer_id)
- .map_err(VideoError::VdaError),
+ QueueOutputResourceResult::Reused(buffer_id) => session.reuse_output_buffer(buffer_id),
QueueOutputResourceResult::Registered(buffer_id) => {
let resource_info =
ctx.get_resource_info(QueueType::Output, resource_bridge, resource_id)?;
let planes = vec![
- libvda::FramePlane {
+ FramePlane {
offset: resource_info.planes[0].offset as i32,
stride: resource_info.planes[0].stride as i32,
},
- libvda::FramePlane {
+ FramePlane {
offset: resource_info.planes[1].offset as i32,
stride: resource_info.planes[1].stride as i32,
},
@@ -621,17 +576,13 @@
// TODO(b/1518105): This is a hack due to the lack of way of telling a number of
// frame buffers explictly in virtio-video v3 RFC. Once we have the way,
// set_output_buffer_count should be called with a value passed by the guest.
- session
- .set_output_buffer_count(OUTPUT_BUFFER_COUNT)
- .map_err(VideoError::VdaError)?;
+ session.set_output_buffer_count(OUTPUT_BUFFER_COUNT)?;
}
- // Take ownership of this file by `into_raw_fd()` as this
+ // Take ownership of this file by `into_raw_descriptor()` as this
// file will be closed by libvda.
- let fd = resource_info.file.into_raw_fd();
- session
- .use_output_buffer(buffer_id as i32, libvda::PixelFormat::NV12, fd, &planes)
- .map_err(VideoError::VdaError)
+ let fd = resource_info.file.into_raw_descriptor();
+ session.use_output_buffer(buffer_id as i32, Format::NV12, fd, &planes)
}
}
}
@@ -653,7 +604,7 @@
let ctx = self.contexts.get_mut(&stream_id)?;
match queue_type {
QueueType::Input => {
- if self.sessions.contains_key(stream_id) {
+ if ctx.session.is_some() {
error!("parameter for input cannot be changed once decoding started");
return Err(VideoError::InvalidParameter);
}
@@ -719,16 +670,17 @@
}
fn drain_stream(&mut self, stream_id: StreamId) -> VideoResult<()> {
- self.sessions
+ self.contexts
.get(&stream_id)?
+ .session
+ .as_ref()
+ .ok_or(VideoError::InvalidOperation)?
.flush()
- .map_err(VideoError::VdaError)?;
- Ok(())
}
fn clear_queue(&mut self, stream_id: StreamId, queue_type: QueueType) -> VideoResult<()> {
let ctx = self.contexts.get_mut(&stream_id)?;
- let session = self.sessions.get(&stream_id)?;
+ let session = ctx.session.as_ref().ok_or(VideoError::InvalidOperation)?;
// TODO(b/153406792): Though QUEUE_CLEAR is defined as a per-queue command in the
// specification, the VDA's `Reset()` clears the input buffers and may (or may not) drop
@@ -738,22 +690,25 @@
// REQBUFS(0). To handle this problem correctly, we need to make libvda expose
// DismissPictureBuffer() method.
match queue_type {
- QueueType::Input => {
- session.reset().map_err(VideoError::VdaError)?;
- }
+ QueueType::Input => session.reset()?,
QueueType::Output => {
- ctx.out_res = Default::default();
+ if std::mem::replace(&mut ctx.is_clear_out_res_needed, false) {
+ ctx.out_res = Default::default();
+ } else {
+ ctx.out_res.queued_res_ids.clear();
+ }
}
- }
+ };
+
Ok(())
}
}
-impl<'a> Device for Decoder<'a> {
+impl<D: DecoderBackend> Device for Decoder<D> {
fn process_cmd(
&mut self,
cmd: VideoCmd,
- poll_ctx: &PollContext<Token>,
+ wait_ctx: &WaitContext<Token>,
resource_bridge: &ResourceRequestSocket,
) -> VideoResult<VideoCmdResponseType> {
use VideoCmd::*;
@@ -780,7 +735,7 @@
// ignore `plane_offsets` as we use `resource_info` given by `resource_bridge` instead.
..
} => {
- self.create_resource(poll_ctx, stream_id, queue_type, resource_id, uuid)?;
+ self.create_resource(wait_ctx, stream_id, queue_type, resource_id, uuid)?;
Ok(Sync(CmdResponse::NoData))
}
ResourceDestroyAll {
@@ -882,15 +837,19 @@
// result that would allow us to return an error to the caller.
use crate::virtio::video::device::VideoEvtResponseType::*;
- use libvda::decode::Event::*;
- let session = match self.sessions.get_mut(&stream_id) {
- Ok(s) => s,
+ let ctx = match self.contexts.get_mut(&stream_id) {
+ Ok(ctx) => ctx,
Err(e) => {
- error!(
- "an event notified for an unknown session {}: {}",
- stream_id, e
- );
+ error!("failed to get a context for session {}: {}", stream_id, e);
+ return None;
+ }
+ };
+
+ let session = match ctx.session.as_mut() {
+ Some(s) => s,
+ None => {
+ error!("session not yet created for context {}", stream_id);
return None;
}
};
@@ -903,50 +862,31 @@
}
};
- let ctx = match self.contexts.get_mut(&stream_id) {
- Ok(ctx) => ctx,
- Err(_) => {
- error!(
- "failed to get a context for session {}: {:?}",
- stream_id, event
- );
- return None;
- }
- };
-
let event_responses = match event {
- ProvidePictureBuffers {
+ DecoderEvent::ProvidePictureBuffers {
min_num_buffers,
width,
height,
- visible_rect_left,
- visible_rect_top,
- visible_rect_right,
- visible_rect_bottom,
+ visible_rect,
} => {
- ctx.handle_provide_picture_buffers(
- min_num_buffers,
- width,
- height,
- visible_rect_left,
- visible_rect_top,
- visible_rect_right,
- visible_rect_bottom,
- );
+ ctx.handle_provide_picture_buffers(min_num_buffers, width, height, visible_rect);
vec![Event(VideoEvt {
typ: EvtType::DecResChanged,
stream_id,
})]
}
- PictureReady {
- buffer_id, // FrameBufferId
+ DecoderEvent::PictureReady {
+ picture_buffer_id, // FrameBufferId
bitstream_id: ts_sec,
- left,
- top,
- right,
- bottom,
+ visible_rect,
} => {
- let resource_id = ctx.handle_picture_ready(buffer_id, left, top, right, bottom)?;
+ let resource_id = ctx.handle_picture_ready(
+ picture_buffer_id,
+ visible_rect.left,
+ visible_rect.top,
+ visible_rect.right,
+ visible_rect.bottom,
+ )?;
let async_response = AsyncCmdResponse::from_response(
AsyncCmdTag::Queue {
stream_id,
@@ -964,7 +904,7 @@
);
vec![AsyncCmd(async_response)]
}
- NotifyEndOfBitstreamBuffer { bitstream_id } => {
+ DecoderEvent::NotifyEndOfBitstreamBuffer(bitstream_id) => {
let resource_id = ctx.handle_notify_end_of_bitstream_buffer(bitstream_id)?;
let async_response = AsyncCmdResponse::from_response(
AsyncCmdTag::Queue {
@@ -980,9 +920,9 @@
);
vec![AsyncCmd(async_response)]
}
- FlushResponse(flush_response) => {
- match flush_response {
- libvda::decode::Response::Success => {
+ DecoderEvent::FlushCompleted(flush_result) => {
+ match flush_result {
+ Ok(()) => {
let eos_resource_id = match ctx.out_res.dequeue_eos_resource_id() {
Some(r) => r,
None => {
@@ -1018,27 +958,27 @@
)),
]
}
- _ => {
+ Err(error) => {
// TODO(b/151810591): If `resp` is `libvda::decode::Response::Canceled`,
// we should notify it to the driver in some way.
error!(
"failed to 'Flush' in VDA (stream id {}): {:?}",
- stream_id, flush_response
+ stream_id, error
);
vec![AsyncCmd(AsyncCmdResponse::from_error(
AsyncCmdTag::Drain { stream_id },
- VideoError::VdaFailure(flush_response),
+ error,
))]
}
}
}
- ResetResponse(reset_response) => {
+ DecoderEvent::ResetCompleted(reset_result) => {
let tag = AsyncCmdTag::Clear {
stream_id,
queue_type: QueueType::Input,
};
- match reset_response {
- libvda::decode::Response::Success => {
+ match reset_result {
+ Ok(()) => {
let mut responses: Vec<_> = desc_map
.create_cancellation_responses(
&stream_id,
@@ -1054,20 +994,17 @@
)));
responses
}
- _ => {
+ Err(error) => {
error!(
"failed to 'Reset' in VDA (stream id {}): {:?}",
- stream_id, reset_response
+ stream_id, error
);
- vec![AsyncCmd(AsyncCmdResponse::from_error(
- tag,
- VideoError::VdaFailure(reset_response),
- ))]
+ vec![AsyncCmd(AsyncCmdResponse::from_error(tag, error))]
}
}
}
- NotifyError(resp) => {
- error!("an error is notified by VDA: {}", resp);
+ DecoderEvent::NotifyError(error) => {
+ error!("an error is notified by VDA: {}", error);
vec![Event(VideoEvt {
typ: EvtType::Error,
stream_id,
@@ -1078,3 +1015,15 @@
Some(event_responses)
}
}
+
+/// Create a new decoder instance using a Libvda decoder instance to perform
+/// the decoding.
+impl<'a> Decoder<&'a libvda::decode::VdaInstance> {
+ pub fn new(vda: &'a libvda::decode::VdaInstance) -> Self {
+ Decoder {
+ decoder: vda,
+ capability: Capability::new(vda.get_capabilities()),
+ contexts: ContextMap::new(),
+ }
+ }
+}
diff --git a/devices/src/virtio/video/device.rs b/devices/src/virtio/video/device.rs
index bd45390..d51405c 100644
--- a/devices/src/virtio/video/device.rs
+++ b/devices/src/virtio/video/device.rs
@@ -4,7 +4,7 @@
//! Definition of the trait `Device` that each backend video device must implement.
-use base::{PollContext, PollToken};
+use base::{PollToken, WaitContext};
use crate::virtio::resource_bridge::ResourceRequestSocket;
use crate::virtio::video::async_cmd_desc_map::AsyncCmdDescMap;
@@ -94,14 +94,14 @@
/// Processes a virtio-video command.
/// If the command expects a synchronous response, it returns a response as `VideoCmdResponseType::Sync`.
/// Otherwise, it returns a name of the descriptor chain that will be used when a response is prepared.
- /// Implementations of this method is passed a PollContext object which can be used to add or remove
+ /// Implementations of this method is passed a WaitContext object which can be used to add or remove
/// FDs to poll. It is expected that only Token::Event items would be added. When a Token::Event
/// event arrives, process_event() will be invoked.
/// TODO(b/149720783): Make this an async function.
fn process_cmd(
&mut self,
cmd: VideoCmd,
- poll_ctx: &PollContext<Token>,
+ wait_ctx: &WaitContext<Token>,
resource_bridge: &ResourceRequestSocket,
) -> VideoResult<VideoCmdResponseType>;
diff --git a/devices/src/virtio/video/encoder/libvda_encoder.rs b/devices/src/virtio/video/encoder/libvda_encoder.rs
index cc5b76f..3f17938 100644
--- a/devices/src/virtio/video/encoder/libvda_encoder.rs
+++ b/devices/src/virtio/video/encoder/libvda_encoder.rs
@@ -5,11 +5,10 @@
use std::collections::btree_map::Entry;
use std::collections::BTreeMap;
use std::fs::File;
-use std::os::unix::io::IntoRawFd;
use libvda::encode::{EncodeCapabilities, VeaImplType, VeaInstance};
-use base::{error, warn};
+use base::{error, warn, IntoRawDescriptor};
use crate::virtio::video::encoder::encoder::*;
use crate::virtio::video::format::{Format, FormatDesc, FormatRange, FrameFormat, Level, Profile};
@@ -52,12 +51,12 @@
frame_formats: vec![FrameFormat {
width: FormatRange {
min: 2,
- max: 1920,
+ max: 4096,
step: 1,
},
height: FormatRange {
min: 2,
- max: 1080,
+ max: 4096,
step: 1,
},
bitrates: vec![FormatRange {
@@ -281,7 +280,7 @@
self.session
.encode(
input_buffer_id as i32,
- resource.into_raw_fd(),
+ resource.into_raw_descriptor(),
&libvda_planes,
timestamp as i64,
force_keyframe,
@@ -298,7 +297,12 @@
self.next_output_buffer_id = self.next_output_buffer_id.wrapping_add(1);
self.session
- .use_output_buffer(output_buffer_id as i32, file.into_raw_fd(), offset, size)
+ .use_output_buffer(
+ output_buffer_id as i32,
+ file.into_raw_descriptor(),
+ offset,
+ size,
+ )
.map_err(|e| EncoderError::Implementation(Box::new(e)))?;
Ok(output_buffer_id)
diff --git a/devices/src/virtio/video/encoder/mod.rs b/devices/src/virtio/video/encoder/mod.rs
index f2e795a..f70734b 100644
--- a/devices/src/virtio/video/encoder/mod.rs
+++ b/devices/src/virtio/video/encoder/mod.rs
@@ -11,7 +11,7 @@
pub use encoder::EncoderError;
pub use libvda_encoder::LibvdaEncoder;
-use base::{error, warn, PollContext};
+use base::{error, warn, WaitContext};
use std::collections::{BTreeMap, BTreeSet};
use crate::virtio::resource_bridge::{self, ResourceRequestSocket};
@@ -168,7 +168,7 @@
fn set_encode_session<U: Encoder<Session = T>>(
&mut self,
encoder: &mut U,
- poll_ctx: &PollContext<Token>,
+ wait_ctx: &WaitContext<Token>,
) -> VideoResult<()> {
if self.encoder_session.is_some() {
error!(
@@ -190,7 +190,7 @@
let event_pipe = new_session.event_pipe();
- poll_ctx
+ wait_ctx
.add(event_pipe, Token::Event { id: self.id })
.map_err(|e| {
error!(
@@ -204,10 +204,10 @@
Ok(())
}
- fn clear_encode_session(&mut self, poll_ctx: &PollContext<Token>) -> VideoResult<()> {
+ fn clear_encode_session(&mut self, wait_ctx: &WaitContext<Token>) -> VideoResult<()> {
if let Some(session) = self.encoder_session.take() {
let event_pipe = session.event_pipe();
- poll_ctx.delete(event_pipe).map_err(|e| {
+ wait_ctx.delete(event_pipe).map_err(|e| {
error!(
"stream: {}: failed to remove fd from poll context: {}",
self.id, e
@@ -573,7 +573,7 @@
fn resource_create(
&mut self,
- poll_ctx: &PollContext<Token>,
+ wait_ctx: &WaitContext<Token>,
resource_bridge: &ResourceRequestSocket,
stream_id: u32,
queue_type: QueueType,
@@ -589,7 +589,7 @@
if !stream.has_encode_session() {
// No encode session would have been created upon the first
// QBUF if there was no previous S_FMT call.
- stream.set_encode_session(&mut self.encoder, poll_ctx)?;
+ stream.set_encode_session(&mut self.encoder, wait_ctx)?;
}
let num_planes = plane_offsets.len();
@@ -924,7 +924,7 @@
fn set_params(
&mut self,
- poll_ctx: &PollContext<Token>,
+ wait_ctx: &WaitContext<Token>,
stream_id: u32,
queue_type: QueueType,
format: Option<Format>,
@@ -991,7 +991,7 @@
// callback which has output buffer size info, in order to populate
// dst_params to have the correct size on subsequent GetParams (G_FMT) calls.
if stream.encoder_session.is_some() {
- stream.clear_encode_session(poll_ctx)?;
+ stream.clear_encode_session(wait_ctx)?;
if !stream.received_input_buffers_event {
// This could happen if two SetParams calls are occuring at the same time.
// For example, the user calls SetParams for the input queue on one thread,
@@ -1006,7 +1006,7 @@
warn!("New encoder session being created while waiting for RequireInputBuffers.")
}
}
- stream.set_encode_session(&mut self.encoder, poll_ctx)?;
+ stream.set_encode_session(&mut self.encoder, wait_ctx)?;
Ok(VideoCmdResponseType::Sync(CmdResponse::NoData))
}
@@ -1082,10 +1082,9 @@
match ctrl_val {
CtrlVal::Bitrate(bitrate) => {
if let Some(ref mut encoder_session) = stream.encoder_session {
- if let Err(e) = encoder_session.request_encoding_params_change(
- stream.dst_bitrate,
- stream.dst_params.frame_rate,
- ) {
+ if let Err(e) = encoder_session
+ .request_encoding_params_change(bitrate, stream.dst_params.frame_rate)
+ {
error!(
"failed to dynamically request encoding params change: {}",
e
@@ -1146,7 +1145,7 @@
fn process_cmd(
&mut self,
req: VideoCmd,
- poll_ctx: &PollContext<Token>,
+ wait_ctx: &WaitContext<Token>,
resource_bridge: &ResourceRequestSocket,
) -> VideoResult<VideoCmdResponseType> {
match req {
@@ -1164,7 +1163,7 @@
plane_offsets,
uuid,
} => self.resource_create(
- poll_ctx,
+ wait_ctx,
resource_bridge,
stream_id,
queue_type,
@@ -1207,7 +1206,7 @@
..
},
} => self.set_params(
- poll_ctx,
+ wait_ctx,
stream_id,
queue_type,
format,
diff --git a/devices/src/virtio/video/error.rs b/devices/src/virtio/video/error.rs
index 11256d3..49e456a 100644
--- a/devices/src/virtio/video/error.rs
+++ b/devices/src/virtio/video/error.rs
@@ -61,6 +61,12 @@
}
}
+impl From<libvda::Error> for VideoError {
+ fn from(error: libvda::Error) -> Self {
+ VideoError::VdaError(error)
+ }
+}
+
impl std::error::Error for VideoError {}
pub type VideoResult<T> = Result<T, VideoError>;
diff --git a/devices/src/virtio/video/format.rs b/devices/src/virtio/video/format.rs
index 7a5e4ed..a7d61ce 100644
--- a/devices/src/virtio/video/format.rs
+++ b/devices/src/virtio/video/format.rs
@@ -273,3 +273,12 @@
Some(format) => (format.width.max, format.height.max),
}
}
+
+/// A rectangle used to describe portions of a frame.
+#[derive(Debug)]
+pub struct Rect {
+ pub left: i32,
+ pub top: i32,
+ pub right: i32,
+ pub bottom: i32,
+}
diff --git a/devices/src/virtio/video/mod.rs b/devices/src/virtio/video/mod.rs
index 637324b..e7c95f0 100644
--- a/devices/src/virtio/video/mod.rs
+++ b/devices/src/virtio/video/mod.rs
@@ -8,10 +8,9 @@
//! [v3 RFC]: https://markmail.org/thread/wxdne5re7aaugbjg
use std::fmt::{self, Display};
-use std::os::unix::io::{AsRawFd, RawFd};
use std::thread;
-use base::{error, Error as SysError, Event};
+use base::{error, AsRawDescriptor, Error as SysError, Event, RawDescriptor};
use data_model::{DataInit, Le32};
use vm_memory::GuestMemory;
@@ -45,14 +44,14 @@
/// An error indicating something went wrong in virtio-video's worker.
#[derive(Debug)]
pub enum Error {
- /// Creating PollContext failed.
- PollContextCreationFailed(SysError),
+ /// Creating WaitContext failed.
+ WaitContextCreationFailed(SysError),
/// A DescriptorChain contains invalid data.
InvalidDescriptorChain(DescriptorError),
/// No available descriptor in which an event is written to.
DescriptorNotAvailable,
/// Error while polling for events.
- PollError(SysError),
+ WaitError(SysError),
/// Failed to read a virtio-video command.
ReadFailure(ReadCmdError),
/// Got response for an unexpected asynchronous command.
@@ -68,12 +67,12 @@
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
match self {
- PollContextCreationFailed(e) => write!(f, "failed to create PollContext: {}", e),
+ WaitContextCreationFailed(e) => write!(f, "failed to create WaitContext: {}", e),
InvalidDescriptorChain(e) => write!(f, "DescriptorChain contains invalid data: {}", e),
DescriptorNotAvailable => {
write!(f, "no available descriptor in which an event is written to")
}
- PollError(err) => write!(f, "failed to poll events: {}", err),
+ WaitError(err) => write!(f, "failed to wait for events: {}", err),
ReadFailure(e) => write!(f, "failed to read a command from the guest: {}", e),
UnexpectedResponse(tag) => {
write!(f, "got a response for an untracked command: {:?}", tag)
@@ -128,12 +127,12 @@
}
impl VirtioDevice for VideoDevice {
- fn keep_fds(&self) -> Vec<RawFd> {
- let mut keep_fds = Vec::new();
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ let mut keep_rds = Vec::new();
if let Some(resource_bridge) = &self.resource_bridge {
- keep_fds.push(resource_bridge.as_raw_fd());
+ keep_rds.push(resource_bridge.as_raw_descriptor());
}
- keep_fds
+ keep_rds
}
fn device_type(&self) -> u32 {
diff --git a/devices/src/virtio/video/worker.rs b/devices/src/virtio/video/worker.rs
index fcdd1cd..0bac2fc 100644
--- a/devices/src/virtio/video/worker.rs
+++ b/devices/src/virtio/video/worker.rs
@@ -6,7 +6,7 @@
use std::collections::VecDeque;
-use base::{error, Event, PollContext};
+use base::{error, info, Event, WaitContext};
use vm_memory::GuestMemory;
use crate::virtio::queue::{DescriptorChain, Queue};
@@ -14,7 +14,7 @@
use crate::virtio::video::async_cmd_desc_map::AsyncCmdDescMap;
use crate::virtio::video::command::{QueueType, VideoCmd};
use crate::virtio::video::device::{
- AsyncCmdResponse, Device, Token, VideoCmdResponseType, VideoEvtResponseType,
+ AsyncCmdResponse, AsyncCmdTag, Device, Token, VideoCmdResponseType, VideoEvtResponseType,
};
use crate::virtio::video::event::{self, EvtType, VideoEvt};
use crate::virtio::video::response::{self, Response};
@@ -82,7 +82,7 @@
fn handle_command_desc<T: Device>(
&self,
device: &mut T,
- poll_ctx: &PollContext<Token>,
+ wait_ctx: &WaitContext<Token>,
desc_map: &mut AsyncCmdDescMap,
desc: DescriptorChain,
) -> Result<VecDeque<WritableResp>> {
@@ -133,7 +133,7 @@
}
// Process the command by the device.
- let process_cmd_response = device.process_cmd(cmd, &poll_ctx, &self.resource_bridge);
+ let process_cmd_response = device.process_cmd(cmd, &wait_ctx, &self.resource_bridge);
match process_cmd_response {
Ok(VideoCmdResponseType::Sync(r)) => {
responses.push_back((desc, r));
@@ -158,12 +158,12 @@
&self,
cmd_queue: &mut Queue,
device: &mut T,
- poll_ctx: &PollContext<Token>,
+ wait_ctx: &WaitContext<Token>,
desc_map: &mut AsyncCmdDescMap,
) -> Result<()> {
let _ = self.cmd_evt.read();
while let Some(desc) = cmd_queue.pop(&self.mem) {
- let mut resps = self.handle_command_desc(device, poll_ctx, desc_map, desc)?;
+ let mut resps = self.handle_command_desc(device, wait_ctx, desc_map, desc)?;
self.write_responses(cmd_queue, &mut resps)?;
}
Ok(())
@@ -187,17 +187,29 @@
tag,
response: cmd_result,
} = async_response;
- let desc = desc_map
- .remove(&tag)
- .ok_or_else(|| Error::UnexpectedResponse(tag))?;
- let cmd_response = match cmd_result {
- Ok(r) => r,
- Err(e) => {
- error!("returning async error response: {}", &e);
- e.into()
+ match desc_map.remove(&tag) {
+ Some(desc) => {
+ let cmd_response = match cmd_result {
+ Ok(r) => r,
+ Err(e) => {
+ error!("returning async error response: {}", &e);
+ e.into()
+ }
+ };
+ responses.push_back((desc, cmd_response))
}
- };
- responses.push_back((desc, cmd_response));
+ None => match tag {
+ // TODO(b/153406792): Drain is cancelled by clearing either of the
+ // stream's queues. To work around a limitation in the VDA api, the
+ // output queue is cleared synchronously without going through VDA.
+ // Because of this, the cancellation response from VDA for the
+ // input queue might fail to find the drain's AsyncCmdTag.
+ AsyncCmdTag::Drain { stream_id: _ } => {
+ info!("ignoring unknown drain response");
+ }
+ _ => return Err(Error::UnexpectedResponse(tag)),
+ },
+ }
}
VideoEvtResponseType::Event(evt) => {
self.write_event(event_queue, evt)?;
@@ -228,27 +240,27 @@
mut event_queue: Queue,
mut device: T,
) -> Result<()> {
- let poll_ctx: PollContext<Token> = PollContext::build_with(&[
+ let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
(&self.cmd_evt, Token::CmdQueue),
(&self.event_evt, Token::EventQueue),
(&self.kill_evt, Token::Kill),
(self.interrupt.get_resample_evt(), Token::InterruptResample),
])
- .map_err(Error::PollContextCreationFailed)?;
+ .map_err(Error::WaitContextCreationFailed)?;
// Stores descriptors in which responses for asynchronous commands will be written.
let mut desc_map: AsyncCmdDescMap = Default::default();
loop {
- let poll_events = poll_ctx.wait().map_err(Error::PollError)?;
+ let wait_events = wait_ctx.wait().map_err(Error::WaitError)?;
- for poll_event in poll_events.iter_readable() {
- match poll_event.token() {
+ for wait_event in wait_events.iter().filter(|e| e.is_readable) {
+ match wait_event.token {
Token::CmdQueue => {
self.handle_command_queue(
&mut cmd_queue,
&mut device,
- &poll_ctx,
+ &wait_ctx,
&mut desc_map,
)?;
}
diff --git a/devices/src/virtio/virtio_device.rs b/devices/src/virtio/virtio_device.rs
index 36f5a56..c181b44 100644
--- a/devices/src/virtio/virtio_device.rs
+++ b/devices/src/virtio/virtio_device.rs
@@ -2,9 +2,7 @@
// 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 base::Event;
+use base::{Event, RawDescriptor};
use vm_memory::GuestMemory;
use super::*;
@@ -28,7 +26,7 @@
/// 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>;
+ fn keep_rds(&self) -> Vec<RawDescriptor>;
/// The virtio device type.
fn device_type(&self) -> u32;
diff --git a/devices/src/virtio/virtio_pci_common_config.rs b/devices/src/virtio/virtio_pci_common_config.rs
index 41d9799..ea8975f 100644
--- a/devices/src/virtio/virtio_pci_common_config.rs
+++ b/devices/src/virtio/virtio_pci_common_config.rs
@@ -243,8 +243,7 @@
mod tests {
use super::*;
- use base::Event;
- use std::os::unix::io::RawFd;
+ use base::{Event, RawDescriptor};
use vm_memory::GuestMemory;
struct DummyDevice(u32);
@@ -252,7 +251,7 @@
const QUEUE_SIZES: &'static [u16] = &[QUEUE_SIZE];
const DUMMY_FEATURES: u64 = 0x5555_aaaa;
impl VirtioDevice for DummyDevice {
- fn keep_fds(&self) -> Vec<RawFd> {
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
Vec::new()
}
fn device_type(&self) -> u32 {
diff --git a/devices/src/virtio/virtio_pci_device.rs b/devices/src/virtio/virtio_pci_device.rs
index e1654a8..7d0913a 100644
--- a/devices/src/virtio/virtio_pci_device.rs
+++ b/devices/src/virtio/virtio_pci_device.rs
@@ -2,12 +2,11 @@
// 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, Ordering};
use std::sync::Arc;
use sync::Mutex;
-use base::{warn, Event, Result};
+use base::{warn, AsRawDescriptor, Event, RawDescriptor, Result};
use data_model::{DataInit, Le32};
use hypervisor::Datamatch;
use libc::ERANGE;
@@ -17,8 +16,8 @@
use super::*;
use crate::pci::{
MsixCap, MsixConfig, PciAddress, PciBarConfiguration, PciCapability, PciCapabilityID,
- PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciInterruptPin,
- PciSubclass,
+ PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciDisplaySubclass, PciHeaderType,
+ PciInterruptPin, PciSubclass,
};
use vm_control::VmIrqRequestSocket;
@@ -236,6 +235,17 @@
let pci_device_id = VIRTIO_PCI_DEVICE_ID_BASE + device.device_type() as u16;
+ let (pci_device_class, pci_device_subclass) = match device.device_type() {
+ TYPE_GPU => (
+ PciClassCode::DisplayController,
+ &PciDisplaySubclass::Other as &dyn PciSubclass,
+ ),
+ _ => (
+ PciClassCode::Other,
+ &PciVirtioSubclass::NonTransitionalBase as &dyn PciSubclass,
+ ),
+ };
+
let num_queues = device.queue_max_sizes().len();
// One MSI-X vector per queue plus one for configuration changes.
@@ -245,8 +255,8 @@
let config_regs = PciConfiguration::new(
VIRTIO_PCI_VENDOR_ID,
pci_device_id,
- PciClassCode::Other,
- &PciVirtioSubclass::NonTransitionalBase,
+ pci_device_class,
+ pci_device_subclass,
None,
PciHeaderType::Device,
VIRTIO_PCI_VENDOR_ID,
@@ -386,17 +396,17 @@
self.pci_address = Some(address);
}
- fn keep_fds(&self) -> Vec<RawFd> {
- let mut fds = self.device.keep_fds();
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ let mut rds = self.device.keep_rds();
if let Some(interrupt_evt) = &self.interrupt_evt {
- fds.push(interrupt_evt.as_raw_fd());
+ rds.push(interrupt_evt.as_raw_descriptor());
}
if let Some(interrupt_resample_evt) = &self.interrupt_resample_evt {
- fds.push(interrupt_resample_evt.as_raw_fd());
+ rds.push(interrupt_resample_evt.as_raw_descriptor());
}
- let fd = self.msix_config.lock().get_msi_socket();
- fds.push(fd);
- fds
+ let descriptor = self.msix_config.lock().get_msi_socket();
+ rds.push(descriptor);
+ rds
}
fn assign_irq(
diff --git a/devices/src/virtio/wl.rs b/devices/src/virtio/wl.rs
index b11f1fa..d2c5180 100644
--- a/devices/src/virtio/wl.rs
+++ b/devices/src/virtio/wl.rs
@@ -39,7 +39,6 @@
use std::mem::size_of;
#[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;
@@ -57,7 +56,8 @@
use base::ioctl_iow_nr;
use base::{
error, pipe, round_up_to_page_size, warn, AsRawDescriptor, Error, Event, FileFlags,
- PollContext, PollToken, Result, ScmSocket, SharedMemory, SharedMemoryUnix,
+ FromRawDescriptor, PollToken, RawDescriptor, Result, ScmSocket, SharedMemory, SharedMemoryUnix,
+ WaitContext,
};
use msg_socket::{MsgError, MsgReceiver, MsgSender};
#[cfg(feature = "wl-dmabuf")]
@@ -70,7 +70,7 @@
use super::resource_bridge::*;
use super::{DescriptorChain, Interrupt, Queue, Reader, VirtioDevice, Writer, TYPE_WL};
use vm_control::{
- MaybeOwnedFd, MemSlot, VmMemoryControlRequestSocket, VmMemoryRequest, VmMemoryResponse,
+ MaybeOwnedDescriptor, MemSlot, VmMemoryControlRequestSocket, VmMemoryRequest, VmMemoryResponse,
};
const VIRTWL_SEND_MAX_ALLOCS: usize = 28;
@@ -273,7 +273,7 @@
WritePipe(io::Error),
RecvVfd(Error),
ReadPipe(io::Error),
- PollContextAdd(Error),
+ WaitContextAdd(Error),
DmabufSync(io::Error),
FromSharedMemory(Error),
WriteResponse(io::Error),
@@ -300,7 +300,7 @@
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),
+ WaitContextAdd(e) => write!(f, "failed to listen to descriptor on wait context: {}", e),
DmabufSync(e) => write!(f, "failed to synchronize DMABuf access: {}", e),
FromSharedMemory(e) => {
write!(f, "failed to create shared memory from descriptor: {}", e)
@@ -531,16 +531,16 @@
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())?;
+ write!(f, " socket: {}", s.as_raw_descriptor())?;
}
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())?;
+ write!(f, " remote: {}", s.as_raw_descriptor())?;
}
if let Some((_, s)) = &self.local_pipe {
- write!(f, " local: {}", s.as_raw_fd())?;
+ write!(f, " local: {}", s.as_raw_descriptor())?;
}
write!(f, " }}")
}
@@ -560,7 +560,7 @@
SharedMemory::named("virtwl_alloc", size_page_aligned).map_err(WlError::NewAlloc)?;
let register_response = vm.request(VmMemoryRequest::RegisterMemory(
- MaybeOwnedFd::Borrowed(vfd_shm.as_raw_descriptor()),
+ MaybeOwnedDescriptor::Borrowed(vfd_shm.as_raw_descriptor()),
vfd_shm.size() as usize,
))?;
match register_response {
@@ -589,13 +589,14 @@
})?;
match allocate_and_register_gpu_memory_response {
VmMemoryResponse::AllocateAndRegisterGpuMemory {
- fd: MaybeOwnedFd::Owned(file),
+ descriptor: MaybeOwnedDescriptor::Owned(file),
pfn,
slot,
desc,
} => {
let mut vfd = WlVfd::default();
- let vfd_shm = SharedMemory::from_file(file).map_err(WlError::NewAlloc)?;
+ let vfd_shm =
+ SharedMemory::from_safe_descriptor(file).map_err(WlError::NewAlloc)?;
vfd.guest_shared_memory = Some((vfd_shm.size(), vfd_shm));
vfd.slot = Some((slot, pfn, vm));
vfd.is_dmabuf = true;
@@ -612,12 +613,12 @@
}
match &self.guest_shared_memory {
- Some((_, fd)) => {
+ Some((_, descriptor)) => {
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 {
+ // Safe as descriptor is a valid dmabuf and incorrect flags will return an error.
+ if unsafe { ioctl_with_ref(descriptor, DMA_BUF_IOCTL_SYNC(), &sync) } < 0 {
Err(WlError::DmabufSync(io::Error::last_os_error()))
} else {
Ok(())
@@ -643,17 +644,17 @@
Ok(vfd)
}
- fn from_file(vm: VmRequester, mut fd: File) -> WlResult<WlVfd> {
+ fn from_file(vm: VmRequester, mut descriptor: 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)) {
+ match descriptor.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()),
+ MaybeOwnedDescriptor::Borrowed(descriptor.as_raw_descriptor()),
size as usize,
))?;
@@ -662,7 +663,8 @@
let mut vfd = WlVfd::default();
vfd.guest_shared_memory = Some((
size,
- SharedMemory::from_file(fd).map_err(WlError::FromSharedMemory)?,
+ SharedMemory::from_file(descriptor)
+ .map_err(WlError::FromSharedMemory)?,
));
vfd.slot = Some((slot, pfn, vm));
Ok(vfd)
@@ -671,14 +673,14 @@
}
}
_ => {
- let flags = match FileFlags::from_file(&fd) {
+ let flags = match FileFlags::from_file(&descriptor) {
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));
+ vfd.local_pipe = Some((flags, descriptor));
Ok(vfd)
}
}
@@ -715,34 +717,37 @@
}
// The FD that gets sent if this VFD is sent over a socket.
- fn send_fd(&self) -> Option<RawFd> {
+ fn send_descriptor(&self) -> Option<RawDescriptor> {
self.guest_shared_memory
.as_ref()
- .map(|(_, fd)| fd.as_raw_descriptor())
- .or(self.socket.as_ref().map(|s| s.as_raw_fd()))
- .or(self.remote_pipe.as_ref().map(|p| p.as_raw_fd()))
+ .map(|(_, shm)| shm.as_raw_descriptor())
+ .or(self.socket.as_ref().map(|s| s.as_raw_descriptor()))
+ .or(self.remote_pipe.as_ref().map(|p| p.as_raw_descriptor()))
}
// The FD that is used for polling for events on this VFD.
- fn poll_fd(&self) -> Option<&dyn AsRawFd> {
+ fn wait_descriptor(&self) -> Option<&dyn AsRawDescriptor> {
self.socket
.as_ref()
- .map(|s| s as &dyn AsRawFd)
- .or(self.local_pipe.as_ref().map(|(_, p)| p as &dyn AsRawFd))
+ .map(|s| s as &dyn AsRawDescriptor)
+ .or(self
+ .local_pipe
+ .as_ref()
+ .map(|(_, p)| p as &dyn AsRawDescriptor))
}
// Sends data/files from the guest to the host over this VFD.
- fn send(&mut self, fds: &[RawFd], data: &mut Reader) -> WlResult<WlResp> {
+ fn send(&mut self, rds: &[RawDescriptor], data: &mut Reader) -> WlResult<WlResp> {
if let Some(socket) = &self.socket {
socket
- .send_with_fds(&data.get_remaining(), fds)
+ .send_with_fds(&data.get_remaining(), rds)
.map_err(WlError::SendVfd)?;
// All remaining data in `data` is now considered consumed.
data.consume(::std::usize::MAX);
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() {
+ // Impossible to send descriptors over a simple pipe.
+ if !rds.is_empty() {
return Ok(WlResp::InvalidType);
}
data.read_to(local_pipe, usize::max_value())
@@ -772,7 +777,7 @@
in_file_queue.extend(
fd_buf[..file_count]
.iter()
- .map(|&fd| unsafe { File::from_raw_fd(fd) }),
+ .map(|&descriptor| unsafe { File::from_raw_descriptor(descriptor) }),
);
return Ok(buf);
}
@@ -828,7 +833,7 @@
vm: VmRequester,
resource_bridge: Option<ResourceRequestSocket>,
use_transition_flags: bool,
- poll_ctx: PollContext<u32>,
+ wait_ctx: WaitContext<u32>,
vfds: Map<u32, WlVfd>,
next_vfd_id: u32,
in_file_queue: Vec<File>,
@@ -848,7 +853,7 @@
wayland_paths,
vm: VmRequester::new(vm_socket),
resource_bridge,
- poll_ctx: PollContext::new().expect("failed to create PollContext"),
+ wait_ctx: WaitContext::new().expect("failed to create WaitContext"),
use_transition_flags,
vfds: Map::new(),
next_vfd_id: NEXT_VFD_ID_BASE,
@@ -881,9 +886,9 @@
} else {
return Ok(WlResp::InvalidFlags);
};
- self.poll_ctx
- .add(vfd.poll_fd().unwrap(), id)
- .map_err(WlError::PollContextAdd)?;
+ self.wait_ctx
+ .add(vfd.wait_descriptor().unwrap(), id)
+ .map_err(WlError::WaitContextAdd)?;
let resp = WlResp::VfdNew {
id,
flags: 0,
@@ -985,9 +990,9 @@
.get(name)
.ok_or(WlError::UnknownSocketName(name.to_string()))?,
)?);
- self.poll_ctx
- .add(vfd.poll_fd().unwrap(), id)
- .map_err(WlError::PollContextAdd)?;
+ self.wait_ctx
+ .add(vfd.wait_descriptor().unwrap(), id)
+ .map_err(WlError::WaitContextAdd)?;
Ok(WlResp::VfdNew {
id,
flags,
@@ -1000,8 +1005,8 @@
}
}
- fn process_poll_context(&mut self) {
- let events = match self.poll_ctx.wait_timeout(Duration::from_secs(0)) {
+ fn process_wait_context(&mut self) {
+ let events = match self.wait_ctx.wait_timeout(Duration::from_secs(0)) {
Ok(v) => v.to_owned(),
Err(e) => {
error!("failed polling for vfd evens: {}", e);
@@ -1009,17 +1014,19 @@
}
};
- for event in events.as_ref().iter_readable() {
- if let Err(e) = self.recv(event.token()) {
+ for event in events.iter().filter(|e| e.is_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) {
+ for event in events.iter().filter(|e| e.is_hungup) {
+ if !event.is_readable {
+ let vfd_id = event.token;
+ if let Some(descriptor) =
+ self.vfds.get(&vfd_id).and_then(|vfd| vfd.wait_descriptor())
+ {
+ if let Err(e) = self.wait_ctx.delete(descriptor) {
warn!("failed to remove hungup vfd from poll context: {}", e);
}
}
@@ -1072,15 +1079,15 @@
}
// Next stage collects corresponding file descriptors for each id.
- let mut fds = [0; VIRTWL_SEND_MAX_ALLOCS];
+ let mut rds = [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()) {
+ for (&send_vfd_id, descriptor) in send_vfd_ids[..vfd_count].iter().zip(rds.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,
+ Some(vfd) => match vfd.send_descriptor() {
+ Some(vfd_fd) => *descriptor = vfd_fd,
None => return Ok(WlResp::InvalidType),
},
None => {
@@ -1093,7 +1100,7 @@
let sock = self.resource_bridge.as_ref().unwrap();
match get_resource_info(sock, id) {
Ok(info) => {
- *fd = info.file.as_raw_fd();
+ *descriptor = info.file.as_raw_descriptor();
bridged_files.push(info.file);
}
Err(ResourceBridgeError::InvalidResource(id)) => {
@@ -1125,7 +1132,7 @@
// 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], reader)? {
+ Some(vfd) => match vfd.send(&rds[..vfd_count], reader)? {
WlResp::Ok => {}
_ => return Ok(WlResp::InvalidType),
},
@@ -1154,10 +1161,10 @@
}
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)?;
+ if let Some(wait_descriptor) = vfd.wait_descriptor() {
+ self.wait_ctx
+ .add(wait_descriptor, self.next_vfd_id)
+ .map_err(WlError::WaitContextAdd)?;
}
self.vfds.insert(self.next_vfd_id, vfd);
self.in_queue.push_back((
@@ -1391,24 +1398,24 @@
InterruptResample,
}
- let poll_ctx: PollContext<Token> = match PollContext::build_with(&[
+ let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
(&in_queue_evt, Token::InQueue),
(&out_queue_evt, Token::OutQueue),
(&kill_evt, Token::Kill),
- (&self.state.poll_ctx, Token::State),
+ (&self.state.wait_ctx, Token::State),
(self.interrupt.get_resample_evt(), Token::InterruptResample),
]) {
Ok(pc) => pc,
Err(e) => {
- error!("failed creating PollContext: {}", e);
+ error!("failed creating WaitContext: {}", e);
return;
}
};
- 'poll: loop {
+ 'wait: loop {
let mut signal_used_in = false;
let mut signal_used_out = false;
- let events = match poll_ctx.wait() {
+ let events = match wait_ctx.wait() {
Ok(v) => v,
Err(e) => {
error!("failed polling for events: {}", e);
@@ -1417,7 +1424,7 @@
};
for event in &events {
- match event.token() {
+ match event.token {
Token::InQueue => {
let _ = in_queue_evt.read();
// Used to buffer descriptor indexes that are invalid for our uses.
@@ -1482,8 +1489,8 @@
}
}
}
- Token::Kill => break 'poll,
- Token::State => self.state.process_poll_context(),
+ Token::Kill => break 'wait,
+ Token::State => self.state.process_wait_context(),
Token::InterruptResample => {
self.interrupt.interrupt_resample();
}
@@ -1580,17 +1587,17 @@
}
impl VirtioDevice for Wl {
- fn keep_fds(&self) -> Vec<RawFd> {
- let mut keep_fds = Vec::new();
+ fn keep_rds(&self) -> Vec<RawDescriptor> {
+ let mut keep_rds = Vec::new();
if let Some(vm_socket) = &self.vm_socket {
- keep_fds.push(vm_socket.as_raw_fd());
+ keep_rds.push(vm_socket.as_raw_descriptor());
}
if let Some(resource_bridge) = &self.resource_bridge {
- keep_fds.push(resource_bridge.as_raw_fd());
+ keep_rds.push(resource_bridge.as_raw_descriptor());
}
- keep_fds
+ keep_rds
}
fn device_type(&self) -> u32 {
diff --git a/disk/Android.bp b/disk/Android.bp
index 4c281e4..53dda95 100644
--- a/disk/Android.bp
+++ b/disk/Android.bp
@@ -41,7 +41,7 @@
srcs: ["src/disk.rs"],
edition: "2018",
features: [
- "composite-disk",
+ "composite-disk", // Added manually
],
rustlibs: [
"libbase_rust",
@@ -49,8 +49,8 @@
"libdata_model",
"libfutures",
"liblibc",
- "libprotobuf",
- "libprotos",
+ "libprotobuf", // Added manually
+ "libprotos", // Added manually
"libtempfile",
"libvm_memory",
],
@@ -96,7 +96,7 @@
// remain-0.2.2
// remove_dir_all-0.5.3
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// tempfile-3.1.0
// thiserror-1.0.22
// thiserror-impl-1.0.22
diff --git a/disk/src/composite.rs b/disk/src/composite.rs
index 0fff37c..a23eca0 100644
--- a/disk/src/composite.rs
+++ b/disk/src/composite.rs
@@ -7,12 +7,11 @@
use std::fs::{File, OpenOptions};
use std::io::{self, ErrorKind, Read, Seek, SeekFrom};
use std::ops::Range;
-use std::os::unix::io::RawFd;
use crate::{create_disk_file, DiskFile, DiskGetLen, ImageType};
use base::{
AsRawDescriptors, FileAllocate, FileReadWriteAtVolatile, FileSetLen, FileSync, PunchHole,
- WriteZeroesAt,
+ RawDescriptor, WriteZeroesAt,
};
use data_model::VolatileSlice;
use protos::cdisk_spec;
@@ -331,7 +330,7 @@
}
impl AsRawDescriptors for CompositeDiskFile {
- fn as_raw_descriptors(&self) -> Vec<RawFd> {
+ fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
self.component_disks
.iter()
.map(|d| d.file.as_raw_descriptors())
@@ -343,9 +342,8 @@
#[cfg(test)]
mod tests {
use super::*;
- use base::SharedMemory;
+ use base::{AsRawDescriptor, SharedMemory};
use data_model::VolatileMemory;
- use std::os::unix::io::AsRawFd;
#[test]
fn block_duplicate_offset_disks() {
@@ -410,7 +408,11 @@
let file1: File = SharedMemory::new(None).unwrap().into();
let file2: File = SharedMemory::new(None).unwrap().into();
let file3: File = SharedMemory::new(None).unwrap().into();
- let mut in_fds = vec![file1.as_raw_fd(), file2.as_raw_fd(), file3.as_raw_fd()];
+ let mut in_fds = vec![
+ file1.as_raw_descriptor(),
+ file2.as_raw_descriptor(),
+ file3.as_raw_descriptor(),
+ ];
in_fds.sort();
let disk_part1 = ComponentDiskPart {
file: Box::new(file1),
diff --git a/disk/src/disk.rs b/disk/src/disk.rs
index 70d58b2..3fa5fca 100644
--- a/disk/src/disk.rs
+++ b/disk/src/disk.rs
@@ -382,7 +382,7 @@
impl TryFrom<File> for SingleFileDisk {
type Error = Error;
fn try_from(inner: File) -> Result<Self> {
- cros_async::new(inner)
+ cros_async::async_from(inner)
.map_err(Error::CreateSingleFileDisk)
.map(|inner| SingleFileDisk { inner })
}
diff --git a/disk/src/qcow/mod.rs b/disk/src/qcow/mod.rs
index 2ef00ab..2b649a3 100644
--- a/disk/src/qcow/mod.rs
+++ b/disk/src/qcow/mod.rs
@@ -7,8 +7,8 @@
mod vec_cache;
use base::{
- error, AsRawDescriptors, FileAllocate, FileReadWriteAtVolatile, FileReadWriteVolatile,
- FileSetLen, FileSync, PunchHole, SeekHole, WriteZeroesAt,
+ error, AsRawDescriptor, AsRawDescriptors, FileAllocate, FileReadWriteAtVolatile,
+ FileReadWriteVolatile, FileSetLen, FileSync, PunchHole, RawDescriptor, SeekHole, WriteZeroesAt,
};
use data_model::{VolatileMemory, VolatileSlice};
use libc::{EINVAL, ENOSPC, ENOTSUP};
@@ -19,7 +19,6 @@
use std::fs::{File, OpenOptions};
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::mem::size_of;
-use std::os::unix::io::{AsRawFd, RawFd};
use std::str;
use crate::qcow::qcow_raw_file::QcowRawFile;
@@ -1534,12 +1533,12 @@
}
impl AsRawDescriptors for QcowFile {
- fn as_raw_descriptors(&self) -> Vec<RawFd> {
- let mut fds = vec![self.raw_file.file().as_raw_fd()];
+ fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
+ let mut descriptors = vec![self.raw_file.file().as_raw_descriptor()];
if let Some(backing) = &self.backing_file {
- fds.append(&mut backing.as_raw_descriptors());
+ descriptors.append(&mut backing.as_raw_descriptors());
}
- fds
+ descriptors
}
}
diff --git a/docker/checkout_commits.env b/docker/checkout_commits.env
index 5556e5a..2c7ad0d 100644
--- a/docker/checkout_commits.env
+++ b/docker/checkout_commits.env
@@ -1,7 +1,7 @@
MESON_COMMIT=a1a8772034aef90e8d58230d8bcfce54ab27bf6a
LIBEPOXY_COMMIT=34ecb908b044446226f4cf8829419664ae0ca544
TPM2_COMMIT=a9bc45bb7fafc65ea8a787894434d409f533b1f1
-PLATFORM2_COMMIT=a386d01923b4d03e939560c09b326e5f38ec2ecc
+PLATFORM2_COMMIT=2079dd5fcd61f1ac39e2fc16595956617f3f1e9e
ADHD_COMMIT=932f912aa5a0c25c1d5806aa4ad9d8d4d4d98e84
DRM_COMMIT=00320d7d68ddc7d815d073bb7c92d9a1f9bb8c31
MINIJAIL_COMMIT=85d797ecbfd7aefbb9486afeaed3cf5f74858562
diff --git a/enumn/Android.bp b/enumn/Android.bp
index 6daf181..8a202f0 100644
--- a/enumn/Android.bp
+++ b/enumn/Android.bp
@@ -31,5 +31,5 @@
// dependent_library ["feature_list"]
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// syn-1.0.53 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
// unicode-xid-0.2.1 "default"
diff --git a/fuse/Android.bp b/fuse/Android.bp
new file mode 100644
index 0000000..8e4260b
--- /dev/null
+++ b/fuse/Android.bp
@@ -0,0 +1,81 @@
+// This file is generated by cargo2android.py --run --device --tests --dependencies --global_defaults=crosvm_defaults --add_workspace.
+
+rust_defaults {
+ name: "fuse_defaults",
+ defaults: ["crosvm_defaults"],
+ crate_name: "fuse",
+ srcs: ["src/lib.rs"],
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ edition: "2018",
+ rustlibs: [
+ "libbase_rust",
+ "libbitflags",
+ "libdata_model",
+ "liblibc",
+ "libthiserror",
+ ],
+ proc_macros: ["libenumn"],
+}
+
+rust_test_host {
+ name: "fuse_host_test_src_lib",
+ defaults: ["fuse_defaults"],
+}
+
+rust_test {
+ name: "fuse_device_test_src_lib",
+ defaults: ["fuse_defaults"],
+}
+
+rust_library {
+ name: "libfuse_rust",
+ defaults: ["crosvm_defaults"],
+ stem: "libfuse",
+ host_supported: true,
+ crate_name: "fuse",
+ srcs: ["src/lib.rs"],
+ edition: "2018",
+ rustlibs: [
+ "libbase_rust",
+ "libbitflags",
+ "libdata_model",
+ "liblibc",
+ "libthiserror",
+ ],
+ proc_macros: ["libenumn"],
+}
+
+// dependent_library ["feature_list"]
+// ../assertions/src/lib.rs
+// ../base/src/lib.rs
+// ../cros_async/src/lib.rs
+// ../data_model/src/lib.rs
+// ../enumn/src/lib.rs
+// ../io_uring/src/lib.rs
+// ../sync/src/lib.rs
+// ../sys_util/poll_token_derive/poll_token_derive.rs
+// ../sys_util/src/lib.rs
+// ../syscall_defines/src/lib.rs
+// ../tempfile/src/lib.rs
+// async-trait-0.1.42
+// bitflags-1.2.1 "default"
+// futures-0.3.8 "alloc"
+// futures-channel-0.3.8 "alloc,futures-sink,sink"
+// futures-core-0.3.8 "alloc"
+// futures-io-0.3.8
+// futures-sink-0.3.8 "alloc"
+// futures-task-0.3.8 "alloc"
+// futures-util-0.3.8 "alloc,futures-sink,sink"
+// libc-0.2.80 "default,std"
+// paste-1.0.3
+// pin-project-1.0.2
+// pin-project-internal-1.0.2
+// pin-utils-0.1.0
+// proc-macro2-1.0.24 "default,proc-macro"
+// quote-1.0.7 "default,proc-macro"
+// slab-0.4.2
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// thiserror-1.0.22
+// thiserror-impl-1.0.22
+// unicode-xid-0.2.1 "default"
diff --git a/fuse/Cargo.toml b/fuse/Cargo.toml
new file mode 100644
index 0000000..94226b5
--- /dev/null
+++ b/fuse/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "fuse"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[lib]
+path = "src/lib.rs"
+
+[dependencies]
+base = { path = "../base" }
+bitflags = "1"
+data_model = { path = "../data_model" }
+enumn = { path = "../enumn" }
+libc = "*"
+thiserror = "1.0.20"
diff --git a/fuse/TEST_MAPPING b/fuse/TEST_MAPPING
new file mode 100644
index 0000000..bc91121
--- /dev/null
+++ b/fuse/TEST_MAPPING
@@ -0,0 +1,13 @@
+// Generated by cargo2android.py for tests in Android.bp
+{
+ "presubmit": [
+ {
+ "host": true,
+ "name": "fuse_host_test_src_lib"
+// Presubmit tries to run x86, but we only support 64-bit builds.
+// },
+// {
+// "name": "fuse_device_test_src_lib"
+ }
+ ]
+}
diff --git a/devices/src/virtio/fs/filesystem.rs b/fuse/src/filesystem.rs
similarity index 98%
rename from devices/src/virtio/fs/filesystem.rs
rename to fuse/src/filesystem.rs
index 94a4546..0cb0d60 100644
--- a/devices/src/virtio/fs/filesystem.rs
+++ b/fuse/src/filesystem.rs
@@ -9,9 +9,11 @@
use std::mem;
use std::time::Duration;
-use crate::virtio::fs::fuse;
+use crate::sys;
-pub use fuse::{FsOptions, IoctlFlags, IoctlIovec, OpenOptions, SetattrValid, ROOT_ID};
+pub use crate::sys::{FsOptions, IoctlFlags, IoctlIovec, OpenOptions, SetattrValid, ROOT_ID};
+
+const MAX_BUFFER_SIZE: u32 = 1 << 20;
/// Information about a path in the filesystem.
pub struct Entry {
@@ -43,9 +45,9 @@
pub entry_timeout: Duration,
}
-impl From<Entry> for fuse::EntryOut {
- fn from(entry: Entry) -> fuse::EntryOut {
- fuse::EntryOut {
+impl From<Entry> for sys::EntryOut {
+ fn from(entry: Entry) -> sys::EntryOut {
+ sys::EntryOut {
nodeid: entry.inode,
generation: entry.generation,
entry_valid: entry.entry_timeout.as_secs(),
@@ -322,8 +324,8 @@
pub pid: libc::pid_t,
}
-impl From<fuse::InHeader> for Context {
- fn from(source: fuse::InHeader) -> Self {
+impl From<sys::InHeader> for Context {
+ fn from(source: sys::InHeader) -> Self {
Context {
uid: source.uid,
gid: source.gid,
@@ -374,6 +376,12 @@
/// details.
type DirIter: DirectoryIterator;
+ /// Maximum size of the buffer that the filesystem can generate data to, including the header.
+ /// This corresponds to max_write in the initialization.
+ fn max_buffer_size(&self) -> u32 {
+ MAX_BUFFER_SIZE
+ }
+
/// Initialize the file system.
///
/// This method is called when a connection to the FUSE kernel module is first established. The
diff --git a/devices/src/virtio/fs/fuzzing.rs b/fuse/src/fuzzing.rs
similarity index 72%
rename from devices/src/virtio/fs/fuzzing.rs
rename to fuse/src/fuzzing.rs
index b8802bc..a12ada8 100644
--- a/devices/src/virtio/fs/fuzzing.rs
+++ b/fuse/src/fuzzing.rs
@@ -2,9 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use crate::virtio::fs::filesystem::{DirEntry, DirectoryIterator, FileSystem};
-use crate::virtio::fs::server::Server;
-use crate::virtio::{Reader, Writer};
+use crate::filesystem::{DirEntry, DirectoryIterator, FileSystem, ZeroCopyReader, ZeroCopyWriter};
+use crate::server::{Reader, Server, Writer};
// Use a file system that does nothing since we are fuzzing the server implementation.
struct NullFs;
@@ -22,7 +21,7 @@
}
/// Fuzz the server implementation.
-pub fn fuzz_server(r: Reader, w: Writer) {
+pub fn fuzz_server<R: Reader + ZeroCopyReader, W: Writer + ZeroCopyWriter>(r: R, w: W) {
let server = Server::new(NullFs);
let _ = server.handle_message(r, w);
diff --git a/fuse/src/lib.rs b/fuse/src/lib.rs
new file mode 100644
index 0000000..8da2265
--- /dev/null
+++ b/fuse/src/lib.rs
@@ -0,0 +1,62 @@
+// Copyright 2020 The Chromium OS 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::FromBytesWithNulError;
+use std::io;
+
+use thiserror::Error as ThisError;
+
+pub mod filesystem;
+#[cfg(fuzzing)]
+pub mod fuzzing;
+pub mod mount;
+mod server;
+#[allow(dead_code)]
+pub mod sys;
+pub mod worker;
+
+pub use mount::mount;
+pub use server::{Reader, Server, Writer};
+
+/// Errors that may occur during the creation or operation of an Fs device.
+#[derive(ThisError, Debug)]
+pub enum Error {
+ /// A request is missing readable descriptors.
+ /// Failed to decode protocol messages.
+ #[error("failed to decode fuse message: {0}")]
+ DecodeMessage(io::Error),
+ /// Failed to encode protocol messages.
+ #[error("failed to encode fuse message: {0}")]
+ EncodeMessage(io::Error),
+ /// Failed to flush protocol messages.
+ #[error("failed to flush fuse message: {0}")]
+ FlushMessage(io::Error),
+ /// Failed to set up FUSE endpoint to talk with.
+ #[error("failed to set up FUSE endpoint to talk with: {0}")]
+ EndpointSetup(io::Error),
+ /// One or more parameters are missing.
+ #[error("one or more parameters are missing")]
+ MissingParameter,
+ /// A C string parameter is invalid.
+ #[error("a c string parameter is invalid: {0}")]
+ InvalidCString(FromBytesWithNulError),
+ /// The `len` field of the header is too small.
+ #[error("the `len` field of the header is too small")]
+ InvalidHeaderLength,
+ /// The `size` field of the `SetxattrIn` message does not match the length
+ /// of the decoded value.
+ #[error(
+ "The `size` field of the `SetxattrIn` message does not match the\
+ length of the decoded value: size = {0}, value.len() = {1}"
+ )]
+ InvalidXattrSize(u32, usize),
+ /// Requested too many `iovec`s for an `ioctl` retry.
+ #[error(
+ "requested too many `iovec`s for an `ioctl` retry reply: requested\
+ {0}, max: {1}"
+ )]
+ TooManyIovecs(usize, usize),
+}
+
+pub type Result<T> = ::std::result::Result<T, Error>;
diff --git a/fuse/src/mount.rs b/fuse/src/mount.rs
new file mode 100644
index 0000000..66276d4
--- /dev/null
+++ b/fuse/src/mount.rs
@@ -0,0 +1,126 @@
+// Copyright 2020 The Chromium OS 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, OsStr};
+use std::fmt;
+use std::io;
+use std::os::unix::ffi::OsStrExt;
+use std::os::unix::io::RawFd;
+
+/// Mount options to pass to mount(2) for a FUSE filesystem. See the [official document](
+/// https://www.kernel.org/doc/html/latest/filesystems/fuse.html#mount-options) for the
+/// descriptions.
+pub enum MountOption {
+ FD(RawFd),
+ RootMode(u32),
+ UserId(libc::uid_t),
+ GroupId(libc::gid_t),
+ DefaultPermissions,
+ AllowOther,
+ MaxRead(u32),
+ BlockSize(u32),
+}
+
+// Implement Display for ToString to convert to actual mount options.
+impl fmt::Display for MountOption {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match &self {
+ MountOption::FD(fd) => write!(f, "fd={}", fd),
+ MountOption::RootMode(mode) => write!(f, "rootmode={:o}", mode),
+ MountOption::UserId(uid) => write!(f, "user_id={}", uid),
+ MountOption::GroupId(gid) => write!(f, "group_id={}", gid),
+ MountOption::DefaultPermissions => write!(f, "default_permissions"),
+ MountOption::AllowOther => write!(f, "allow_other"),
+ MountOption::MaxRead(size) => write!(f, "max_read={}", size),
+ MountOption::BlockSize(size) => write!(f, "blksize={}", size),
+ }
+ }
+}
+
+fn join_mount_options(options: &[MountOption]) -> String {
+ if !options.is_empty() {
+ let mut concat = options[0].to_string();
+ for opt in &options[1..] {
+ concat.push(',');
+ concat.push_str(&opt.to_string());
+ }
+ concat
+ } else {
+ String::new()
+ }
+}
+
+/// Initiates a FUSE mount at `mountpoint` directory with `flags` and `options` via mount(2). The
+/// caller should provide a file descriptor (backed by /dev/fuse) with `MountOption::FD`. After
+/// this function completes, the FUSE filesystem can start to handle the requests, e.g. via
+/// `fuse::worker::start_message_loop()`.
+///
+/// This operation requires CAP_SYS_ADMIN privilege, but the privilege can be dropped afterward.
+pub fn mount<P: AsRef<OsStr>>(
+ mountpoint: P,
+ name: &str,
+ flags: libc::c_ulong,
+ options: &[MountOption],
+) -> Result<(), io::Error> {
+ let mount_name = CString::new(name.as_bytes())?;
+ let fs_type = CString::new(String::from("fuse.") + name)?;
+ let mountpoint = CString::new(mountpoint.as_ref().as_bytes())?;
+ let mount_options = CString::new(join_mount_options(options))?;
+
+ // Safe because pointer arguments all points to null-terminiated CStrings.
+ let retval = unsafe {
+ libc::mount(
+ mount_name.as_ptr(),
+ mountpoint.as_ptr(),
+ fs_type.as_ptr(),
+ flags,
+ mount_options.as_ptr() as *const std::ffi::c_void,
+ )
+ };
+ if retval < 0 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn basic_options_concatenate_in_order() {
+ assert_eq!("".to_string(), join_mount_options(&[]));
+
+ assert_eq!(
+ "fd=42".to_string(),
+ join_mount_options(&[MountOption::FD(42),])
+ );
+
+ assert_eq!(
+ "fd=42,rootmode=40111,allow_other,user_id=12,group_id=34,max_read=4096".to_string(),
+ join_mount_options(&[
+ MountOption::FD(42),
+ MountOption::RootMode(
+ libc::S_IFDIR | libc::S_IXUSR | libc::S_IXGRP | libc::S_IXOTH
+ ),
+ MountOption::AllowOther,
+ MountOption::UserId(12),
+ MountOption::GroupId(34),
+ MountOption::MaxRead(4096),
+ ])
+ );
+
+ assert_eq!(
+ "fd=42,default_permissions,user_id=12,group_id=34,max_read=4096".to_string(),
+ join_mount_options(&[
+ MountOption::FD(42),
+ MountOption::DefaultPermissions,
+ MountOption::UserId(12),
+ MountOption::GroupId(34),
+ MountOption::MaxRead(4096),
+ ])
+ );
+ }
+}
diff --git a/devices/src/virtio/fs/server.rs b/fuse/src/server.rs
similarity index 78%
rename from devices/src/virtio/fs/server.rs
rename to fuse/src/server.rs
index 6aefcdc..77894bf 100644
--- a/devices/src/virtio/fs/server.rs
+++ b/fuse/src/server.rs
@@ -3,55 +3,46 @@
// found in the LICENSE file.
use std::ffi::CStr;
-use std::fs::File;
-use std::io::{self, Read, Write};
+use std::io;
use std::mem::{size_of, MaybeUninit};
use std::time::Duration;
use base::error;
use data_model::DataInit;
-use crate::virtio::fs::filesystem::{
+use crate::filesystem::{
Context, DirEntry, DirectoryIterator, Entry, FileSystem, GetxattrReply, IoctlReply,
ListxattrReply, ZeroCopyReader, ZeroCopyWriter,
};
-use crate::virtio::fs::fuse::*;
-use crate::virtio::fs::{Error, Result};
-use crate::virtio::{Reader, Writer};
+use crate::sys::*;
+use crate::{Error, Result};
-const MAX_BUFFER_SIZE: u32 = 1 << 20;
const DIRENT_PADDING: [u8; 8] = [0; 8];
-struct ZCReader(Reader);
+/// A trait for reading from the underlying FUSE endpoint.
+pub trait Reader: io::Read {}
-impl ZeroCopyReader for ZCReader {
- fn read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {
- self.0.read_to_at(f, count, off)
- }
-}
+/// A trait for writing to the underlying FUSE endpoint. The FUSE device expects the write
+/// operation to happen in one write transaction. Since there are cases when data needs to be
+/// generated earlier than the header, it implies the writer implementation to keep an internal
+/// buffer. The buffer then can be flushed once header and data are both prepared.
+pub trait Writer: io::Write {
+ /// Allows a closure to generate and write data at the current writer's offset. The current
+ /// writer is passed as a mutable reference to the closure. As an example, this provides an
+ /// adapter for the read implementation of a filesystem to write directly to the final buffer
+ /// without generating the FUSE header first.
+ ///
+ /// Notes: An alternative implementation would be to return a slightly different writer for the
+ /// API client to write to the offset. Since the API needs to be called for more than one time,
+ /// it imposes some complexity to deal with borrowing and mutability. The current approach
+ /// simply does not need to create a different writer, thus no need to deal with the mentioned
+ /// complexity.
+ fn write_at<F>(&mut self, offset: usize, f: F) -> io::Result<usize>
+ where
+ F: Fn(&mut Self) -> io::Result<usize>;
-impl io::Read for ZCReader {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- self.0.read(buf)
- }
-}
-
-struct ZCWriter(Writer);
-
-impl ZeroCopyWriter for ZCWriter {
- fn write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {
- self.0.write_from_at(f, count, off)
- }
-}
-
-impl io::Write for ZCWriter {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- self.0.write(buf)
- }
-
- fn flush(&mut self) -> io::Result<()> {
- self.0.flush()
- }
+ /// Checks if the writer can still accept certain amount of data.
+ fn has_sufficient_buffer(&self, size: u32) -> bool;
}
pub struct Server<F: FileSystem + Sync> {
@@ -63,10 +54,14 @@
Server { fs }
}
- pub fn handle_message(&self, mut r: Reader, w: Writer) -> Result<usize> {
+ pub fn handle_message<R: Reader + ZeroCopyReader, W: Writer + ZeroCopyWriter>(
+ &self,
+ mut r: R,
+ w: W,
+ ) -> Result<usize> {
let in_header = InHeader::from_reader(&mut r).map_err(Error::DecodeMessage)?;
- if in_header.len > MAX_BUFFER_SIZE {
+ if in_header.len > self.fs.max_buffer_size() {
return reply_error(
io::Error::from_raw_os_error(libc::ENOMEM),
in_header.unique,
@@ -127,7 +122,7 @@
}
}
- fn lookup(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn lookup<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let namelen = (in_header.len as usize)
.checked_sub(size_of::<InHeader>())
.ok_or(Error::InvalidHeaderLength)?;
@@ -152,7 +147,7 @@
}
}
- fn forget(&self, in_header: InHeader, mut r: Reader) -> Result<usize> {
+ fn forget<R: Reader>(&self, in_header: InHeader, mut r: R) -> Result<usize> {
let ForgetIn { nlookup } = ForgetIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
self.fs
@@ -162,7 +157,7 @@
Ok(0)
}
- fn getattr(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn getattr<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let GetattrIn {
flags,
dummy: _,
@@ -192,7 +187,7 @@
}
}
- fn setattr(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn setattr<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let setattr_in = SetattrIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
let handle = if setattr_in.valid & FATTR_FH != 0 {
@@ -225,7 +220,7 @@
}
}
- fn readlink(&self, in_header: InHeader, w: Writer) -> Result<usize> {
+ fn readlink<W: Writer>(&self, in_header: InHeader, w: W) -> Result<usize> {
match self
.fs
.readlink(Context::from(in_header), in_header.nodeid.into())
@@ -238,7 +233,7 @@
}
}
- fn symlink(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn symlink<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
// Unfortunately the name and linkname are encoded one after another and
// separated by a nul character.
let len = (in_header.len as usize)
@@ -276,7 +271,7 @@
}
}
- fn mknod(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn mknod<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let MknodIn {
mode, rdev, umask, ..
} = MknodIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
@@ -315,7 +310,7 @@
}
}
- fn mkdir(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn mkdir<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let MkdirIn { mode, umask } = MkdirIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
let buflen = (in_header.len as usize)
@@ -351,7 +346,7 @@
}
}
- fn unlink(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn unlink<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let namelen = (in_header.len as usize)
.checked_sub(size_of::<InHeader>())
.ok_or(Error::InvalidHeaderLength)?;
@@ -370,7 +365,7 @@
}
}
- fn rmdir(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn rmdir<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let namelen = (in_header.len as usize)
.checked_sub(size_of::<InHeader>())
.ok_or(Error::InvalidHeaderLength)?;
@@ -389,14 +384,14 @@
}
}
- fn do_rename(
+ fn do_rename<R: Reader, W: Writer>(
&self,
in_header: InHeader,
msg_size: usize,
newdir: u64,
flags: u32,
- mut r: Reader,
- w: Writer,
+ mut r: R,
+ w: W,
) -> Result<usize> {
let buflen = (in_header.len as usize)
.checked_sub(size_of::<InHeader>())
@@ -429,13 +424,13 @@
}
}
- fn rename(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn rename<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let RenameIn { newdir } = RenameIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
self.do_rename(in_header, size_of::<RenameIn>(), newdir, 0, r, w)
}
- fn rename2(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn rename2<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let Rename2In { newdir, flags, .. } =
Rename2In::from_reader(&mut r).map_err(Error::DecodeMessage)?;
@@ -444,7 +439,7 @@
self.do_rename(in_header, size_of::<Rename2In>(), newdir, flags, r, w)
}
- fn link(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn link<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let LinkIn { oldnodeid } = LinkIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
let namelen = (in_header.len as usize)
@@ -471,7 +466,7 @@
}
}
- fn open(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn open<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let OpenIn { flags, .. } = OpenIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
match self
@@ -491,7 +486,12 @@
}
}
- fn read(&self, in_header: InHeader, mut r: Reader, mut w: Writer) -> Result<usize> {
+ fn read<R: Reader, W: ZeroCopyWriter + Writer>(
+ &self,
+ in_header: InHeader,
+ mut r: R,
+ mut w: W,
+ ) -> Result<usize> {
let ReadIn {
fh,
offset,
@@ -502,7 +502,7 @@
..
} = ReadIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
- if size > MAX_BUFFER_SIZE {
+ if size > self.fs.max_buffer_size() {
return reply_error(
io::Error::from_raw_os_error(libc::ENOMEM),
in_header.unique,
@@ -516,19 +516,19 @@
None
};
- // Split the writer into 2 pieces: one for the `OutHeader` and the rest for the data.
- let data_writer = ZCWriter(w.split_at(size_of::<OutHeader>()));
-
- match self.fs.read(
- Context::from(in_header),
- in_header.nodeid.into(),
- fh.into(),
- data_writer,
- size,
- offset,
- owner,
- flags,
- ) {
+ // Skip for the header size to write the data first.
+ match w.write_at(size_of::<OutHeader>(), |writer| {
+ self.fs.read(
+ Context::from(in_header),
+ in_header.nodeid.into(),
+ fh.into(),
+ writer,
+ size,
+ offset,
+ owner,
+ flags,
+ )
+ }) {
Ok(count) => {
// Don't use `reply_ok` because we need to set a custom size length for the
// header.
@@ -539,13 +539,19 @@
};
w.write_all(out.as_slice()).map_err(Error::EncodeMessage)?;
+ w.flush().map_err(Error::FlushMessage)?;
Ok(out.len as usize)
}
Err(e) => reply_error(e, in_header.unique, w),
}
}
- fn write(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn write<R: Reader + ZeroCopyReader, W: Writer>(
+ &self,
+ in_header: InHeader,
+ mut r: R,
+ w: W,
+ ) -> Result<usize> {
let WriteIn {
fh,
offset,
@@ -556,7 +562,7 @@
..
} = WriteIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
- if size > MAX_BUFFER_SIZE {
+ if size > self.fs.max_buffer_size() {
return reply_error(
io::Error::from_raw_os_error(libc::ENOMEM),
in_header.unique,
@@ -572,13 +578,11 @@
let delayed_write = write_flags & WRITE_CACHE != 0;
- let data_reader = ZCReader(r);
-
match self.fs.write(
Context::from(in_header),
in_header.nodeid.into(),
fh.into(),
- data_reader,
+ r,
size,
offset,
owner,
@@ -597,7 +601,7 @@
}
}
- fn statfs(&self, in_header: InHeader, w: Writer) -> Result<usize> {
+ fn statfs<W: Writer>(&self, in_header: InHeader, w: W) -> Result<usize> {
match self
.fs
.statfs(Context::from(in_header), in_header.nodeid.into())
@@ -607,7 +611,7 @@
}
}
- fn release(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn release<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let ReleaseIn {
fh,
flags,
@@ -637,7 +641,7 @@
}
}
- fn fsync(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn fsync<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let FsyncIn {
fh, fsync_flags, ..
} = FsyncIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
@@ -654,7 +658,7 @@
}
}
- fn setxattr(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn setxattr<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let SetxattrIn { size, flags } =
SetxattrIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
@@ -678,7 +682,7 @@
let (name, value) = buf.split_at(split_pos);
if size != value.len() as u32 {
- return Err(Error::InvalidXattrSize((size, value.len())));
+ return Err(Error::InvalidXattrSize(size, value.len()));
}
match self.fs.setxattr(
@@ -693,7 +697,7 @@
}
}
- fn getxattr(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn getxattr<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let GetxattrIn { size, .. } =
GetxattrIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
@@ -706,7 +710,7 @@
r.read_exact(&mut name).map_err(Error::DecodeMessage)?;
- if size > MAX_BUFFER_SIZE {
+ if size > self.fs.max_buffer_size() {
return reply_error(
io::Error::from_raw_os_error(libc::ENOMEM),
in_header.unique,
@@ -733,11 +737,16 @@
}
}
- fn listxattr(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn listxattr<R: Reader, W: Writer>(
+ &self,
+ in_header: InHeader,
+ mut r: R,
+ w: W,
+ ) -> Result<usize> {
let GetxattrIn { size, .. } =
GetxattrIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
- if size > MAX_BUFFER_SIZE {
+ if size > self.fs.max_buffer_size() {
return reply_error(
io::Error::from_raw_os_error(libc::ENOMEM),
in_header.unique,
@@ -762,7 +771,12 @@
}
}
- fn removexattr(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn removexattr<R: Reader, W: Writer>(
+ &self,
+ in_header: InHeader,
+ mut r: R,
+ w: W,
+ ) -> Result<usize> {
let namelen = (in_header.len as usize)
.checked_sub(size_of::<InHeader>())
.ok_or(Error::InvalidHeaderLength)?;
@@ -783,7 +797,7 @@
}
}
- fn flush(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn flush<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let FlushIn {
fh,
unused: _,
@@ -802,7 +816,7 @@
}
}
- fn init(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn init<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let InitIn {
major,
minor,
@@ -873,7 +887,7 @@
flags: enabled.bits(),
max_background: ::std::u16::MAX,
congestion_threshold: (::std::u16::MAX / 4) * 3,
- max_write: MAX_BUFFER_SIZE,
+ max_write: self.fs.max_buffer_size(),
time_gran: 1, // nanoseconds
..Default::default()
};
@@ -884,7 +898,7 @@
}
}
- fn opendir(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn opendir<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let OpenIn { flags, .. } = OpenIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
match self
@@ -904,12 +918,17 @@
}
}
- fn readdir(&self, in_header: InHeader, mut r: Reader, mut w: Writer) -> Result<usize> {
+ fn readdir<R: Reader, W: Writer>(
+ &self,
+ in_header: InHeader,
+ mut r: R,
+ mut w: W,
+ ) -> Result<usize> {
let ReadIn {
fh, offset, size, ..
} = ReadIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
- if size > MAX_BUFFER_SIZE {
+ if size > self.fs.max_buffer_size() {
return reply_error(
io::Error::from_raw_os_error(libc::ENOMEM),
in_header.unique,
@@ -917,8 +936,7 @@
);
}
- let available_bytes = w.available_bytes();
- if available_bytes < size as usize {
+ if !w.has_sufficient_buffer(size) {
return reply_error(
io::Error::from_raw_os_error(libc::ENOMEM),
in_header.unique,
@@ -927,31 +945,36 @@
}
// Skip over enough bytes for the header.
- let mut cursor = w.split_at(size_of::<OutHeader>());
let unique = in_header.unique;
-
- match self.fs.readdir(
- Context::from(in_header),
- in_header.nodeid.into(),
- fh.into(),
- size,
- offset,
- ) {
- Ok(mut entries) => {
- let mut total_written = 0;
- while let Some(dirent) = entries.next() {
- let remaining = (size as usize).saturating_sub(total_written);
- match add_dirent(&mut cursor, remaining, dirent, None) {
- // No more space left in the buffer.
- Ok(0) => break,
- Ok(bytes_written) => {
- total_written += bytes_written;
+ let result = w.write_at(size_of::<OutHeader>(), |cursor| {
+ match self.fs.readdir(
+ Context::from(in_header),
+ in_header.nodeid.into(),
+ fh.into(),
+ size,
+ offset,
+ ) {
+ Ok(mut entries) => {
+ let mut total_written = 0;
+ while let Some(dirent) = entries.next() {
+ let remaining = (size as usize).saturating_sub(total_written);
+ match add_dirent(cursor, remaining, dirent, None) {
+ // No more space left in the buffer.
+ Ok(0) => break,
+ Ok(bytes_written) => {
+ total_written += bytes_written;
+ }
+ Err(e) => return Err(e),
}
- Err(e) => return reply_error(e, unique, w),
}
+ Ok(total_written)
}
- reply_readdir(total_written, unique, w)
+ Err(e) => Err(e),
}
+ });
+
+ match result {
+ Ok(total_written) => reply_readdir(total_written, unique, w),
Err(e) => reply_error(e, unique, w),
}
}
@@ -986,12 +1009,17 @@
Ok((dir_entry, entry))
}
- fn readdirplus(&self, in_header: InHeader, mut r: Reader, mut w: Writer) -> Result<usize> {
+ fn readdirplus<R: Reader, W: Writer>(
+ &self,
+ in_header: InHeader,
+ mut r: R,
+ mut w: W,
+ ) -> Result<usize> {
let ReadIn {
fh, offset, size, ..
} = ReadIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
- if size > MAX_BUFFER_SIZE {
+ if size > self.fs.max_buffer_size() {
return reply_error(
io::Error::from_raw_os_error(libc::ENOMEM),
in_header.unique,
@@ -999,8 +1027,7 @@
);
}
- let available_bytes = w.available_bytes();
- if available_bytes < size as usize {
+ if !w.has_sufficient_buffer(size) {
return reply_error(
io::Error::from_raw_os_error(libc::ENOMEM),
in_header.unique,
@@ -1009,63 +1036,72 @@
}
// Skip over enough bytes for the header.
- let mut cursor = w.split_at(size_of::<OutHeader>());
let unique = in_header.unique;
-
- match self.fs.readdir(
- Context::from(in_header),
- in_header.nodeid.into(),
- fh.into(),
- size,
- offset,
- ) {
- Ok(mut entries) => {
- let mut total_written = 0;
- while let Some(dirent) = entries.next() {
- let mut entry_inode = None;
- match self.handle_dirent(&in_header, dirent).and_then(|(d, e)| {
- entry_inode = Some(e.inode);
- let remaining = (size as usize).saturating_sub(total_written);
- add_dirent(&mut cursor, remaining, d, Some(e))
- }) {
- Ok(0) => {
- // No more space left in the buffer but we need to undo the lookup
- // that created the Entry or we will end up with mismatched lookup
- // counts.
- if let Some(inode) = entry_inode {
- self.fs.forget(Context::from(in_header), inode.into(), 1);
+ let result = w.write_at(size_of::<OutHeader>(), |cursor| {
+ match self.fs.readdir(
+ Context::from(in_header),
+ in_header.nodeid.into(),
+ fh.into(),
+ size,
+ offset,
+ ) {
+ Ok(mut entries) => {
+ let mut total_written = 0;
+ while let Some(dirent) = entries.next() {
+ let mut entry_inode = None;
+ match self.handle_dirent(&in_header, dirent).and_then(|(d, e)| {
+ entry_inode = Some(e.inode);
+ let remaining = (size as usize).saturating_sub(total_written);
+ add_dirent(cursor, remaining, d, Some(e))
+ }) {
+ Ok(0) => {
+ // No more space left in the buffer but we need to undo the lookup
+ // that created the Entry or we will end up with mismatched lookup
+ // counts.
+ if let Some(inode) = entry_inode {
+ self.fs.forget(Context::from(in_header), inode.into(), 1);
+ }
+ break;
}
- break;
- }
- Ok(bytes_written) => {
- total_written += bytes_written;
- }
- Err(e) => {
- if let Some(inode) = entry_inode {
- self.fs.forget(Context::from(in_header), inode.into(), 1);
+ Ok(bytes_written) => {
+ total_written += bytes_written;
}
+ Err(e) => {
+ if let Some(inode) = entry_inode {
+ self.fs.forget(Context::from(in_header), inode.into(), 1);
+ }
- if total_written == 0 {
- // We haven't filled any entries yet so we can just propagate
- // the error.
- return reply_error(e, unique, w);
+ if total_written == 0 {
+ // We haven't filled any entries yet so we can just propagate
+ // the error.
+ return Err(e);
+ }
+
+ // We already filled in some entries. Returning an error now will
+ // cause lookup count mismatches for those entries so just return
+ // whatever we already have.
+ break;
}
-
- // We already filled in some entries. Returning an error now will
- // cause lookup count mismatches for those entries so just return
- // whatever we already have.
- break;
}
}
+ Ok(total_written)
}
-
- reply_readdir(total_written, unique, w)
+ Err(e) => Err(e),
}
+ });
+
+ match result {
+ Ok(total_written) => reply_readdir(total_written, unique, w),
Err(e) => reply_error(e, unique, w),
}
}
- fn releasedir(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn releasedir<R: Reader, W: Writer>(
+ &self,
+ in_header: InHeader,
+ mut r: R,
+ w: W,
+ ) -> Result<usize> {
let ReleaseIn { fh, flags, .. } =
ReleaseIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
@@ -1080,7 +1116,7 @@
}
}
- fn fsyncdir(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn fsyncdir<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let FsyncIn {
fh, fsync_flags, ..
} = FsyncIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
@@ -1097,7 +1133,7 @@
}
}
- fn getlk(&self, in_header: InHeader, mut _r: Reader, w: Writer) -> Result<usize> {
+ fn getlk<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize> {
if let Err(e) = self.fs.getlk() {
reply_error(e, in_header.unique, w)
} else {
@@ -1105,7 +1141,7 @@
}
}
- fn setlk(&self, in_header: InHeader, mut _r: Reader, w: Writer) -> Result<usize> {
+ fn setlk<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize> {
if let Err(e) = self.fs.setlk() {
reply_error(e, in_header.unique, w)
} else {
@@ -1113,7 +1149,7 @@
}
}
- fn setlkw(&self, in_header: InHeader, mut _r: Reader, w: Writer) -> Result<usize> {
+ fn setlkw<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize> {
if let Err(e) = self.fs.setlkw() {
reply_error(e, in_header.unique, w)
} else {
@@ -1121,7 +1157,7 @@
}
}
- fn access(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn access<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let AccessIn { mask, .. } = AccessIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
match self
@@ -1133,7 +1169,7 @@
}
}
- fn create(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn create<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let CreateIn {
flags, mode, umask, ..
} = CreateIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
@@ -1196,7 +1232,7 @@
Ok(0)
}
- fn bmap(&self, in_header: InHeader, mut _r: Reader, w: Writer) -> Result<usize> {
+ fn bmap<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize> {
if let Err(e) = self.fs.bmap() {
reply_error(e, in_header.unique, w)
} else {
@@ -1211,7 +1247,7 @@
Ok(0)
}
- fn ioctl(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn ioctl<R: Reader, W: Writer>(&self, in_header: InHeader, mut r: R, w: W) -> Result<usize> {
let IoctlIn {
fh,
flags,
@@ -1243,7 +1279,7 @@
}
}
- fn poll(&self, in_header: InHeader, mut _r: Reader, w: Writer) -> Result<usize> {
+ fn poll<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize> {
if let Err(e) = self.fs.poll() {
reply_error(e, in_header.unique, w)
} else {
@@ -1251,7 +1287,12 @@
}
}
- fn notify_reply(&self, in_header: InHeader, mut _r: Reader, w: Writer) -> Result<usize> {
+ fn notify_reply<R: Reader, W: Writer>(
+ &self,
+ in_header: InHeader,
+ mut _r: R,
+ w: W,
+ ) -> Result<usize> {
if let Err(e) = self.fs.notify_reply() {
reply_error(e, in_header.unique, w)
} else {
@@ -1259,12 +1300,17 @@
}
}
- fn batch_forget(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn batch_forget<R: Reader, W: Writer>(
+ &self,
+ in_header: InHeader,
+ mut r: R,
+ w: W,
+ ) -> Result<usize> {
let BatchForgetIn { count, .. } =
BatchForgetIn::from_reader(&mut r).map_err(Error::DecodeMessage)?;
if let Some(size) = (count as usize).checked_mul(size_of::<ForgetOne>()) {
- if size > MAX_BUFFER_SIZE as usize {
+ if size > self.fs.max_buffer_size() as usize {
return reply_error(
io::Error::from_raw_os_error(libc::ENOMEM),
in_header.unique,
@@ -1294,7 +1340,12 @@
Ok(0)
}
- fn fallocate(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn fallocate<R: Reader, W: Writer>(
+ &self,
+ in_header: InHeader,
+ mut r: R,
+ w: W,
+ ) -> Result<usize> {
let FallocateIn {
fh,
offset,
@@ -1316,7 +1367,7 @@
}
}
- fn lseek(&self, in_header: InHeader, mut _r: Reader, w: Writer) -> Result<usize> {
+ fn lseek<R: Reader, W: Writer>(&self, in_header: InHeader, mut _r: R, w: W) -> Result<usize> {
if let Err(e) = self.fs.lseek() {
reply_error(e, in_header.unique, w)
} else {
@@ -1324,7 +1375,12 @@
}
}
- fn copy_file_range(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
+ fn copy_file_range<R: Reader, W: Writer>(
+ &self,
+ in_header: InHeader,
+ mut r: R,
+ w: W,
+ ) -> Result<usize> {
let CopyFileRangeIn {
fh_src,
off_src,
@@ -1359,19 +1415,19 @@
}
}
-fn retry_ioctl(
+fn retry_ioctl<W: Writer>(
unique: u64,
input: Vec<IoctlIovec>,
output: Vec<IoctlIovec>,
- mut w: Writer,
+ mut w: W,
) -> Result<usize> {
// We don't need to check for overflow here because if adding these 2 values caused an overflow
// we would have run out of memory before reaching this point.
if input.len() + output.len() > IOCTL_MAX_IOV {
- return Err(Error::TooManyIovecs((
+ return Err(Error::TooManyIovecs(
input.len() + output.len(),
IOCTL_MAX_IOV,
- )));
+ ));
}
let len = size_of::<OutHeader>()
@@ -1399,11 +1455,12 @@
w.write_all(i.as_slice()).map_err(Error::EncodeMessage)?;
}
+ w.flush().map_err(Error::FlushMessage)?;
debug_assert_eq!(len, total_bytes);
Ok(len)
}
-fn finish_ioctl(unique: u64, res: io::Result<Vec<u8>>, w: Writer) -> Result<usize> {
+fn finish_ioctl<W: Writer>(unique: u64, res: io::Result<Vec<u8>>, w: W) -> Result<usize> {
let (out, data) = match res {
Ok(data) => {
let out = IoctlOut {
@@ -1423,7 +1480,7 @@
reply_ok(Some(out), data.as_ref().map(|d| &d[..]), unique, w)
}
-fn reply_readdir(len: usize, unique: u64, mut w: Writer) -> Result<usize> {
+fn reply_readdir<W: Writer>(len: usize, unique: u64, mut w: W) -> Result<usize> {
let out = OutHeader {
len: (size_of::<OutHeader>() + len) as u32,
error: 0,
@@ -1431,14 +1488,15 @@
};
w.write_all(out.as_slice()).map_err(Error::EncodeMessage)?;
+ w.flush().map_err(Error::FlushMessage)?;
Ok(out.len as usize)
}
-fn reply_ok<T: DataInit>(
+fn reply_ok<T: DataInit, W: Writer>(
out: Option<T>,
data: Option<&[u8]>,
unique: u64,
- mut w: Writer,
+ mut w: W,
) -> Result<usize> {
let mut len = size_of::<OutHeader>();
@@ -1470,11 +1528,12 @@
w.write_all(data).map_err(Error::EncodeMessage)?;
}
+ w.flush().map_err(Error::FlushMessage)?;
debug_assert_eq!(len, total_bytes);
Ok(len)
}
-fn reply_error(e: io::Error, unique: u64, mut w: Writer) -> Result<usize> {
+fn reply_error<W: Writer>(e: io::Error, unique: u64, mut w: W) -> Result<usize> {
let header = OutHeader {
len: size_of::<OutHeader>() as u32,
error: -e.raw_os_error().unwrap_or(libc::EIO),
@@ -1483,6 +1542,7 @@
w.write_all(header.as_slice())
.map_err(Error::EncodeMessage)?;
+ w.flush().map_err(Error::FlushMessage)?;
Ok(header.len as usize)
}
@@ -1493,8 +1553,8 @@
CStr::from_bytes_with_nul(buf).map_err(Error::InvalidCString)
}
-fn add_dirent(
- cursor: &mut Writer,
+fn add_dirent<W: Writer>(
+ cursor: &mut W,
max: usize,
d: DirEntry,
entry: Option<Entry>,
diff --git a/devices/src/virtio/fs/fuse.rs b/fuse/src/sys.rs
similarity index 100%
rename from devices/src/virtio/fs/fuse.rs
rename to fuse/src/sys.rs
diff --git a/fuse/src/worker.rs b/fuse/src/worker.rs
new file mode 100644
index 0000000..334738a
--- /dev/null
+++ b/fuse/src/worker.rs
@@ -0,0 +1,137 @@
+// Copyright 2020 The Chromium OS 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, BufRead, BufReader, Cursor, Read, Write};
+use std::mem::size_of;
+use std::os::unix::fs::FileExt;
+
+use crate::filesystem::{FileSystem, ZeroCopyReader, ZeroCopyWriter};
+use crate::server::{Reader, Server, Writer};
+use crate::sys;
+use crate::{Error, Result};
+
+struct DevFuseReader<'a> {
+ // File representing /dev/fuse for reading, with sufficient buffer to accommodate a FUSE read
+ // transaction.
+ reader: &'a mut BufReader<File>,
+}
+
+impl<'a> DevFuseReader<'a> {
+ pub fn new(reader: &'a mut BufReader<File>) -> Self {
+ DevFuseReader { reader }
+ }
+}
+
+impl Read for DevFuseReader<'_> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.reader.read(buf)
+ }
+}
+
+impl Reader for DevFuseReader<'_> {}
+
+impl ZeroCopyReader for DevFuseReader<'_> {
+ fn read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {
+ let buf = self.reader.fill_buf()?;
+ let end = std::cmp::min(count, buf.len());
+ let written = f.write_at(&buf[..end], off)?;
+ self.reader.consume(written);
+ Ok(written)
+ }
+}
+
+struct DevFuseWriter<'a> {
+ // File representing /dev/fuse for writing.
+ dev_fuse: &'a mut File,
+
+ // An internal buffer to allow generating data and header out of order, such that they can be
+ // flushed at once. This is wrapped by a cursor for tracking the current written position.
+ write_buf: &'a mut Cursor<Vec<u8>>,
+}
+
+impl<'a> DevFuseWriter<'a> {
+ pub fn new(dev_fuse: &'a mut File, write_buf: &'a mut Cursor<Vec<u8>>) -> Self {
+ debug_assert_eq!(write_buf.position(), 0);
+
+ DevFuseWriter {
+ dev_fuse,
+ write_buf,
+ }
+ }
+}
+
+impl Write for DevFuseWriter<'_> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.write_buf.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.dev_fuse.write_all(&self.write_buf.get_ref()[..])?;
+ self.write_buf.set_position(0);
+ self.write_buf.get_mut().clear();
+ Ok(())
+ }
+}
+
+impl Writer for DevFuseWriter<'_> {
+ fn write_at<F>(&mut self, offset: usize, f: F) -> io::Result<usize>
+ where
+ F: Fn(&mut Self) -> io::Result<usize>,
+ {
+ // Restore the cursor for idempotent.
+ let original = self.write_buf.position();
+ self.write_buf.set_position(offset as u64);
+ let r = f(self);
+ self.write_buf.set_position(original);
+ r
+ }
+
+ fn has_sufficient_buffer(&self, size: u32) -> bool {
+ (self.write_buf.position() as usize + size as usize) < self.write_buf.get_ref().capacity()
+ }
+}
+
+impl ZeroCopyWriter for DevFuseWriter<'_> {
+ fn write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {
+ let pos = self.write_buf.position() as usize;
+ let end = pos + count;
+ let buf = self.write_buf.get_mut();
+
+ let old_end = buf.len();
+ buf.resize(end, 0);
+ let read = f.read_at(&mut buf[pos..end], off)?;
+
+ let new_end = pos + read;
+ debug_assert!(new_end >= old_end);
+ buf.truncate(new_end);
+ self.write_buf.set_position(new_end as u64);
+ Ok(read)
+ }
+}
+
+/// Start the FUSE message handling loop. Returns when an error happens.
+pub fn start_message_loop<F: FileSystem + Sync>(
+ dev_fuse: File,
+ max_write: u32,
+ max_read: u32,
+ fs: F,
+) -> Result<()> {
+ let server = Server::new(fs);
+ let mut buf_reader = BufReader::with_capacity(
+ max_write as usize + size_of::<sys::InHeader>() + size_of::<sys::WriteIn>(),
+ dev_fuse.try_clone().map_err(Error::EndpointSetup)?,
+ );
+
+ let mut write_buf = Cursor::new(Vec::with_capacity(max_read as usize));
+ let mut wfile = dev_fuse.try_clone().map_err(Error::EndpointSetup)?;
+ loop {
+ let dev_fuse_reader = DevFuseReader::new(&mut buf_reader);
+ let dev_fuse_writer = DevFuseWriter::new(&mut wfile, &mut write_buf);
+
+ if let Err(e) = server.handle_message(dev_fuse_reader, dev_fuse_writer) {
+ return Err(e);
+ }
+ }
+}
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index 1a10b2a..ab2e065 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -9,6 +9,7 @@
data_model = { path = "../data_model" }
devices = { path = "../devices" }
disk = { path = "../disk" }
+fuse = { path = "../fuse" }
kernel_loader = { path = "../kernel_loader" }
libc = "*"
rand = "0.6"
diff --git a/fuzz/block_fuzzer.rs b/fuzz/block_fuzzer.rs
index 0cd5b07..ee193e4 100644
--- a/fuzz/block_fuzzer.rs
+++ b/fuzz/block_fuzzer.rs
@@ -6,7 +6,6 @@
use std::io::{Cursor, Read, Seek, SeekFrom};
use std::mem::size_of;
-use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
@@ -76,10 +75,9 @@
q.max_size = QUEUE_SIZE;
let queue_evts: Vec<Event> = vec![Event::new().unwrap()];
- let queue_fd = queue_evts[0].as_raw_fd();
- let queue_evt = unsafe { Event::from_raw_fd(libc::dup(queue_fd)) };
+ let queue_evt = queue_evts[0].try_clone().unwrap();
- let features = base_features();
+ let features = base_features(false);
let disk_file = tempfile::tempfile().unwrap();
let mut block = Block::new(features, Box::new(disk_file), false, true, 512, None).unwrap();
diff --git a/fuzz/fs_server_fuzzer.rs b/fuzz/fs_server_fuzzer.rs
index 1d0d211..f1154c5 100644
--- a/fuzz/fs_server_fuzzer.rs
+++ b/fuzz/fs_server_fuzzer.rs
@@ -7,8 +7,8 @@
use std::convert::TryInto;
use cros_fuzz::fuzz_target;
-use devices::virtio::fs::fuzzing::fuzz_server;
use devices::virtio::{create_descriptor_chain, DescriptorType, Reader, Writer};
+use fuse::fuzzing::fuzz_server;
use vm_memory::{GuestAddress, GuestMemory};
const MEM_SIZE: u64 = 256 * 1024 * 1024;
diff --git a/gpu_buffer/Android.bp b/gpu_buffer/Android.bp
index 572ca42..514eaf8 100644
--- a/gpu_buffer/Android.bp
+++ b/gpu_buffer/Android.bp
@@ -62,14 +62,31 @@
// dependent_library ["feature_list"]
// ../assertions/src/lib.rs
// ../base/src/lib.rs
+// ../cros_async/src/lib.rs
// ../data_model/src/lib.rs
+// ../io_uring/src/lib.rs
// ../sync/src/lib.rs
// ../sys_util/poll_token_derive/poll_token_derive.rs
// ../sys_util/src/lib.rs
// ../syscall_defines/src/lib.rs
// ../tempfile/src/lib.rs
+// async-trait-0.1.42
+// futures-0.3.8 "alloc"
+// futures-channel-0.3.8 "alloc,futures-sink,sink"
+// futures-core-0.3.8 "alloc"
+// futures-io-0.3.8
+// futures-sink-0.3.8 "alloc"
+// futures-task-0.3.8 "alloc"
+// futures-util-0.3.8 "alloc,futures-sink,sink"
// libc-0.2.80 "default,std"
+// paste-1.0.3
+// pin-project-1.0.2
+// pin-project-internal-1.0.2
+// pin-utils-0.1.0
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// slab-0.4.2
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// thiserror-1.0.22
+// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/gpu_display/Android.bp b/gpu_display/Android.bp
index cae43f1..368259b 100644
--- a/gpu_display/Android.bp
+++ b/gpu_display/Android.bp
@@ -97,16 +97,33 @@
// dependent_library ["feature_list"]
// ../assertions/src/lib.rs
// ../base/src/lib.rs
+// ../cros_async/src/lib.rs
// ../data_model/src/lib.rs
+// ../io_uring/src/lib.rs
// ../linux_input_sys/src/lib.rs
// ../sync/src/lib.rs
// ../sys_util/poll_token_derive/poll_token_derive.rs
// ../sys_util/src/lib.rs
// ../syscall_defines/src/lib.rs
// ../tempfile/src/lib.rs
+// async-trait-0.1.42
// cc-1.0.25
+// futures-0.3.8 "alloc"
+// futures-channel-0.3.8 "alloc,futures-sink,sink"
+// futures-core-0.3.8 "alloc"
+// futures-io-0.3.8
+// futures-sink-0.3.8 "alloc"
+// futures-task-0.3.8 "alloc"
+// futures-util-0.3.8 "alloc,futures-sink,sink"
// libc-0.2.80 "default,std"
+// paste-1.0.3
+// pin-project-1.0.2
+// pin-project-internal-1.0.2
+// pin-utils-0.1.0
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// slab-0.4.2
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// thiserror-1.0.22
+// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/gpu_display/src/event_device.rs b/gpu_display/src/event_device.rs
index 5aae55c..4453c84 100644
--- a/gpu_display/src/event_device.rs
+++ b/gpu_display/src/event_device.rs
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+use base::{AsRawDescriptor, RawDescriptor};
use data_model::DataInit;
use linux_input_sys::{virtio_input_event, InputEventDecoder};
use std::collections::VecDeque;
use std::io::{self, Error, ErrorKind, Read, Write};
use std::iter::ExactSizeIterator;
-use std::os::unix::io::{AsRawFd, RawFd};
use std::os::unix::net::UnixStream;
const EVENT_SIZE: usize = virtio_input_event::SIZE;
@@ -150,8 +150,8 @@
}
}
-impl AsRawFd for EventDevice {
- fn as_raw_fd(&self) -> RawFd {
- self.event_socket.as_raw_fd()
+impl AsRawDescriptor for EventDevice {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.event_socket.as_raw_descriptor()
}
}
diff --git a/gpu_display/src/gpu_display_stub.rs b/gpu_display/src/gpu_display_stub.rs
index 70e7187..09aa03d 100644
--- a/gpu_display/src/gpu_display_stub.rs
+++ b/gpu_display/src/gpu_display_stub.rs
@@ -4,11 +4,10 @@
use std::collections::BTreeMap;
use std::num::NonZeroU32;
-use std::os::unix::io::{AsRawFd, RawFd};
use crate::{DisplayT, EventDevice, GpuDisplayError, GpuDisplayFramebuffer};
-use base::Event;
+use base::{AsRawDescriptor, Event, RawDescriptor};
use data_model::VolatileSlice;
type SurfaceId = NonZeroU32;
@@ -130,7 +129,7 @@
}
pub struct DisplayStub {
- /// This event is never triggered and is used solely to fulfill AsRawFd.
+ /// This event is never triggered and is used solely to fulfill AsRawDescriptor.
event: Event,
surfaces: SurfacesHelper,
}
@@ -185,7 +184,7 @@
fn import_dmabuf(
&mut self,
- _fd: RawFd,
+ _fd: RawDescriptor,
_offset: u32,
_stride: u32,
_modifiers: u64,
@@ -225,8 +224,8 @@
}
}
-impl AsRawFd for DisplayStub {
- fn as_raw_fd(&self) -> RawFd {
- self.event.as_raw_fd()
+impl AsRawDescriptor for DisplayStub {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.event.as_raw_descriptor()
}
}
diff --git a/gpu_display/src/gpu_display_wl.rs b/gpu_display/src/gpu_display_wl.rs
index 28d9a1d..d6365ac 100644
--- a/gpu_display/src/gpu_display_wl.rs
+++ b/gpu_display/src/gpu_display_wl.rs
@@ -17,12 +17,12 @@
use std::cell::Cell;
use std::collections::HashMap;
use std::ffi::{CStr, CString};
-use std::os::unix::io::{AsRawFd, RawFd};
use std::path::Path;
use std::ptr::{null, null_mut};
use base::{
- round_up_to_page_size, AsRawDescriptor, MemoryMapping, MemoryMappingBuilder, SharedMemory,
+ round_up_to_page_size, AsRawDescriptor, MemoryMapping, MemoryMappingBuilder, RawDescriptor,
+ SharedMemory,
};
use data_model::VolatileMemory;
@@ -84,7 +84,7 @@
/// 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
+/// The user of `GpuDisplay` can use `AsRawDescriptor` to poll on the compositor connection's file
/// descriptor. When the connection is readable, `dispatch_events` can be called to process it.
pub struct DisplayWl {
dmabufs: HashMap<u32, DwlDmabuf>,
@@ -146,7 +146,7 @@
impl DisplayT for DisplayWl {
fn import_dmabuf(
&mut self,
- fd: RawFd,
+ fd: RawDescriptor,
offset: u32,
stride: u32,
modifiers: u64,
@@ -352,8 +352,8 @@
}
}
-impl AsRawFd for DisplayWl {
- fn as_raw_fd(&self) -> RawFd {
+impl AsRawDescriptor for DisplayWl {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
// Safe given that the context pointer is valid.
unsafe { dwl_context_fd(self.ctx.0) }
}
diff --git a/gpu_display/src/gpu_display_x.rs b/gpu_display/src/gpu_display_x.rs
index 54f7c5c..5d6a9b6 100644
--- a/gpu_display/src/gpu_display_x.rs
+++ b/gpu_display/src/gpu_display_x.rs
@@ -18,7 +18,6 @@
use std::mem::{transmute_copy, zeroed};
use std::num::NonZeroU32;
use std::os::raw::c_ulong;
-use std::os::unix::io::{AsRawFd, RawFd};
use std::ptr::{null, null_mut, NonNull};
use std::rc::Rc;
use std::time::Duration;
@@ -30,7 +29,7 @@
EventDeviceKind, GpuDisplayError, GpuDisplayFramebuffer,
};
-use base::{error, PollContext, PollToken, WatchingEvents};
+use base::{error, AsRawDescriptor, EventType, PollToken, RawDescriptor, WaitContext};
use data_model::VolatileSlice;
const BUFFER_COUNT: usize = 2;
@@ -95,8 +94,8 @@
}
}
-impl AsRawFd for XDisplay {
- fn as_raw_fd(&self) -> RawFd {
+impl AsRawDescriptor for XDisplay {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
unsafe { xlib::XConnectionNumber(self.as_ptr()) }
}
}
@@ -542,7 +541,7 @@
}
pub struct DisplayX {
- poll_ctx: PollContext<DisplayXPollToken>,
+ wait_ctx: WaitContext<DisplayXPollToken>,
display: XDisplay,
screen: XScreen,
visual: *mut xlib::Visual,
@@ -553,7 +552,7 @@
impl DisplayX {
pub fn open_display(display: Option<&str>) -> Result<DisplayX, GpuDisplayError> {
- let poll_ctx = PollContext::new().map_err(|_| GpuDisplayError::Allocate)?;
+ let wait_ctx = WaitContext::new().map_err(|_| GpuDisplayError::Allocate)?;
let display_cstr = match display.map(CString::new) {
Some(Ok(s)) => Some(s),
@@ -573,7 +572,7 @@
None => return Err(GpuDisplayError::Connect),
};
- poll_ctx
+ wait_ctx
.add(&display, DisplayXPollToken::Display)
.map_err(|_| GpuDisplayError::Allocate)?;
@@ -618,7 +617,7 @@
x_free(visual_info);
Ok(DisplayX {
- poll_ctx,
+ wait_ctx,
display,
screen,
visual,
@@ -675,28 +674,28 @@
}
fn handle_poll_ctx(&mut self) -> base::Result<()> {
- let poll_events = self.poll_ctx.wait_timeout(Duration::default())?.to_owned();
- for poll_event in poll_events.as_ref().iter_writable() {
- if let DisplayXPollToken::EventDevice { event_device_id } = poll_event.token() {
+ let wait_events = self.wait_ctx.wait_timeout(Duration::default())?;
+ for wait_event in wait_events.iter().filter(|e| e.is_writable) {
+ if let DisplayXPollToken::EventDevice { event_device_id } = wait_event.token {
if let Some(event_device) = self.event_device_mut(event_device_id) {
if !event_device.flush_buffered_events()? {
continue;
}
}
// Although this looks exactly like the previous if-block, we need to reborrow self
- // as immutable in order to make use of self.poll_ctx.
+ // as immutable in order to make use of self.wait_ctx.
if let Some(event_device) = self.event_device(event_device_id) {
- self.poll_ctx.modify(
+ self.wait_ctx.modify(
event_device,
- WatchingEvents::empty().set_read(),
+ EventType::Read,
DisplayXPollToken::EventDevice { event_device_id },
)?;
}
}
}
- for poll_event in poll_events.as_ref().iter_readable() {
- match poll_event.token() {
+ for wait_event in wait_events.iter().filter(|e| e.is_readable) {
+ match wait_event.token {
DisplayXPollToken::Display => self.dispatch_display_events(),
DisplayXPollToken::EventDevice { event_device_id } => {
self.handle_event_device(event_device_id)
@@ -772,7 +771,7 @@
#[allow(unused_variables)]
fn import_dmabuf(
&mut self,
- fd: RawFd,
+ fd: RawDescriptor,
offset: u32,
stride: u32,
modifiers: u64,
@@ -802,7 +801,7 @@
fn import_event_device(&mut self, event_device: EventDevice) -> Result<u32, GpuDisplayError> {
let new_event_device_id = self.next_id;
- self.poll_ctx
+ self.wait_ctx
.add(
&event_device,
DisplayXPollToken::EventDevice {
@@ -836,8 +835,8 @@
}
}
-impl AsRawFd for DisplayX {
- fn as_raw_fd(&self) -> RawFd {
- self.poll_ctx.as_raw_fd()
+impl AsRawDescriptor for DisplayX {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.wait_ctx.as_raw_descriptor()
}
}
diff --git a/gpu_display/src/lib.rs b/gpu_display/src/lib.rs
index 94b5547..0ffae87 100644
--- a/gpu_display/src/lib.rs
+++ b/gpu_display/src/lib.rs
@@ -5,10 +5,9 @@
//! Crate for displaying simple surfaces and GPU buffers over wayland.
use std::fmt::{self, Display};
-use std::os::unix::io::{AsRawFd, RawFd};
use std::path::Path;
-use base::Error as SysError;
+use base::{AsRawDescriptor, Error as SysError, RawDescriptor};
use data_model::VolatileSlice;
mod event_device;
@@ -119,10 +118,10 @@
}
}
-trait DisplayT: AsRawFd {
+trait DisplayT: AsRawDescriptor {
fn import_dmabuf(
&mut self,
- fd: RawFd,
+ fd: RawDescriptor,
offset: u32,
stride: u32,
modifiers: u64,
@@ -164,7 +163,7 @@
/// 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
+/// The user of `GpuDisplay` can use `AsRawDescriptor` 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 {
inner: Box<dyn DisplayT>,
@@ -213,7 +212,7 @@
/// 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,
+ fd: RawDescriptor,
offset: u32,
stride: u32,
modifiers: u64,
@@ -325,8 +324,8 @@
}
}
-impl AsRawFd for GpuDisplay {
- fn as_raw_fd(&self) -> RawFd {
- self.inner.as_raw_fd()
+impl AsRawDescriptor for GpuDisplay {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.inner.as_raw_descriptor()
}
}
diff --git a/gpu_renderer/Android.bp b/gpu_renderer/Android.bp
index 97c04a7..2b62bd4 100644
--- a/gpu_renderer/Android.bp
+++ b/gpu_renderer/Android.bp
@@ -107,7 +107,7 @@
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// thiserror-1.0.22
// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/gpu_renderer/src/lib.rs b/gpu_renderer/src/lib.rs
index c735170..ade794b 100644
--- a/gpu_renderer/src/lib.rs
+++ b/gpu_renderer/src/lib.rs
@@ -8,7 +8,7 @@
mod generated;
mod vsnprintf;
-use base::{ExternalMapping, ExternalMappingError, ExternalMappingResult};
+use base::{ExternalMapping, ExternalMappingError, ExternalMappingResult, FromRawDescriptor};
use std::cell::RefCell;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use std::ffi::CString;
@@ -16,7 +16,6 @@
use std::fs::File;
use std::mem::{size_of, transmute};
use std::os::raw::{c_char, c_void};
-use std::os::unix::io::FromRawFd;
use std::ptr::null_mut;
use std::rc::Rc;
use std::result;
@@ -228,6 +227,12 @@
self.set_flag(GFXSTREAM_RENDERER_FLAGS_NO_VK_BIT, !v)
}
+ #[cfg(feature = "gfxstream")]
+ pub fn use_guest_angle(self, v: bool) -> RendererFlags {
+ const GFXSTREAM_RENDERER_FLAGS_GUEST_USES_ANGLE: u32 = 1 << 21;
+ self.set_flag(GFXSTREAM_RENDERER_FLAGS_GUEST_USES_ANGLE, v)
+ }
+
pub fn use_external_blob(self, v: bool) -> RendererFlags {
self.set_flag(VIRGL_RENDERER_USE_EXTERNAL_BLOB, v)
}
@@ -640,7 +645,7 @@
return Err(Error::Unsupported);
}
- let dmabuf = unsafe { File::from_raw_fd(fd) };
+ let dmabuf = unsafe { File::from_raw_descriptor(fd) };
Ok(dmabuf)
}
#[cfg(not(feature = "virtio-gpu-next"))]
@@ -668,7 +673,7 @@
// Safe because the FD was just returned by a successful virglrenderer call so it must
// be valid and owned by us.
- let dmabuf = unsafe { File::from_raw_fd(query.out_fds[0]) };
+ let dmabuf = unsafe { File::from_raw_descriptor(query.out_fds[0]) };
Ok(dmabuf)
}
diff --git a/hypervisor/Android.bp b/hypervisor/Android.bp
index 92e5dae..a040ab9 100644
--- a/hypervisor/Android.bp
+++ b/hypervisor/Android.bp
@@ -75,6 +75,7 @@
// ../tempfile/src/lib.rs
// ../vm_memory/src/lib.rs
// async-trait-0.1.42
+// base-0.1.0
// downcast-rs-1.2.0 "default,std"
// futures-0.3.8 "alloc,async-await,default,executor,futures-executor,std"
// futures-channel-0.3.8 "alloc,futures-sink,sink,std"
@@ -97,7 +98,7 @@
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// thiserror-1.0.22
// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/hypervisor/src/aarch64.rs b/hypervisor/src/aarch64.rs
index 584e983..da253dc 100644
--- a/hypervisor/src/aarch64.rs
+++ b/hypervisor/src/aarch64.rs
@@ -7,6 +7,12 @@
use crate::{Hypervisor, IrqRoute, IrqSource, IrqSourceChip, Vcpu, Vm};
+/// Represents a version of Power State Coordination Interface (PSCI).
+pub struct PsciVersion {
+ pub major: u32,
+ pub minor: u32,
+}
+
/// A wrapper for using a VM on aarch64 and getting/setting its state.
pub trait VmAArch64: Vm {
/// Gets the `Hypervisor` that created this VM.
@@ -30,6 +36,13 @@
/// Sets the value of a register on this VCPU. `reg_id` is the register ID, as specified in the
/// KVM API documentation for KVM_SET_ONE_REG.
fn set_one_reg(&self, reg_id: u64, data: u64) -> Result<()>;
+
+ /// Gets the value of a register on this VCPU. `reg_id` is the register ID, as specified in the
+ /// KVM API documentation for KVM_GET_ONE_REG.
+ fn get_one_reg(&self, reg_id: u64) -> Result<u64>;
+
+ /// Gets the current PSCI version.
+ fn get_psci_version(&self) -> Result<PsciVersion>;
}
impl_downcast!(VcpuAArch64);
diff --git a/hypervisor/src/kvm/aarch64.rs b/hypervisor/src/kvm/aarch64.rs
index 8efde70..a88bda1 100644
--- a/hypervisor/src/kvm/aarch64.rs
+++ b/hypervisor/src/kvm/aarch64.rs
@@ -9,7 +9,8 @@
use super::{KvmVcpu, KvmVm};
use crate::{
- ClockState, DeviceKind, Hypervisor, IrqSourceChip, VcpuAArch64, VcpuFeature, VmAArch64, VmCap,
+ ClockState, DeviceKind, Hypervisor, IrqSourceChip, PsciVersion, VcpuAArch64, VcpuFeature,
+ VmAArch64, VmCap,
};
impl KvmVm {
@@ -156,6 +157,42 @@
errno_result()
}
}
+
+ fn get_one_reg(&self, reg_id: u64) -> Result<u64> {
+ let val: u64 = 0;
+ let mut onereg = kvm_one_reg {
+ id: reg_id,
+ addr: (&val as *const u64) as u64,
+ };
+
+ // Safe because 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_GET_ONE_REG(), &mut onereg) };
+ if ret == 0 {
+ Ok(val)
+ } else {
+ return errno_result();
+ }
+ }
+
+ fn get_psci_version(&self) -> Result<PsciVersion> {
+ // The definition of KVM_REG_ARM_PSCI_VERSION is in arch/arm64/include/uapi/asm/kvm.h.
+ const KVM_REG_ARM_PSCI_VERSION: u64 =
+ KVM_REG_ARM64 | (KVM_REG_SIZE_U64 as u64) | (KVM_REG_ARM_FW as u64);
+
+ match self.get_one_reg(KVM_REG_ARM_PSCI_VERSION) {
+ Ok(v) => {
+ let major = (v >> PSCI_VERSION_MAJOR_SHIFT) as u32;
+ let minor = (v as u32) & PSCI_VERSION_MINOR_MASK;
+ Ok(PsciVersion { major, minor })
+ }
+ Err(_) => {
+ // When `KVM_REG_ARM_PSCI_VERSION` is not supported, we can return PSCI 0.2, as vCPU
+ // has been initialized with `KVM_ARM_VCPU_PSCI_0_2` successfully.
+ Ok(PsciVersion { major: 0, minor: 2 })
+ }
+ }
+ }
}
// This function translates an IrqSrouceChip to the kvm u32 equivalent. It has a different
diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs
index bfb9bb1..ba06d4f 100644
--- a/hypervisor/src/kvm/mod.rs
+++ b/hypervisor/src/kvm/mod.rs
@@ -13,12 +13,11 @@
use x86_64::*;
use std::cell::RefCell;
-use std::cmp::{min, Ordering};
+use std::cmp::{min, Reverse};
use std::collections::{BTreeMap, BinaryHeap};
use std::convert::TryFrom;
use std::mem::{size_of, ManuallyDrop};
use std::os::raw::{c_char, c_int, c_ulong, c_void};
-use std::os::unix::io::{AsRawFd, RawFd};
use std::ptr::copy_nonoverlapping;
use std::sync::atomic::AtomicU64;
use std::sync::Arc;
@@ -126,12 +125,6 @@
}
}
-impl AsRawFd for Kvm {
- fn as_raw_fd(&self) -> RawFd {
- self.kvm.as_raw_descriptor()
- }
-}
-
impl Hypervisor for Kvm {
fn try_clone(&self) -> Result<Self> {
Ok(Kvm {
@@ -151,31 +144,14 @@
}
}
-// Used to invert the order when stored in a max-heap.
-#[derive(Copy, Clone, Eq, PartialEq)]
-struct MemSlotOrd(MemSlot);
-
-impl Ord for MemSlotOrd {
- fn cmp(&self, other: &MemSlotOrd) -> 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 MemSlotOrd {
- fn partial_cmp(&self, other: &MemSlotOrd) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
/// A wrapper around creating and using a KVM VM.
pub struct KvmVm {
kvm: Kvm,
vm: SafeDescriptor,
guest_mem: GuestMemory,
mem_regions: Arc<Mutex<BTreeMap<MemSlot, Box<dyn MappedRegion>>>>,
- mem_slot_gaps: Arc<Mutex<BinaryHeap<MemSlotOrd>>>,
+ /// A min heap of MemSlot numbers that were used and then removed and can now be re-used
+ mem_slot_gaps: Arc<Mutex<BinaryHeap<Reverse<MemSlot>>>>,
}
impl KvmVm {
@@ -214,11 +190,10 @@
}
fn create_vcpu(&self, id: usize) -> Result<KvmVcpu> {
- let id = c_ulong::try_from(id).unwrap();
let run_mmap_size = self.kvm.get_vcpu_mmap_size()?;
// Safe because we know that our file is a VM fd and we verify the return result.
- let fd = unsafe { ioctl_with_val(self, KVM_CREATE_VCPU(), id) };
+ let fd = unsafe { ioctl_with_val(self, KVM_CREATE_VCPU(), c_ulong::try_from(id).unwrap()) };
if fd < 0 {
return errno_result();
}
@@ -235,6 +210,7 @@
Ok(KvmVcpu {
vm: self.vm.try_clone()?,
vcpu,
+ id,
run_mmap,
vcpu_run_handle_fingerprint: Default::default(),
})
@@ -278,14 +254,14 @@
resample_evt: Option<&Event>,
) -> Result<()> {
let mut irqfd = kvm_irqfd {
- fd: evt.as_raw_fd() as u32,
+ fd: evt.as_raw_descriptor() as u32,
gsi,
..Default::default()
};
if let Some(r_evt) = resample_evt {
irqfd.flags = KVM_IRQFD_FLAG_RESAMPLE;
- irqfd.resamplefd = r_evt.as_raw_fd() as u32;
+ irqfd.resamplefd = r_evt.as_raw_descriptor() as u32;
}
// Safe because we know that our file is a VM fd, we know the kernel will only read the
@@ -305,7 +281,7 @@
/// `register_irqfd`.
pub fn unregister_irqfd(&self, gsi: u32, evt: &Event) -> Result<()> {
let irqfd = kvm_irqfd {
- fd: evt.as_raw_fd() as u32,
+ fd: evt.as_raw_descriptor() as u32,
gsi,
flags: KVM_IRQFD_FLAG_DEASSIGN,
..Default::default()
@@ -385,7 +361,7 @@
IoEventAddress::Pio(p) => p as u64,
IoEventAddress::Mmio(m) => m,
},
- fd: evt.as_raw_fd(),
+ fd: evt.as_raw_descriptor(),
flags,
..Default::default()
};
@@ -468,7 +444,7 @@
};
if let Err(e) = res {
- gaps.push(MemSlotOrd(slot));
+ gaps.push(Reverse(slot));
return Err(e);
}
regions.insert(slot, mem);
@@ -496,7 +472,7 @@
unsafe {
set_user_memory_region(&self.vm, slot, false, false, 0, 0, std::ptr::null_mut())?;
}
- self.mem_slot_gaps.lock().push(MemSlotOrd(slot));
+ self.mem_slot_gaps.lock().push(Reverse(slot));
// This remove will always succeed because of the contains_key check above.
Ok(regions.remove(&slot).unwrap())
}
@@ -553,7 +529,7 @@
}
fn register_ioevent(
- &self,
+ &mut self,
evt: &Event,
addr: IoEventAddress,
datamatch: Datamatch,
@@ -562,7 +538,7 @@
}
fn unregister_ioevent(
- &self,
+ &mut self,
evt: &Event,
addr: IoEventAddress,
datamatch: Datamatch,
@@ -570,6 +546,11 @@
self.ioeventfd(evt, addr, datamatch, true)
}
+ fn handle_io_events(&self, _addr: IoEventAddress, _data: &[u8]) -> Result<()> {
+ // KVM delivers IO events in-kernel with ioeventfds, so this is a no-op
+ Ok(())
+ }
+
fn get_pvclock(&self) -> Result<ClockState> {
self.get_pvclock_arch()
}
@@ -585,16 +566,11 @@
}
}
-impl AsRawFd for KvmVm {
- fn as_raw_fd(&self) -> RawFd {
- self.vm.as_raw_descriptor()
- }
-}
-
/// A wrapper around using a KVM Vcpu.
pub struct KvmVcpu {
vm: SafeDescriptor,
vcpu: SafeDescriptor,
+ id: usize,
run_mmap: MemoryMapping,
vcpu_run_handle_fingerprint: Arc<AtomicU64>,
}
@@ -619,6 +595,7 @@
Ok(KvmVcpu {
vm,
vcpu,
+ id: self.id,
run_mmap,
vcpu_run_handle_fingerprint,
})
@@ -680,6 +657,10 @@
Ok(ManuallyDrop::into_inner(vcpu_run_handle))
}
+ fn id(&self) -> usize {
+ self.id
+ }
+
#[allow(clippy::cast_ptr_alignment)]
fn set_immediate_exit(&self, exit: bool) {
// Safe because we know we mapped enough memory to hold the kvm_run struct because the
@@ -706,11 +687,6 @@
f
}
- fn handle_io_events(&self, _addr: IoEventAddress) -> Result<()> {
- // KVM delivers IO events in-kernel with ioeventfds, so this is a no-op
- Ok(())
- }
-
#[allow(clippy::cast_ptr_alignment)]
fn set_data(&self, data: &[u8]) -> Result<()> {
// Safe because we know we mapped enough memory to hold the kvm_run struct because the
@@ -996,8 +972,8 @@
}
}
-impl AsRawFd for KvmVcpu {
- fn as_raw_fd(&self) -> RawFd {
+impl AsRawDescriptor for KvmVcpu {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
self.vcpu.as_raw_descriptor()
}
}
@@ -1040,7 +1016,7 @@
address_lo: *address as u32,
address_hi: (*address >> 32) as u32,
data: *data,
- pad: 0,
+ ..Default::default()
},
},
..Default::default()
@@ -1109,8 +1085,7 @@
#[cfg(test)]
mod tests {
use super::*;
- use base::{pagesize, MemoryMappingArena, MemoryMappingBuilder};
- use std::os::unix::io::FromRawFd;
+ use base::{pagesize, FromRawDescriptor, MemoryMappingArena, MemoryMappingBuilder};
use std::thread;
use vm_memory::GuestAddress;
@@ -1313,7 +1288,7 @@
vm.register_irqfd(4, &evtfd1, Some(&evtfd2)).unwrap();
vm.unregister_irqfd(4, &evtfd1).unwrap();
// Ensures the ioctl is actually reading the resamplefd.
- vm.register_irqfd(4, &evtfd1, Some(unsafe { &Event::from_raw_fd(-1) }))
+ vm.register_irqfd(4, &evtfd1, Some(unsafe { &Event::from_raw_descriptor(-1) }))
.unwrap_err();
}
@@ -1339,7 +1314,7 @@
fn register_ioevent() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
- let vm = KvmVm::new(&kvm, gm).unwrap();
+ let mut vm = KvmVm::new(&kvm, gm).unwrap();
let evtfd = Event::new().unwrap();
vm.register_ioevent(&evtfd, IoEventAddress::Pio(0xf4), Datamatch::AnyLength)
.unwrap();
@@ -1375,7 +1350,7 @@
fn unregister_ioevent() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
- let vm = KvmVm::new(&kvm, gm).unwrap();
+ let mut vm = KvmVm::new(&kvm, gm).unwrap();
let evtfd = Event::new().unwrap();
vm.register_ioevent(&evtfd, IoEventAddress::Pio(0xf4), Datamatch::AnyLength)
.unwrap();
diff --git a/hypervisor/src/kvm/x86_64.rs b/hypervisor/src/kvm/x86_64.rs
index ae9535e..3123380 100644
--- a/hypervisor/src/kvm/x86_64.rs
+++ b/hypervisor/src/kvm/x86_64.rs
@@ -4,13 +4,12 @@
use base::IoctlNr;
use std::convert::TryInto;
-use std::os::unix::io::AsRawFd;
use libc::E2BIG;
use base::{
errno_result, error, ioctl, ioctl_with_mut_ptr, ioctl_with_mut_ref, ioctl_with_ptr,
- ioctl_with_ref, ioctl_with_val, Error, MappedRegion, Result,
+ ioctl_with_ref, ioctl_with_val, AsRawDescriptor, Error, MappedRegion, Result,
};
use data_model::vec_with_array_field;
use kvm_sys::*;
@@ -26,8 +25,8 @@
type KvmCpuId = kvm::CpuId;
-fn get_cpuid_with_initial_capacity<T: AsRawFd>(
- fd: &T,
+fn get_cpuid_with_initial_capacity<T: AsRawDescriptor>(
+ descriptor: &T,
kind: IoctlNr,
initial_capacity: usize,
) -> Result<CpuId> {
@@ -40,7 +39,7 @@
// 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 within KvmCpuId,
// which is set to the allocated size above.
- ioctl_with_mut_ptr(fd, kind, kvm_cpuid.as_mut_ptr())
+ ioctl_with_mut_ptr(descriptor, kind, kvm_cpuid.as_mut_ptr())
};
if ret < 0 {
let err = Error::last();
@@ -344,12 +343,12 @@
impl VcpuX86_64 for KvmVcpu {
#[allow(clippy::cast_ptr_alignment)]
- fn request_interrupt_window(&self) {
+ fn set_interrupt_window_requested(&self, requested: bool) {
// 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) };
- run.request_interrupt_window = 1;
+ run.request_interrupt_window = if requested { 1 } else { 0 };
}
#[allow(clippy::cast_ptr_alignment)]
@@ -377,6 +376,16 @@
}
}
+ fn inject_nmi(&self) -> Result<()> {
+ // Safe because we know that our file is a VCPU fd.
+ let ret = unsafe { ioctl(self, KVM_NMI()) };
+ if ret == 0 {
+ Ok(())
+ } else {
+ errno_result()
+ }
+ }
+
fn get_regs(&self) -> Result<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.
@@ -555,6 +564,45 @@
const KVM_MAX_ENTRIES: usize = 256;
get_cpuid_with_initial_capacity(self, KVM_GET_SUPPORTED_HV_CPUID(), KVM_MAX_ENTRIES)
}
+
+ fn set_guest_debug(&self, addrs: &[GuestAddress], enable_singlestep: bool) -> Result<()> {
+ use kvm_sys::*;
+ let mut dbg: kvm_guest_debug = Default::default();
+
+ if addrs.len() > 4 {
+ error!(
+ "Support 4 breakpoints at most but {} addresses are passed",
+ addrs.len()
+ );
+ return Err(base::Error::new(libc::EINVAL));
+ }
+
+ dbg.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
+ if enable_singlestep {
+ dbg.control |= KVM_GUESTDBG_SINGLESTEP;
+ }
+
+ // Set bits 9 and 10.
+ // bit 9: GE (global exact breakpoint enable) flag.
+ // bit 10: always 1.
+ dbg.arch.debugreg[7] = 0x0600;
+
+ for i in 0..addrs.len() {
+ dbg.arch.debugreg[i] = addrs[i].0;
+ // Set global breakpoint enable flag
+ dbg.arch.debugreg[7] |= 2 << (i * 2);
+ }
+
+ let ret = unsafe {
+ // Here we trust the kernel not to read past the end of the kvm_guest_debug struct.
+ ioctl_with_ref(self, KVM_SET_GUEST_DEBUG(), &dbg)
+ };
+ if ret == 0 {
+ Ok(())
+ } else {
+ errno_result()
+ }
+ }
}
impl KvmVcpu {
diff --git a/hypervisor/src/lib.rs b/hypervisor/src/lib.rs
index 9f63ac6..c6cf45a 100644
--- a/hypervisor/src/lib.rs
+++ b/hypervisor/src/lib.rs
@@ -12,7 +12,7 @@
use std::os::raw::c_int;
-use base::{Event, MappedRegion, Result, SafeDescriptor};
+use base::{Event, MappedRegion, RawDescriptor, Result, SafeDescriptor};
use msg_socket::MsgOnSocket;
use vm_memory::{GuestAddress, GuestMemory};
@@ -109,7 +109,7 @@
/// In all cases where `evt` is signaled, the ordinary vmexit to userspace that would be
/// triggered is prevented.
fn register_ioevent(
- &self,
+ &mut self,
evt: &Event,
addr: IoEventAddress,
datamatch: Datamatch,
@@ -120,12 +120,18 @@
/// The `evt`, `addr`, and `datamatch` set must be the same as the ones passed into
/// `register_ioevent`.
fn unregister_ioevent(
- &self,
+ &mut self,
evt: &Event,
addr: IoEventAddress,
datamatch: Datamatch,
) -> Result<()>;
+ /// Trigger any matching registered io events based on an MMIO or PIO write at `addr`. The
+ /// `data` slice represents the contents and length of the write, which is used to compare with
+ /// the registered io events' Datamatch values. If the hypervisor does in-kernel IO event
+ /// delivery, this is a no-op.
+ fn handle_io_events(&self, addr: IoEventAddress, data: &[u8]) -> Result<()>;
+
/// Retrieves the current timestamp of the paravirtual clock as seen by the current guest.
/// Only works on VMs that support `VmCap::PvClock`.
fn get_pvclock(&self) -> Result<ClockState>;
@@ -215,6 +221,9 @@
/// `take_run_handle` for this `Vcpu`.
fn run(&self, run_handle: &VcpuRunHandle) -> Result<VcpuExit>;
+ /// Returns the vcpu id.
+ fn id(&self) -> usize;
+
/// Sets the bit that requests an immediate exit.
fn set_immediate_exit(&self, exit: bool);
@@ -227,10 +236,6 @@
/// signal-safe way when called.
fn set_local_immediate_exit_fn(&self) -> extern "C" fn();
- /// Trigger any io events based on the memory mapped IO at `addr`. If the hypervisor does
- /// in-kernel IO event delivery, this is a no-op.
- fn handle_io_events(&self, addr: IoEventAddress) -> Result<()>;
-
/// Sets the data received by a mmio read, ioport in, or hypercall instruction.
///
/// This function should be called after `Vcpu::run` returns an `VcpuExit::IoIn`,
@@ -254,13 +259,14 @@
downcast_rs::impl_downcast!(sync Vcpu);
/// An address either in programmable I/O space or in memory mapped I/O space.
-#[derive(Copy, Clone, Debug, MsgOnSocket)]
+#[derive(Copy, Clone, Debug, MsgOnSocket, PartialEq, Eq, std::hash::Hash)]
pub enum IoEventAddress {
Pio(u64),
Mmio(u64),
}
/// Used in `Vm::register_ioevent` to indicate a size and optionally value to match.
+#[derive(PartialEq, Eq)]
pub enum Datamatch {
AnyLength,
U8(Option<u8>),
diff --git a/hypervisor/src/x86_64.rs b/hypervisor/src/x86_64.rs
index 7b9a7dc..ae4cb44 100644
--- a/hypervisor/src/x86_64.rs
+++ b/hypervisor/src/x86_64.rs
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use base::{error, Result};
+use base::{error, RawDescriptor, Result};
use bit_field::*;
use downcast_rs::impl_downcast;
use msg_socket::MsgOnSocket;
@@ -39,8 +39,9 @@
/// A wrapper around creating and using a VCPU on x86_64.
pub trait VcpuX86_64: Vcpu {
- /// Request the VCPU to exit when it becomes possible to inject interrupts into the guest.
- fn request_interrupt_window(&self);
+ /// Sets or clears the flag that requests the VCPU to exit when it becomes possible to inject
+ /// interrupts into the guest.
+ fn set_interrupt_window_requested(&self, requested: bool);
/// Checks if we can inject an interrupt into the VCPU.
fn ready_for_interrupt(&self) -> bool;
@@ -48,6 +49,9 @@
/// Injects interrupt vector `irq` into the VCPU.
fn interrupt(&self, irq: u32) -> Result<()>;
+ /// Injects a non-maskable interrupt into the VCPU.
+ fn inject_nmi(&self) -> Result<()>;
+
/// Gets the VCPU general purpose registers.
fn get_regs(&self) -> Result<Regs>;
@@ -90,6 +94,9 @@
/// Gets the system emulated hyper-v CPUID values.
fn get_hyperv_cpuid(&self) -> Result<CpuId>;
+
+ /// Sets up debug registers and configure vcpu for handling guest debug events.
+ fn set_guest_debug(&self, addrs: &[GuestAddress], enable_singlestep: bool) -> Result<()>;
}
impl_downcast!(VcpuX86_64);
@@ -154,6 +161,10 @@
External = 0b111,
}
+// These MSI structures are for Intel's implementation of MSI. The PCI spec defines most of MSI,
+// but the Intel spec defines the format of messages for raising interrupts. The PCI spec defines
+// three u32s -- the address, address_high, and data -- but Intel only makes use of the address and
+// data. The Intel portion of the specification is in Volume 3 section 10.11.
#[bitfield]
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct MsiAddressMessage {
@@ -174,7 +185,8 @@
#[bits = 3]
pub delivery_mode: DeliveryMode,
pub reserved: BitField3,
- pub level: BitField1,
+ #[bits = 1]
+ pub level: Level,
#[bits = 1]
pub trigger: TriggerMode,
pub reserved2: BitField16,
@@ -187,6 +199,14 @@
Pending = 1,
}
+/// The level of a level-triggered interrupt: asserted or deasserted.
+#[bitfield]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Level {
+ Deassert = 0,
+ Assert = 1,
+}
+
/// Represents a IOAPIC redirection table entry.
#[bitfield]
#[derive(Clone, Copy, Default, PartialEq, Eq)]
diff --git a/io_uring/Android.bp b/io_uring/Android.bp
index 35033d0..e19df03 100644
--- a/io_uring/Android.bp
+++ b/io_uring/Android.bp
@@ -1,4 +1,4 @@
-// This file is generated by cargo2android.py --run --device --tests --dependencies --global_defaults=crosvm_defaults --add_workspace.
+// This file is generated by cargo2android.py --run --device --tests --dependencies --global_defaults=crosvm_defaults.
rust_defaults {
name: "io_uring_defaults",
@@ -9,8 +9,8 @@
auto_gen_config: true,
edition: "2018",
rustlibs: [
- "libbase_rust",
"liblibc",
+ "libsys_util",
"libsyscall_defines",
"libtempfile",
],
@@ -34,15 +34,14 @@
srcs: ["src/lib.rs"],
edition: "2018",
rustlibs: [
- "libbase_rust",
"liblibc",
+ "libsys_util",
"libsyscall_defines",
],
}
// dependent_library ["feature_list"]
// ../assertions/src/lib.rs
-// ../base/src/lib.rs
// ../data_model/src/lib.rs
// ../sync/src/lib.rs
// ../sys_util/poll_token_derive/poll_token_derive.rs
@@ -52,5 +51,5 @@
// libc-0.2.80 "default,std"
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// syn-1.0.53 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
// unicode-xid-0.2.1 "default"
diff --git a/io_uring/Cargo.toml b/io_uring/Cargo.toml
index ad3a815..1b633d3 100644
--- a/io_uring/Cargo.toml
+++ b/io_uring/Cargo.toml
@@ -7,7 +7,7 @@
[dependencies]
libc = "*"
syscall_defines = { path = "../syscall_defines" }
-base = { path = "../base" }
+sys_util = { path = "../sys_util" }
[dev-dependencies]
tempfile = { path = "../tempfile" }
diff --git a/io_uring/src/uring.rs b/io_uring/src/uring.rs
index cc6ed0f..48461c3 100644
--- a/io_uring/src/uring.rs
+++ b/io_uring/src/uring.rs
@@ -14,7 +14,7 @@
use std::ptr::null_mut;
use std::sync::atomic::{AtomicU32, Ordering};
-use base::{MappedRegion, MemoryMapping, MemoryMappingBuilder, WatchingEvents};
+use sys_util::{MappedRegion, MemoryMapping, Protection, WatchingEvents};
use crate::bindings::*;
use crate::syscalls::*;
@@ -30,11 +30,11 @@
/// The call to `io_uring_setup` failed with the given errno.
Setup(libc::c_int),
/// Failed to map the completion ring.
- MappingCompleteRing(base::MmapError),
+ MappingCompleteRing(sys_util::MmapError),
/// Failed to map the submit ring.
- MappingSubmitRing(base::MmapError),
+ MappingSubmitRing(sys_util::MmapError),
/// Failed to map submit entries.
- MappingSubmitEntries(base::MmapError),
+ MappingSubmitEntries(sys_util::MmapError),
/// Too many ops are already queued.
NoSpace,
}
@@ -78,7 +78,7 @@
/// # use std::fs::File;
/// # use std::os::unix::io::AsRawFd;
/// # use std::path::Path;
-/// # use base::WatchingEvents;
+/// # use sys_util::WatchingEvents;
/// # use io_uring::URingContext;
/// let f = File::open(Path::new("/dev/zero")).unwrap();
/// let mut uring = URingContext::new(16).unwrap();
@@ -121,40 +121,40 @@
// Safe because we trust the kernel to set valid sizes in `io_uring_setup` and any error
// is checked.
let submit_ring = SubmitQueueState::new(
- MemoryMappingBuilder::new(
+ MemoryMapping::from_fd_offset_protection_populate(
+ &ring_file,
ring_params.sq_off.array as usize
+ ring_params.sq_entries as usize * std::mem::size_of::<u32>(),
+ u64::from(IORING_OFF_SQ_RING),
+ Protection::read_write(),
+ true,
)
- .from_descriptor(&ring_file)
- .offset(u64::from(IORING_OFF_SQ_RING))
- .populate()
- .build()
.map_err(Error::MappingSubmitRing)?,
&ring_params,
);
let num_sqe = ring_params.sq_entries as usize;
let submit_queue_entries = SubmitQueueEntries {
- mmap: MemoryMappingBuilder::new(
+ mmap: MemoryMapping::from_fd_offset_protection_populate(
+ &ring_file,
ring_params.sq_entries as usize * std::mem::size_of::<io_uring_sqe>(),
+ u64::from(IORING_OFF_SQES),
+ Protection::read_write(),
+ true,
)
- .from_descriptor(&ring_file)
- .offset(u64::from(IORING_OFF_SQES))
- .populate()
- .build()
.map_err(Error::MappingSubmitEntries)?,
len: num_sqe,
};
let complete_ring = CompleteQueueState::new(
- MemoryMappingBuilder::new(
+ MemoryMapping::from_fd_offset_protection_populate(
+ &ring_file,
ring_params.cq_off.cqes as usize
+ ring_params.cq_entries as usize * std::mem::size_of::<io_uring_cqe>(),
+ u64::from(IORING_OFF_CQ_RING),
+ Protection::read_write(),
+ true,
)
- .from_descriptor(&ring_file)
- .offset(u64::from(IORING_OFF_CQ_RING))
- .populate()
- .build()
.map_err(Error::MappingCompleteRing)?,
&ring_params,
);
@@ -735,7 +735,7 @@
use std::path::{Path, PathBuf};
use std::time::Duration;
- use base::PollContext;
+ use sys_util::PollContext;
use tempfile::{tempfile, TempDir};
use super::*;
diff --git a/kernel_cmdline/src/kernel_cmdline.rs b/kernel_cmdline/src/kernel_cmdline.rs
index d2777c7..c836e12 100644
--- a/kernel_cmdline/src/kernel_cmdline.rs
+++ b/kernel_cmdline/src/kernel_cmdline.rs
@@ -39,10 +39,7 @@
pub type Result<T> = result::Result<T, Error>;
fn valid_char(c: char) -> bool {
- match c {
- ' '..='~' => true,
- _ => false,
- }
+ matches!(c, ' '..='~')
}
fn valid_str(s: &str) -> Result<()> {
diff --git a/kernel_loader/Android.bp b/kernel_loader/Android.bp
index f9ec170..609785d 100644
--- a/kernel_loader/Android.bp
+++ b/kernel_loader/Android.bp
@@ -76,7 +76,7 @@
// rand_core-0.5.1 "alloc,getrandom,std"
// remove_dir_all-0.5.3
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// tempfile-3.1.0
// thiserror-1.0.22
// thiserror-impl-1.0.22
diff --git a/kvm/Android.bp b/kvm/Android.bp
index addc6fa..ba3751e 100644
--- a/kvm/Android.bp
+++ b/kvm/Android.bp
@@ -118,6 +118,7 @@
// ../tempfile/src/lib.rs
// ../vm_memory/src/lib.rs
// async-trait-0.1.42
+// base-0.1.0
// futures-0.3.8 "alloc,async-await,default,executor,futures-executor,std"
// futures-channel-0.3.8 "alloc,futures-sink,sink,std"
// futures-core-0.3.8 "alloc,std"
@@ -139,7 +140,7 @@
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// thiserror-1.0.22
// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/kvm/src/lib.rs b/kvm/src/lib.rs
index 04b964f..c2ac848 100644
--- a/kvm/src/lib.rs
+++ b/kvm/src/lib.rs
@@ -13,12 +13,11 @@
use std::mem::size_of;
use std::ops::{Deref, DerefMut};
use std::os::raw::*;
-use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::ptr::copy_nonoverlapping;
use std::sync::Arc;
use sync::Mutex;
-use base::{AsRawDescriptor, RawDescriptor};
+use base::{AsRawDescriptor, FromRawDescriptor, RawDescriptor};
use data_model::vec_with_array_field;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
@@ -44,7 +43,7 @@
Err(Error::last())
}
-unsafe fn set_user_memory_region<F: AsRawFd>(
+unsafe fn set_user_memory_region<F: AsRawDescriptor>(
fd: &F,
slot: u32,
read_only: bool,
@@ -103,7 +102,7 @@
}
// Safe because we verify that ret is valid and we own the fd.
Ok(Kvm {
- kvm: unsafe { File::from_raw_fd(ret) },
+ kvm: unsafe { File::from_raw_descriptor(ret) },
})
}
@@ -194,9 +193,9 @@
}
}
-impl AsRawFd for Kvm {
- fn as_raw_fd(&self) -> RawFd {
- self.kvm.as_raw_fd()
+impl AsRawDescriptor for Kvm {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.kvm.as_raw_descriptor()
}
}
@@ -271,7 +270,7 @@
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) };
+ let vm_file = unsafe { File::from_raw_descriptor(ret) };
guest_mem.with_regions(|index, guest_addr, size, host_addr, _| {
unsafe {
// Safe because the guest regions are guaranteed not to overlap.
@@ -712,7 +711,7 @@
IoeventAddress::Pio(p) => p as u64,
IoeventAddress::Mmio(m) => m,
},
- fd: evt.as_raw_fd(),
+ fd: evt.as_raw_descriptor(),
flags,
..Default::default()
};
@@ -742,8 +741,8 @@
) -> 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,
+ fd: evt.as_raw_descriptor() as u32,
+ resamplefd: resample_evt.as_raw_descriptor() as u32,
gsi,
..Default::default()
};
@@ -770,7 +769,7 @@
))]
pub fn unregister_irqfd(&self, evt: &Event, gsi: u32) -> Result<()> {
let irqfd = kvm_irqfd {
- fd: evt.as_raw_fd() as u32,
+ fd: evt.as_raw_descriptor() as u32,
gsi,
flags: KVM_IRQFD_FLAG_DEASSIGN,
..Default::default()
@@ -837,9 +836,9 @@
}
}
-impl AsRawFd for Vm {
- fn as_raw_fd(&self) -> RawFd {
- self.vm.as_raw_fd()
+impl AsRawDescriptor for Vm {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.vm.as_raw_descriptor()
}
}
@@ -948,7 +947,7 @@
// 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 vcpu = unsafe { File::from_raw_descriptor(vcpu_fd) };
let run_mmap = MemoryMappingBuilder::new(run_mmap_size)
.from_descriptor(&vcpu)
@@ -1458,12 +1457,6 @@
}
}
-impl AsRawFd for Vcpu {
- fn as_raw_fd(&self) -> RawFd {
- self.vcpu.as_raw_fd()
- }
-}
-
impl AsRawDescriptor for Vcpu {
fn as_raw_descriptor(&self) -> RawDescriptor {
self.vcpu.as_raw_descriptor()
@@ -1629,8 +1622,8 @@
}
}
-impl AsRawFd for RunnableVcpu {
- fn as_raw_fd(&self) -> RawFd {
+impl AsRawDescriptor for RunnableVcpu {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
self.vcpu.as_raw_descriptor()
}
}
@@ -1941,7 +1934,7 @@
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 { &Event::from_raw_fd(-1) }, 4)
+ vm.register_irqfd_resample(&evtfd1, unsafe { &Event::from_raw_descriptor(-1) }, 4)
.unwrap_err();
}
diff --git a/kvm_sys/Android.bp b/kvm_sys/Android.bp
index b83c3c1..d7c0801 100644
--- a/kvm_sys/Android.bp
+++ b/kvm_sys/Android.bp
@@ -68,14 +68,31 @@
// dependent_library ["feature_list"]
// ../assertions/src/lib.rs
// ../base/src/lib.rs
+// ../cros_async/src/lib.rs
// ../data_model/src/lib.rs
+// ../io_uring/src/lib.rs
// ../sync/src/lib.rs
// ../sys_util/poll_token_derive/poll_token_derive.rs
// ../sys_util/src/lib.rs
// ../syscall_defines/src/lib.rs
// ../tempfile/src/lib.rs
+// async-trait-0.1.42
+// futures-0.3.8 "alloc"
+// futures-channel-0.3.8 "alloc,futures-sink,sink"
+// futures-core-0.3.8 "alloc"
+// futures-io-0.3.8
+// futures-sink-0.3.8 "alloc"
+// futures-task-0.3.8 "alloc"
+// futures-util-0.3.8 "alloc,futures-sink,sink"
// libc-0.2.80 "default,std"
+// paste-1.0.3
+// pin-project-1.0.2
+// pin-project-internal-1.0.2
+// pin-utils-0.1.0
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// slab-0.4.2
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// thiserror-1.0.22
+// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/kvm_sys/src/aarch64/bindings.rs b/kvm_sys/src/aarch64/bindings.rs
index 0dd7f5a..7e5303a 100644
--- a/kvm_sys/src/aarch64/bindings.rs
+++ b/kvm_sys/src/aarch64/bindings.rs
@@ -2,15 +2,22 @@
// 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 */
+/*
+ * automatically generated by bindgen 0.49.2.
+ * From chromeos-linux v5.4 include/linux/kvm.h
+ * $ cd /path/to/kernel/v5.4/
+ * $ make headers_install ARCH=arm64 INSTALL_HDR_PATH=arm64_v5_4_headers
+ * $ cd arm64_v5_4_headers
+ * $ bindgen --with-derive-default -o bindings.rs include/linux/kvm.h -- -Iinclude
+ */
#[repr(C)]
#[derive(Default)]
-pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
impl<T> __IncompleteArrayField<T> {
#[inline]
pub fn new() -> Self {
- __IncompleteArrayField(::std::marker::PhantomData)
+ __IncompleteArrayField(::std::marker::PhantomData, [])
}
#[inline]
pub unsafe fn as_ptr(&self) -> *const T {
@@ -30,7 +37,7 @@
}
}
impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
- fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
fmt.write_str("__IncompleteArrayField")
}
}
@@ -40,455 +47,634 @@
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_VCPU_PMU_V3: ::std::os::raw::c_uint = 3;
-pub const KVM_ARM_VCPU_PMU_V3_CTRL: ::std::os::raw::c_uint = 0;
-pub const KVM_ARM_VCPU_PMU_V3_IRQ: ::std::os::raw::c_uint = 0;
-pub const KVM_ARM_VCPU_PMU_V3_INIT: ::std::os::raw::c_uint = 1;
-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_EXIT_HYPERV: ::std::os::raw::c_uint = 27;
-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_EXIT_HYPERV_SYNIC: ::std::os::raw::c_uint = 1;
-pub const KVM_EXIT_HYPERV_HCALL: ::std::os::raw::c_uint = 2;
-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_CAP_ARM_PMU_V3: ::std::os::raw::c_uint = 126;
-pub const KVM_CAP_IMMEDIATE_EXIT: ::std::os::raw::c_uint = 136;
-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 const __BITS_PER_LONG: u32 = 64;
+pub const __FD_SETSIZE: u32 = 1024;
+pub const _IOC_NRBITS: u32 = 8;
+pub const _IOC_TYPEBITS: u32 = 8;
+pub const _IOC_SIZEBITS: u32 = 14;
+pub const _IOC_DIRBITS: u32 = 2;
+pub const _IOC_NRMASK: u32 = 255;
+pub const _IOC_TYPEMASK: u32 = 255;
+pub const _IOC_SIZEMASK: u32 = 16383;
+pub const _IOC_DIRMASK: u32 = 3;
+pub const _IOC_NRSHIFT: u32 = 0;
+pub const _IOC_TYPESHIFT: u32 = 8;
+pub const _IOC_SIZESHIFT: u32 = 16;
+pub const _IOC_DIRSHIFT: u32 = 30;
+pub const _IOC_NONE: u32 = 0;
+pub const _IOC_WRITE: u32 = 1;
+pub const _IOC_READ: u32 = 2;
+pub const IOC_IN: u32 = 1073741824;
+pub const IOC_OUT: u32 = 2147483648;
+pub const IOC_INOUT: u32 = 3221225472;
+pub const IOCSIZE_MASK: u32 = 1073676288;
+pub const IOCSIZE_SHIFT: u32 = 16;
+pub const KVM_SPSR_EL1: u32 = 0;
+pub const KVM_SPSR_SVC: u32 = 0;
+pub const KVM_SPSR_ABT: u32 = 1;
+pub const KVM_SPSR_UND: u32 = 2;
+pub const KVM_SPSR_IRQ: u32 = 3;
+pub const KVM_SPSR_FIQ: u32 = 4;
+pub const KVM_NR_SPSR: u32 = 5;
+pub const PSCI_0_2_FN_BASE: u32 = 2214592512;
+pub const PSCI_0_2_64BIT: u32 = 1073741824;
+pub const PSCI_0_2_FN64_BASE: u32 = 3288334336;
+pub const PSCI_0_2_POWER_STATE_ID_MASK: u32 = 65535;
+pub const PSCI_0_2_POWER_STATE_ID_SHIFT: u32 = 0;
+pub const PSCI_0_2_POWER_STATE_TYPE_SHIFT: u32 = 16;
+pub const PSCI_0_2_POWER_STATE_TYPE_MASK: u32 = 65536;
+pub const PSCI_0_2_POWER_STATE_AFFL_SHIFT: u32 = 24;
+pub const PSCI_0_2_POWER_STATE_AFFL_MASK: u32 = 50331648;
+pub const PSCI_1_0_EXT_POWER_STATE_ID_MASK: u32 = 268435455;
+pub const PSCI_1_0_EXT_POWER_STATE_ID_SHIFT: u32 = 0;
+pub const PSCI_1_0_EXT_POWER_STATE_TYPE_SHIFT: u32 = 30;
+pub const PSCI_1_0_EXT_POWER_STATE_TYPE_MASK: u32 = 1073741824;
+pub const PSCI_0_2_AFFINITY_LEVEL_ON: u32 = 0;
+pub const PSCI_0_2_AFFINITY_LEVEL_OFF: u32 = 1;
+pub const PSCI_0_2_AFFINITY_LEVEL_ON_PENDING: u32 = 2;
+pub const PSCI_0_2_TOS_UP_MIGRATE: u32 = 0;
+pub const PSCI_0_2_TOS_UP_NO_MIGRATE: u32 = 1;
+pub const PSCI_0_2_TOS_MP: u32 = 2;
+pub const PSCI_VERSION_MAJOR_SHIFT: u32 = 16;
+pub const PSCI_VERSION_MINOR_MASK: u32 = 65535;
+pub const PSCI_VERSION_MAJOR_MASK: i32 = -65536;
+pub const PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT: u32 = 1;
+pub const PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK: u32 = 2;
+pub const PSCI_1_0_SUSPEND_MODE_PC: u32 = 0;
+pub const PSCI_1_0_SUSPEND_MODE_OSI: u32 = 1;
+pub const PSCI_RET_SUCCESS: u32 = 0;
+pub const PSCI_RET_NOT_SUPPORTED: i32 = -1;
+pub const PSCI_RET_INVALID_PARAMS: i32 = -2;
+pub const PSCI_RET_DENIED: i32 = -3;
+pub const PSCI_RET_ALREADY_ON: i32 = -4;
+pub const PSCI_RET_ON_PENDING: i32 = -5;
+pub const PSCI_RET_INTERNAL_FAILURE: i32 = -6;
+pub const PSCI_RET_NOT_PRESENT: i32 = -7;
+pub const PSCI_RET_DISABLED: i32 = -8;
+pub const PSCI_RET_INVALID_ADDRESS: i32 = -9;
+pub const HWCAP_FP: u32 = 1;
+pub const HWCAP_ASIMD: u32 = 2;
+pub const HWCAP_EVTSTRM: u32 = 4;
+pub const HWCAP_AES: u32 = 8;
+pub const HWCAP_PMULL: u32 = 16;
+pub const HWCAP_SHA1: u32 = 32;
+pub const HWCAP_SHA2: u32 = 64;
+pub const HWCAP_CRC32: u32 = 128;
+pub const HWCAP_ATOMICS: u32 = 256;
+pub const HWCAP_FPHP: u32 = 512;
+pub const HWCAP_ASIMDHP: u32 = 1024;
+pub const HWCAP_CPUID: u32 = 2048;
+pub const HWCAP_ASIMDRDM: u32 = 4096;
+pub const HWCAP_JSCVT: u32 = 8192;
+pub const HWCAP_FCMA: u32 = 16384;
+pub const HWCAP_LRCPC: u32 = 32768;
+pub const HWCAP_DCPOP: u32 = 65536;
+pub const HWCAP_SHA3: u32 = 131072;
+pub const HWCAP_SM3: u32 = 262144;
+pub const HWCAP_SM4: u32 = 524288;
+pub const HWCAP_ASIMDDP: u32 = 1048576;
+pub const HWCAP_SHA512: u32 = 2097152;
+pub const HWCAP_SVE: u32 = 4194304;
+pub const HWCAP_ASIMDFHM: u32 = 8388608;
+pub const HWCAP_DIT: u32 = 16777216;
+pub const HWCAP_USCAT: u32 = 33554432;
+pub const HWCAP_ILRCPC: u32 = 67108864;
+pub const HWCAP_FLAGM: u32 = 134217728;
+pub const HWCAP_SSBS: u32 = 268435456;
+pub const HWCAP_SB: u32 = 536870912;
+pub const HWCAP_PACA: u32 = 1073741824;
+pub const HWCAP_PACG: u32 = 2147483648;
+pub const HWCAP2_DCPODP: u32 = 1;
+pub const HWCAP2_SVE2: u32 = 2;
+pub const HWCAP2_SVEAES: u32 = 4;
+pub const HWCAP2_SVEPMULL: u32 = 8;
+pub const HWCAP2_SVEBITPERM: u32 = 16;
+pub const HWCAP2_SVESHA3: u32 = 32;
+pub const HWCAP2_SVESM4: u32 = 64;
+pub const HWCAP2_FLAGM2: u32 = 128;
+pub const HWCAP2_FRINT: u32 = 256;
+pub const HWCAP2_RNG: u32 = 512;
+pub const __SVE_VQ_BYTES: u32 = 16;
+pub const __SVE_VQ_MIN: u32 = 1;
+pub const __SVE_VQ_MAX: u32 = 512;
+pub const __SVE_VL_MIN: u32 = 16;
+pub const __SVE_VL_MAX: u32 = 8192;
+pub const __SVE_NUM_ZREGS: u32 = 32;
+pub const __SVE_NUM_PREGS: u32 = 16;
+pub const __SVE_ZREGS_OFFSET: u32 = 0;
+pub const PSR_MODE_EL0t: u32 = 0;
+pub const PSR_MODE_EL1t: u32 = 4;
+pub const PSR_MODE_EL1h: u32 = 5;
+pub const PSR_MODE_EL2t: u32 = 8;
+pub const PSR_MODE_EL2h: u32 = 9;
+pub const PSR_MODE_EL3t: u32 = 12;
+pub const PSR_MODE_EL3h: u32 = 13;
+pub const PSR_MODE_MASK: u32 = 15;
+pub const PSR_MODE32_BIT: u32 = 16;
+pub const PSR_F_BIT: u32 = 64;
+pub const PSR_I_BIT: u32 = 128;
+pub const PSR_A_BIT: u32 = 256;
+pub const PSR_D_BIT: u32 = 512;
+pub const PSR_SSBS_BIT: u32 = 4096;
+pub const PSR_PAN_BIT: u32 = 4194304;
+pub const PSR_UAO_BIT: u32 = 8388608;
+pub const PSR_DIT_BIT: u32 = 16777216;
+pub const PSR_V_BIT: u32 = 268435456;
+pub const PSR_C_BIT: u32 = 536870912;
+pub const PSR_Z_BIT: u32 = 1073741824;
+pub const PSR_N_BIT: u32 = 2147483648;
+pub const PSR_f: u32 = 4278190080;
+pub const PSR_s: u32 = 16711680;
+pub const PSR_x: u32 = 65280;
+pub const PSR_c: u32 = 255;
+pub const PTRACE_SYSEMU: u32 = 31;
+pub const PTRACE_SYSEMU_SINGLESTEP: u32 = 32;
+pub const SVE_PT_REGS_MASK: u32 = 1;
+pub const SVE_PT_REGS_FPSIMD: u32 = 0;
+pub const SVE_PT_REGS_SVE: u32 = 1;
+pub const SVE_PT_VL_INHERIT: u32 = 2;
+pub const SVE_PT_VL_ONEXEC: u32 = 4;
+pub const KVM_COALESCED_MMIO_PAGE_OFFSET: u32 = 1;
+pub const KVM_ARM_TARGET_AEM_V8: u32 = 0;
+pub const KVM_ARM_TARGET_FOUNDATION_V8: u32 = 1;
+pub const KVM_ARM_TARGET_CORTEX_A57: u32 = 2;
+pub const KVM_ARM_TARGET_XGENE_POTENZA: u32 = 3;
+pub const KVM_ARM_TARGET_CORTEX_A53: u32 = 4;
+pub const KVM_ARM_TARGET_GENERIC_V8: u32 = 5;
+pub const KVM_ARM_NUM_TARGETS: u32 = 6;
+pub const KVM_ARM_DEVICE_TYPE_SHIFT: u32 = 0;
+pub const KVM_ARM_DEVICE_TYPE_MASK: u32 = 65535;
+pub const KVM_ARM_DEVICE_ID_SHIFT: u32 = 16;
+pub const KVM_ARM_DEVICE_ID_MASK: u32 = 4294901760;
+pub const KVM_ARM_DEVICE_VGIC_V2: u32 = 0;
+pub const KVM_VGIC_V2_ADDR_TYPE_DIST: u32 = 0;
+pub const KVM_VGIC_V2_ADDR_TYPE_CPU: u32 = 1;
+pub const KVM_VGIC_V2_DIST_SIZE: u32 = 4096;
+pub const KVM_VGIC_V2_CPU_SIZE: u32 = 8192;
+pub const KVM_VGIC_V3_ADDR_TYPE_DIST: u32 = 2;
+pub const KVM_VGIC_V3_ADDR_TYPE_REDIST: u32 = 3;
+pub const KVM_VGIC_ITS_ADDR_TYPE: u32 = 4;
+pub const KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION: u32 = 5;
+pub const KVM_ARM_VCPU_POWER_OFF: u32 = 0;
+pub const KVM_ARM_VCPU_EL1_32BIT: u32 = 1;
+pub const KVM_ARM_VCPU_PSCI_0_2: u32 = 2;
+pub const KVM_ARM_VCPU_PMU_V3: u32 = 3;
+pub const KVM_ARM_VCPU_SVE: u32 = 4;
+pub const KVM_ARM_VCPU_PTRAUTH_ADDRESS: u32 = 5;
+pub const KVM_ARM_VCPU_PTRAUTH_GENERIC: u32 = 6;
+pub const KVM_ARM_MAX_DBG_REGS: u32 = 16;
+pub const KVM_GUESTDBG_USE_SW_BP: u32 = 65536;
+pub const KVM_GUESTDBG_USE_HW: u32 = 131072;
+pub const KVM_REG_ARM_COPROC_MASK: u32 = 268369920;
+pub const KVM_REG_ARM_COPROC_SHIFT: u32 = 16;
+pub const KVM_REG_ARM_CORE: u32 = 1048576;
+pub const KVM_REG_ARM_DEMUX: u32 = 1114112;
+pub const KVM_REG_ARM_DEMUX_ID_MASK: u32 = 65280;
+pub const KVM_REG_ARM_DEMUX_ID_SHIFT: u32 = 8;
+pub const KVM_REG_ARM_DEMUX_ID_CCSIDR: u32 = 0;
+pub const KVM_REG_ARM_DEMUX_VAL_MASK: u32 = 255;
+pub const KVM_REG_ARM_DEMUX_VAL_SHIFT: u32 = 0;
+pub const KVM_REG_ARM64_SYSREG: u32 = 1245184;
+pub const KVM_REG_ARM64_SYSREG_OP0_MASK: u32 = 49152;
+pub const KVM_REG_ARM64_SYSREG_OP0_SHIFT: u32 = 14;
+pub const KVM_REG_ARM64_SYSREG_OP1_MASK: u32 = 14336;
+pub const KVM_REG_ARM64_SYSREG_OP1_SHIFT: u32 = 11;
+pub const KVM_REG_ARM64_SYSREG_CRN_MASK: u32 = 1920;
+pub const KVM_REG_ARM64_SYSREG_CRN_SHIFT: u32 = 7;
+pub const KVM_REG_ARM64_SYSREG_CRM_MASK: u32 = 120;
+pub const KVM_REG_ARM64_SYSREG_CRM_SHIFT: u32 = 3;
+pub const KVM_REG_ARM64_SYSREG_OP2_MASK: u32 = 7;
+pub const KVM_REG_ARM64_SYSREG_OP2_SHIFT: u32 = 0;
+pub const KVM_REG_ARM_FW: u32 = 1310720;
+pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL: u32 = 0;
+pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL: u32 = 1;
+pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED: u32 = 2;
+pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL: u32 = 0;
+pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: u32 = 1;
+pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: u32 = 2;
+pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: u32 = 3;
+pub const KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED: u32 = 16;
+pub const KVM_REG_ARM64_SVE: u32 = 1376256;
+pub const KVM_REG_ARM64_SVE_ZREG_BASE: u32 = 0;
+pub const KVM_REG_ARM64_SVE_PREG_BASE: u32 = 1024;
+pub const KVM_REG_ARM64_SVE_FFR_BASE: u32 = 1536;
+pub const KVM_ARM64_SVE_NUM_ZREGS: u32 = 32;
+pub const KVM_ARM64_SVE_NUM_PREGS: u32 = 16;
+pub const KVM_ARM64_SVE_MAX_SLICES: u32 = 32;
+pub const KVM_ARM64_SVE_VQ_MIN: u32 = 1;
+pub const KVM_ARM64_SVE_VQ_MAX: u32 = 512;
+pub const KVM_ARM64_SVE_VLS_WORDS: u32 = 8;
+pub const KVM_DEV_ARM_VGIC_GRP_ADDR: u32 = 0;
+pub const KVM_DEV_ARM_VGIC_GRP_DIST_REGS: u32 = 1;
+pub const KVM_DEV_ARM_VGIC_GRP_CPU_REGS: u32 = 2;
+pub const KVM_DEV_ARM_VGIC_CPUID_SHIFT: u32 = 32;
+pub const KVM_DEV_ARM_VGIC_CPUID_MASK: u64 = 1095216660480;
+pub const KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT: u32 = 32;
+pub const KVM_DEV_ARM_VGIC_V3_MPIDR_MASK: i64 = -4294967296;
+pub const KVM_DEV_ARM_VGIC_OFFSET_SHIFT: u32 = 0;
+pub const KVM_DEV_ARM_VGIC_OFFSET_MASK: u32 = 4294967295;
+pub const KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK: u32 = 65535;
+pub const KVM_DEV_ARM_VGIC_GRP_NR_IRQS: u32 = 3;
+pub const KVM_DEV_ARM_VGIC_GRP_CTRL: u32 = 4;
+pub const KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: u32 = 5;
+pub const KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: u32 = 6;
+pub const KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: u32 = 7;
+pub const KVM_DEV_ARM_VGIC_GRP_ITS_REGS: u32 = 8;
+pub const KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT: u32 = 10;
+pub const KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK: u32 = 4294966272;
+pub const KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK: u32 = 1023;
+pub const VGIC_LEVEL_INFO_LINE_LEVEL: u32 = 0;
+pub const KVM_DEV_ARM_VGIC_CTRL_INIT: u32 = 0;
+pub const KVM_DEV_ARM_ITS_SAVE_TABLES: u32 = 1;
+pub const KVM_DEV_ARM_ITS_RESTORE_TABLES: u32 = 2;
+pub const KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES: u32 = 3;
+pub const KVM_DEV_ARM_ITS_CTRL_RESET: u32 = 4;
+pub const KVM_ARM_VCPU_PMU_V3_CTRL: u32 = 0;
+pub const KVM_ARM_VCPU_PMU_V3_IRQ: u32 = 0;
+pub const KVM_ARM_VCPU_PMU_V3_INIT: u32 = 1;
+pub const KVM_ARM_VCPU_TIMER_CTRL: u32 = 1;
+pub const KVM_ARM_VCPU_TIMER_IRQ_VTIMER: u32 = 0;
+pub const KVM_ARM_VCPU_TIMER_IRQ_PTIMER: u32 = 1;
+pub const KVM_ARM_IRQ_VCPU2_SHIFT: u32 = 28;
+pub const KVM_ARM_IRQ_VCPU2_MASK: u32 = 15;
+pub const KVM_ARM_IRQ_TYPE_SHIFT: u32 = 24;
+pub const KVM_ARM_IRQ_TYPE_MASK: u32 = 15;
+pub const KVM_ARM_IRQ_VCPU_SHIFT: u32 = 16;
+pub const KVM_ARM_IRQ_VCPU_MASK: u32 = 255;
+pub const KVM_ARM_IRQ_NUM_SHIFT: u32 = 0;
+pub const KVM_ARM_IRQ_NUM_MASK: u32 = 65535;
+pub const KVM_ARM_IRQ_TYPE_CPU: u32 = 0;
+pub const KVM_ARM_IRQ_TYPE_SPI: u32 = 1;
+pub const KVM_ARM_IRQ_TYPE_PPI: u32 = 2;
+pub const KVM_ARM_IRQ_CPU_IRQ: u32 = 0;
+pub const KVM_ARM_IRQ_CPU_FIQ: u32 = 1;
+pub const KVM_ARM_IRQ_GIC_MAX: u32 = 127;
+pub const KVM_NR_IRQCHIPS: u32 = 1;
+pub const KVM_PSCI_FN_BASE: u32 = 2512501342;
+pub const KVM_PSCI_RET_SUCCESS: u32 = 0;
+pub const KVM_PSCI_RET_NI: i32 = -1;
+pub const KVM_PSCI_RET_INVAL: i32 = -2;
+pub const KVM_PSCI_RET_DENIED: i32 = -3;
+pub const KVM_API_VERSION: u32 = 12;
+pub const KVM_TRC_SHIFT: u32 = 16;
+pub const KVM_TRC_ENTRYEXIT: u32 = 65536;
+pub const KVM_TRC_HANDLER: u32 = 131072;
+pub const KVM_TRC_VMENTRY: u32 = 65537;
+pub const KVM_TRC_VMEXIT: u32 = 65538;
+pub const KVM_TRC_PAGE_FAULT: u32 = 131073;
+pub const KVM_TRC_HEAD_SIZE: u32 = 12;
+pub const KVM_TRC_CYCLE_SIZE: u32 = 8;
+pub const KVM_TRC_EXTRA_MAX: u32 = 7;
+pub const KVM_TRC_INJ_VIRQ: u32 = 131074;
+pub const KVM_TRC_REDELIVER_EVT: u32 = 131075;
+pub const KVM_TRC_PEND_INTR: u32 = 131076;
+pub const KVM_TRC_IO_READ: u32 = 131077;
+pub const KVM_TRC_IO_WRITE: u32 = 131078;
+pub const KVM_TRC_CR_READ: u32 = 131079;
+pub const KVM_TRC_CR_WRITE: u32 = 131080;
+pub const KVM_TRC_DR_READ: u32 = 131081;
+pub const KVM_TRC_DR_WRITE: u32 = 131082;
+pub const KVM_TRC_MSR_READ: u32 = 131083;
+pub const KVM_TRC_MSR_WRITE: u32 = 131084;
+pub const KVM_TRC_CPUID: u32 = 131085;
+pub const KVM_TRC_INTR: u32 = 131086;
+pub const KVM_TRC_NMI: u32 = 131087;
+pub const KVM_TRC_VMMCALL: u32 = 131088;
+pub const KVM_TRC_HLT: u32 = 131089;
+pub const KVM_TRC_CLTS: u32 = 131090;
+pub const KVM_TRC_LMSW: u32 = 131091;
+pub const KVM_TRC_APIC_ACCESS: u32 = 131092;
+pub const KVM_TRC_TDP_FAULT: u32 = 131093;
+pub const KVM_TRC_GTLB_WRITE: u32 = 131094;
+pub const KVM_TRC_STLB_WRITE: u32 = 131095;
+pub const KVM_TRC_STLB_INVAL: u32 = 131096;
+pub const KVM_TRC_PPC_INSTR: u32 = 131097;
+pub const KVM_MEM_LOG_DIRTY_PAGES: u32 = 1;
+pub const KVM_MEM_READONLY: u32 = 2;
+pub const KVM_PIT_SPEAKER_DUMMY: u32 = 1;
+pub const KVM_S390_CMMA_PEEK: u32 = 1;
+pub const KVM_EXIT_HYPERV_SYNIC: u32 = 1;
+pub const KVM_EXIT_HYPERV_HCALL: u32 = 2;
+pub const KVM_S390_GET_SKEYS_NONE: u32 = 1;
+pub const KVM_S390_SKEYS_MAX: u32 = 1048576;
+pub const KVM_EXIT_UNKNOWN: u32 = 0;
+pub const KVM_EXIT_EXCEPTION: u32 = 1;
+pub const KVM_EXIT_IO: u32 = 2;
+pub const KVM_EXIT_HYPERCALL: u32 = 3;
+pub const KVM_EXIT_DEBUG: u32 = 4;
+pub const KVM_EXIT_HLT: u32 = 5;
+pub const KVM_EXIT_MMIO: u32 = 6;
+pub const KVM_EXIT_IRQ_WINDOW_OPEN: u32 = 7;
+pub const KVM_EXIT_SHUTDOWN: u32 = 8;
+pub const KVM_EXIT_FAIL_ENTRY: u32 = 9;
+pub const KVM_EXIT_INTR: u32 = 10;
+pub const KVM_EXIT_SET_TPR: u32 = 11;
+pub const KVM_EXIT_TPR_ACCESS: u32 = 12;
+pub const KVM_EXIT_S390_SIEIC: u32 = 13;
+pub const KVM_EXIT_S390_RESET: u32 = 14;
+pub const KVM_EXIT_DCR: u32 = 15;
+pub const KVM_EXIT_NMI: u32 = 16;
+pub const KVM_EXIT_INTERNAL_ERROR: u32 = 17;
+pub const KVM_EXIT_OSI: u32 = 18;
+pub const KVM_EXIT_PAPR_HCALL: u32 = 19;
+pub const KVM_EXIT_S390_UCONTROL: u32 = 20;
+pub const KVM_EXIT_WATCHDOG: u32 = 21;
+pub const KVM_EXIT_S390_TSCH: u32 = 22;
+pub const KVM_EXIT_EPR: u32 = 23;
+pub const KVM_EXIT_SYSTEM_EVENT: u32 = 24;
+pub const KVM_EXIT_S390_STSI: u32 = 25;
+pub const KVM_EXIT_IOAPIC_EOI: u32 = 26;
+pub const KVM_EXIT_HYPERV: u32 = 27;
+pub const KVM_INTERNAL_ERROR_EMULATION: u32 = 1;
+pub const KVM_INTERNAL_ERROR_SIMUL_EX: u32 = 2;
+pub const KVM_INTERNAL_ERROR_DELIVERY_EV: u32 = 3;
+pub const KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON: u32 = 4;
+pub const KVM_EXIT_IO_IN: u32 = 0;
+pub const KVM_EXIT_IO_OUT: u32 = 1;
+pub const KVM_S390_RESET_POR: u32 = 1;
+pub const KVM_S390_RESET_CLEAR: u32 = 2;
+pub const KVM_S390_RESET_SUBSYSTEM: u32 = 4;
+pub const KVM_S390_RESET_CPU_INIT: u32 = 8;
+pub const KVM_S390_RESET_IPL: u32 = 16;
+pub const KVM_SYSTEM_EVENT_SHUTDOWN: u32 = 1;
+pub const KVM_SYSTEM_EVENT_RESET: u32 = 2;
+pub const KVM_SYSTEM_EVENT_CRASH: u32 = 3;
+pub const SYNC_REGS_SIZE_BYTES: u32 = 2048;
+pub const KVM_S390_MEMOP_LOGICAL_READ: u32 = 0;
+pub const KVM_S390_MEMOP_LOGICAL_WRITE: u32 = 1;
+pub const KVM_S390_MEMOP_F_CHECK_ONLY: u32 = 1;
+pub const KVM_S390_MEMOP_F_INJECT_EXCEPTION: u32 = 2;
+pub const KVM_MP_STATE_RUNNABLE: u32 = 0;
+pub const KVM_MP_STATE_UNINITIALIZED: u32 = 1;
+pub const KVM_MP_STATE_INIT_RECEIVED: u32 = 2;
+pub const KVM_MP_STATE_HALTED: u32 = 3;
+pub const KVM_MP_STATE_SIPI_RECEIVED: u32 = 4;
+pub const KVM_MP_STATE_STOPPED: u32 = 5;
+pub const KVM_MP_STATE_CHECK_STOP: u32 = 6;
+pub const KVM_MP_STATE_OPERATING: u32 = 7;
+pub const KVM_MP_STATE_LOAD: u32 = 8;
+pub const KVM_S390_SIGP_STOP: u32 = 4294836224;
+pub const KVM_S390_PROGRAM_INT: u32 = 4294836225;
+pub const KVM_S390_SIGP_SET_PREFIX: u32 = 4294836226;
+pub const KVM_S390_RESTART: u32 = 4294836227;
+pub const KVM_S390_INT_PFAULT_INIT: u32 = 4294836228;
+pub const KVM_S390_INT_PFAULT_DONE: u32 = 4294836229;
+pub const KVM_S390_MCHK: u32 = 4294840320;
+pub const KVM_S390_INT_CLOCK_COMP: u32 = 4294905860;
+pub const KVM_S390_INT_CPU_TIMER: u32 = 4294905861;
+pub const KVM_S390_INT_VIRTIO: u32 = 4294911491;
+pub const KVM_S390_INT_SERVICE: u32 = 4294910977;
+pub const KVM_S390_INT_EMERGENCY: u32 = 4294906369;
+pub const KVM_S390_INT_EXTERNAL_CALL: u32 = 4294906370;
+pub const KVM_S390_INT_IO_MIN: u32 = 0;
+pub const KVM_S390_INT_IO_MAX: u32 = 4294836223;
+pub const KVM_S390_INT_IO_AI_MASK: u32 = 67108864;
+pub const KVM_S390_PGM_FLAGS_ILC_VALID: u32 = 1;
+pub const KVM_S390_PGM_FLAGS_ILC_0: u32 = 2;
+pub const KVM_S390_PGM_FLAGS_ILC_1: u32 = 4;
+pub const KVM_S390_PGM_FLAGS_ILC_MASK: u32 = 6;
+pub const KVM_S390_PGM_FLAGS_NO_REWIND: u32 = 8;
+pub const KVM_S390_STOP_FLAG_STORE_STATUS: u32 = 1;
+pub const KVM_GUESTDBG_ENABLE: u32 = 1;
+pub const KVM_GUESTDBG_SINGLESTEP: u32 = 2;
+pub const KVM_X86_DISABLE_EXITS_MWAIT: u32 = 1;
+pub const KVM_X86_DISABLE_EXITS_HLT: u32 = 2;
+pub const KVM_X86_DISABLE_EXITS_PAUSE: u32 = 4;
+pub const KVM_X86_DISABLE_EXITS_CSTATE: u32 = 8;
+pub const KVM_X86_DISABLE_VALID_EXITS: u32 = 15;
+pub const KVM_PPC_PVINFO_FLAGS_EV_IDLE: u32 = 1;
+pub const KVM_PPC_PAGE_SIZES_MAX_SZ: u32 = 8;
+pub const KVM_PPC_PAGE_SIZES_REAL: u32 = 1;
+pub const KVM_PPC_1T_SEGMENTS: u32 = 2;
+pub const KVM_PPC_NO_HASH: u32 = 4;
+pub const KVMIO: u32 = 174;
+pub const KVM_VM_S390_UCONTROL: u32 = 1;
+pub const KVM_VM_PPC_HV: u32 = 1;
+pub const KVM_VM_PPC_PR: u32 = 2;
+pub const KVM_VM_MIPS_AUTO: u32 = 0;
+pub const KVM_VM_MIPS_VZ: u32 = 1;
+pub const KVM_VM_MIPS_TE: u32 = 2;
+pub const KVM_S390_SIE_PAGE_OFFSET: u32 = 1;
+pub const KVM_VM_TYPE_ARM_IPA_SIZE_MASK: u32 = 255;
+pub const KVM_CAP_IRQCHIP: u32 = 0;
+pub const KVM_CAP_HLT: u32 = 1;
+pub const KVM_CAP_MMU_SHADOW_CACHE_CONTROL: u32 = 2;
+pub const KVM_CAP_USER_MEMORY: u32 = 3;
+pub const KVM_CAP_SET_TSS_ADDR: u32 = 4;
+pub const KVM_CAP_VAPIC: u32 = 6;
+pub const KVM_CAP_EXT_CPUID: u32 = 7;
+pub const KVM_CAP_CLOCKSOURCE: u32 = 8;
+pub const KVM_CAP_NR_VCPUS: u32 = 9;
+pub const KVM_CAP_NR_MEMSLOTS: u32 = 10;
+pub const KVM_CAP_PIT: u32 = 11;
+pub const KVM_CAP_NOP_IO_DELAY: u32 = 12;
+pub const KVM_CAP_PV_MMU: u32 = 13;
+pub const KVM_CAP_MP_STATE: u32 = 14;
+pub const KVM_CAP_COALESCED_MMIO: u32 = 15;
+pub const KVM_CAP_SYNC_MMU: u32 = 16;
+pub const KVM_CAP_IOMMU: u32 = 18;
+pub const KVM_CAP_DESTROY_MEMORY_REGION_WORKS: u32 = 21;
+pub const KVM_CAP_USER_NMI: u32 = 22;
+pub const KVM_CAP_SET_GUEST_DEBUG: u32 = 23;
+pub const KVM_CAP_IRQ_ROUTING: u32 = 25;
+pub const KVM_CAP_IRQ_INJECT_STATUS: u32 = 26;
+pub const KVM_CAP_ASSIGN_DEV_IRQ: u32 = 29;
+pub const KVM_CAP_JOIN_MEMORY_REGIONS_WORKS: u32 = 30;
+pub const KVM_CAP_IRQFD: u32 = 32;
+pub const KVM_CAP_SET_BOOT_CPU_ID: u32 = 34;
+pub const KVM_CAP_IOEVENTFD: u32 = 36;
+pub const KVM_CAP_SET_IDENTITY_MAP_ADDR: u32 = 37;
+pub const KVM_CAP_ADJUST_CLOCK: u32 = 39;
+pub const KVM_CAP_INTERNAL_ERROR_DATA: u32 = 40;
+pub const KVM_CAP_VCPU_EVENTS: u32 = 41;
+pub const KVM_CAP_S390_PSW: u32 = 42;
+pub const KVM_CAP_PPC_SEGSTATE: u32 = 43;
+pub const KVM_CAP_HYPERV: u32 = 44;
+pub const KVM_CAP_HYPERV_VAPIC: u32 = 45;
+pub const KVM_CAP_HYPERV_SPIN: u32 = 46;
+pub const KVM_CAP_PCI_SEGMENT: u32 = 47;
+pub const KVM_CAP_PPC_PAIRED_SINGLES: u32 = 48;
+pub const KVM_CAP_INTR_SHADOW: u32 = 49;
+pub const KVM_CAP_X86_ROBUST_SINGLESTEP: u32 = 51;
+pub const KVM_CAP_PPC_OSI: u32 = 52;
+pub const KVM_CAP_PPC_UNSET_IRQ: u32 = 53;
+pub const KVM_CAP_ENABLE_CAP: u32 = 54;
+pub const KVM_CAP_PPC_GET_PVINFO: u32 = 57;
+pub const KVM_CAP_PPC_IRQ_LEVEL: u32 = 58;
+pub const KVM_CAP_ASYNC_PF: u32 = 59;
+pub const KVM_CAP_TSC_CONTROL: u32 = 60;
+pub const KVM_CAP_GET_TSC_KHZ: u32 = 61;
+pub const KVM_CAP_PPC_BOOKE_SREGS: u32 = 62;
+pub const KVM_CAP_SPAPR_TCE: u32 = 63;
+pub const KVM_CAP_PPC_SMT: u32 = 64;
+pub const KVM_CAP_PPC_RMA: u32 = 65;
+pub const KVM_CAP_MAX_VCPUS: u32 = 66;
+pub const KVM_CAP_PPC_HIOR: u32 = 67;
+pub const KVM_CAP_PPC_PAPR: u32 = 68;
+pub const KVM_CAP_SW_TLB: u32 = 69;
+pub const KVM_CAP_ONE_REG: u32 = 70;
+pub const KVM_CAP_S390_GMAP: u32 = 71;
+pub const KVM_CAP_TSC_DEADLINE_TIMER: u32 = 72;
+pub const KVM_CAP_S390_UCONTROL: u32 = 73;
+pub const KVM_CAP_SYNC_REGS: u32 = 74;
+pub const KVM_CAP_PCI_2_3: u32 = 75;
+pub const KVM_CAP_KVMCLOCK_CTRL: u32 = 76;
+pub const KVM_CAP_SIGNAL_MSI: u32 = 77;
+pub const KVM_CAP_PPC_GET_SMMU_INFO: u32 = 78;
+pub const KVM_CAP_S390_COW: u32 = 79;
+pub const KVM_CAP_PPC_ALLOC_HTAB: u32 = 80;
+pub const KVM_CAP_READONLY_MEM: u32 = 81;
+pub const KVM_CAP_IRQFD_RESAMPLE: u32 = 82;
+pub const KVM_CAP_PPC_BOOKE_WATCHDOG: u32 = 83;
+pub const KVM_CAP_PPC_HTAB_FD: u32 = 84;
+pub const KVM_CAP_S390_CSS_SUPPORT: u32 = 85;
+pub const KVM_CAP_PPC_EPR: u32 = 86;
+pub const KVM_CAP_ARM_PSCI: u32 = 87;
+pub const KVM_CAP_ARM_SET_DEVICE_ADDR: u32 = 88;
+pub const KVM_CAP_DEVICE_CTRL: u32 = 89;
+pub const KVM_CAP_IRQ_MPIC: u32 = 90;
+pub const KVM_CAP_PPC_RTAS: u32 = 91;
+pub const KVM_CAP_IRQ_XICS: u32 = 92;
+pub const KVM_CAP_ARM_EL1_32BIT: u32 = 93;
+pub const KVM_CAP_SPAPR_MULTITCE: u32 = 94;
+pub const KVM_CAP_EXT_EMUL_CPUID: u32 = 95;
+pub const KVM_CAP_HYPERV_TIME: u32 = 96;
+pub const KVM_CAP_IOAPIC_POLARITY_IGNORED: u32 = 97;
+pub const KVM_CAP_ENABLE_CAP_VM: u32 = 98;
+pub const KVM_CAP_S390_IRQCHIP: u32 = 99;
+pub const KVM_CAP_IOEVENTFD_NO_LENGTH: u32 = 100;
+pub const KVM_CAP_VM_ATTRIBUTES: u32 = 101;
+pub const KVM_CAP_ARM_PSCI_0_2: u32 = 102;
+pub const KVM_CAP_PPC_FIXUP_HCALL: u32 = 103;
+pub const KVM_CAP_PPC_ENABLE_HCALL: u32 = 104;
+pub const KVM_CAP_CHECK_EXTENSION_VM: u32 = 105;
+pub const KVM_CAP_S390_USER_SIGP: u32 = 106;
+pub const KVM_CAP_S390_VECTOR_REGISTERS: u32 = 107;
+pub const KVM_CAP_S390_MEM_OP: u32 = 108;
+pub const KVM_CAP_S390_USER_STSI: u32 = 109;
+pub const KVM_CAP_S390_SKEYS: u32 = 110;
+pub const KVM_CAP_MIPS_FPU: u32 = 111;
+pub const KVM_CAP_MIPS_MSA: u32 = 112;
+pub const KVM_CAP_S390_INJECT_IRQ: u32 = 113;
+pub const KVM_CAP_S390_IRQ_STATE: u32 = 114;
+pub const KVM_CAP_PPC_HWRNG: u32 = 115;
+pub const KVM_CAP_DISABLE_QUIRKS: u32 = 116;
+pub const KVM_CAP_X86_SMM: u32 = 117;
+pub const KVM_CAP_MULTI_ADDRESS_SPACE: u32 = 118;
+pub const KVM_CAP_GUEST_DEBUG_HW_BPS: u32 = 119;
+pub const KVM_CAP_GUEST_DEBUG_HW_WPS: u32 = 120;
+pub const KVM_CAP_SPLIT_IRQCHIP: u32 = 121;
+pub const KVM_CAP_IOEVENTFD_ANY_LENGTH: u32 = 122;
+pub const KVM_CAP_HYPERV_SYNIC: u32 = 123;
+pub const KVM_CAP_S390_RI: u32 = 124;
+pub const KVM_CAP_SPAPR_TCE_64: u32 = 125;
+pub const KVM_CAP_ARM_PMU_V3: u32 = 126;
+pub const KVM_CAP_VCPU_ATTRIBUTES: u32 = 127;
+pub const KVM_CAP_MAX_VCPU_ID: u32 = 128;
+pub const KVM_CAP_X2APIC_API: u32 = 129;
+pub const KVM_CAP_S390_USER_INSTR0: u32 = 130;
+pub const KVM_CAP_MSI_DEVID: u32 = 131;
+pub const KVM_CAP_PPC_HTM: u32 = 132;
+pub const KVM_CAP_SPAPR_RESIZE_HPT: u32 = 133;
+pub const KVM_CAP_PPC_MMU_RADIX: u32 = 134;
+pub const KVM_CAP_PPC_MMU_HASH_V3: u32 = 135;
+pub const KVM_CAP_IMMEDIATE_EXIT: u32 = 136;
+pub const KVM_CAP_MIPS_VZ: u32 = 137;
+pub const KVM_CAP_MIPS_TE: u32 = 138;
+pub const KVM_CAP_MIPS_64BIT: u32 = 139;
+pub const KVM_CAP_S390_GS: u32 = 140;
+pub const KVM_CAP_S390_AIS: u32 = 141;
+pub const KVM_CAP_SPAPR_TCE_VFIO: u32 = 142;
+pub const KVM_CAP_X86_DISABLE_EXITS: u32 = 143;
+pub const KVM_CAP_ARM_USER_IRQ: u32 = 144;
+pub const KVM_CAP_S390_CMMA_MIGRATION: u32 = 145;
+pub const KVM_CAP_PPC_FWNMI: u32 = 146;
+pub const KVM_CAP_PPC_SMT_POSSIBLE: u32 = 147;
+pub const KVM_CAP_HYPERV_SYNIC2: u32 = 148;
+pub const KVM_CAP_HYPERV_VP_INDEX: u32 = 149;
+pub const KVM_CAP_S390_AIS_MIGRATION: u32 = 150;
+pub const KVM_CAP_PPC_GET_CPU_CHAR: u32 = 151;
+pub const KVM_CAP_S390_BPB: u32 = 152;
+pub const KVM_CAP_GET_MSR_FEATURES: u32 = 153;
+pub const KVM_CAP_HYPERV_EVENTFD: u32 = 154;
+pub const KVM_CAP_HYPERV_TLBFLUSH: u32 = 155;
+pub const KVM_CAP_S390_HPAGE_1M: u32 = 156;
+pub const KVM_CAP_NESTED_STATE: u32 = 157;
+pub const KVM_CAP_ARM_INJECT_SERROR_ESR: u32 = 158;
+pub const KVM_CAP_MSR_PLATFORM_INFO: u32 = 159;
+pub const KVM_CAP_PPC_NESTED_HV: u32 = 160;
+pub const KVM_CAP_HYPERV_SEND_IPI: u32 = 161;
+pub const KVM_CAP_COALESCED_PIO: u32 = 162;
+pub const KVM_CAP_HYPERV_ENLIGHTENED_VMCS: u32 = 163;
+pub const KVM_CAP_EXCEPTION_PAYLOAD: u32 = 164;
+pub const KVM_CAP_ARM_VM_IPA_SIZE: u32 = 165;
+pub const KVM_CAP_MANUAL_DIRTY_LOG_PROTECT: u32 = 166;
+pub const KVM_CAP_HYPERV_CPUID: u32 = 167;
+pub const KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2: u32 = 168;
+pub const KVM_CAP_PPC_IRQ_XIVE: u32 = 169;
+pub const KVM_CAP_ARM_SVE: u32 = 170;
+pub const KVM_CAP_ARM_PTRAUTH_ADDRESS: u32 = 171;
+pub const KVM_CAP_ARM_PTRAUTH_GENERIC: u32 = 172;
+pub const KVM_CAP_PMU_EVENT_FILTER: u32 = 173;
+pub const KVM_CAP_ARM_IRQ_LINE_LAYOUT_2: u32 = 174;
+pub const KVM_CAP_HYPERV_DIRECT_TLBFLUSH: u32 = 175;
+pub const KVM_IRQ_ROUTING_IRQCHIP: u32 = 1;
+pub const KVM_IRQ_ROUTING_MSI: u32 = 2;
+pub const KVM_IRQ_ROUTING_S390_ADAPTER: u32 = 3;
+pub const KVM_IRQ_ROUTING_HV_SINT: u32 = 4;
+pub const KVM_IRQFD_FLAG_DEASSIGN: u32 = 1;
+pub const KVM_IRQFD_FLAG_RESAMPLE: u32 = 2;
+pub const KVM_CLOCK_TSC_STABLE: u32 = 2;
+pub const KVM_MMU_FSL_BOOKE_NOHV: u32 = 0;
+pub const KVM_MMU_FSL_BOOKE_HV: u32 = 1;
+pub const KVM_REG_ARCH_MASK: i64 = -72057594037927936;
+pub const KVM_REG_GENERIC: u32 = 0;
+pub const KVM_REG_PPC: u64 = 1152921504606846976;
+pub const KVM_REG_X86: u64 = 2305843009213693952;
+pub const KVM_REG_IA64: u64 = 3458764513820540928;
+pub const KVM_REG_ARM: u64 = 4611686018427387904;
+pub const KVM_REG_S390: u64 = 5764607523034234880;
+pub const KVM_REG_ARM64: u64 = 6917529027641081856;
+pub const KVM_REG_MIPS: u64 = 8070450532247928832;
+pub const KVM_REG_RISCV: i64 = -9223372036854775808;
+pub const KVM_REG_SIZE_SHIFT: u32 = 52;
+pub const KVM_REG_SIZE_MASK: u64 = 67553994410557440;
+pub const KVM_REG_SIZE_U8: u32 = 0;
+pub const KVM_REG_SIZE_U16: u64 = 4503599627370496;
+pub const KVM_REG_SIZE_U32: u64 = 9007199254740992;
+pub const KVM_REG_SIZE_U64: u64 = 13510798882111488;
+pub const KVM_REG_SIZE_U128: u64 = 18014398509481984;
+pub const KVM_REG_SIZE_U256: u64 = 22517998136852480;
+pub const KVM_REG_SIZE_U512: u64 = 27021597764222976;
+pub const KVM_REG_SIZE_U1024: u64 = 31525197391593472;
+pub const KVM_REG_SIZE_U2048: u64 = 36028797018963968;
+pub const KVM_MSI_VALID_DEVID: u32 = 1;
+pub const KVM_CREATE_DEVICE_TEST: u32 = 1;
+pub const KVM_DEV_VFIO_GROUP: u32 = 1;
+pub const KVM_DEV_VFIO_GROUP_ADD: u32 = 1;
+pub const KVM_DEV_VFIO_GROUP_DEL: u32 = 2;
+pub const KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE: u32 = 3;
+pub const KVM_S390_STORE_STATUS_NOADDR: i32 = -1;
+pub const KVM_S390_STORE_STATUS_PREFIXED: i32 = -2;
+pub const KVM_DEV_ASSIGN_ENABLE_IOMMU: u32 = 1;
+pub const KVM_DEV_ASSIGN_PCI_2_3: u32 = 2;
+pub const KVM_DEV_ASSIGN_MASK_INTX: u32 = 4;
+pub const KVM_DEV_IRQ_HOST_INTX: u32 = 1;
+pub const KVM_DEV_IRQ_HOST_MSI: u32 = 2;
+pub const KVM_DEV_IRQ_HOST_MSIX: u32 = 4;
+pub const KVM_DEV_IRQ_GUEST_INTX: u32 = 256;
+pub const KVM_DEV_IRQ_GUEST_MSI: u32 = 512;
+pub const KVM_DEV_IRQ_GUEST_MSIX: u32 = 1024;
+pub const KVM_DEV_IRQ_HOST_MASK: u32 = 255;
+pub const KVM_DEV_IRQ_GUEST_MASK: u32 = 65280;
+pub const KVM_MAX_MSIX_PER_DEV: u32 = 256;
+pub const KVM_X2APIC_API_USE_32BIT_IDS: u32 = 1;
+pub const KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK: u32 = 2;
+pub const KVM_ARM_DEV_EL1_VTIMER: u32 = 1;
+pub const KVM_ARM_DEV_EL1_PTIMER: u32 = 2;
+pub const KVM_ARM_DEV_PMU: u32 = 4;
+pub const KVM_HYPERV_CONN_ID_MASK: u32 = 16777215;
+pub const KVM_HYPERV_EVENTFD_DEASSIGN: u32 = 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;
@@ -578,6 +764,7 @@
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_time64_t = ::std::os::raw::c_longlong;
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;
@@ -592,6 +779,7 @@
pub type __be64 = __u64;
pub type __sum16 = __u16;
pub type __wsum = __u32;
+pub type __poll_t = ::std::os::raw::c_uint;
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct user_pt_regs {
@@ -654,12 +842,13 @@
);
}
#[repr(C)]
+#[repr(align(16))]
#[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,
+ pub __reserved: [__u32; 2usize],
}
#[test]
fn bindgen_test_layout_user_fpsimd_state() {
@@ -669,6 +858,11 @@
concat!("Size of: ", stringify!(user_fpsimd_state))
);
assert_eq!(
+ ::std::mem::align_of::<user_fpsimd_state>(),
+ 16usize,
+ concat!("Alignment of ", stringify!(user_fpsimd_state))
+ );
+ assert_eq!(
unsafe { &(*(::std::ptr::null::<user_fpsimd_state>())).vregs as *const _ as usize },
0usize,
concat!(
@@ -698,6 +892,16 @@
stringify!(fpcr)
)
);
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<user_fpsimd_state>())).__reserved as *const _ as usize },
+ 520usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(user_fpsimd_state),
+ "::",
+ stringify!(__reserved)
+ )
+ );
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
@@ -810,6 +1014,220 @@
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
+pub struct user_sve_header {
+ pub size: __u32,
+ pub max_size: __u32,
+ pub vl: __u16,
+ pub max_vl: __u16,
+ pub flags: __u16,
+ pub __reserved: __u16,
+}
+#[test]
+fn bindgen_test_layout_user_sve_header() {
+ assert_eq!(
+ ::std::mem::size_of::<user_sve_header>(),
+ 16usize,
+ concat!("Size of: ", stringify!(user_sve_header))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<user_sve_header>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(user_sve_header))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<user_sve_header>())).size as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(user_sve_header),
+ "::",
+ stringify!(size)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<user_sve_header>())).max_size as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(user_sve_header),
+ "::",
+ stringify!(max_size)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<user_sve_header>())).vl as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(user_sve_header),
+ "::",
+ stringify!(vl)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<user_sve_header>())).max_vl as *const _ as usize },
+ 10usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(user_sve_header),
+ "::",
+ stringify!(max_vl)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<user_sve_header>())).flags as *const _ as usize },
+ 12usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(user_sve_header),
+ "::",
+ stringify!(flags)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<user_sve_header>())).__reserved as *const _ as usize },
+ 14usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(user_sve_header),
+ "::",
+ stringify!(__reserved)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct user_pac_mask {
+ pub data_mask: __u64,
+ pub insn_mask: __u64,
+}
+#[test]
+fn bindgen_test_layout_user_pac_mask() {
+ assert_eq!(
+ ::std::mem::size_of::<user_pac_mask>(),
+ 16usize,
+ concat!("Size of: ", stringify!(user_pac_mask))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<user_pac_mask>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(user_pac_mask))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<user_pac_mask>())).data_mask as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(user_pac_mask),
+ "::",
+ stringify!(data_mask)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<user_pac_mask>())).insn_mask as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(user_pac_mask),
+ "::",
+ stringify!(insn_mask)
+ )
+ );
+}
+#[repr(C)]
+#[repr(align(16))]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct user_pac_address_keys {
+ pub apiakey: __uint128_t,
+ pub apibkey: __uint128_t,
+ pub apdakey: __uint128_t,
+ pub apdbkey: __uint128_t,
+}
+#[test]
+fn bindgen_test_layout_user_pac_address_keys() {
+ assert_eq!(
+ ::std::mem::size_of::<user_pac_address_keys>(),
+ 64usize,
+ concat!("Size of: ", stringify!(user_pac_address_keys))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<user_pac_address_keys>(),
+ 16usize,
+ concat!("Alignment of ", stringify!(user_pac_address_keys))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<user_pac_address_keys>())).apiakey as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(user_pac_address_keys),
+ "::",
+ stringify!(apiakey)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<user_pac_address_keys>())).apibkey as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(user_pac_address_keys),
+ "::",
+ stringify!(apibkey)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<user_pac_address_keys>())).apdakey as *const _ as usize },
+ 32usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(user_pac_address_keys),
+ "::",
+ stringify!(apdakey)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<user_pac_address_keys>())).apdbkey as *const _ as usize },
+ 48usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(user_pac_address_keys),
+ "::",
+ stringify!(apdbkey)
+ )
+ );
+}
+#[repr(C)]
+#[repr(align(16))]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct user_pac_generic_keys {
+ pub apgakey: __uint128_t,
+}
+#[test]
+fn bindgen_test_layout_user_pac_generic_keys() {
+ assert_eq!(
+ ::std::mem::size_of::<user_pac_generic_keys>(),
+ 16usize,
+ concat!("Size of: ", stringify!(user_pac_generic_keys))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<user_pac_generic_keys>(),
+ 16usize,
+ concat!("Alignment of ", stringify!(user_pac_generic_keys))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<user_pac_generic_keys>())).apgakey as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(user_pac_generic_keys),
+ "::",
+ stringify!(apgakey)
+ )
+ );
+}
+#[repr(C)]
+#[repr(align(16))]
+#[derive(Debug, Default, Copy, Clone)]
pub struct kvm_regs {
pub regs: user_pt_regs,
pub sp_el1: __u64,
@@ -826,6 +1244,11 @@
concat!("Size of: ", stringify!(kvm_regs))
);
assert_eq!(
+ ::std::mem::align_of::<kvm_regs>(),
+ 16usize,
+ concat!("Alignment of ", stringify!(kvm_regs))
+ );
+ assert_eq!(
unsafe { &(*(::std::ptr::null::<kvm_regs>())).regs as *const _ as usize },
0usize,
concat!(
@@ -1049,19 +1472,31 @@
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
-pub struct kvm_sync_regs {}
+pub struct kvm_sync_regs {
+ pub device_irq_level: __u64,
+}
#[test]
fn bindgen_test_layout_kvm_sync_regs() {
assert_eq!(
::std::mem::size_of::<kvm_sync_regs>(),
- 0usize,
+ 8usize,
concat!("Size of: ", stringify!(kvm_sync_regs))
);
assert_eq!(
::std::mem::align_of::<kvm_sync_regs>(),
- 1usize,
+ 8usize,
concat!("Alignment of ", stringify!(kvm_sync_regs))
);
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sync_regs>())).device_irq_level as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sync_regs),
+ "::",
+ stringify!(device_irq_level)
+ )
+ );
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
@@ -1081,6 +1516,117 @@
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_vcpu_events {
+ pub exception: kvm_vcpu_events__bindgen_ty_1,
+ pub reserved: [__u32; 12usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_vcpu_events__bindgen_ty_1 {
+ pub serror_pending: __u8,
+ pub serror_has_esr: __u8,
+ pub pad: [__u8; 6usize],
+ pub serror_esr: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_vcpu_events__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_vcpu_events__bindgen_ty_1>(),
+ 16usize,
+ concat!("Size of: ", stringify!(kvm_vcpu_events__bindgen_ty_1))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_vcpu_events__bindgen_ty_1>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_vcpu_events__bindgen_ty_1))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_1>())).serror_pending as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vcpu_events__bindgen_ty_1),
+ "::",
+ stringify!(serror_pending)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_1>())).serror_has_esr as *const _
+ as usize
+ },
+ 1usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vcpu_events__bindgen_ty_1),
+ "::",
+ stringify!(serror_has_esr)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_1>())).pad as *const _ as usize
+ },
+ 2usize,
+ 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>())).serror_esr as *const _
+ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vcpu_events__bindgen_ty_1),
+ "::",
+ stringify!(serror_esr)
+ )
+ );
+}
+#[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>(),
+ 8usize,
+ 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>())).reserved as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vcpu_events),
+ "::",
+ stringify!(reserved)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct kvm_user_trace_setup {
pub buf_size: __u32,
pub buf_nr: __u32,
@@ -1657,6 +2203,399 @@
)
);
}
+#[doc = " kvm_s390_cmma_log - Used for CMMA migration."]
+#[doc = ""]
+#[doc = " Used both for input and output."]
+#[doc = ""]
+#[doc = " @start_gfn: Guest page number to start from."]
+#[doc = " @count: Size of the result buffer."]
+#[doc = " @flags: Control operation mode via KVM_S390_CMMA_* flags"]
+#[doc = " @remaining: Used with KVM_S390_GET_CMMA_BITS. Indicates how many dirty"]
+#[doc = " pages are still remaining."]
+#[doc = " @mask: Used with KVM_S390_SET_CMMA_BITS. Bitmap of bits to actually set"]
+#[doc = " in the PGSTE."]
+#[doc = " @values: Pointer to the values buffer."]
+#[doc = ""]
+#[doc = " Used in KVM_S390_{G,S}ET_CMMA_BITS ioctls."]
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_s390_cmma_log {
+ pub start_gfn: __u64,
+ pub count: __u32,
+ pub flags: __u32,
+ pub __bindgen_anon_1: kvm_s390_cmma_log__bindgen_ty_1,
+ pub values: __u64,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_s390_cmma_log__bindgen_ty_1 {
+ pub remaining: __u64,
+ pub mask: __u64,
+ _bindgen_union_align: u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_cmma_log__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_s390_cmma_log__bindgen_ty_1>(),
+ 8usize,
+ concat!("Size of: ", stringify!(kvm_s390_cmma_log__bindgen_ty_1))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_s390_cmma_log__bindgen_ty_1>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_s390_cmma_log__bindgen_ty_1))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_s390_cmma_log__bindgen_ty_1>())).remaining as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_s390_cmma_log__bindgen_ty_1),
+ "::",
+ stringify!(remaining)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_s390_cmma_log__bindgen_ty_1>())).mask as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_s390_cmma_log__bindgen_ty_1),
+ "::",
+ stringify!(mask)
+ )
+ );
+}
+impl Default for kvm_s390_cmma_log__bindgen_ty_1 {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_cmma_log() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_s390_cmma_log>(),
+ 32usize,
+ concat!("Size of: ", stringify!(kvm_s390_cmma_log))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_s390_cmma_log>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_s390_cmma_log))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_s390_cmma_log>())).start_gfn as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_s390_cmma_log),
+ "::",
+ stringify!(start_gfn)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_s390_cmma_log>())).count as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_s390_cmma_log),
+ "::",
+ stringify!(count)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_s390_cmma_log>())).flags as *const _ as usize },
+ 12usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_s390_cmma_log),
+ "::",
+ stringify!(flags)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_s390_cmma_log>())).values as *const _ as usize },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_s390_cmma_log),
+ "::",
+ stringify!(values)
+ )
+ );
+}
+impl Default for kvm_s390_cmma_log {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_hyperv_exit {
+ pub type_: __u32,
+ pub pad1: __u32,
+ pub u: kvm_hyperv_exit__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_hyperv_exit__bindgen_ty_1 {
+ pub synic: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1,
+ pub hcall: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2,
+ _bindgen_union_align: [u64; 4usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1 {
+ pub msr: __u32,
+ pub pad2: __u32,
+ pub control: __u64,
+ pub evt_page: __u64,
+ pub msg_page: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>(),
+ 32usize,
+ concat!(
+ "Size of: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).msr as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(msr)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).pad2 as *const _
+ as usize
+ },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(pad2)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).control
+ as *const _ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(control)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).evt_page
+ as *const _ as usize
+ },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(evt_page)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).msg_page
+ as *const _ as usize
+ },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(msg_page)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2 {
+ pub input: __u64,
+ pub result: __u64,
+ pub params: [__u64; 2usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>(),
+ 32usize,
+ concat!(
+ "Size of: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>())).input
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2),
+ "::",
+ stringify!(input)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>())).result
+ as *const _ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2),
+ "::",
+ stringify!(result)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>())).params
+ as *const _ as usize
+ },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2),
+ "::",
+ stringify!(params)
+ )
+ );
+}
+#[test]
+fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_hyperv_exit__bindgen_ty_1>(),
+ 32usize,
+ concat!("Size of: ", stringify!(kvm_hyperv_exit__bindgen_ty_1))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_hyperv_exit__bindgen_ty_1>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_hyperv_exit__bindgen_ty_1))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1>())).synic as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1),
+ "::",
+ stringify!(synic)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1>())).hcall as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1),
+ "::",
+ stringify!(hcall)
+ )
+ );
+}
+impl Default for kvm_hyperv_exit__bindgen_ty_1 {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[test]
+fn bindgen_test_layout_kvm_hyperv_exit() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_hyperv_exit>(),
+ 40usize,
+ concat!("Size of: ", stringify!(kvm_hyperv_exit))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_hyperv_exit>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_hyperv_exit))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_hyperv_exit>())).type_ as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit),
+ "::",
+ stringify!(type_)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_hyperv_exit>())).pad1 as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit),
+ "::",
+ stringify!(pad1)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_hyperv_exit>())).u as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit),
+ "::",
+ stringify!(u)
+ )
+ );
+}
+impl Default for kvm_hyperv_exit {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct kvm_run {
@@ -1675,11 +2614,6 @@
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,
@@ -1706,6 +2640,11 @@
pub padding: [::std::os::raw::c_char; 256usize],
_bindgen_union_align: [u64; 32usize],
}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_1 {
+ pub hardware_exit_reason: __u64,
+}
#[test]
fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_1() {
assert_eq!(
@@ -2842,174 +3781,6 @@
)
);
}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct kvm_hyperv_exit {
- pub type_: __u32,
- pub pad: __u32,
- pub u: kvm_hyperv_exit__bindgen_ty_1,
-}
-#[test]
-fn bindgen_test_layout_kvm_hyperv_exit() {
- assert_eq!(
- ::std::mem::size_of::<kvm_hyperv_exit>(),
- 40usize,
- concat!("Size of: ", stringify!(kvm_hyperv_exit))
- );
- assert_eq!(
- ::std::mem::align_of::<kvm_hyperv_exit>(),
- 8usize,
- concat!("Alignment of ", stringify!(kvm_hyperv_exit))
- );
- assert_eq!(
- unsafe { &(*(::std::ptr::null::<kvm_hyperv_exit>())).u as *const _ as usize },
- 8usize,
- concat!(
- "Offset of field: ",
- stringify!(kvm_hyperv_exit),
- "::",
- stringify!(u)
- )
- );
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union kvm_hyperv_exit__bindgen_ty_1 {
- pub synic: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1,
- pub hcall: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2,
-}
-#[test]
-fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1() {
- assert_eq!(
- ::std::mem::size_of::<kvm_hyperv_exit__bindgen_ty_1>(),
- 32usize,
- concat!("Size of: ", stringify!(kvm_hyperv_exit__bindgen_ty_1))
- );
- assert_eq!(
- ::std::mem::align_of::<kvm_hyperv_exit__bindgen_ty_1>(),
- 8usize,
- concat!("Alignment of ", stringify!(kvm_hyperv_exit__bindgen_ty_1))
- );
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1 {
- pub msr: __u32,
- pub pad: __u32,
- pub control: __u64,
- pub evt_page: __u64,
- pub msg_page: __u64,
-}
-#[test]
-fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1() {
- assert_eq!(
- ::std::mem::size_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>(),
- 32usize,
- concat!(
- "Size of: ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1)
- )
- );
- assert_eq!(
- ::std::mem::align_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>(),
- 8usize,
- concat!(
- "Alignment of ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).control
- as *const _ as usize
- },
- 8usize,
- concat!(
- "Offset of field: ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
- "::",
- stringify!(control)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).evt_page
- as *const _ as usize
- },
- 16usize,
- concat!(
- "Offset of field: ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
- "::",
- stringify!(evt_page)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).msg_page
- as *const _ as usize
- },
- 24usize,
- concat!(
- "Offset of field: ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
- "::",
- stringify!(msg_page)
- )
- );
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2 {
- pub input: __u64,
- pub result: __u64,
- pub params: [__u64; 2],
-}
-#[test]
-fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2() {
- assert_eq!(
- ::std::mem::size_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>(),
- 32usize,
- concat!(
- "Size of: ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2)
- )
- );
- assert_eq!(
- ::std::mem::align_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>(),
- 8usize,
- concat!(
- "Alignment of ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>())).result
- as *const _ as usize
- },
- 8usize,
- concat!(
- "Offset of field: ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2),
- "::",
- stringify!(result)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>())).params
- as *const _ as usize
- },
- 16usize,
- concat!(
- "Offset of field: ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2),
- "::",
- stringify!(params)
- )
- );
-}
#[test]
fn bindgen_test_layout_kvm_run__bindgen_ty_1() {
assert_eq!(
@@ -3237,6 +4008,16 @@
)
);
assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).hyperv as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_run__bindgen_ty_1),
+ "::",
+ stringify!(hyperv)
+ )
+ );
+ assert_eq!(
unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).padding as *const _ as usize },
0usize,
concat!(
@@ -3257,7 +4038,7 @@
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],
+ _bindgen_union_align: [u64; 256usize],
}
#[test]
fn bindgen_test_layout_kvm_run__bindgen_ty_2() {
@@ -3268,7 +4049,7 @@
);
assert_eq!(
::std::mem::align_of::<kvm_run__bindgen_ty_2>(),
- 1usize,
+ 8usize,
concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_2))
);
assert_eq!(
@@ -3440,11 +4221,68 @@
}
}
#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
+#[derive(Copy, Clone)]
pub struct kvm_coalesced_mmio_zone {
pub addr: __u64,
pub size: __u32,
+ pub __bindgen_anon_1: kvm_coalesced_mmio_zone__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_coalesced_mmio_zone__bindgen_ty_1 {
pub pad: __u32,
+ pub pio: __u32,
+ _bindgen_union_align: u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_coalesced_mmio_zone__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_coalesced_mmio_zone__bindgen_ty_1>(),
+ 4usize,
+ concat!(
+ "Size of: ",
+ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_coalesced_mmio_zone__bindgen_ty_1>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_coalesced_mmio_zone__bindgen_ty_1>())).pad as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1),
+ "::",
+ stringify!(pad)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_coalesced_mmio_zone__bindgen_ty_1>())).pio as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1),
+ "::",
+ stringify!(pio)
+ )
+ );
+}
+impl Default for kvm_coalesced_mmio_zone__bindgen_ty_1 {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
}
#[test]
fn bindgen_test_layout_kvm_coalesced_mmio_zone() {
@@ -3478,24 +4316,71 @@
stringify!(size)
)
);
+}
+impl Default for kvm_coalesced_mmio_zone {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_coalesced_mmio {
+ pub phys_addr: __u64,
+ pub len: __u32,
+ pub __bindgen_anon_1: kvm_coalesced_mmio__bindgen_ty_1,
+ pub data: [__u8; 8usize],
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_coalesced_mmio__bindgen_ty_1 {
+ pub pad: __u32,
+ pub pio: __u32,
+ _bindgen_union_align: u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_coalesced_mmio__bindgen_ty_1() {
assert_eq!(
- unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio_zone>())).pad as *const _ as usize },
- 12usize,
+ ::std::mem::size_of::<kvm_coalesced_mmio__bindgen_ty_1>(),
+ 4usize,
+ concat!("Size of: ", stringify!(kvm_coalesced_mmio__bindgen_ty_1))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_coalesced_mmio__bindgen_ty_1>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(kvm_coalesced_mmio__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_coalesced_mmio__bindgen_ty_1>())).pad as *const _ as usize
+ },
+ 0usize,
concat!(
"Offset of field: ",
- stringify!(kvm_coalesced_mmio_zone),
+ stringify!(kvm_coalesced_mmio__bindgen_ty_1),
"::",
stringify!(pad)
)
);
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_coalesced_mmio__bindgen_ty_1>())).pio as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_coalesced_mmio__bindgen_ty_1),
+ "::",
+ stringify!(pio)
+ )
+ );
}
-#[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],
+impl Default for kvm_coalesced_mmio__bindgen_ty_1 {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
}
#[test]
fn bindgen_test_layout_kvm_coalesced_mmio() {
@@ -3530,16 +4415,6 @@
)
);
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!(
@@ -3550,14 +4425,16 @@
)
);
}
+impl Default for kvm_coalesced_mmio {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
#[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() {
@@ -3604,6 +4481,11 @@
)
);
}
+impl Default for kvm_coalesced_mmio_ring {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct kvm_translation {
@@ -3907,6 +4789,116 @@
}
}
#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_clear_dirty_log {
+ pub slot: __u32,
+ pub num_pages: __u32,
+ pub first_page: __u64,
+ pub __bindgen_anon_1: kvm_clear_dirty_log__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_clear_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_clear_dirty_log__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_clear_dirty_log__bindgen_ty_1>(),
+ 8usize,
+ concat!("Size of: ", stringify!(kvm_clear_dirty_log__bindgen_ty_1))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_clear_dirty_log__bindgen_ty_1>(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(kvm_clear_dirty_log__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_clear_dirty_log__bindgen_ty_1>())).dirty_bitmap as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_clear_dirty_log__bindgen_ty_1),
+ "::",
+ stringify!(dirty_bitmap)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_clear_dirty_log__bindgen_ty_1>())).padding2 as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_clear_dirty_log__bindgen_ty_1),
+ "::",
+ stringify!(padding2)
+ )
+ );
+}
+impl Default for kvm_clear_dirty_log__bindgen_ty_1 {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[test]
+fn bindgen_test_layout_kvm_clear_dirty_log() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_clear_dirty_log>(),
+ 24usize,
+ concat!("Size of: ", stringify!(kvm_clear_dirty_log))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_clear_dirty_log>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_clear_dirty_log))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_clear_dirty_log>())).slot as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_clear_dirty_log),
+ "::",
+ stringify!(slot)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_clear_dirty_log>())).num_pages as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_clear_dirty_log),
+ "::",
+ stringify!(num_pages)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_clear_dirty_log>())).first_page as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_clear_dirty_log),
+ "::",
+ stringify!(first_page)
+ )
+ );
+}
+impl Default for kvm_clear_dirty_log {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[repr(C)]
#[derive(Debug, Default)]
pub struct kvm_signal_mask {
pub len: __u32,
@@ -4265,7 +5257,8 @@
pub exc_access_id: __u8,
pub per_access_id: __u8,
pub op_access_id: __u8,
- pub pad: [__u8; 3usize],
+ pub flags: __u8,
+ pub pad: [__u8; 2usize],
}
#[test]
fn bindgen_test_layout_kvm_s390_pgm_info() {
@@ -4392,12 +5385,22 @@
)
);
assert_eq!(
- unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).pad as *const _ as usize },
+ unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).flags as *const _ as usize },
37usize,
concat!(
"Offset of field: ",
stringify!(kvm_s390_pgm_info),
"::",
+ stringify!(flags)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).pad as *const _ as usize },
+ 38usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_s390_pgm_info),
+ "::",
stringify!(pad)
)
);
@@ -4608,7 +5611,6 @@
pub type_: __u64,
pub u: kvm_s390_irq__bindgen_ty_1,
}
-
#[repr(C)]
#[derive(Copy, Clone)]
pub union kvm_s390_irq__bindgen_ty_1 {
@@ -4894,7 +5896,7 @@
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;
+pub type _bindgen_ty_1 = u32;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct kvm_ioeventfd {
@@ -5204,7 +6206,8 @@
pub struct kvm_ppc_smmu_info {
pub flags: __u64,
pub slb_size: __u32,
- pub pad: __u32,
+ pub data_keys: __u16,
+ pub instr_keys: __u16,
pub sps: [kvm_ppc_one_seg_page_size; 8usize],
}
#[test]
@@ -5240,13 +6243,23 @@
)
);
assert_eq!(
- unsafe { &(*(::std::ptr::null::<kvm_ppc_smmu_info>())).pad as *const _ as usize },
+ unsafe { &(*(::std::ptr::null::<kvm_ppc_smmu_info>())).data_keys as *const _ as usize },
12usize,
concat!(
"Offset of field: ",
stringify!(kvm_ppc_smmu_info),
"::",
- stringify!(pad)
+ stringify!(data_keys)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_ppc_smmu_info>())).instr_keys as *const _ as usize },
+ 14usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_ppc_smmu_info),
+ "::",
+ stringify!(instr_keys)
)
);
assert_eq!(
@@ -5262,6 +6275,56 @@
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_ppc_resize_hpt {
+ pub flags: __u64,
+ pub shift: __u32,
+ pub pad: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_ppc_resize_hpt() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_ppc_resize_hpt>(),
+ 16usize,
+ concat!("Size of: ", stringify!(kvm_ppc_resize_hpt))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_ppc_resize_hpt>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_ppc_resize_hpt))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_ppc_resize_hpt>())).flags as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_ppc_resize_hpt),
+ "::",
+ stringify!(flags)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_ppc_resize_hpt>())).shift as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_ppc_resize_hpt),
+ "::",
+ stringify!(shift)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_ppc_resize_hpt>())).pad as *const _ as usize },
+ 12usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_ppc_resize_hpt),
+ "::",
+ stringify!(pad)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct kvm_irq_routing_irqchip {
pub irqchip: __u32,
pub pin: __u32,
@@ -5300,12 +6363,64 @@
);
}
#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
+#[derive(Copy, Clone)]
pub struct kvm_irq_routing_msi {
pub address_lo: __u32,
pub address_hi: __u32,
pub data: __u32,
+ pub __bindgen_anon_1: kvm_irq_routing_msi__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_irq_routing_msi__bindgen_ty_1 {
pub pad: __u32,
+ pub devid: __u32,
+ _bindgen_union_align: u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing_msi__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_irq_routing_msi__bindgen_ty_1>(),
+ 4usize,
+ concat!("Size of: ", stringify!(kvm_irq_routing_msi__bindgen_ty_1))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_irq_routing_msi__bindgen_ty_1>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(kvm_irq_routing_msi__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_irq_routing_msi__bindgen_ty_1>())).pad as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_irq_routing_msi__bindgen_ty_1),
+ "::",
+ stringify!(pad)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_irq_routing_msi__bindgen_ty_1>())).devid as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_irq_routing_msi__bindgen_ty_1),
+ "::",
+ stringify!(devid)
+ )
+ );
+}
+impl Default for kvm_irq_routing_msi__bindgen_ty_1 {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
}
#[test]
fn bindgen_test_layout_kvm_irq_routing_msi() {
@@ -5349,16 +6464,11 @@
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)
- )
- );
+}
+impl Default for kvm_irq_routing_msi {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
@@ -5445,6 +6555,45 @@
);
}
#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_irq_routing_hv_sint {
+ pub vcpu: __u32,
+ pub sint: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing_hv_sint() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_irq_routing_hv_sint>(),
+ 8usize,
+ concat!("Size of: ", stringify!(kvm_irq_routing_hv_sint))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_irq_routing_hv_sint>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(kvm_irq_routing_hv_sint))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_irq_routing_hv_sint>())).vcpu as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_irq_routing_hv_sint),
+ "::",
+ stringify!(vcpu)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_irq_routing_hv_sint>())).sint as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_irq_routing_hv_sint),
+ "::",
+ stringify!(sint)
+ )
+ );
+}
+#[repr(C)]
#[derive(Copy, Clone)]
pub struct kvm_irq_routing_entry {
pub gsi: __u32,
@@ -5459,6 +6608,7 @@
pub irqchip: kvm_irq_routing_irqchip,
pub msi: kvm_irq_routing_msi,
pub adapter: kvm_irq_routing_s390_adapter,
+ pub hv_sint: kvm_irq_routing_hv_sint,
pub pad: [__u32; 8usize],
_bindgen_union_align: [u64; 4usize],
}
@@ -5517,6 +6667,19 @@
);
assert_eq!(
unsafe {
+ &(*(::std::ptr::null::<kvm_irq_routing_entry__bindgen_ty_1>())).hv_sint as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_irq_routing_entry__bindgen_ty_1),
+ "::",
+ stringify!(hv_sint)
+ )
+ );
+ assert_eq!(
+ unsafe {
&(*(::std::ptr::null::<kvm_irq_routing_entry__bindgen_ty_1>())).pad as *const _ as usize
},
0usize,
@@ -5606,8 +6769,6 @@
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() {
@@ -5964,7 +7125,8 @@
pub address_hi: __u32,
pub data: __u32,
pub flags: __u32,
- pub pad: [__u8; 16usize],
+ pub devid: __u32,
+ pub pad: [__u8; 12usize],
}
#[test]
fn bindgen_test_layout_kvm_msi() {
@@ -6019,12 +7181,22 @@
)
);
assert_eq!(
- unsafe { &(*(::std::ptr::null::<kvm_msi>())).pad as *const _ as usize },
+ unsafe { &(*(::std::ptr::null::<kvm_msi>())).devid as *const _ as usize },
16usize,
concat!(
"Offset of field: ",
stringify!(kvm_msi),
"::",
+ stringify!(devid)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_msi>())).pad as *const _ as usize },
+ 20usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_msi),
+ "::",
stringify!(pad)
)
);
@@ -6186,8 +7358,49 @@
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;
+pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS: kvm_device_type = 8;
+pub const kvm_device_type_KVM_DEV_TYPE_XIVE: kvm_device_type = 9;
+pub const kvm_device_type_KVM_DEV_TYPE_MAX: kvm_device_type = 10;
+pub type kvm_device_type = u32;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_vfio_spapr_tce {
+ pub groupfd: __s32,
+ pub tablefd: __s32,
+}
+#[test]
+fn bindgen_test_layout_kvm_vfio_spapr_tce() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_vfio_spapr_tce>(),
+ 8usize,
+ concat!("Size of: ", stringify!(kvm_vfio_spapr_tce))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_vfio_spapr_tce>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(kvm_vfio_spapr_tce))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_vfio_spapr_tce>())).groupfd as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vfio_spapr_tce),
+ "::",
+ stringify!(groupfd)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_vfio_spapr_tce>())).tablefd as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vfio_spapr_tce),
+ "::",
+ stringify!(tablefd)
+ )
+ );
+}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct kvm_s390_ucas_mapping {
@@ -6239,6 +7452,482 @@
);
}
#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_enc_region {
+ pub addr: __u64,
+ pub size: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_enc_region() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_enc_region>(),
+ 16usize,
+ concat!("Size of: ", stringify!(kvm_enc_region))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_enc_region>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_enc_region))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_enc_region>())).addr as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_enc_region),
+ "::",
+ stringify!(addr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_enc_region>())).size as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_enc_region),
+ "::",
+ stringify!(size)
+ )
+ );
+}
+pub const sev_cmd_id_KVM_SEV_INIT: sev_cmd_id = 0;
+pub const sev_cmd_id_KVM_SEV_ES_INIT: sev_cmd_id = 1;
+pub const sev_cmd_id_KVM_SEV_LAUNCH_START: sev_cmd_id = 2;
+pub const sev_cmd_id_KVM_SEV_LAUNCH_UPDATE_DATA: sev_cmd_id = 3;
+pub const sev_cmd_id_KVM_SEV_LAUNCH_UPDATE_VMSA: sev_cmd_id = 4;
+pub const sev_cmd_id_KVM_SEV_LAUNCH_SECRET: sev_cmd_id = 5;
+pub const sev_cmd_id_KVM_SEV_LAUNCH_MEASURE: sev_cmd_id = 6;
+pub const sev_cmd_id_KVM_SEV_LAUNCH_FINISH: sev_cmd_id = 7;
+pub const sev_cmd_id_KVM_SEV_SEND_START: sev_cmd_id = 8;
+pub const sev_cmd_id_KVM_SEV_SEND_UPDATE_DATA: sev_cmd_id = 9;
+pub const sev_cmd_id_KVM_SEV_SEND_UPDATE_VMSA: sev_cmd_id = 10;
+pub const sev_cmd_id_KVM_SEV_SEND_FINISH: sev_cmd_id = 11;
+pub const sev_cmd_id_KVM_SEV_RECEIVE_START: sev_cmd_id = 12;
+pub const sev_cmd_id_KVM_SEV_RECEIVE_UPDATE_DATA: sev_cmd_id = 13;
+pub const sev_cmd_id_KVM_SEV_RECEIVE_UPDATE_VMSA: sev_cmd_id = 14;
+pub const sev_cmd_id_KVM_SEV_RECEIVE_FINISH: sev_cmd_id = 15;
+pub const sev_cmd_id_KVM_SEV_GUEST_STATUS: sev_cmd_id = 16;
+pub const sev_cmd_id_KVM_SEV_DBG_DECRYPT: sev_cmd_id = 17;
+pub const sev_cmd_id_KVM_SEV_DBG_ENCRYPT: sev_cmd_id = 18;
+pub const sev_cmd_id_KVM_SEV_CERT_EXPORT: sev_cmd_id = 19;
+pub const sev_cmd_id_KVM_SEV_NR_MAX: sev_cmd_id = 20;
+pub type sev_cmd_id = u32;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sev_cmd {
+ pub id: __u32,
+ pub data: __u64,
+ pub error: __u32,
+ pub sev_fd: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_sev_cmd() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_sev_cmd>(),
+ 24usize,
+ concat!("Size of: ", stringify!(kvm_sev_cmd))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_sev_cmd>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_sev_cmd))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_cmd>())).id as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_cmd),
+ "::",
+ stringify!(id)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_cmd>())).data as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_cmd),
+ "::",
+ stringify!(data)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_cmd>())).error as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_cmd),
+ "::",
+ stringify!(error)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_cmd>())).sev_fd as *const _ as usize },
+ 20usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_cmd),
+ "::",
+ stringify!(sev_fd)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sev_launch_start {
+ pub handle: __u32,
+ pub policy: __u32,
+ pub dh_uaddr: __u64,
+ pub dh_len: __u32,
+ pub session_uaddr: __u64,
+ pub session_len: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_sev_launch_start() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_sev_launch_start>(),
+ 40usize,
+ concat!("Size of: ", stringify!(kvm_sev_launch_start))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_sev_launch_start>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_sev_launch_start))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_start>())).handle as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_start),
+ "::",
+ stringify!(handle)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_start>())).policy as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_start),
+ "::",
+ stringify!(policy)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_start>())).dh_uaddr as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_start),
+ "::",
+ stringify!(dh_uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_start>())).dh_len as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_start),
+ "::",
+ stringify!(dh_len)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_sev_launch_start>())).session_uaddr as *const _ as usize
+ },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_start),
+ "::",
+ stringify!(session_uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_sev_launch_start>())).session_len as *const _ as usize
+ },
+ 32usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_start),
+ "::",
+ stringify!(session_len)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sev_launch_update_data {
+ pub uaddr: __u64,
+ pub len: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_sev_launch_update_data() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_sev_launch_update_data>(),
+ 16usize,
+ concat!("Size of: ", stringify!(kvm_sev_launch_update_data))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_sev_launch_update_data>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_sev_launch_update_data))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_sev_launch_update_data>())).uaddr as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_update_data),
+ "::",
+ stringify!(uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_update_data>())).len as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_update_data),
+ "::",
+ stringify!(len)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sev_launch_secret {
+ pub hdr_uaddr: __u64,
+ pub hdr_len: __u32,
+ pub guest_uaddr: __u64,
+ pub guest_len: __u32,
+ pub trans_uaddr: __u64,
+ pub trans_len: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_sev_launch_secret() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_sev_launch_secret>(),
+ 48usize,
+ concat!("Size of: ", stringify!(kvm_sev_launch_secret))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_sev_launch_secret>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_sev_launch_secret))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_secret>())).hdr_uaddr as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_secret),
+ "::",
+ stringify!(hdr_uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_secret>())).hdr_len as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_secret),
+ "::",
+ stringify!(hdr_len)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_sev_launch_secret>())).guest_uaddr as *const _ as usize
+ },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_secret),
+ "::",
+ stringify!(guest_uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_secret>())).guest_len as *const _ as usize },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_secret),
+ "::",
+ stringify!(guest_len)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_sev_launch_secret>())).trans_uaddr as *const _ as usize
+ },
+ 32usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_secret),
+ "::",
+ stringify!(trans_uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_secret>())).trans_len as *const _ as usize },
+ 40usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_secret),
+ "::",
+ stringify!(trans_len)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sev_launch_measure {
+ pub uaddr: __u64,
+ pub len: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_sev_launch_measure() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_sev_launch_measure>(),
+ 16usize,
+ concat!("Size of: ", stringify!(kvm_sev_launch_measure))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_sev_launch_measure>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_sev_launch_measure))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_measure>())).uaddr as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_measure),
+ "::",
+ stringify!(uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_measure>())).len as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_measure),
+ "::",
+ stringify!(len)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sev_guest_status {
+ pub handle: __u32,
+ pub policy: __u32,
+ pub state: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_sev_guest_status() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_sev_guest_status>(),
+ 12usize,
+ concat!("Size of: ", stringify!(kvm_sev_guest_status))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_sev_guest_status>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(kvm_sev_guest_status))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_guest_status>())).handle as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_guest_status),
+ "::",
+ stringify!(handle)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_guest_status>())).policy as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_guest_status),
+ "::",
+ stringify!(policy)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_guest_status>())).state as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_guest_status),
+ "::",
+ stringify!(state)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sev_dbg {
+ pub src_uaddr: __u64,
+ pub dst_uaddr: __u64,
+ pub len: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_sev_dbg() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_sev_dbg>(),
+ 24usize,
+ concat!("Size of: ", stringify!(kvm_sev_dbg))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_sev_dbg>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_sev_dbg))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_dbg>())).src_uaddr as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_dbg),
+ "::",
+ stringify!(src_uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_dbg>())).dst_uaddr as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_dbg),
+ "::",
+ stringify!(dst_uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_dbg>())).len as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_dbg),
+ "::",
+ stringify!(len)
+ )
+ );
+}
+#[repr(C)]
#[derive(Copy, Clone)]
pub struct kvm_assigned_pci_dev {
pub assigned_dev_id: __u32,
@@ -6578,4 +8267,65 @@
)
);
}
-pub type __uint128_t = [u64; 2];
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_hyperv_eventfd {
+ pub conn_id: __u32,
+ pub fd: __s32,
+ pub flags: __u32,
+ pub padding: [__u32; 3usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_hyperv_eventfd() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_hyperv_eventfd>(),
+ 24usize,
+ concat!("Size of: ", stringify!(kvm_hyperv_eventfd))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_hyperv_eventfd>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(kvm_hyperv_eventfd))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_hyperv_eventfd>())).conn_id as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_eventfd),
+ "::",
+ stringify!(conn_id)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_hyperv_eventfd>())).fd as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_eventfd),
+ "::",
+ stringify!(fd)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_hyperv_eventfd>())).flags as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_eventfd),
+ "::",
+ stringify!(flags)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_hyperv_eventfd>())).padding as *const _ as usize },
+ 12usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_eventfd),
+ "::",
+ stringify!(padding)
+ )
+ );
+}
+pub type __uint128_t = u128;
diff --git a/kvm_sys/src/x86/bindings.rs b/kvm_sys/src/x86/bindings.rs
index 629d83a..789cc2e 100644
--- a/kvm_sys/src/x86/bindings.rs
+++ b/kvm_sys/src/x86/bindings.rs
@@ -2,7 +2,14 @@
// 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 */
+/*
+ * automatically generated by bindgen 0.49.2.
+ * From chromeos-linux v5.4 include/linux/kvm.h
+ * $ cd /path/to/kernel/v5.4/
+ * $ make headers_install ARCH=x86 INSTALL_HDR_PATH=x86_v5_4_headers
+ * $ cd x86_v5_4_headers
+ * $ bindgen --with-derive-default -o bindings.rs include/linux/kvm.h -- -Iinclude
+ */
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
@@ -13,7 +20,6 @@
storage: Storage,
align: [Align; 0],
}
-
impl<Storage, Align> __BindgenBitfieldUnit<Storage, Align>
where
Storage: AsRef<[u8]> + AsMut<[u8]>,
@@ -22,74 +28,78 @@
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 bit_index = if cfg!(target_endian = "big") {
+ 7 - (index % 8)
+ } else {
+ 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 bit_index = if cfg!(target_endian = "big") {
+ 7 - (index % 8)
+ } else {
+ 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;
+ let index = if cfg!(target_endian = "big") {
+ bit_width as usize - 1 - i
+ } else {
+ i
+ };
+ val |= 1 << index;
}
}
-
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);
+ let index = if cfg!(target_endian = "big") {
+ bit_width as usize - 1 - i
+ } else {
+ i
+ };
+ self.set_bit(index + bit_offset, val_bit_is_set);
}
}
}
#[repr(C)]
#[derive(Default)]
-pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
+pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
impl<T> __IncompleteArrayField<T> {
#[inline]
pub fn new() -> Self {
- __IncompleteArrayField(::std::marker::PhantomData)
+ __IncompleteArrayField(::std::marker::PhantomData, [])
}
#[inline]
pub unsafe fn as_ptr(&self) -> *const T {
@@ -109,7 +119,7 @@
}
}
impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
- fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
fmt.write_str("__IncompleteArrayField")
}
}
@@ -119,360 +129,502 @@
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_EXIT_HYPERV: ::std::os::raw::c_uint = 27;
-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_EXIT_HYPERV_SYNIC: ::std::os::raw::c_uint = 1;
-pub const KVM_EXIT_HYPERV_HCALL: ::std::os::raw::c_uint = 2;
-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_CAP_HYPERV_SYNIC: ::std::os::raw::c_uint = 123;
-pub const KVM_CAP_ARM_PMU_V3: ::std::os::raw::c_uint = 126;
-pub const KVM_CAP_IMMEDIATE_EXIT: ::std::os::raw::c_uint = 136;
-pub const KVM_CAP_HYPERV_SYNIC2: ::std::os::raw::c_uint = 148;
-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;
+#[repr(C)]
+pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
+impl<T> __BindgenUnionField<T> {
+ #[inline]
+ pub fn new() -> Self {
+ __BindgenUnionField(::std::marker::PhantomData)
+ }
+ #[inline]
+ pub unsafe fn as_ref(&self) -> &T {
+ ::std::mem::transmute(self)
+ }
+ #[inline]
+ pub unsafe fn as_mut(&mut self) -> &mut T {
+ ::std::mem::transmute(self)
+ }
+}
+impl<T> ::std::default::Default for __BindgenUnionField<T> {
+ #[inline]
+ fn default() -> Self {
+ Self::new()
+ }
+}
+impl<T> ::std::clone::Clone for __BindgenUnionField<T> {
+ #[inline]
+ fn clone(&self) -> Self {
+ Self::new()
+ }
+}
+impl<T> ::std::marker::Copy for __BindgenUnionField<T> {}
+impl<T> ::std::fmt::Debug for __BindgenUnionField<T> {
+ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+ fmt.write_str("__BindgenUnionField")
+ }
+}
+impl<T> ::std::hash::Hash for __BindgenUnionField<T> {
+ fn hash<H: ::std::hash::Hasher>(&self, _state: &mut H) {}
+}
+impl<T> ::std::cmp::PartialEq for __BindgenUnionField<T> {
+ fn eq(&self, _other: &__BindgenUnionField<T>) -> bool {
+ true
+ }
+}
+impl<T> ::std::cmp::Eq for __BindgenUnionField<T> {}
+pub const __BITS_PER_LONG: u32 = 64;
+pub const __FD_SETSIZE: u32 = 1024;
+pub const _IOC_NRBITS: u32 = 8;
+pub const _IOC_TYPEBITS: u32 = 8;
+pub const _IOC_SIZEBITS: u32 = 14;
+pub const _IOC_DIRBITS: u32 = 2;
+pub const _IOC_NRMASK: u32 = 255;
+pub const _IOC_TYPEMASK: u32 = 255;
+pub const _IOC_SIZEMASK: u32 = 16383;
+pub const _IOC_DIRMASK: u32 = 3;
+pub const _IOC_NRSHIFT: u32 = 0;
+pub const _IOC_TYPESHIFT: u32 = 8;
+pub const _IOC_SIZESHIFT: u32 = 16;
+pub const _IOC_DIRSHIFT: u32 = 30;
+pub const _IOC_NONE: u32 = 0;
+pub const _IOC_WRITE: u32 = 1;
+pub const _IOC_READ: u32 = 2;
+pub const IOC_IN: u32 = 1073741824;
+pub const IOC_OUT: u32 = 2147483648;
+pub const IOC_INOUT: u32 = 3221225472;
+pub const IOCSIZE_MASK: u32 = 1073676288;
+pub const IOCSIZE_SHIFT: u32 = 16;
+pub const KVM_PIO_PAGE_OFFSET: u32 = 1;
+pub const KVM_COALESCED_MMIO_PAGE_OFFSET: u32 = 2;
+pub const DE_VECTOR: u32 = 0;
+pub const DB_VECTOR: u32 = 1;
+pub const BP_VECTOR: u32 = 3;
+pub const OF_VECTOR: u32 = 4;
+pub const BR_VECTOR: u32 = 5;
+pub const UD_VECTOR: u32 = 6;
+pub const NM_VECTOR: u32 = 7;
+pub const DF_VECTOR: u32 = 8;
+pub const TS_VECTOR: u32 = 10;
+pub const NP_VECTOR: u32 = 11;
+pub const SS_VECTOR: u32 = 12;
+pub const GP_VECTOR: u32 = 13;
+pub const PF_VECTOR: u32 = 14;
+pub const MF_VECTOR: u32 = 16;
+pub const AC_VECTOR: u32 = 17;
+pub const MC_VECTOR: u32 = 18;
+pub const XM_VECTOR: u32 = 19;
+pub const VE_VECTOR: u32 = 20;
+pub const KVM_NR_INTERRUPTS: u32 = 256;
+pub const KVM_IOAPIC_NUM_PINS: u32 = 24;
+pub const KVM_IRQCHIP_PIC_MASTER: u32 = 0;
+pub const KVM_IRQCHIP_PIC_SLAVE: u32 = 1;
+pub const KVM_IRQCHIP_IOAPIC: u32 = 2;
+pub const KVM_NR_IRQCHIPS: u32 = 3;
+pub const KVM_RUN_X86_SMM: u32 = 1;
+pub const KVM_APIC_REG_SIZE: u32 = 1024;
+pub const KVM_CPUID_FLAG_SIGNIFCANT_INDEX: u32 = 1;
+pub const KVM_CPUID_FLAG_STATEFUL_FUNC: u32 = 2;
+pub const KVM_CPUID_FLAG_STATE_READ_NEXT: u32 = 4;
+pub const KVM_GUESTDBG_USE_SW_BP: u32 = 65536;
+pub const KVM_GUESTDBG_USE_HW_BP: u32 = 131072;
+pub const KVM_GUESTDBG_INJECT_DB: u32 = 262144;
+pub const KVM_GUESTDBG_INJECT_BP: u32 = 524288;
+pub const KVM_PIT_FLAGS_HPET_LEGACY: u32 = 1;
+pub const KVM_VCPUEVENT_VALID_NMI_PENDING: u32 = 1;
+pub const KVM_VCPUEVENT_VALID_SIPI_VECTOR: u32 = 2;
+pub const KVM_VCPUEVENT_VALID_SHADOW: u32 = 4;
+pub const KVM_VCPUEVENT_VALID_SMM: u32 = 8;
+pub const KVM_VCPUEVENT_VALID_PAYLOAD: u32 = 16;
+pub const KVM_X86_SHADOW_INT_MOV_SS: u32 = 1;
+pub const KVM_X86_SHADOW_INT_STI: u32 = 2;
+pub const KVM_MAX_XCRS: u32 = 16;
+pub const KVM_SYNC_X86_REGS: u32 = 1;
+pub const KVM_SYNC_X86_SREGS: u32 = 2;
+pub const KVM_SYNC_X86_EVENTS: u32 = 4;
+pub const KVM_SYNC_X86_VALID_FIELDS: u32 = 7;
+pub const KVM_X86_QUIRK_LINT0_REENABLED: u32 = 1;
+pub const KVM_X86_QUIRK_CD_NW_CLEARED: u32 = 2;
+pub const KVM_X86_QUIRK_LAPIC_MMIO_HOLE: u32 = 4;
+pub const KVM_X86_QUIRK_OUT_7E_INC_RIP: u32 = 8;
+pub const KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT: u32 = 16;
+pub const KVM_STATE_NESTED_FORMAT_VMX: u32 = 0;
+pub const KVM_STATE_NESTED_FORMAT_SVM: u32 = 1;
+pub const KVM_STATE_NESTED_GUEST_MODE: u32 = 1;
+pub const KVM_STATE_NESTED_RUN_PENDING: u32 = 2;
+pub const KVM_STATE_NESTED_EVMCS: u32 = 4;
+pub const KVM_STATE_NESTED_SMM_GUEST_MODE: u32 = 1;
+pub const KVM_STATE_NESTED_SMM_VMXON: u32 = 2;
+pub const KVM_STATE_NESTED_VMX_VMCS_SIZE: u32 = 4096;
+pub const KVM_PMU_EVENT_ALLOW: u32 = 0;
+pub const KVM_PMU_EVENT_DENY: u32 = 1;
+pub const KVM_API_VERSION: u32 = 12;
+pub const KVM_TRC_SHIFT: u32 = 16;
+pub const KVM_TRC_ENTRYEXIT: u32 = 65536;
+pub const KVM_TRC_HANDLER: u32 = 131072;
+pub const KVM_TRC_VMENTRY: u32 = 65537;
+pub const KVM_TRC_VMEXIT: u32 = 65538;
+pub const KVM_TRC_PAGE_FAULT: u32 = 131073;
+pub const KVM_TRC_HEAD_SIZE: u32 = 12;
+pub const KVM_TRC_CYCLE_SIZE: u32 = 8;
+pub const KVM_TRC_EXTRA_MAX: u32 = 7;
+pub const KVM_TRC_INJ_VIRQ: u32 = 131074;
+pub const KVM_TRC_REDELIVER_EVT: u32 = 131075;
+pub const KVM_TRC_PEND_INTR: u32 = 131076;
+pub const KVM_TRC_IO_READ: u32 = 131077;
+pub const KVM_TRC_IO_WRITE: u32 = 131078;
+pub const KVM_TRC_CR_READ: u32 = 131079;
+pub const KVM_TRC_CR_WRITE: u32 = 131080;
+pub const KVM_TRC_DR_READ: u32 = 131081;
+pub const KVM_TRC_DR_WRITE: u32 = 131082;
+pub const KVM_TRC_MSR_READ: u32 = 131083;
+pub const KVM_TRC_MSR_WRITE: u32 = 131084;
+pub const KVM_TRC_CPUID: u32 = 131085;
+pub const KVM_TRC_INTR: u32 = 131086;
+pub const KVM_TRC_NMI: u32 = 131087;
+pub const KVM_TRC_VMMCALL: u32 = 131088;
+pub const KVM_TRC_HLT: u32 = 131089;
+pub const KVM_TRC_CLTS: u32 = 131090;
+pub const KVM_TRC_LMSW: u32 = 131091;
+pub const KVM_TRC_APIC_ACCESS: u32 = 131092;
+pub const KVM_TRC_TDP_FAULT: u32 = 131093;
+pub const KVM_TRC_GTLB_WRITE: u32 = 131094;
+pub const KVM_TRC_STLB_WRITE: u32 = 131095;
+pub const KVM_TRC_STLB_INVAL: u32 = 131096;
+pub const KVM_TRC_PPC_INSTR: u32 = 131097;
+pub const KVM_MEM_LOG_DIRTY_PAGES: u32 = 1;
+pub const KVM_MEM_READONLY: u32 = 2;
+pub const KVM_PIT_SPEAKER_DUMMY: u32 = 1;
+pub const KVM_S390_CMMA_PEEK: u32 = 1;
+pub const KVM_EXIT_HYPERV_SYNIC: u32 = 1;
+pub const KVM_EXIT_HYPERV_HCALL: u32 = 2;
+pub const KVM_S390_GET_SKEYS_NONE: u32 = 1;
+pub const KVM_S390_SKEYS_MAX: u32 = 1048576;
+pub const KVM_EXIT_UNKNOWN: u32 = 0;
+pub const KVM_EXIT_EXCEPTION: u32 = 1;
+pub const KVM_EXIT_IO: u32 = 2;
+pub const KVM_EXIT_HYPERCALL: u32 = 3;
+pub const KVM_EXIT_DEBUG: u32 = 4;
+pub const KVM_EXIT_HLT: u32 = 5;
+pub const KVM_EXIT_MMIO: u32 = 6;
+pub const KVM_EXIT_IRQ_WINDOW_OPEN: u32 = 7;
+pub const KVM_EXIT_SHUTDOWN: u32 = 8;
+pub const KVM_EXIT_FAIL_ENTRY: u32 = 9;
+pub const KVM_EXIT_INTR: u32 = 10;
+pub const KVM_EXIT_SET_TPR: u32 = 11;
+pub const KVM_EXIT_TPR_ACCESS: u32 = 12;
+pub const KVM_EXIT_S390_SIEIC: u32 = 13;
+pub const KVM_EXIT_S390_RESET: u32 = 14;
+pub const KVM_EXIT_DCR: u32 = 15;
+pub const KVM_EXIT_NMI: u32 = 16;
+pub const KVM_EXIT_INTERNAL_ERROR: u32 = 17;
+pub const KVM_EXIT_OSI: u32 = 18;
+pub const KVM_EXIT_PAPR_HCALL: u32 = 19;
+pub const KVM_EXIT_S390_UCONTROL: u32 = 20;
+pub const KVM_EXIT_WATCHDOG: u32 = 21;
+pub const KVM_EXIT_S390_TSCH: u32 = 22;
+pub const KVM_EXIT_EPR: u32 = 23;
+pub const KVM_EXIT_SYSTEM_EVENT: u32 = 24;
+pub const KVM_EXIT_S390_STSI: u32 = 25;
+pub const KVM_EXIT_IOAPIC_EOI: u32 = 26;
+pub const KVM_EXIT_HYPERV: u32 = 27;
+pub const KVM_INTERNAL_ERROR_EMULATION: u32 = 1;
+pub const KVM_INTERNAL_ERROR_SIMUL_EX: u32 = 2;
+pub const KVM_INTERNAL_ERROR_DELIVERY_EV: u32 = 3;
+pub const KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON: u32 = 4;
+pub const KVM_EXIT_IO_IN: u32 = 0;
+pub const KVM_EXIT_IO_OUT: u32 = 1;
+pub const KVM_S390_RESET_POR: u32 = 1;
+pub const KVM_S390_RESET_CLEAR: u32 = 2;
+pub const KVM_S390_RESET_SUBSYSTEM: u32 = 4;
+pub const KVM_S390_RESET_CPU_INIT: u32 = 8;
+pub const KVM_S390_RESET_IPL: u32 = 16;
+pub const KVM_SYSTEM_EVENT_SHUTDOWN: u32 = 1;
+pub const KVM_SYSTEM_EVENT_RESET: u32 = 2;
+pub const KVM_SYSTEM_EVENT_CRASH: u32 = 3;
+pub const SYNC_REGS_SIZE_BYTES: u32 = 2048;
+pub const KVM_S390_MEMOP_LOGICAL_READ: u32 = 0;
+pub const KVM_S390_MEMOP_LOGICAL_WRITE: u32 = 1;
+pub const KVM_S390_MEMOP_F_CHECK_ONLY: u32 = 1;
+pub const KVM_S390_MEMOP_F_INJECT_EXCEPTION: u32 = 2;
+pub const KVM_MP_STATE_RUNNABLE: u32 = 0;
+pub const KVM_MP_STATE_UNINITIALIZED: u32 = 1;
+pub const KVM_MP_STATE_INIT_RECEIVED: u32 = 2;
+pub const KVM_MP_STATE_HALTED: u32 = 3;
+pub const KVM_MP_STATE_SIPI_RECEIVED: u32 = 4;
+pub const KVM_MP_STATE_STOPPED: u32 = 5;
+pub const KVM_MP_STATE_CHECK_STOP: u32 = 6;
+pub const KVM_MP_STATE_OPERATING: u32 = 7;
+pub const KVM_MP_STATE_LOAD: u32 = 8;
+pub const KVM_S390_SIGP_STOP: u32 = 4294836224;
+pub const KVM_S390_PROGRAM_INT: u32 = 4294836225;
+pub const KVM_S390_SIGP_SET_PREFIX: u32 = 4294836226;
+pub const KVM_S390_RESTART: u32 = 4294836227;
+pub const KVM_S390_INT_PFAULT_INIT: u32 = 4294836228;
+pub const KVM_S390_INT_PFAULT_DONE: u32 = 4294836229;
+pub const KVM_S390_MCHK: u32 = 4294840320;
+pub const KVM_S390_INT_CLOCK_COMP: u32 = 4294905860;
+pub const KVM_S390_INT_CPU_TIMER: u32 = 4294905861;
+pub const KVM_S390_INT_VIRTIO: u32 = 4294911491;
+pub const KVM_S390_INT_SERVICE: u32 = 4294910977;
+pub const KVM_S390_INT_EMERGENCY: u32 = 4294906369;
+pub const KVM_S390_INT_EXTERNAL_CALL: u32 = 4294906370;
+pub const KVM_S390_INT_IO_MIN: u32 = 0;
+pub const KVM_S390_INT_IO_MAX: u32 = 4294836223;
+pub const KVM_S390_INT_IO_AI_MASK: u32 = 67108864;
+pub const KVM_S390_PGM_FLAGS_ILC_VALID: u32 = 1;
+pub const KVM_S390_PGM_FLAGS_ILC_0: u32 = 2;
+pub const KVM_S390_PGM_FLAGS_ILC_1: u32 = 4;
+pub const KVM_S390_PGM_FLAGS_ILC_MASK: u32 = 6;
+pub const KVM_S390_PGM_FLAGS_NO_REWIND: u32 = 8;
+pub const KVM_S390_STOP_FLAG_STORE_STATUS: u32 = 1;
+pub const KVM_GUESTDBG_ENABLE: u32 = 1;
+pub const KVM_GUESTDBG_SINGLESTEP: u32 = 2;
+pub const KVM_X86_DISABLE_EXITS_MWAIT: u32 = 1;
+pub const KVM_X86_DISABLE_EXITS_HLT: u32 = 2;
+pub const KVM_X86_DISABLE_EXITS_PAUSE: u32 = 4;
+pub const KVM_X86_DISABLE_EXITS_CSTATE: u32 = 8;
+pub const KVM_X86_DISABLE_VALID_EXITS: u32 = 15;
+pub const KVM_PPC_PVINFO_FLAGS_EV_IDLE: u32 = 1;
+pub const KVM_PPC_PAGE_SIZES_MAX_SZ: u32 = 8;
+pub const KVM_PPC_PAGE_SIZES_REAL: u32 = 1;
+pub const KVM_PPC_1T_SEGMENTS: u32 = 2;
+pub const KVM_PPC_NO_HASH: u32 = 4;
+pub const KVMIO: u32 = 174;
+pub const KVM_VM_S390_UCONTROL: u32 = 1;
+pub const KVM_VM_PPC_HV: u32 = 1;
+pub const KVM_VM_PPC_PR: u32 = 2;
+pub const KVM_VM_MIPS_AUTO: u32 = 0;
+pub const KVM_VM_MIPS_VZ: u32 = 1;
+pub const KVM_VM_MIPS_TE: u32 = 2;
+pub const KVM_S390_SIE_PAGE_OFFSET: u32 = 1;
+pub const KVM_VM_TYPE_ARM_IPA_SIZE_MASK: u32 = 255;
+pub const KVM_CAP_IRQCHIP: u32 = 0;
+pub const KVM_CAP_HLT: u32 = 1;
+pub const KVM_CAP_MMU_SHADOW_CACHE_CONTROL: u32 = 2;
+pub const KVM_CAP_USER_MEMORY: u32 = 3;
+pub const KVM_CAP_SET_TSS_ADDR: u32 = 4;
+pub const KVM_CAP_VAPIC: u32 = 6;
+pub const KVM_CAP_EXT_CPUID: u32 = 7;
+pub const KVM_CAP_CLOCKSOURCE: u32 = 8;
+pub const KVM_CAP_NR_VCPUS: u32 = 9;
+pub const KVM_CAP_NR_MEMSLOTS: u32 = 10;
+pub const KVM_CAP_PIT: u32 = 11;
+pub const KVM_CAP_NOP_IO_DELAY: u32 = 12;
+pub const KVM_CAP_PV_MMU: u32 = 13;
+pub const KVM_CAP_MP_STATE: u32 = 14;
+pub const KVM_CAP_COALESCED_MMIO: u32 = 15;
+pub const KVM_CAP_SYNC_MMU: u32 = 16;
+pub const KVM_CAP_IOMMU: u32 = 18;
+pub const KVM_CAP_DESTROY_MEMORY_REGION_WORKS: u32 = 21;
+pub const KVM_CAP_USER_NMI: u32 = 22;
+pub const KVM_CAP_SET_GUEST_DEBUG: u32 = 23;
+pub const KVM_CAP_REINJECT_CONTROL: u32 = 24;
+pub const KVM_CAP_IRQ_ROUTING: u32 = 25;
+pub const KVM_CAP_IRQ_INJECT_STATUS: u32 = 26;
+pub const KVM_CAP_ASSIGN_DEV_IRQ: u32 = 29;
+pub const KVM_CAP_JOIN_MEMORY_REGIONS_WORKS: u32 = 30;
+pub const KVM_CAP_MCE: u32 = 31;
+pub const KVM_CAP_IRQFD: u32 = 32;
+pub const KVM_CAP_PIT2: u32 = 33;
+pub const KVM_CAP_SET_BOOT_CPU_ID: u32 = 34;
+pub const KVM_CAP_PIT_STATE2: u32 = 35;
+pub const KVM_CAP_IOEVENTFD: u32 = 36;
+pub const KVM_CAP_SET_IDENTITY_MAP_ADDR: u32 = 37;
+pub const KVM_CAP_XEN_HVM: u32 = 38;
+pub const KVM_CAP_ADJUST_CLOCK: u32 = 39;
+pub const KVM_CAP_INTERNAL_ERROR_DATA: u32 = 40;
+pub const KVM_CAP_VCPU_EVENTS: u32 = 41;
+pub const KVM_CAP_S390_PSW: u32 = 42;
+pub const KVM_CAP_PPC_SEGSTATE: u32 = 43;
+pub const KVM_CAP_HYPERV: u32 = 44;
+pub const KVM_CAP_HYPERV_VAPIC: u32 = 45;
+pub const KVM_CAP_HYPERV_SPIN: u32 = 46;
+pub const KVM_CAP_PCI_SEGMENT: u32 = 47;
+pub const KVM_CAP_PPC_PAIRED_SINGLES: u32 = 48;
+pub const KVM_CAP_INTR_SHADOW: u32 = 49;
+pub const KVM_CAP_DEBUGREGS: u32 = 50;
+pub const KVM_CAP_X86_ROBUST_SINGLESTEP: u32 = 51;
+pub const KVM_CAP_PPC_OSI: u32 = 52;
+pub const KVM_CAP_PPC_UNSET_IRQ: u32 = 53;
+pub const KVM_CAP_ENABLE_CAP: u32 = 54;
+pub const KVM_CAP_XSAVE: u32 = 55;
+pub const KVM_CAP_XCRS: u32 = 56;
+pub const KVM_CAP_PPC_GET_PVINFO: u32 = 57;
+pub const KVM_CAP_PPC_IRQ_LEVEL: u32 = 58;
+pub const KVM_CAP_ASYNC_PF: u32 = 59;
+pub const KVM_CAP_TSC_CONTROL: u32 = 60;
+pub const KVM_CAP_GET_TSC_KHZ: u32 = 61;
+pub const KVM_CAP_PPC_BOOKE_SREGS: u32 = 62;
+pub const KVM_CAP_SPAPR_TCE: u32 = 63;
+pub const KVM_CAP_PPC_SMT: u32 = 64;
+pub const KVM_CAP_PPC_RMA: u32 = 65;
+pub const KVM_CAP_MAX_VCPUS: u32 = 66;
+pub const KVM_CAP_PPC_HIOR: u32 = 67;
+pub const KVM_CAP_PPC_PAPR: u32 = 68;
+pub const KVM_CAP_SW_TLB: u32 = 69;
+pub const KVM_CAP_ONE_REG: u32 = 70;
+pub const KVM_CAP_S390_GMAP: u32 = 71;
+pub const KVM_CAP_TSC_DEADLINE_TIMER: u32 = 72;
+pub const KVM_CAP_S390_UCONTROL: u32 = 73;
+pub const KVM_CAP_SYNC_REGS: u32 = 74;
+pub const KVM_CAP_PCI_2_3: u32 = 75;
+pub const KVM_CAP_KVMCLOCK_CTRL: u32 = 76;
+pub const KVM_CAP_SIGNAL_MSI: u32 = 77;
+pub const KVM_CAP_PPC_GET_SMMU_INFO: u32 = 78;
+pub const KVM_CAP_S390_COW: u32 = 79;
+pub const KVM_CAP_PPC_ALLOC_HTAB: u32 = 80;
+pub const KVM_CAP_READONLY_MEM: u32 = 81;
+pub const KVM_CAP_IRQFD_RESAMPLE: u32 = 82;
+pub const KVM_CAP_PPC_BOOKE_WATCHDOG: u32 = 83;
+pub const KVM_CAP_PPC_HTAB_FD: u32 = 84;
+pub const KVM_CAP_S390_CSS_SUPPORT: u32 = 85;
+pub const KVM_CAP_PPC_EPR: u32 = 86;
+pub const KVM_CAP_ARM_PSCI: u32 = 87;
+pub const KVM_CAP_ARM_SET_DEVICE_ADDR: u32 = 88;
+pub const KVM_CAP_DEVICE_CTRL: u32 = 89;
+pub const KVM_CAP_IRQ_MPIC: u32 = 90;
+pub const KVM_CAP_PPC_RTAS: u32 = 91;
+pub const KVM_CAP_IRQ_XICS: u32 = 92;
+pub const KVM_CAP_ARM_EL1_32BIT: u32 = 93;
+pub const KVM_CAP_SPAPR_MULTITCE: u32 = 94;
+pub const KVM_CAP_EXT_EMUL_CPUID: u32 = 95;
+pub const KVM_CAP_HYPERV_TIME: u32 = 96;
+pub const KVM_CAP_IOAPIC_POLARITY_IGNORED: u32 = 97;
+pub const KVM_CAP_ENABLE_CAP_VM: u32 = 98;
+pub const KVM_CAP_S390_IRQCHIP: u32 = 99;
+pub const KVM_CAP_IOEVENTFD_NO_LENGTH: u32 = 100;
+pub const KVM_CAP_VM_ATTRIBUTES: u32 = 101;
+pub const KVM_CAP_ARM_PSCI_0_2: u32 = 102;
+pub const KVM_CAP_PPC_FIXUP_HCALL: u32 = 103;
+pub const KVM_CAP_PPC_ENABLE_HCALL: u32 = 104;
+pub const KVM_CAP_CHECK_EXTENSION_VM: u32 = 105;
+pub const KVM_CAP_S390_USER_SIGP: u32 = 106;
+pub const KVM_CAP_S390_VECTOR_REGISTERS: u32 = 107;
+pub const KVM_CAP_S390_MEM_OP: u32 = 108;
+pub const KVM_CAP_S390_USER_STSI: u32 = 109;
+pub const KVM_CAP_S390_SKEYS: u32 = 110;
+pub const KVM_CAP_MIPS_FPU: u32 = 111;
+pub const KVM_CAP_MIPS_MSA: u32 = 112;
+pub const KVM_CAP_S390_INJECT_IRQ: u32 = 113;
+pub const KVM_CAP_S390_IRQ_STATE: u32 = 114;
+pub const KVM_CAP_PPC_HWRNG: u32 = 115;
+pub const KVM_CAP_DISABLE_QUIRKS: u32 = 116;
+pub const KVM_CAP_X86_SMM: u32 = 117;
+pub const KVM_CAP_MULTI_ADDRESS_SPACE: u32 = 118;
+pub const KVM_CAP_GUEST_DEBUG_HW_BPS: u32 = 119;
+pub const KVM_CAP_GUEST_DEBUG_HW_WPS: u32 = 120;
+pub const KVM_CAP_SPLIT_IRQCHIP: u32 = 121;
+pub const KVM_CAP_IOEVENTFD_ANY_LENGTH: u32 = 122;
+pub const KVM_CAP_HYPERV_SYNIC: u32 = 123;
+pub const KVM_CAP_S390_RI: u32 = 124;
+pub const KVM_CAP_SPAPR_TCE_64: u32 = 125;
+pub const KVM_CAP_ARM_PMU_V3: u32 = 126;
+pub const KVM_CAP_VCPU_ATTRIBUTES: u32 = 127;
+pub const KVM_CAP_MAX_VCPU_ID: u32 = 128;
+pub const KVM_CAP_X2APIC_API: u32 = 129;
+pub const KVM_CAP_S390_USER_INSTR0: u32 = 130;
+pub const KVM_CAP_MSI_DEVID: u32 = 131;
+pub const KVM_CAP_PPC_HTM: u32 = 132;
+pub const KVM_CAP_SPAPR_RESIZE_HPT: u32 = 133;
+pub const KVM_CAP_PPC_MMU_RADIX: u32 = 134;
+pub const KVM_CAP_PPC_MMU_HASH_V3: u32 = 135;
+pub const KVM_CAP_IMMEDIATE_EXIT: u32 = 136;
+pub const KVM_CAP_MIPS_VZ: u32 = 137;
+pub const KVM_CAP_MIPS_TE: u32 = 138;
+pub const KVM_CAP_MIPS_64BIT: u32 = 139;
+pub const KVM_CAP_S390_GS: u32 = 140;
+pub const KVM_CAP_S390_AIS: u32 = 141;
+pub const KVM_CAP_SPAPR_TCE_VFIO: u32 = 142;
+pub const KVM_CAP_X86_DISABLE_EXITS: u32 = 143;
+pub const KVM_CAP_ARM_USER_IRQ: u32 = 144;
+pub const KVM_CAP_S390_CMMA_MIGRATION: u32 = 145;
+pub const KVM_CAP_PPC_FWNMI: u32 = 146;
+pub const KVM_CAP_PPC_SMT_POSSIBLE: u32 = 147;
+pub const KVM_CAP_HYPERV_SYNIC2: u32 = 148;
+pub const KVM_CAP_HYPERV_VP_INDEX: u32 = 149;
+pub const KVM_CAP_S390_AIS_MIGRATION: u32 = 150;
+pub const KVM_CAP_PPC_GET_CPU_CHAR: u32 = 151;
+pub const KVM_CAP_S390_BPB: u32 = 152;
+pub const KVM_CAP_GET_MSR_FEATURES: u32 = 153;
+pub const KVM_CAP_HYPERV_EVENTFD: u32 = 154;
+pub const KVM_CAP_HYPERV_TLBFLUSH: u32 = 155;
+pub const KVM_CAP_S390_HPAGE_1M: u32 = 156;
+pub const KVM_CAP_NESTED_STATE: u32 = 157;
+pub const KVM_CAP_ARM_INJECT_SERROR_ESR: u32 = 158;
+pub const KVM_CAP_MSR_PLATFORM_INFO: u32 = 159;
+pub const KVM_CAP_PPC_NESTED_HV: u32 = 160;
+pub const KVM_CAP_HYPERV_SEND_IPI: u32 = 161;
+pub const KVM_CAP_COALESCED_PIO: u32 = 162;
+pub const KVM_CAP_HYPERV_ENLIGHTENED_VMCS: u32 = 163;
+pub const KVM_CAP_EXCEPTION_PAYLOAD: u32 = 164;
+pub const KVM_CAP_ARM_VM_IPA_SIZE: u32 = 165;
+pub const KVM_CAP_MANUAL_DIRTY_LOG_PROTECT: u32 = 166;
+pub const KVM_CAP_HYPERV_CPUID: u32 = 167;
+pub const KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2: u32 = 168;
+pub const KVM_CAP_PPC_IRQ_XIVE: u32 = 169;
+pub const KVM_CAP_ARM_SVE: u32 = 170;
+pub const KVM_CAP_ARM_PTRAUTH_ADDRESS: u32 = 171;
+pub const KVM_CAP_ARM_PTRAUTH_GENERIC: u32 = 172;
+pub const KVM_CAP_PMU_EVENT_FILTER: u32 = 173;
+pub const KVM_CAP_ARM_IRQ_LINE_LAYOUT_2: u32 = 174;
+pub const KVM_CAP_HYPERV_DIRECT_TLBFLUSH: u32 = 175;
+pub const KVM_IRQ_ROUTING_IRQCHIP: u32 = 1;
+pub const KVM_IRQ_ROUTING_MSI: u32 = 2;
+pub const KVM_IRQ_ROUTING_S390_ADAPTER: u32 = 3;
+pub const KVM_IRQ_ROUTING_HV_SINT: u32 = 4;
+pub const KVM_IRQFD_FLAG_DEASSIGN: u32 = 1;
+pub const KVM_IRQFD_FLAG_RESAMPLE: u32 = 2;
+pub const KVM_CLOCK_TSC_STABLE: u32 = 2;
+pub const KVM_MMU_FSL_BOOKE_NOHV: u32 = 0;
+pub const KVM_MMU_FSL_BOOKE_HV: u32 = 1;
+pub const KVM_REG_ARCH_MASK: i64 = -72057594037927936;
+pub const KVM_REG_GENERIC: u32 = 0;
+pub const KVM_REG_PPC: u64 = 1152921504606846976;
+pub const KVM_REG_X86: u64 = 2305843009213693952;
+pub const KVM_REG_IA64: u64 = 3458764513820540928;
+pub const KVM_REG_ARM: u64 = 4611686018427387904;
+pub const KVM_REG_S390: u64 = 5764607523034234880;
+pub const KVM_REG_ARM64: u64 = 6917529027641081856;
+pub const KVM_REG_MIPS: u64 = 8070450532247928832;
+pub const KVM_REG_RISCV: i64 = -9223372036854775808;
+pub const KVM_REG_SIZE_SHIFT: u32 = 52;
+pub const KVM_REG_SIZE_MASK: u64 = 67553994410557440;
+pub const KVM_REG_SIZE_U8: u32 = 0;
+pub const KVM_REG_SIZE_U16: u64 = 4503599627370496;
+pub const KVM_REG_SIZE_U32: u64 = 9007199254740992;
+pub const KVM_REG_SIZE_U64: u64 = 13510798882111488;
+pub const KVM_REG_SIZE_U128: u64 = 18014398509481984;
+pub const KVM_REG_SIZE_U256: u64 = 22517998136852480;
+pub const KVM_REG_SIZE_U512: u64 = 27021597764222976;
+pub const KVM_REG_SIZE_U1024: u64 = 31525197391593472;
+pub const KVM_REG_SIZE_U2048: u64 = 36028797018963968;
+pub const KVM_MSI_VALID_DEVID: u32 = 1;
+pub const KVM_CREATE_DEVICE_TEST: u32 = 1;
+pub const KVM_DEV_VFIO_GROUP: u32 = 1;
+pub const KVM_DEV_VFIO_GROUP_ADD: u32 = 1;
+pub const KVM_DEV_VFIO_GROUP_DEL: u32 = 2;
+pub const KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE: u32 = 3;
+pub const KVM_S390_STORE_STATUS_NOADDR: i32 = -1;
+pub const KVM_S390_STORE_STATUS_PREFIXED: i32 = -2;
+pub const KVM_DEV_ASSIGN_ENABLE_IOMMU: u32 = 1;
+pub const KVM_DEV_ASSIGN_PCI_2_3: u32 = 2;
+pub const KVM_DEV_ASSIGN_MASK_INTX: u32 = 4;
+pub const KVM_DEV_IRQ_HOST_INTX: u32 = 1;
+pub const KVM_DEV_IRQ_HOST_MSI: u32 = 2;
+pub const KVM_DEV_IRQ_HOST_MSIX: u32 = 4;
+pub const KVM_DEV_IRQ_GUEST_INTX: u32 = 256;
+pub const KVM_DEV_IRQ_GUEST_MSI: u32 = 512;
+pub const KVM_DEV_IRQ_GUEST_MSIX: u32 = 1024;
+pub const KVM_DEV_IRQ_HOST_MASK: u32 = 255;
+pub const KVM_DEV_IRQ_GUEST_MASK: u32 = 65280;
+pub const KVM_MAX_MSIX_PER_DEV: u32 = 256;
+pub const KVM_X2APIC_API_USE_32BIT_IDS: u32 = 1;
+pub const KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK: u32 = 2;
+pub const KVM_ARM_DEV_EL1_VTIMER: u32 = 1;
+pub const KVM_ARM_DEV_EL1_PTIMER: u32 = 2;
+pub const KVM_ARM_DEV_PMU: u32 = 4;
+pub const KVM_HYPERV_CONN_ID_MASK: u32 = 16777215;
+pub const KVM_HYPERV_EVENTFD_DEASSIGN: u32 = 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;
@@ -562,6 +714,7 @@
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_time64_t = ::std::os::raw::c_longlong;
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;
@@ -576,6 +729,7 @@
pub type __be64 = __u64;
pub type __sum16 = __u16;
pub type __wsum = __u32;
+pub type __poll_t = ::std::os::raw::c_uint;
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct kvm_memory_alias {
@@ -2056,8 +2210,6 @@
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() {
@@ -2831,7 +2983,9 @@
pub sipi_vector: __u32,
pub flags: __u32,
pub smi: kvm_vcpu_events__bindgen_ty_4,
- pub reserved: [__u32; 9usize],
+ pub reserved: [__u8; 27usize],
+ pub exception_has_payload: __u8,
+ pub exception_payload: __u64,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
@@ -2839,7 +2993,7 @@
pub injected: __u8,
pub nr: __u8,
pub has_error_code: __u8,
- pub pad: __u8,
+ pub pending: __u8,
pub error_code: __u32,
}
#[test]
@@ -2893,14 +3047,14 @@
);
assert_eq!(
unsafe {
- &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_1>())).pad as *const _ as usize
+ &(*(::std::ptr::null::<kvm_vcpu_events__bindgen_ty_1>())).pending as *const _ as usize
},
3usize,
concat!(
"Offset of field: ",
stringify!(kvm_vcpu_events__bindgen_ty_1),
"::",
- stringify!(pad)
+ stringify!(pending)
)
);
assert_eq!(
@@ -3135,7 +3289,7 @@
);
assert_eq!(
::std::mem::align_of::<kvm_vcpu_events>(),
- 4usize,
+ 8usize,
concat!("Alignment of ", stringify!(kvm_vcpu_events))
);
assert_eq!(
@@ -3208,6 +3362,30 @@
stringify!(reserved)
)
);
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_vcpu_events>())).exception_has_payload as *const _ as usize
+ },
+ 55usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vcpu_events),
+ "::",
+ stringify!(exception_has_payload)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_vcpu_events>())).exception_payload as *const _ as usize
+ },
+ 56usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vcpu_events),
+ "::",
+ stringify!(exception_payload)
+ )
+ );
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
@@ -3427,19 +3605,438 @@
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
-pub struct kvm_sync_regs {}
+pub struct kvm_sync_regs {
+ pub regs: kvm_regs,
+ pub sregs: kvm_sregs,
+ pub events: kvm_vcpu_events,
+}
#[test]
fn bindgen_test_layout_kvm_sync_regs() {
assert_eq!(
::std::mem::size_of::<kvm_sync_regs>(),
- 0usize,
+ 520usize,
concat!("Size of: ", stringify!(kvm_sync_regs))
);
assert_eq!(
::std::mem::align_of::<kvm_sync_regs>(),
- 1usize,
+ 8usize,
concat!("Alignment of ", stringify!(kvm_sync_regs))
);
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sync_regs>())).regs as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sync_regs),
+ "::",
+ stringify!(regs)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sync_regs>())).sregs as *const _ as usize },
+ 144usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sync_regs),
+ "::",
+ stringify!(sregs)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sync_regs>())).events as *const _ as usize },
+ 456usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sync_regs),
+ "::",
+ stringify!(events)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_vmx_nested_state_data {
+ pub vmcs12: [__u8; 4096usize],
+ pub shadow_vmcs12: [__u8; 4096usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_vmx_nested_state_data() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_vmx_nested_state_data>(),
+ 8192usize,
+ concat!("Size of: ", stringify!(kvm_vmx_nested_state_data))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_vmx_nested_state_data>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(kvm_vmx_nested_state_data))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_vmx_nested_state_data>())).vmcs12 as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vmx_nested_state_data),
+ "::",
+ stringify!(vmcs12)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_vmx_nested_state_data>())).shadow_vmcs12 as *const _ as usize
+ },
+ 4096usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vmx_nested_state_data),
+ "::",
+ stringify!(shadow_vmcs12)
+ )
+ );
+}
+impl Default for kvm_vmx_nested_state_data {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_vmx_nested_state_hdr {
+ pub vmxon_pa: __u64,
+ pub vmcs12_pa: __u64,
+ pub smm: kvm_vmx_nested_state_hdr__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_vmx_nested_state_hdr__bindgen_ty_1 {
+ pub flags: __u16,
+}
+#[test]
+fn bindgen_test_layout_kvm_vmx_nested_state_hdr__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_vmx_nested_state_hdr__bindgen_ty_1>(),
+ 2usize,
+ concat!(
+ "Size of: ",
+ stringify!(kvm_vmx_nested_state_hdr__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_vmx_nested_state_hdr__bindgen_ty_1>(),
+ 2usize,
+ concat!(
+ "Alignment of ",
+ stringify!(kvm_vmx_nested_state_hdr__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_vmx_nested_state_hdr__bindgen_ty_1>())).flags as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vmx_nested_state_hdr__bindgen_ty_1),
+ "::",
+ stringify!(flags)
+ )
+ );
+}
+#[test]
+fn bindgen_test_layout_kvm_vmx_nested_state_hdr() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_vmx_nested_state_hdr>(),
+ 24usize,
+ concat!("Size of: ", stringify!(kvm_vmx_nested_state_hdr))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_vmx_nested_state_hdr>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_vmx_nested_state_hdr))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_vmx_nested_state_hdr>())).vmxon_pa as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vmx_nested_state_hdr),
+ "::",
+ stringify!(vmxon_pa)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_vmx_nested_state_hdr>())).vmcs12_pa as *const _ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vmx_nested_state_hdr),
+ "::",
+ stringify!(vmcs12_pa)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_vmx_nested_state_hdr>())).smm as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vmx_nested_state_hdr),
+ "::",
+ stringify!(smm)
+ )
+ );
+}
+#[repr(C)]
+pub struct kvm_nested_state {
+ pub flags: __u16,
+ pub format: __u16,
+ pub size: __u32,
+ pub hdr: kvm_nested_state__bindgen_ty_1,
+ pub data: kvm_nested_state__bindgen_ty_2,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_nested_state__bindgen_ty_1 {
+ pub vmx: kvm_vmx_nested_state_hdr,
+ pub pad: [__u8; 120usize],
+ _bindgen_union_align: [u64; 15usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_nested_state__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_nested_state__bindgen_ty_1>(),
+ 120usize,
+ concat!("Size of: ", stringify!(kvm_nested_state__bindgen_ty_1))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_nested_state__bindgen_ty_1>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_nested_state__bindgen_ty_1))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_nested_state__bindgen_ty_1>())).vmx as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_nested_state__bindgen_ty_1),
+ "::",
+ stringify!(vmx)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_nested_state__bindgen_ty_1>())).pad as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_nested_state__bindgen_ty_1),
+ "::",
+ stringify!(pad)
+ )
+ );
+}
+impl Default for kvm_nested_state__bindgen_ty_1 {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[repr(C)]
+pub struct kvm_nested_state__bindgen_ty_2 {
+ pub vmx: __BindgenUnionField<[kvm_vmx_nested_state_data; 0usize]>,
+ pub bindgen_union_field: [u8; 0usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_nested_state__bindgen_ty_2() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_nested_state__bindgen_ty_2>(),
+ 0usize,
+ concat!("Size of: ", stringify!(kvm_nested_state__bindgen_ty_2))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_nested_state__bindgen_ty_2>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(kvm_nested_state__bindgen_ty_2))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_nested_state__bindgen_ty_2>())).vmx as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_nested_state__bindgen_ty_2),
+ "::",
+ stringify!(vmx)
+ )
+ );
+}
+impl Default for kvm_nested_state__bindgen_ty_2 {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[test]
+fn bindgen_test_layout_kvm_nested_state() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_nested_state>(),
+ 128usize,
+ concat!("Size of: ", stringify!(kvm_nested_state))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_nested_state>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_nested_state))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_nested_state>())).flags as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_nested_state),
+ "::",
+ stringify!(flags)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_nested_state>())).format as *const _ as usize },
+ 2usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_nested_state),
+ "::",
+ stringify!(format)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_nested_state>())).size as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_nested_state),
+ "::",
+ stringify!(size)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_nested_state>())).hdr as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_nested_state),
+ "::",
+ stringify!(hdr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_nested_state>())).data as *const _ as usize },
+ 128usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_nested_state),
+ "::",
+ stringify!(data)
+ )
+ );
+}
+impl Default for kvm_nested_state {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct kvm_pmu_event_filter {
+ pub action: __u32,
+ pub nevents: __u32,
+ pub fixed_counter_bitmap: __u32,
+ pub flags: __u32,
+ pub pad: [__u32; 4usize],
+ pub events: __IncompleteArrayField<__u64>,
+}
+#[test]
+fn bindgen_test_layout_kvm_pmu_event_filter() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_pmu_event_filter>(),
+ 32usize,
+ concat!("Size of: ", stringify!(kvm_pmu_event_filter))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_pmu_event_filter>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_pmu_event_filter))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_pmu_event_filter>())).action as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_pmu_event_filter),
+ "::",
+ stringify!(action)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_pmu_event_filter>())).nevents as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_pmu_event_filter),
+ "::",
+ stringify!(nevents)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_pmu_event_filter>())).fixed_counter_bitmap as *const _
+ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_pmu_event_filter),
+ "::",
+ stringify!(fixed_counter_bitmap)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_pmu_event_filter>())).flags as *const _ as usize },
+ 12usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_pmu_event_filter),
+ "::",
+ stringify!(flags)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_pmu_event_filter>())).pad as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_pmu_event_filter),
+ "::",
+ stringify!(pad)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_pmu_event_filter>())).events as *const _ as usize },
+ 32usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_pmu_event_filter),
+ "::",
+ stringify!(events)
+ )
+ );
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
@@ -4043,6 +4640,399 @@
)
);
}
+#[doc = " kvm_s390_cmma_log - Used for CMMA migration."]
+#[doc = ""]
+#[doc = " Used both for input and output."]
+#[doc = ""]
+#[doc = " @start_gfn: Guest page number to start from."]
+#[doc = " @count: Size of the result buffer."]
+#[doc = " @flags: Control operation mode via KVM_S390_CMMA_* flags"]
+#[doc = " @remaining: Used with KVM_S390_GET_CMMA_BITS. Indicates how many dirty"]
+#[doc = " pages are still remaining."]
+#[doc = " @mask: Used with KVM_S390_SET_CMMA_BITS. Bitmap of bits to actually set"]
+#[doc = " in the PGSTE."]
+#[doc = " @values: Pointer to the values buffer."]
+#[doc = ""]
+#[doc = " Used in KVM_S390_{G,S}ET_CMMA_BITS ioctls."]
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_s390_cmma_log {
+ pub start_gfn: __u64,
+ pub count: __u32,
+ pub flags: __u32,
+ pub __bindgen_anon_1: kvm_s390_cmma_log__bindgen_ty_1,
+ pub values: __u64,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_s390_cmma_log__bindgen_ty_1 {
+ pub remaining: __u64,
+ pub mask: __u64,
+ _bindgen_union_align: u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_cmma_log__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_s390_cmma_log__bindgen_ty_1>(),
+ 8usize,
+ concat!("Size of: ", stringify!(kvm_s390_cmma_log__bindgen_ty_1))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_s390_cmma_log__bindgen_ty_1>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_s390_cmma_log__bindgen_ty_1))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_s390_cmma_log__bindgen_ty_1>())).remaining as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_s390_cmma_log__bindgen_ty_1),
+ "::",
+ stringify!(remaining)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_s390_cmma_log__bindgen_ty_1>())).mask as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_s390_cmma_log__bindgen_ty_1),
+ "::",
+ stringify!(mask)
+ )
+ );
+}
+impl Default for kvm_s390_cmma_log__bindgen_ty_1 {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[test]
+fn bindgen_test_layout_kvm_s390_cmma_log() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_s390_cmma_log>(),
+ 32usize,
+ concat!("Size of: ", stringify!(kvm_s390_cmma_log))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_s390_cmma_log>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_s390_cmma_log))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_s390_cmma_log>())).start_gfn as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_s390_cmma_log),
+ "::",
+ stringify!(start_gfn)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_s390_cmma_log>())).count as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_s390_cmma_log),
+ "::",
+ stringify!(count)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_s390_cmma_log>())).flags as *const _ as usize },
+ 12usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_s390_cmma_log),
+ "::",
+ stringify!(flags)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_s390_cmma_log>())).values as *const _ as usize },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_s390_cmma_log),
+ "::",
+ stringify!(values)
+ )
+ );
+}
+impl Default for kvm_s390_cmma_log {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_hyperv_exit {
+ pub type_: __u32,
+ pub pad1: __u32,
+ pub u: kvm_hyperv_exit__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_hyperv_exit__bindgen_ty_1 {
+ pub synic: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1,
+ pub hcall: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2,
+ _bindgen_union_align: [u64; 4usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1 {
+ pub msr: __u32,
+ pub pad2: __u32,
+ pub control: __u64,
+ pub evt_page: __u64,
+ pub msg_page: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>(),
+ 32usize,
+ concat!(
+ "Size of: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).msr as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(msr)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).pad2 as *const _
+ as usize
+ },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(pad2)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).control
+ as *const _ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(control)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).evt_page
+ as *const _ as usize
+ },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(evt_page)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).msg_page
+ as *const _ as usize
+ },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(msg_page)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2 {
+ pub input: __u64,
+ pub result: __u64,
+ pub params: [__u64; 2usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>(),
+ 32usize,
+ concat!(
+ "Size of: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>())).input
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2),
+ "::",
+ stringify!(input)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>())).result
+ as *const _ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2),
+ "::",
+ stringify!(result)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>())).params
+ as *const _ as usize
+ },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2),
+ "::",
+ stringify!(params)
+ )
+ );
+}
+#[test]
+fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_hyperv_exit__bindgen_ty_1>(),
+ 32usize,
+ concat!("Size of: ", stringify!(kvm_hyperv_exit__bindgen_ty_1))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_hyperv_exit__bindgen_ty_1>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_hyperv_exit__bindgen_ty_1))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1>())).synic as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1),
+ "::",
+ stringify!(synic)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1>())).hcall as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit__bindgen_ty_1),
+ "::",
+ stringify!(hcall)
+ )
+ );
+}
+impl Default for kvm_hyperv_exit__bindgen_ty_1 {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[test]
+fn bindgen_test_layout_kvm_hyperv_exit() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_hyperv_exit>(),
+ 40usize,
+ concat!("Size of: ", stringify!(kvm_hyperv_exit))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_hyperv_exit>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_hyperv_exit))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_hyperv_exit>())).type_ as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit),
+ "::",
+ stringify!(type_)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_hyperv_exit>())).pad1 as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit),
+ "::",
+ stringify!(pad1)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_hyperv_exit>())).u as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_exit),
+ "::",
+ stringify!(u)
+ )
+ );
+}
+impl Default for kvm_hyperv_exit {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct kvm_run {
@@ -4061,11 +5051,6 @@
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,
@@ -4092,6 +5077,11 @@
pub padding: [::std::os::raw::c_char; 256usize],
_bindgen_union_align: [u64; 32usize],
}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_run__bindgen_ty_1__bindgen_ty_1 {
+ pub hardware_exit_reason: __u64,
+}
#[test]
fn bindgen_test_layout_kvm_run__bindgen_ty_1__bindgen_ty_1() {
assert_eq!(
@@ -5228,174 +6218,6 @@
)
);
}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct kvm_hyperv_exit {
- pub type_: __u32,
- pub pad: __u32,
- pub u: kvm_hyperv_exit__bindgen_ty_1,
-}
-#[test]
-fn bindgen_test_layout_kvm_hyperv_exit() {
- assert_eq!(
- ::std::mem::size_of::<kvm_hyperv_exit>(),
- 40usize,
- concat!("Size of: ", stringify!(kvm_hyperv_exit))
- );
- assert_eq!(
- ::std::mem::align_of::<kvm_hyperv_exit>(),
- 8usize,
- concat!("Alignment of ", stringify!(kvm_hyperv_exit))
- );
- assert_eq!(
- unsafe { &(*(::std::ptr::null::<kvm_hyperv_exit>())).u as *const _ as usize },
- 8usize,
- concat!(
- "Offset of field: ",
- stringify!(kvm_hyperv_exit),
- "::",
- stringify!(u)
- )
- );
-}
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub union kvm_hyperv_exit__bindgen_ty_1 {
- pub synic: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1,
- pub hcall: kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2,
-}
-#[test]
-fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1() {
- assert_eq!(
- ::std::mem::size_of::<kvm_hyperv_exit__bindgen_ty_1>(),
- 32usize,
- concat!("Size of: ", stringify!(kvm_hyperv_exit__bindgen_ty_1))
- );
- assert_eq!(
- ::std::mem::align_of::<kvm_hyperv_exit__bindgen_ty_1>(),
- 8usize,
- concat!("Alignment of ", stringify!(kvm_hyperv_exit__bindgen_ty_1))
- );
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1 {
- pub msr: __u32,
- pub pad: __u32,
- pub control: __u64,
- pub evt_page: __u64,
- pub msg_page: __u64,
-}
-#[test]
-fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1() {
- assert_eq!(
- ::std::mem::size_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>(),
- 32usize,
- concat!(
- "Size of: ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1)
- )
- );
- assert_eq!(
- ::std::mem::align_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>(),
- 8usize,
- concat!(
- "Alignment of ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).control
- as *const _ as usize
- },
- 8usize,
- concat!(
- "Offset of field: ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
- "::",
- stringify!(control)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).evt_page
- as *const _ as usize
- },
- 16usize,
- concat!(
- "Offset of field: ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
- "::",
- stringify!(evt_page)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1>())).msg_page
- as *const _ as usize
- },
- 24usize,
- concat!(
- "Offset of field: ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_1),
- "::",
- stringify!(msg_page)
- )
- );
-}
-#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
-pub struct kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2 {
- pub input: __u64,
- pub result: __u64,
- pub params: [__u64; 2],
-}
-#[test]
-fn bindgen_test_layout_kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2() {
- assert_eq!(
- ::std::mem::size_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>(),
- 32usize,
- concat!(
- "Size of: ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2)
- )
- );
- assert_eq!(
- ::std::mem::align_of::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>(),
- 8usize,
- concat!(
- "Alignment of ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>())).result
- as *const _ as usize
- },
- 8usize,
- concat!(
- "Offset of field: ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2),
- "::",
- stringify!(result)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2>())).params
- as *const _ as usize
- },
- 16usize,
- concat!(
- "Offset of field: ",
- stringify!(kvm_hyperv_exit__bindgen_ty_1__bindgen_ty_2),
- "::",
- stringify!(params)
- )
- );
-}
#[test]
fn bindgen_test_layout_kvm_run__bindgen_ty_1() {
assert_eq!(
@@ -5623,6 +6445,16 @@
)
);
assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).hyperv as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_run__bindgen_ty_1),
+ "::",
+ stringify!(hyperv)
+ )
+ );
+ assert_eq!(
unsafe { &(*(::std::ptr::null::<kvm_run__bindgen_ty_1>())).padding as *const _ as usize },
0usize,
concat!(
@@ -5643,7 +6475,7 @@
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],
+ _bindgen_union_align: [u64; 256usize],
}
#[test]
fn bindgen_test_layout_kvm_run__bindgen_ty_2() {
@@ -5654,7 +6486,7 @@
);
assert_eq!(
::std::mem::align_of::<kvm_run__bindgen_ty_2>(),
- 1usize,
+ 8usize,
concat!("Alignment of ", stringify!(kvm_run__bindgen_ty_2))
);
assert_eq!(
@@ -5826,11 +6658,68 @@
}
}
#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
+#[derive(Copy, Clone)]
pub struct kvm_coalesced_mmio_zone {
pub addr: __u64,
pub size: __u32,
+ pub __bindgen_anon_1: kvm_coalesced_mmio_zone__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_coalesced_mmio_zone__bindgen_ty_1 {
pub pad: __u32,
+ pub pio: __u32,
+ _bindgen_union_align: u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_coalesced_mmio_zone__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_coalesced_mmio_zone__bindgen_ty_1>(),
+ 4usize,
+ concat!(
+ "Size of: ",
+ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_coalesced_mmio_zone__bindgen_ty_1>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_coalesced_mmio_zone__bindgen_ty_1>())).pad as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1),
+ "::",
+ stringify!(pad)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_coalesced_mmio_zone__bindgen_ty_1>())).pio as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_coalesced_mmio_zone__bindgen_ty_1),
+ "::",
+ stringify!(pio)
+ )
+ );
+}
+impl Default for kvm_coalesced_mmio_zone__bindgen_ty_1 {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
}
#[test]
fn bindgen_test_layout_kvm_coalesced_mmio_zone() {
@@ -5864,24 +6753,71 @@
stringify!(size)
)
);
+}
+impl Default for kvm_coalesced_mmio_zone {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_coalesced_mmio {
+ pub phys_addr: __u64,
+ pub len: __u32,
+ pub __bindgen_anon_1: kvm_coalesced_mmio__bindgen_ty_1,
+ pub data: [__u8; 8usize],
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_coalesced_mmio__bindgen_ty_1 {
+ pub pad: __u32,
+ pub pio: __u32,
+ _bindgen_union_align: u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_coalesced_mmio__bindgen_ty_1() {
assert_eq!(
- unsafe { &(*(::std::ptr::null::<kvm_coalesced_mmio_zone>())).pad as *const _ as usize },
- 12usize,
+ ::std::mem::size_of::<kvm_coalesced_mmio__bindgen_ty_1>(),
+ 4usize,
+ concat!("Size of: ", stringify!(kvm_coalesced_mmio__bindgen_ty_1))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_coalesced_mmio__bindgen_ty_1>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(kvm_coalesced_mmio__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_coalesced_mmio__bindgen_ty_1>())).pad as *const _ as usize
+ },
+ 0usize,
concat!(
"Offset of field: ",
- stringify!(kvm_coalesced_mmio_zone),
+ stringify!(kvm_coalesced_mmio__bindgen_ty_1),
"::",
stringify!(pad)
)
);
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_coalesced_mmio__bindgen_ty_1>())).pio as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_coalesced_mmio__bindgen_ty_1),
+ "::",
+ stringify!(pio)
+ )
+ );
}
-#[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],
+impl Default for kvm_coalesced_mmio__bindgen_ty_1 {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
}
#[test]
fn bindgen_test_layout_kvm_coalesced_mmio() {
@@ -5916,16 +6852,6 @@
)
);
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!(
@@ -5936,14 +6862,16 @@
)
);
}
+impl Default for kvm_coalesced_mmio {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
#[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() {
@@ -5990,6 +6918,11 @@
)
);
}
+impl Default for kvm_coalesced_mmio_ring {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct kvm_translation {
@@ -6293,6 +7226,116 @@
}
}
#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct kvm_clear_dirty_log {
+ pub slot: __u32,
+ pub num_pages: __u32,
+ pub first_page: __u64,
+ pub __bindgen_anon_1: kvm_clear_dirty_log__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_clear_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_clear_dirty_log__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_clear_dirty_log__bindgen_ty_1>(),
+ 8usize,
+ concat!("Size of: ", stringify!(kvm_clear_dirty_log__bindgen_ty_1))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_clear_dirty_log__bindgen_ty_1>(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(kvm_clear_dirty_log__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_clear_dirty_log__bindgen_ty_1>())).dirty_bitmap as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_clear_dirty_log__bindgen_ty_1),
+ "::",
+ stringify!(dirty_bitmap)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_clear_dirty_log__bindgen_ty_1>())).padding2 as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_clear_dirty_log__bindgen_ty_1),
+ "::",
+ stringify!(padding2)
+ )
+ );
+}
+impl Default for kvm_clear_dirty_log__bindgen_ty_1 {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[test]
+fn bindgen_test_layout_kvm_clear_dirty_log() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_clear_dirty_log>(),
+ 24usize,
+ concat!("Size of: ", stringify!(kvm_clear_dirty_log))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_clear_dirty_log>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_clear_dirty_log))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_clear_dirty_log>())).slot as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_clear_dirty_log),
+ "::",
+ stringify!(slot)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_clear_dirty_log>())).num_pages as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_clear_dirty_log),
+ "::",
+ stringify!(num_pages)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_clear_dirty_log>())).first_page as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_clear_dirty_log),
+ "::",
+ stringify!(first_page)
+ )
+ );
+}
+impl Default for kvm_clear_dirty_log {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
+#[repr(C)]
#[derive(Debug, Default)]
pub struct kvm_signal_mask {
pub len: __u32,
@@ -6651,7 +7694,8 @@
pub exc_access_id: __u8,
pub per_access_id: __u8,
pub op_access_id: __u8,
- pub pad: [__u8; 3usize],
+ pub flags: __u8,
+ pub pad: [__u8; 2usize],
}
#[test]
fn bindgen_test_layout_kvm_s390_pgm_info() {
@@ -6778,12 +7822,22 @@
)
);
assert_eq!(
- unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).pad as *const _ as usize },
+ unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).flags as *const _ as usize },
37usize,
concat!(
"Offset of field: ",
stringify!(kvm_s390_pgm_info),
"::",
+ stringify!(flags)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_s390_pgm_info>())).pad as *const _ as usize },
+ 38usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_s390_pgm_info),
+ "::",
stringify!(pad)
)
);
@@ -7279,7 +8333,7 @@
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;
+pub type _bindgen_ty_1 = u32;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct kvm_ioeventfd {
@@ -7589,7 +8643,8 @@
pub struct kvm_ppc_smmu_info {
pub flags: __u64,
pub slb_size: __u32,
- pub pad: __u32,
+ pub data_keys: __u16,
+ pub instr_keys: __u16,
pub sps: [kvm_ppc_one_seg_page_size; 8usize],
}
#[test]
@@ -7625,13 +8680,23 @@
)
);
assert_eq!(
- unsafe { &(*(::std::ptr::null::<kvm_ppc_smmu_info>())).pad as *const _ as usize },
+ unsafe { &(*(::std::ptr::null::<kvm_ppc_smmu_info>())).data_keys as *const _ as usize },
12usize,
concat!(
"Offset of field: ",
stringify!(kvm_ppc_smmu_info),
"::",
- stringify!(pad)
+ stringify!(data_keys)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_ppc_smmu_info>())).instr_keys as *const _ as usize },
+ 14usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_ppc_smmu_info),
+ "::",
+ stringify!(instr_keys)
)
);
assert_eq!(
@@ -7647,6 +8712,56 @@
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_ppc_resize_hpt {
+ pub flags: __u64,
+ pub shift: __u32,
+ pub pad: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_ppc_resize_hpt() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_ppc_resize_hpt>(),
+ 16usize,
+ concat!("Size of: ", stringify!(kvm_ppc_resize_hpt))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_ppc_resize_hpt>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_ppc_resize_hpt))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_ppc_resize_hpt>())).flags as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_ppc_resize_hpt),
+ "::",
+ stringify!(flags)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_ppc_resize_hpt>())).shift as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_ppc_resize_hpt),
+ "::",
+ stringify!(shift)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_ppc_resize_hpt>())).pad as *const _ as usize },
+ 12usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_ppc_resize_hpt),
+ "::",
+ stringify!(pad)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct kvm_irq_routing_irqchip {
pub irqchip: __u32,
pub pin: __u32,
@@ -7685,12 +8800,64 @@
);
}
#[repr(C)]
-#[derive(Debug, Default, Copy, Clone)]
+#[derive(Copy, Clone)]
pub struct kvm_irq_routing_msi {
pub address_lo: __u32,
pub address_hi: __u32,
pub data: __u32,
+ pub __bindgen_anon_1: kvm_irq_routing_msi__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union kvm_irq_routing_msi__bindgen_ty_1 {
pub pad: __u32,
+ pub devid: __u32,
+ _bindgen_union_align: u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing_msi__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_irq_routing_msi__bindgen_ty_1>(),
+ 4usize,
+ concat!("Size of: ", stringify!(kvm_irq_routing_msi__bindgen_ty_1))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_irq_routing_msi__bindgen_ty_1>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(kvm_irq_routing_msi__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_irq_routing_msi__bindgen_ty_1>())).pad as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_irq_routing_msi__bindgen_ty_1),
+ "::",
+ stringify!(pad)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_irq_routing_msi__bindgen_ty_1>())).devid as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_irq_routing_msi__bindgen_ty_1),
+ "::",
+ stringify!(devid)
+ )
+ );
+}
+impl Default for kvm_irq_routing_msi__bindgen_ty_1 {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
}
#[test]
fn bindgen_test_layout_kvm_irq_routing_msi() {
@@ -7734,16 +8901,11 @@
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)
- )
- );
+}
+impl Default for kvm_irq_routing_msi {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
@@ -7830,6 +8992,45 @@
);
}
#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_irq_routing_hv_sint {
+ pub vcpu: __u32,
+ pub sint: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_irq_routing_hv_sint() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_irq_routing_hv_sint>(),
+ 8usize,
+ concat!("Size of: ", stringify!(kvm_irq_routing_hv_sint))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_irq_routing_hv_sint>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(kvm_irq_routing_hv_sint))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_irq_routing_hv_sint>())).vcpu as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_irq_routing_hv_sint),
+ "::",
+ stringify!(vcpu)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_irq_routing_hv_sint>())).sint as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_irq_routing_hv_sint),
+ "::",
+ stringify!(sint)
+ )
+ );
+}
+#[repr(C)]
#[derive(Copy, Clone)]
pub struct kvm_irq_routing_entry {
pub gsi: __u32,
@@ -7844,6 +9045,7 @@
pub irqchip: kvm_irq_routing_irqchip,
pub msi: kvm_irq_routing_msi,
pub adapter: kvm_irq_routing_s390_adapter,
+ pub hv_sint: kvm_irq_routing_hv_sint,
pub pad: [__u32; 8usize],
_bindgen_union_align: [u64; 4usize],
}
@@ -7902,6 +9104,19 @@
);
assert_eq!(
unsafe {
+ &(*(::std::ptr::null::<kvm_irq_routing_entry__bindgen_ty_1>())).hv_sint as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_irq_routing_entry__bindgen_ty_1),
+ "::",
+ stringify!(hv_sint)
+ )
+ );
+ assert_eq!(
+ unsafe {
&(*(::std::ptr::null::<kvm_irq_routing_entry__bindgen_ty_1>())).pad as *const _ as usize
},
0usize,
@@ -7991,8 +9206,6 @@
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() {
@@ -8537,7 +9750,8 @@
pub address_hi: __u32,
pub data: __u32,
pub flags: __u32,
- pub pad: [__u8; 16usize],
+ pub devid: __u32,
+ pub pad: [__u8; 12usize],
}
#[test]
fn bindgen_test_layout_kvm_msi() {
@@ -8592,12 +9806,22 @@
)
);
assert_eq!(
- unsafe { &(*(::std::ptr::null::<kvm_msi>())).pad as *const _ as usize },
+ unsafe { &(*(::std::ptr::null::<kvm_msi>())).devid as *const _ as usize },
16usize,
concat!(
"Offset of field: ",
stringify!(kvm_msi),
"::",
+ stringify!(devid)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_msi>())).pad as *const _ as usize },
+ 20usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_msi),
+ "::",
stringify!(pad)
)
);
@@ -8759,8 +9983,49 @@
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;
+pub const kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS: kvm_device_type = 8;
+pub const kvm_device_type_KVM_DEV_TYPE_XIVE: kvm_device_type = 9;
+pub const kvm_device_type_KVM_DEV_TYPE_MAX: kvm_device_type = 10;
+pub type kvm_device_type = u32;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_vfio_spapr_tce {
+ pub groupfd: __s32,
+ pub tablefd: __s32,
+}
+#[test]
+fn bindgen_test_layout_kvm_vfio_spapr_tce() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_vfio_spapr_tce>(),
+ 8usize,
+ concat!("Size of: ", stringify!(kvm_vfio_spapr_tce))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_vfio_spapr_tce>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(kvm_vfio_spapr_tce))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_vfio_spapr_tce>())).groupfd as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vfio_spapr_tce),
+ "::",
+ stringify!(groupfd)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_vfio_spapr_tce>())).tablefd as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_vfio_spapr_tce),
+ "::",
+ stringify!(tablefd)
+ )
+ );
+}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct kvm_s390_ucas_mapping {
@@ -8812,6 +10077,482 @@
);
}
#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_enc_region {
+ pub addr: __u64,
+ pub size: __u64,
+}
+#[test]
+fn bindgen_test_layout_kvm_enc_region() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_enc_region>(),
+ 16usize,
+ concat!("Size of: ", stringify!(kvm_enc_region))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_enc_region>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_enc_region))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_enc_region>())).addr as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_enc_region),
+ "::",
+ stringify!(addr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_enc_region>())).size as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_enc_region),
+ "::",
+ stringify!(size)
+ )
+ );
+}
+pub const sev_cmd_id_KVM_SEV_INIT: sev_cmd_id = 0;
+pub const sev_cmd_id_KVM_SEV_ES_INIT: sev_cmd_id = 1;
+pub const sev_cmd_id_KVM_SEV_LAUNCH_START: sev_cmd_id = 2;
+pub const sev_cmd_id_KVM_SEV_LAUNCH_UPDATE_DATA: sev_cmd_id = 3;
+pub const sev_cmd_id_KVM_SEV_LAUNCH_UPDATE_VMSA: sev_cmd_id = 4;
+pub const sev_cmd_id_KVM_SEV_LAUNCH_SECRET: sev_cmd_id = 5;
+pub const sev_cmd_id_KVM_SEV_LAUNCH_MEASURE: sev_cmd_id = 6;
+pub const sev_cmd_id_KVM_SEV_LAUNCH_FINISH: sev_cmd_id = 7;
+pub const sev_cmd_id_KVM_SEV_SEND_START: sev_cmd_id = 8;
+pub const sev_cmd_id_KVM_SEV_SEND_UPDATE_DATA: sev_cmd_id = 9;
+pub const sev_cmd_id_KVM_SEV_SEND_UPDATE_VMSA: sev_cmd_id = 10;
+pub const sev_cmd_id_KVM_SEV_SEND_FINISH: sev_cmd_id = 11;
+pub const sev_cmd_id_KVM_SEV_RECEIVE_START: sev_cmd_id = 12;
+pub const sev_cmd_id_KVM_SEV_RECEIVE_UPDATE_DATA: sev_cmd_id = 13;
+pub const sev_cmd_id_KVM_SEV_RECEIVE_UPDATE_VMSA: sev_cmd_id = 14;
+pub const sev_cmd_id_KVM_SEV_RECEIVE_FINISH: sev_cmd_id = 15;
+pub const sev_cmd_id_KVM_SEV_GUEST_STATUS: sev_cmd_id = 16;
+pub const sev_cmd_id_KVM_SEV_DBG_DECRYPT: sev_cmd_id = 17;
+pub const sev_cmd_id_KVM_SEV_DBG_ENCRYPT: sev_cmd_id = 18;
+pub const sev_cmd_id_KVM_SEV_CERT_EXPORT: sev_cmd_id = 19;
+pub const sev_cmd_id_KVM_SEV_NR_MAX: sev_cmd_id = 20;
+pub type sev_cmd_id = u32;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sev_cmd {
+ pub id: __u32,
+ pub data: __u64,
+ pub error: __u32,
+ pub sev_fd: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_sev_cmd() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_sev_cmd>(),
+ 24usize,
+ concat!("Size of: ", stringify!(kvm_sev_cmd))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_sev_cmd>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_sev_cmd))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_cmd>())).id as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_cmd),
+ "::",
+ stringify!(id)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_cmd>())).data as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_cmd),
+ "::",
+ stringify!(data)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_cmd>())).error as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_cmd),
+ "::",
+ stringify!(error)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_cmd>())).sev_fd as *const _ as usize },
+ 20usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_cmd),
+ "::",
+ stringify!(sev_fd)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sev_launch_start {
+ pub handle: __u32,
+ pub policy: __u32,
+ pub dh_uaddr: __u64,
+ pub dh_len: __u32,
+ pub session_uaddr: __u64,
+ pub session_len: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_sev_launch_start() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_sev_launch_start>(),
+ 40usize,
+ concat!("Size of: ", stringify!(kvm_sev_launch_start))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_sev_launch_start>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_sev_launch_start))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_start>())).handle as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_start),
+ "::",
+ stringify!(handle)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_start>())).policy as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_start),
+ "::",
+ stringify!(policy)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_start>())).dh_uaddr as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_start),
+ "::",
+ stringify!(dh_uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_start>())).dh_len as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_start),
+ "::",
+ stringify!(dh_len)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_sev_launch_start>())).session_uaddr as *const _ as usize
+ },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_start),
+ "::",
+ stringify!(session_uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_sev_launch_start>())).session_len as *const _ as usize
+ },
+ 32usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_start),
+ "::",
+ stringify!(session_len)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sev_launch_update_data {
+ pub uaddr: __u64,
+ pub len: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_sev_launch_update_data() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_sev_launch_update_data>(),
+ 16usize,
+ concat!("Size of: ", stringify!(kvm_sev_launch_update_data))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_sev_launch_update_data>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_sev_launch_update_data))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_sev_launch_update_data>())).uaddr as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_update_data),
+ "::",
+ stringify!(uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_update_data>())).len as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_update_data),
+ "::",
+ stringify!(len)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sev_launch_secret {
+ pub hdr_uaddr: __u64,
+ pub hdr_len: __u32,
+ pub guest_uaddr: __u64,
+ pub guest_len: __u32,
+ pub trans_uaddr: __u64,
+ pub trans_len: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_sev_launch_secret() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_sev_launch_secret>(),
+ 48usize,
+ concat!("Size of: ", stringify!(kvm_sev_launch_secret))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_sev_launch_secret>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_sev_launch_secret))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_secret>())).hdr_uaddr as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_secret),
+ "::",
+ stringify!(hdr_uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_secret>())).hdr_len as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_secret),
+ "::",
+ stringify!(hdr_len)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_sev_launch_secret>())).guest_uaddr as *const _ as usize
+ },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_secret),
+ "::",
+ stringify!(guest_uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_secret>())).guest_len as *const _ as usize },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_secret),
+ "::",
+ stringify!(guest_len)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<kvm_sev_launch_secret>())).trans_uaddr as *const _ as usize
+ },
+ 32usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_secret),
+ "::",
+ stringify!(trans_uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_secret>())).trans_len as *const _ as usize },
+ 40usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_secret),
+ "::",
+ stringify!(trans_len)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sev_launch_measure {
+ pub uaddr: __u64,
+ pub len: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_sev_launch_measure() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_sev_launch_measure>(),
+ 16usize,
+ concat!("Size of: ", stringify!(kvm_sev_launch_measure))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_sev_launch_measure>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_sev_launch_measure))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_measure>())).uaddr as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_measure),
+ "::",
+ stringify!(uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_launch_measure>())).len as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_launch_measure),
+ "::",
+ stringify!(len)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sev_guest_status {
+ pub handle: __u32,
+ pub policy: __u32,
+ pub state: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_sev_guest_status() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_sev_guest_status>(),
+ 12usize,
+ concat!("Size of: ", stringify!(kvm_sev_guest_status))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_sev_guest_status>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(kvm_sev_guest_status))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_guest_status>())).handle as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_guest_status),
+ "::",
+ stringify!(handle)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_guest_status>())).policy as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_guest_status),
+ "::",
+ stringify!(policy)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_guest_status>())).state as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_guest_status),
+ "::",
+ stringify!(state)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_sev_dbg {
+ pub src_uaddr: __u64,
+ pub dst_uaddr: __u64,
+ pub len: __u32,
+}
+#[test]
+fn bindgen_test_layout_kvm_sev_dbg() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_sev_dbg>(),
+ 24usize,
+ concat!("Size of: ", stringify!(kvm_sev_dbg))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_sev_dbg>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(kvm_sev_dbg))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_dbg>())).src_uaddr as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_dbg),
+ "::",
+ stringify!(src_uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_dbg>())).dst_uaddr as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_dbg),
+ "::",
+ stringify!(dst_uaddr)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_sev_dbg>())).len as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_sev_dbg),
+ "::",
+ stringify!(len)
+ )
+ );
+}
+#[repr(C)]
#[derive(Copy, Clone)]
pub struct kvm_assigned_pci_dev {
pub assigned_dev_id: __u32,
@@ -9151,3 +10892,64 @@
)
);
}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct kvm_hyperv_eventfd {
+ pub conn_id: __u32,
+ pub fd: __s32,
+ pub flags: __u32,
+ pub padding: [__u32; 3usize],
+}
+#[test]
+fn bindgen_test_layout_kvm_hyperv_eventfd() {
+ assert_eq!(
+ ::std::mem::size_of::<kvm_hyperv_eventfd>(),
+ 24usize,
+ concat!("Size of: ", stringify!(kvm_hyperv_eventfd))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<kvm_hyperv_eventfd>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(kvm_hyperv_eventfd))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_hyperv_eventfd>())).conn_id as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_eventfd),
+ "::",
+ stringify!(conn_id)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_hyperv_eventfd>())).fd as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_eventfd),
+ "::",
+ stringify!(fd)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_hyperv_eventfd>())).flags as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_eventfd),
+ "::",
+ stringify!(flags)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<kvm_hyperv_eventfd>())).padding as *const _ as usize },
+ 12usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(kvm_hyperv_eventfd),
+ "::",
+ stringify!(padding)
+ )
+ );
+}
diff --git a/linux_input_sys/Android.bp b/linux_input_sys/Android.bp
index 5cb0418..fc8c9cc 100644
--- a/linux_input_sys/Android.bp
+++ b/linux_input_sys/Android.bp
@@ -42,14 +42,31 @@
// dependent_library ["feature_list"]
// ../assertions/src/lib.rs
// ../base/src/lib.rs
+// ../cros_async/src/lib.rs
// ../data_model/src/lib.rs
+// ../io_uring/src/lib.rs
// ../sync/src/lib.rs
// ../sys_util/poll_token_derive/poll_token_derive.rs
// ../sys_util/src/lib.rs
// ../syscall_defines/src/lib.rs
// ../tempfile/src/lib.rs
+// async-trait-0.1.42
+// futures-0.3.8 "alloc"
+// futures-channel-0.3.8 "alloc,futures-sink,sink"
+// futures-core-0.3.8 "alloc"
+// futures-io-0.3.8
+// futures-sink-0.3.8 "alloc"
+// futures-task-0.3.8 "alloc"
+// futures-util-0.3.8 "alloc,futures-sink,sink"
// libc-0.2.80 "default,std"
+// paste-1.0.3
+// pin-project-1.0.2
+// pin-project-internal-1.0.2
+// pin-utils-0.1.0
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// slab-0.4.2
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// thiserror-1.0.22
+// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/msg_socket/Android.bp b/msg_socket/Android.bp
index 6fb3edc..234dd2b 100644
--- a/msg_socket/Android.bp
+++ b/msg_socket/Android.bp
@@ -126,6 +126,7 @@
// ../syscall_defines/src/lib.rs
// ../tempfile/src/lib.rs
// async-trait-0.1.42
+// base-0.1.0
// futures-0.3.8 "alloc,async-await,default,executor,futures-executor,std"
// futures-channel-0.3.8 "alloc,futures-sink,sink,std"
// futures-core-0.3.8 "alloc,std"
@@ -147,7 +148,7 @@
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// thiserror-1.0.22
// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/msg_socket/msg_on_socket_derive/Android.bp b/msg_socket/msg_on_socket_derive/Android.bp
index 27ddaa3..d95b4ed 100644
--- a/msg_socket/msg_on_socket_derive/Android.bp
+++ b/msg_socket/msg_on_socket_derive/Android.bp
@@ -29,7 +29,8 @@
}
// dependent_library ["feature_list"]
+// base-0.1.0
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// syn-1.0.53 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
// unicode-xid-0.2.1 "default"
diff --git a/msg_socket/msg_on_socket_derive/Cargo.toml b/msg_socket/msg_on_socket_derive/Cargo.toml
index 002a3ae..206c03a 100644
--- a/msg_socket/msg_on_socket_derive/Cargo.toml
+++ b/msg_socket/msg_on_socket_derive/Cargo.toml
@@ -5,6 +5,7 @@
edition = "2018"
[dependencies]
+base = "*"
proc-macro2 = "^1"
quote = "^1"
syn = "^1"
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
index d287ac0..98b3549 100644
--- a/msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs
+++ b/msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs
@@ -44,10 +44,7 @@
}
fn is_named_struct(ds: &DataStruct) -> bool {
- match &ds.fields {
- Fields::Named(_f) => true,
- _ => false,
- }
+ matches!(&ds.fields, Fields::Named(_f))
}
/************************** Named Struct Impls ********************************************/
@@ -133,8 +130,8 @@
}
quote! {
- fn uses_fd() -> bool {
- #(<#field_types>::uses_fd())||*
+ fn uses_descriptor() -> bool {
+ #(<#field_types>::uses_descriptor())||*
}
}
}
@@ -145,7 +142,7 @@
fn msg_size(&self) -> usize {
#msg_size
}
- fn fd_count(&self) -> usize {
+ fn descriptor_count(&self) -> usize {
#fd_count
}
}
@@ -174,7 +171,7 @@
quote! {
unsafe fn read_from_buffer(
buffer: &[u8],
- fds: &[std::os::unix::io::RawFd],
+ fds: &[RawDescriptor],
) -> msg_socket::MsgResult<(Self, usize)> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
@@ -206,7 +203,7 @@
fn write_to_buffer(
&self,
buffer: &mut [u8],
- fds: &mut [std::os::unix::io::RawFd],
+ fds: &mut [RawDescriptor],
) -> msg_socket::MsgResult<usize> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
@@ -240,13 +237,13 @@
}
}
- if variant_field_types.len() == 0 {
+ if variant_field_types.is_empty() {
return quote!();
}
quote! {
- fn uses_fd() -> bool {
- #(<#variant_field_types>::uses_fd())||*
+ fn uses_descriptor() -> bool {
+ #(<#variant_field_types>::uses_descriptor())||*
}
}
}
@@ -270,7 +267,7 @@
msg_size_match_variants.push(v);
let v = quote! {
- #name::#variant_name { #(#tmp_names),* } => #(#tmp_names.fd_count())+*,
+ #name::#variant_name { #(#tmp_names),* } => #(#tmp_names.descriptor_count())+*,
};
fd_count_match_variants.push(v);
}
@@ -288,7 +285,7 @@
msg_size_match_variants.push(v);
let v = quote! {
- #name::#variant_name(#(#tmp_names),*) => #(#tmp_names.fd_count())+*,
+ #name::#variant_name(#(#tmp_names),*) => #(#tmp_names.descriptor_count())+*,
};
fd_count_match_variants.push(v);
}
@@ -308,7 +305,7 @@
#(#msg_size_match_variants)*
}
}
- fn fd_count(&self) -> usize {
+ fn descriptor_count(&self) -> usize {
match self {
#(#fd_count_match_variants)*
}
@@ -373,7 +370,7 @@
quote! {
unsafe fn read_from_buffer(
buffer: &[u8],
- fds: &[std::os::unix::io::RawFd],
+ fds: &[RawDescriptor],
) -> msg_socket::MsgResult<(Self, usize)> {
let v = buffer.get(0).ok_or(msg_socket::MsgError::WrongMsgBufferSize)?;
match v {
@@ -449,7 +446,7 @@
fn write_to_buffer(
&self,
buffer: &mut [u8],
- fds: &mut [std::os::unix::io::RawFd],
+ fds: &mut [RawDescriptor],
) -> msg_socket::MsgResult<usize> {
if buffer.is_empty() {
return Err(msg_socket::MsgError::WrongMsgBufferSize)
@@ -508,14 +505,14 @@
}
fn define_uses_fd_for_tuples(fields: &[StructField]) -> TokenStream {
- if fields.len() == 0 {
+ if fields.is_empty() {
return quote!();
}
let field_types = fields.iter().map(|f| &f.ty);
quote! {
- fn uses_fd() -> bool {
- #(<#field_types>::uses_fd())||*
+ fn uses_descriptor() -> bool {
+ #(<#field_types>::uses_descriptor())||*
}
}
}
@@ -534,7 +531,7 @@
quote! {
unsafe fn read_from_buffer(
buffer: &[u8],
- fds: &[std::os::unix::io::RawFd],
+ fds: &[RawDescriptor],
) -> msg_socket::MsgResult<(Self, usize)> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
@@ -562,7 +559,7 @@
fn write_to_buffer(
&self,
buffer: &mut [u8],
- fds: &mut [std::os::unix::io::RawFd],
+ fds: &mut [RawDescriptor],
) -> msg_socket::MsgResult<usize> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
@@ -579,13 +576,13 @@
.filter(|f| !f.skipped)
.map(|f| &f.member)
.collect();
- if fields.len() > 0 {
+ if !fields.is_empty() {
(
quote! {
#( self.#fields.msg_size() as usize )+*
},
quote! {
- #( self.#fields.fd_count() as usize )+*
+ #( self.#fields.descriptor_count() as usize )+*
},
)
} else {
@@ -621,29 +618,31 @@
let input: DeriveInput = parse_quote! {
struct MyMsg {
a: u8,
- b: RawFd,
+ b: RawDescriptor,
c: u32,
}
};
let expected = quote! {
impl msg_socket::MsgOnSocket for MyMsg {
- fn uses_fd() -> bool {
- <u8>::uses_fd() || <RawFd>::uses_fd() || <u32>::uses_fd()
+ fn uses_descriptor() -> bool {
+ <u8>::uses_descriptor()
+ || <RawDescriptor>::uses_descriptor()
+ || <u32>::uses_descriptor()
}
fn msg_size(&self) -> usize {
self.a.msg_size() as usize
+ self.b.msg_size() as usize
+ self.c.msg_size() as usize
}
- fn fd_count(&self) -> usize {
- self.a.fd_count() as usize
- + self.b.fd_count() as usize
- + self.c.fd_count() as usize
+ fn descriptor_count(&self) -> usize {
+ self.a.descriptor_count() as usize
+ + self.b.descriptor_count() as usize
+ + self.c.descriptor_count() as usize
}
unsafe fn read_from_buffer(
buffer: &[u8],
- fds: &[std::os::unix::io::RawFd],
+ fds: &[RawDescriptor],
) -> msg_socket::MsgResult<(Self, usize)> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
@@ -651,7 +650,8 @@
__offset += t.0.msg_size();
__fd_offset += t.1;
let a = t.0;
- let t = <RawFd>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
+ let t = <RawDescriptor>::read_from_buffer(
+ &buffer[__offset..], &fds[__fd_offset..])?;
__offset += t.0.msg_size();
__fd_offset += t.1;
let b = t.0;
@@ -664,7 +664,7 @@
fn write_to_buffer(
&self,
buffer: &mut [u8],
- fds: &mut [std::os::unix::io::RawFd],
+ fds: &mut [RawDescriptor],
) -> msg_socket::MsgResult<usize> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
@@ -700,21 +700,21 @@
let expected = quote! {
impl msg_socket::MsgOnSocket for MyMsg {
- fn uses_fd() -> bool {
- <u8>::uses_fd() || <u32>::uses_fd() || <File>::uses_fd()
+ fn uses_descriptor() -> bool {
+ <u8>::uses_descriptor() || <u32>::uses_descriptor() || <File>::uses_descriptor()
}
fn msg_size(&self) -> usize {
self.0.msg_size() as usize
+ self.1.msg_size() as usize + self.2.msg_size() as usize
}
- fn fd_count(&self) -> usize {
- self.0.fd_count() as usize
- + self.1.fd_count() as usize
- + self.2.fd_count() as usize
+ fn descriptor_count(&self) -> usize {
+ self.0.descriptor_count() as usize
+ + self.1.descriptor_count() as usize
+ + self.2.descriptor_count() as usize
}
unsafe fn read_from_buffer(
buffer: &[u8],
- fds: &[std::os::unix::io::RawFd],
+ fds: &[RawDescriptor],
) -> msg_socket::MsgResult<(Self, usize)> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
@@ -735,7 +735,7 @@
fn write_to_buffer(
&self,
buffer: &mut [u8],
- fds: &mut [std::os::unix::io::RawFd],
+ fds: &mut [RawDescriptor],
) -> msg_socket::MsgResult<usize> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
@@ -765,15 +765,17 @@
B,
C {
f0: u8,
- f1: RawFd,
+ f1: RawDescriptor,
},
}
};
let expected = quote! {
impl msg_socket::MsgOnSocket for MyMsg {
- fn uses_fd() -> bool {
- <u8>::uses_fd() || <u8>::uses_fd() || <RawFd>::uses_fd()
+ fn uses_descriptor() -> bool {
+ <u8>::uses_descriptor()
+ || <u8>::uses_descriptor()
+ || <RawDescriptor>::uses_descriptor()
}
fn msg_size(&self) -> usize {
1 + match self {
@@ -782,16 +784,16 @@
MyMsg::C { f0, f1 } => f0.msg_size() + f1.msg_size(),
}
}
- fn fd_count(&self) -> usize {
+ fn descriptor_count(&self) -> usize {
match self {
- MyMsg::A(enum_field0) => enum_field0.fd_count(),
+ MyMsg::A(enum_field0) => enum_field0.descriptor_count(),
MyMsg::B => 0,
- MyMsg::C { f0, f1 } => f0.fd_count() + f1.fd_count(),
+ MyMsg::C { f0, f1 } => f0.descriptor_count() + f1.descriptor_count(),
}
}
unsafe fn read_from_buffer(
buffer: &[u8],
- fds: &[std::os::unix::io::RawFd],
+ fds: &[RawDescriptor],
) -> msg_socket::MsgResult<(Self, usize)> {
let v = buffer
.get(0)
@@ -814,7 +816,7 @@
__offset += t.0.msg_size();
__fd_offset += t.1;
let f0 = t.0;
- let t = <RawFd>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
+ let t = <RawDescriptor>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
__offset += t.0.msg_size();
__fd_offset += t.1;
let f1 = t.0;
@@ -826,7 +828,7 @@
fn write_to_buffer(
&self,
buffer: &mut [u8],
- fds: &mut [std::os::unix::io::RawFd],
+ fds: &mut [RawDescriptor],
) -> msg_socket::MsgResult<usize> {
if buffer.is_empty() {
return Err(msg_socket::MsgError::WrongMsgBufferSize)
@@ -880,12 +882,12 @@
fn msg_size(&self) -> usize {
0
}
- fn fd_count(&self) -> usize {
+ fn descriptor_count(&self) -> usize {
0
}
unsafe fn read_from_buffer(
buffer: &[u8],
- fds: &[std::os::unix::io::RawFd],
+ fds: &[RawDescriptor],
) -> msg_socket::MsgResult<(Self, usize)> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
@@ -894,7 +896,7 @@
fn write_to_buffer(
&self,
buffer: &mut [u8],
- fds: &mut [std::os::unix::io::RawFd],
+ fds: &mut [RawDescriptor],
) -> msg_socket::MsgResult<usize> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
diff --git a/msg_socket/src/lib.rs b/msg_socket/src/lib.rs
index 0a9dc24..db3e1d0 100644
--- a/msg_socket/src/lib.rs
+++ b/msg_socket/src/lib.rs
@@ -3,11 +3,14 @@
// found in the LICENSE file.
mod msg_on_socket;
+mod serializable_descriptors;
-use base::{handle_eintr, net::UnixSeqpacket, Error as SysError, ScmSocket, UnsyncMarker};
+use base::{
+ handle_eintr, net::UnixSeqpacket, AsRawDescriptor, Error as SysError, RawDescriptor, ScmSocket,
+ UnsyncMarker,
+};
use std::io::{IoSlice, Result};
use std::marker::PhantomData;
-use std::os::unix::io::{AsRawFd, RawFd};
pub use crate::msg_on_socket::*;
pub use msg_on_socket_derive::*;
@@ -85,15 +88,15 @@
}
}
-impl<I: MsgOnSocket, O: MsgOnSocket> AsRawFd for MsgSocket<I, O> {
- fn as_raw_fd(&self) -> RawFd {
- self.sock.as_raw_fd()
+impl<I: MsgOnSocket, O: MsgOnSocket> AsRawDescriptor for MsgSocket<I, O> {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.sock.as_raw_descriptor()
}
}
-impl<I: MsgOnSocket, O: MsgOnSocket> AsRawFd for &MsgSocket<I, O> {
- fn as_raw_fd(&self) -> RawFd {
- self.sock.as_raw_fd()
+impl<I: MsgOnSocket, O: MsgOnSocket> AsRawDescriptor for &MsgSocket<I, O> {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.sock.as_raw_descriptor()
}
}
@@ -103,9 +106,9 @@
}
}
-impl<M: MsgOnSocket> AsRawFd for Sender<M> {
- fn as_raw_fd(&self) -> RawFd {
- self.sock.as_raw_fd()
+impl<M: MsgOnSocket> AsRawDescriptor for Sender<M> {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.sock.as_raw_descriptor()
}
}
@@ -115,9 +118,9 @@
}
}
-impl<M: MsgOnSocket> AsRawFd for Receiver<M> {
- fn as_raw_fd(&self) -> RawFd {
- self.sock.as_raw_fd()
+impl<M: MsgOnSocket> AsRawDescriptor for Receiver<M> {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.sock.as_raw_descriptor()
}
}
@@ -126,18 +129,18 @@
type M: MsgOnSocket;
fn send(&self, msg: &Self::M) -> MsgResult<()> {
let msg_size = msg.msg_size();
- let fd_size = msg.fd_count();
+ let descriptor_size = msg.descriptor_count();
let mut msg_buffer: Vec<u8> = vec![0; msg_size];
- let mut fd_buffer: Vec<RawFd> = vec![0; fd_size];
+ let mut descriptor_buffer: Vec<RawDescriptor> = vec![0; descriptor_size];
- let fd_size = msg.write_to_buffer(&mut msg_buffer, &mut fd_buffer)?;
+ let descriptor_size = msg.write_to_buffer(&mut msg_buffer, &mut descriptor_buffer)?;
let sock: &UnixSeqpacket = self.as_ref();
- if fd_size == 0 {
+ if descriptor_size == 0 {
handle_eintr!(sock.send(&msg_buffer))
.map_err(|e| MsgError::Send(SysError::new(e.raw_os_error().unwrap_or(0))))?;
} else {
let ioslice = IoSlice::new(&msg_buffer[..]);
- sock.send_with_fds(&[ioslice], &fd_buffer[0..fd_size])
+ sock.send_with_fds(&[ioslice], &descriptor_buffer[0..descriptor_size])
.map_err(MsgError::Send)?;
}
Ok(())
@@ -150,8 +153,8 @@
fn recv(&self) -> MsgResult<Self::M> {
let sock: &UnixSeqpacket = self.as_ref();
- let (msg_buffer, fd_buffer) = {
- if Self::M::uses_fd() {
+ let (msg_buffer, descriptor_buffer) = {
+ if Self::M::uses_descriptor() {
sock.recv_as_vec_with_fds()
.map_err(|e| MsgError::Recv(SysError::new(e.raw_os_error().unwrap_or(0))))?
} else {
@@ -178,9 +181,10 @@
}
// Safe because fd buffer is read from socket.
- let (v, read_fd_size) = unsafe { Self::M::read_from_buffer(&msg_buffer, &fd_buffer)? };
- if fd_buffer.len() != read_fd_size {
- return Err(MsgError::NotExpectFd);
+ let (v, read_descriptor_size) =
+ unsafe { Self::M::read_from_buffer(&msg_buffer, &descriptor_buffer)? };
+ if descriptor_buffer.len() != read_descriptor_size {
+ return Err(MsgError::NotExpectDescriptor);
}
Ok(v)
}
@@ -211,7 +215,7 @@
}
pub async fn next(&mut self) -> MsgResult<O> {
- let p = cros_async::new(self.inner).unwrap();
+ let p = cros_async::async_from(&self.inner.sock).unwrap();
p.wait_readable().await.unwrap();
self.inner.recv()
}
diff --git a/msg_socket/src/msg_on_socket.rs b/msg_socket/src/msg_on_socket.rs
index 38ccf3c..2b890b6 100644
--- a/msg_socket/src/msg_on_socket.rs
+++ b/msg_socket/src/msg_on_socket.rs
@@ -6,15 +6,11 @@
mod tuple;
use std::fmt::{self, Display};
-use std::fs::File;
use std::mem::{size_of, transmute_copy, MaybeUninit};
-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 std::sync::Arc;
-use base::{Error as SysError, Event};
+use base::{Error as SysError, RawDescriptor};
use data_model::*;
use slice::{slice_read_helper, slice_write_helper};
@@ -35,14 +31,14 @@
/// There was no data received when the socket `recv`-ed.
RecvZero,
/// There was no associated file descriptor received for a request that expected it.
- ExpectFd,
+ ExpectDescriptor,
/// There was some associated file descriptor received but not used when deserialize.
- NotExpectFd,
+ NotExpectDescriptor,
/// Failed to set flags on the file descriptor.
- SettingFdFlags(SysError),
+ SettingDescriptorFlags(SysError),
/// 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,
+ WrongDescriptorBufferSize,
/// 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,
@@ -65,10 +61,12 @@
expected, actual
),
RecvZero => write!(f, "received zero data"),
- ExpectFd => write!(f, "missing associated file descriptor for request"),
- NotExpectFd => write!(f, "unexpected file descriptor is unused"),
- SettingFdFlags(e) => write!(f, "failed setting flags on the message FD: {}", e),
- WrongFdBufferSize => write!(f, "fd buffer size too small"),
+ ExpectDescriptor => write!(f, "missing associated file descriptor for request"),
+ NotExpectDescriptor => write!(f, "unexpected file descriptor is unused"),
+ SettingDescriptorFlags(e) => {
+ write!(f, "failed setting flags on the message descriptor: {}", e)
+ }
+ WrongDescriptorBufferSize => write!(f, "descriptor buffer size too small"),
WrongMsgBufferSize => write!(f, "msg buffer size too small"),
}
}
@@ -81,16 +79,16 @@
///
/// e.g.
/// ```
-/// use std::os::unix::io::RawFd;
+/// use base::RawDescriptor;
/// enum Message {
/// VariantA(u8),
-/// VariantB(u32, RawFd),
+/// VariantB(u32, RawDescriptor),
/// 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 B, we need 4 bytes and 1 RawDescriptor 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.
@@ -99,8 +97,8 @@
/// 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 {
- // `true` if this structure can potentially serialize fds.
- fn uses_fd() -> bool {
+ // `true` if this structure can potentially serialize descriptors.
+ fn uses_descriptor() -> bool {
false
}
@@ -114,9 +112,9 @@
Self::fixed_size().unwrap()
}
- /// Number of FDs in this message. This must be overridden if `uses_fd()` returns true.
- fn fd_count(&self) -> usize {
- assert!(!Self::uses_fd());
+ /// Number of FDs in this message. This must be overridden if `uses_descriptor()` returns true.
+ fn descriptor_count(&self) -> usize {
+ assert!(!Self::uses_descriptor());
0
}
/// Returns (self, fd read count).
@@ -125,29 +123,29 @@
/// 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)>;
+ unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawDescriptor]) -> MsgResult<(Self, usize)>;
/// Serialize self to buffers.
- fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize>;
+ fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawDescriptor]) -> MsgResult<usize>;
}
impl MsgOnSocket for SysError {
fn fixed_size() -> Option<usize> {
Some(size_of::<u32>())
}
- unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+ unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawDescriptor]) -> 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> {
+ fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawDescriptor]) -> MsgResult<usize> {
let v = self.errno() as u32;
v.write_to_buffer(buffer, fds)
}
}
impl<T: MsgOnSocket> MsgOnSocket for Option<T> {
- fn uses_fd() -> bool {
- T::uses_fd()
+ fn uses_descriptor() -> bool {
+ T::uses_descriptor()
}
fn msg_size(&self) -> usize {
@@ -157,14 +155,14 @@
}
}
- fn fd_count(&self) -> usize {
+ fn descriptor_count(&self) -> usize {
match self {
- Some(v) => v.fd_count(),
+ Some(v) => v.descriptor_count(),
None => 0,
}
}
- unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+ unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawDescriptor]) -> MsgResult<(Self, usize)> {
match buffer[0] {
0 => Ok((None, 0)),
1 => {
@@ -175,7 +173,7 @@
}
}
- fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
+ fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawDescriptor]) -> MsgResult<usize> {
match self {
None => {
buffer[0] = 0;
@@ -190,23 +188,23 @@
}
impl<T: MsgOnSocket> MsgOnSocket for Arc<T> {
- fn uses_fd() -> bool {
- T::uses_fd()
+ fn uses_descriptor() -> bool {
+ T::uses_descriptor()
}
fn msg_size(&self) -> usize {
(**self).msg_size()
}
- fn fd_count(&self) -> usize {
- (**self).fd_count()
+ fn descriptor_count(&self) -> usize {
+ (**self).descriptor_count()
}
- unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+ unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawDescriptor]) -> MsgResult<(Self, usize)> {
T::read_from_buffer(buffer, fds).map(|(v, count)| (Arc::new(v), count))
}
- fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
+ fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawDescriptor]) -> MsgResult<usize> {
(**self).write_to_buffer(buffer, fds)
}
}
@@ -216,59 +214,21 @@
Some(0)
}
- unsafe fn read_from_buffer(_buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+ unsafe fn read_from_buffer(_buffer: &[u8], _fds: &[RawDescriptor]) -> MsgResult<(Self, usize)> {
Ok(((), 0))
}
- fn write_to_buffer(&self, _buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
+ fn write_to_buffer(&self, _buffer: &mut [u8], _fds: &mut [RawDescriptor]) -> MsgResult<usize> {
Ok(0)
}
}
-macro_rules! rawfd_impl {
- ($type:ident) => {
- impl MsgOnSocket for $type {
- fn uses_fd() -> bool {
- true
- }
- fn msg_size(&self) -> usize {
- 0
- }
- fn fd_count(&self) -> 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]), 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.as_raw_fd();
- Ok(1)
- }
- }
- };
-}
-
-rawfd_impl!(Event);
-rawfd_impl!(File);
-rawfd_impl!(UnixStream);
-rawfd_impl!(TcpStream);
-rawfd_impl!(TcpListener);
-rawfd_impl!(UdpSocket);
-rawfd_impl!(UnixListener);
-rawfd_impl!(UnixDatagram);
-
// usize could be different sizes on different targets. We always use u64.
impl MsgOnSocket for usize {
fn msg_size(&self) -> usize {
size_of::<u64>()
}
- unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+ unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawDescriptor]) -> MsgResult<(Self, usize)> {
if buffer.len() < size_of::<u64>() {
return Err(MsgError::WrongMsgBufferSize);
}
@@ -276,7 +236,7 @@
Ok((t as usize, 0))
}
- fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
+ fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawDescriptor]) -> MsgResult<usize> {
if buffer.len() < size_of::<u64>() {
return Err(MsgError::WrongMsgBufferSize);
}
@@ -291,7 +251,7 @@
fn msg_size(&self) -> usize {
size_of::<u8>()
}
- unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+ unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawDescriptor]) -> MsgResult<(Self, usize)> {
if buffer.len() < size_of::<u8>() {
return Err(MsgError::WrongMsgBufferSize);
}
@@ -302,7 +262,7 @@
_ => Err(MsgError::InvalidType),
}
}
- fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
+ fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawDescriptor]) -> MsgResult<usize> {
if buffer.len() < size_of::<u8>() {
return Err(MsgError::WrongMsgBufferSize);
}
@@ -318,7 +278,10 @@
Some(size_of::<$native_type>())
}
- unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+ unsafe fn read_from_buffer(
+ buffer: &[u8],
+ _fds: &[RawDescriptor],
+ ) -> MsgResult<(Self, usize)> {
if buffer.len() < size_of::<$native_type>() {
return Err(MsgError::WrongMsgBufferSize);
}
@@ -326,7 +289,11 @@
Ok((t.into(), 0))
}
- fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
+ fn write_to_buffer(
+ &self,
+ buffer: &mut [u8],
+ _fds: &mut [RawDescriptor],
+ ) -> MsgResult<usize> {
if buffer.len() < size_of::<$native_type>() {
return Err(MsgError::WrongMsgBufferSize);
}
@@ -348,7 +315,7 @@
le_impl!(Le64, u64);
fn simple_read<T: MsgOnSocket>(buffer: &[u8], offset: &mut usize) -> MsgResult<T> {
- assert!(!T::uses_fd());
+ assert!(!T::uses_descriptor());
// Safety for T::read_from_buffer depends on the given FDs being valid, but we pass no FDs.
let (v, _) = unsafe { T::read_from_buffer(&buffer[*offset..], &[])? };
*offset += v.msg_size();
@@ -356,7 +323,7 @@
}
fn simple_write<T: MsgOnSocket>(v: T, buffer: &mut [u8], offset: &mut usize) -> MsgResult<()> {
- assert!(!T::uses_fd());
+ assert!(!T::uses_descriptor());
v.write_to_buffer(&mut buffer[*offset..], &mut [])?;
*offset += v.msg_size();
Ok(())
@@ -380,8 +347,8 @@
($N:expr, $t: ident $($ts:ident)*)
=> {
impl<T: MsgOnSocket + Clone> MsgOnSocket for [T; $N] {
- fn uses_fd() -> bool {
- T::uses_fd()
+ fn uses_descriptor() -> bool {
+ T::uses_descriptor()
}
fn fixed_size() -> Option<usize> {
@@ -395,15 +362,16 @@
}
}
- fn fd_count(&self) -> usize {
- if T::uses_fd() {
- self.iter().map(|i| i.fd_count()).sum()
+ fn descriptor_count(&self) -> usize {
+ if T::uses_descriptor() {
+ self.iter().map(|i| i.descriptor_count()).sum()
} else {
0
}
}
- unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+ unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawDescriptor])
+ -> MsgResult<(Self, usize)> {
// Taken from the canonical example of initializing an array, the `assume_init` can
// be assumed safe because the array elements (`MaybeUninit<T>` in this case)
// themselves don't require initializing.
@@ -425,7 +393,7 @@
fn write_to_buffer(
&self,
buffer: &mut [u8],
- fds: &mut [RawFd],
+ fds: &mut [RawDescriptor],
) -> MsgResult<usize> {
slice_write_helper(self, buffer, fds)
}
diff --git a/msg_socket/src/msg_on_socket/slice.rs b/msg_socket/src/msg_on_socket/slice.rs
index 7b6ef28..05df5e1 100644
--- a/msg_socket/src/msg_on_socket/slice.rs
+++ b/msg_socket/src/msg_on_socket/slice.rs
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+use base::RawDescriptor;
use std::mem::{size_of, ManuallyDrop, MaybeUninit};
-use std::os::unix::io::RawFd;
use std::ptr::drop_in_place;
use crate::{MsgOnSocket, MsgResult};
@@ -17,7 +17,7 @@
/// requirements that the `msgs` are only used on success of this function
pub unsafe fn slice_read_helper<T: MsgOnSocket>(
buffer: &[u8],
- fds: &[RawFd],
+ fds: &[RawDescriptor],
msgs: &mut [MaybeUninit<T>],
) -> MsgResult<usize> {
let mut offset = 0usize;
@@ -64,7 +64,7 @@
pub fn slice_write_helper<T: MsgOnSocket>(
msgs: &[T],
buffer: &mut [u8],
- fds: &mut [RawFd],
+ fds: &mut [RawDescriptor],
) -> MsgResult<usize> {
let mut offset = 0usize;
let mut fd_offset = 0usize;
@@ -86,8 +86,8 @@
}
impl<T: MsgOnSocket> MsgOnSocket for Vec<T> {
- fn uses_fd() -> bool {
- T::uses_fd()
+ fn uses_descriptor() -> bool {
+ T::uses_descriptor()
}
fn fixed_size() -> Option<usize> {
@@ -102,15 +102,15 @@
size_of::<u64>() + vec_size
}
- fn fd_count(&self) -> usize {
- if T::uses_fd() {
- self.iter().map(|i| i.fd_count()).sum()
+ fn descriptor_count(&self) -> usize {
+ if T::uses_descriptor() {
+ self.iter().map(|i| i.descriptor_count()).sum()
} else {
0
}
}
- unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+ unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawDescriptor]) -> MsgResult<(Self, usize)> {
let mut offset = 0;
let len = simple_read::<u64>(buffer, &mut offset)? as usize;
let mut msgs: Vec<MaybeUninit<T>> = Vec::with_capacity(len);
@@ -123,7 +123,7 @@
))
}
- fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
+ fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawDescriptor]) -> MsgResult<usize> {
let mut offset = 0;
simple_write(self.len() as u64, buffer, &mut offset)?;
slice_write_helper(self, &mut buffer[offset..], fds)
diff --git a/msg_socket/src/msg_on_socket/tuple.rs b/msg_socket/src/msg_on_socket/tuple.rs
index f960ce5..90784bf 100644
--- a/msg_socket/src/msg_on_socket/tuple.rs
+++ b/msg_socket/src/msg_on_socket/tuple.rs
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+use base::RawDescriptor;
use std::mem::size_of;
-use std::os::unix::io::RawFd;
use crate::{MsgOnSocket, MsgResult};
@@ -16,7 +16,7 @@
unsafe fn tuple_read_helper<T: MsgOnSocket>(
buffer: &[u8],
- fds: &[RawFd],
+ fds: &[RawDescriptor],
buffer_index: &mut usize,
fd_index: &mut usize,
) -> MsgResult<T> {
@@ -36,7 +36,7 @@
fn tuple_write_helper<T: MsgOnSocket>(
v: &T,
buffer: &mut [u8],
- fds: &mut [RawFd],
+ fds: &mut [RawDescriptor],
buffer_index: &mut usize,
fd_index: &mut usize,
) -> MsgResult<()> {
@@ -59,12 +59,12 @@
($t: ident) => {
#[allow(unused_variables, non_snake_case)]
impl<$t: MsgOnSocket> MsgOnSocket for ($t,) {
- fn uses_fd() -> bool {
- $t::uses_fd()
+ fn uses_descriptor() -> bool {
+ $t::uses_descriptor()
}
- fn fd_count(&self) -> usize {
- self.0.fd_count()
+ fn descriptor_count(&self) -> usize {
+ self.0.descriptor_count()
}
fn fixed_size() -> Option<usize> {
@@ -75,7 +75,7 @@
self.0.msg_size()
}
- unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+ unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawDescriptor]) -> MsgResult<(Self, usize)> {
let (t, s) = $t::read_from_buffer(buffer, fds)?;
Ok(((t,), s))
}
@@ -83,7 +83,7 @@
fn write_to_buffer(
&self,
buffer: &mut [u8],
- fds: &mut [RawFd],
+ fds: &mut [RawDescriptor],
) -> MsgResult<usize> {
self.0.write_to_buffer(buffer, fds)
}
@@ -92,16 +92,16 @@
($t: ident, $($ts:ident),*) => {
#[allow(unused_variables, non_snake_case)]
impl<$t: MsgOnSocket $(, $ts: MsgOnSocket)*> MsgOnSocket for ($t$(, $ts)*) {
- fn uses_fd() -> bool {
- $t::uses_fd() $(|| $ts::uses_fd())*
+ fn uses_descriptor() -> bool {
+ $t::uses_descriptor() $(|| $ts::uses_descriptor())*
}
- fn fd_count(&self) -> usize {
- if Self::uses_fd() {
+ fn descriptor_count(&self) -> usize {
+ if Self::uses_descriptor() {
return 0;
}
let ($t $(,$ts)*) = self;
- $t.fd_count() $(+ $ts.fd_count())*
+ $t.descriptor_count() $(+ $ts.descriptor_count())*
}
fn fixed_size() -> Option<usize> {
@@ -118,7 +118,7 @@
tuple_size_helper($t) $(+ tuple_size_helper($ts))*
}
- unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+ unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawDescriptor]) -> MsgResult<(Self, usize)> {
let mut buffer_index = 0;
let mut fd_index = 0;
Ok((
@@ -137,7 +137,7 @@
fn write_to_buffer(
&self,
buffer: &mut [u8],
- fds: &mut [RawFd],
+ fds: &mut [RawDescriptor],
) -> MsgResult<usize> {
let mut buffer_index = 0;
let mut fd_index = 0;
diff --git a/msg_socket/src/serializable_descriptors.rs b/msg_socket/src/serializable_descriptors.rs
new file mode 100644
index 0000000..21ce84b
--- /dev/null
+++ b/msg_socket/src/serializable_descriptors.rs
@@ -0,0 +1,85 @@
+// Copyright 2020 The Chromium OS 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::msg_on_socket::{MsgError, MsgOnSocket, MsgResult};
+use base::{AsRawDescriptor, Event, FromRawDescriptor, RawDescriptor};
+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};
+
+macro_rules! rawdescriptor_impl {
+ ($type:ident) => {
+ impl MsgOnSocket for $type {
+ fn uses_descriptor() -> bool {
+ true
+ }
+ fn msg_size(&self) -> usize {
+ 0
+ }
+ fn descriptor_count(&self) -> usize {
+ 1
+ }
+ unsafe fn read_from_buffer(
+ _buffer: &[u8],
+ descriptors: &[RawDescriptor],
+ ) -> MsgResult<(Self, usize)> {
+ if descriptors.len() < 1 {
+ return Err(MsgError::ExpectDescriptor);
+ }
+ Ok(($type::from_raw_descriptor(descriptors[0]), 1))
+ }
+ fn write_to_buffer(
+ &self,
+ _buffer: &mut [u8],
+ descriptors: &mut [RawDescriptor],
+ ) -> MsgResult<usize> {
+ if descriptors.is_empty() {
+ return Err(MsgError::WrongDescriptorBufferSize);
+ }
+ descriptors[0] = self.as_raw_descriptor();
+ Ok(1)
+ }
+ }
+ };
+}
+
+rawdescriptor_impl!(Event);
+rawdescriptor_impl!(File);
+
+macro_rules! rawfd_impl {
+ ($type:ident) => {
+ impl MsgOnSocket for $type {
+ fn uses_descriptor() -> bool {
+ true
+ }
+ fn msg_size(&self) -> usize {
+ 0
+ }
+ fn descriptor_count(&self) -> usize {
+ 1
+ }
+ unsafe fn read_from_buffer(_buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+ if fds.len() < 1 {
+ return Err(MsgError::ExpectDescriptor);
+ }
+ Ok(($type::from_raw_fd(fds[0]), 1))
+ }
+ fn write_to_buffer(&self, _buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
+ if fds.is_empty() {
+ return Err(MsgError::WrongDescriptorBufferSize);
+ }
+ fds[0] = self.as_raw_fd();
+ Ok(1)
+ }
+ }
+ };
+}
+
+rawfd_impl!(UnixStream);
+rawfd_impl!(TcpStream);
+rawfd_impl!(TcpListener);
+rawfd_impl!(UdpSocket);
+rawfd_impl!(UnixListener);
+rawfd_impl!(UnixDatagram);
diff --git a/msg_socket/tests/enum.rs b/msg_socket/tests/enum.rs
index 526793b..7f5998b 100644
--- a/msg_socket/tests/enum.rs
+++ b/msg_socket/tests/enum.rs
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use base::Event;
+use base::{Event, RawDescriptor};
use msg_socket::*;
diff --git a/msg_socket/tests/struct.rs b/msg_socket/tests/struct.rs
index 8c97e57..8e3c93f 100644
--- a/msg_socket/tests/struct.rs
+++ b/msg_socket/tests/struct.rs
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use base::Event;
+use base::{Event, RawDescriptor};
use msg_socket::*;
diff --git a/msg_socket/tests/tuple.rs b/msg_socket/tests/tuple.rs
index b7e0056..ae00813 100644
--- a/msg_socket/tests/tuple.rs
+++ b/msg_socket/tests/tuple.rs
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use base::Event;
+use base::{Event, RawDescriptor};
use msg_socket::*;
#[derive(MsgOnSocket)]
diff --git a/net_sys/Android.bp b/net_sys/Android.bp
index aa73582..c2d8b4a 100644
--- a/net_sys/Android.bp
+++ b/net_sys/Android.bp
@@ -38,14 +38,31 @@
// dependent_library ["feature_list"]
// ../assertions/src/lib.rs
// ../base/src/lib.rs
+// ../cros_async/src/lib.rs
// ../data_model/src/lib.rs
+// ../io_uring/src/lib.rs
// ../sync/src/lib.rs
// ../sys_util/poll_token_derive/poll_token_derive.rs
// ../sys_util/src/lib.rs
// ../syscall_defines/src/lib.rs
// ../tempfile/src/lib.rs
+// async-trait-0.1.42
+// futures-0.3.8 "alloc"
+// futures-channel-0.3.8 "alloc,futures-sink,sink"
+// futures-core-0.3.8 "alloc"
+// futures-io-0.3.8
+// futures-sink-0.3.8 "alloc"
+// futures-task-0.3.8 "alloc"
+// futures-util-0.3.8 "alloc,futures-sink,sink"
// libc-0.2.80 "default,std"
+// paste-1.0.3
+// pin-project-1.0.2
+// pin-project-internal-1.0.2
+// pin-utils-0.1.0
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// slab-0.4.2
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// thiserror-1.0.22
+// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/net_util/Android.bp b/net_util/Android.bp
index e95c373..66a1a8e 100644
--- a/net_util/Android.bp
+++ b/net_util/Android.bp
@@ -44,15 +44,32 @@
// dependent_library ["feature_list"]
// ../assertions/src/lib.rs
// ../base/src/lib.rs
+// ../cros_async/src/lib.rs
// ../data_model/src/lib.rs
+// ../io_uring/src/lib.rs
// ../net_sys/src/lib.rs
// ../sync/src/lib.rs
// ../sys_util/poll_token_derive/poll_token_derive.rs
// ../sys_util/src/lib.rs
// ../syscall_defines/src/lib.rs
// ../tempfile/src/lib.rs
+// async-trait-0.1.42
+// futures-0.3.8 "alloc"
+// futures-channel-0.3.8 "alloc,futures-sink,sink"
+// futures-core-0.3.8 "alloc"
+// futures-io-0.3.8
+// futures-sink-0.3.8 "alloc"
+// futures-task-0.3.8 "alloc"
+// futures-util-0.3.8 "alloc,futures-sink,sink"
// libc-0.2.80 "default,std"
+// paste-1.0.3
+// pin-project-1.0.2
+// pin-project-internal-1.0.2
+// pin-utils-0.1.0
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// slab-0.4.2
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// thiserror-1.0.22
+// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/net_util/src/lib.rs b/net_util/src/lib.rs
index 483a1a0..bb17cb4 100644
--- a/net_util/src/lib.rs
+++ b/net_util/src/lib.rs
@@ -16,7 +16,10 @@
use base::Error as SysError;
use base::FileReadWriteVolatile;
-use base::{ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val, volatile_impl, IoctlNr};
+use base::{
+ ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val, volatile_impl, AsRawDescriptor,
+ FromRawDescriptor, IoctlNr, RawDescriptor,
+};
#[derive(Debug)]
pub enum Error {
@@ -171,8 +174,8 @@
}
impl Tap {
- pub unsafe fn from_raw_fd(fd: RawFd) -> Result<Tap> {
- let tap_file = File::from_raw_fd(fd);
+ pub unsafe fn from_raw_descriptor(fd: RawDescriptor) -> Result<Tap> {
+ let tap_file = File::from_raw_descriptor(fd);
// Get the interface name since we will need it for some ioctls.
let mut ifreq: net_sys::ifreq = Default::default();
@@ -203,7 +206,7 @@
}
// We just checked that the fd is valid.
- let tuntap = unsafe { File::from_raw_fd(fd) };
+ let tuntap = unsafe { File::from_raw_descriptor(fd) };
// 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(), ifreq) };
@@ -226,7 +229,7 @@
}
}
-pub trait TapT: FileReadWriteVolatile + Read + Write + AsRawFd + Send + Sized {
+pub trait TapT: FileReadWriteVolatile + Read + Write + AsRawDescriptor + 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.
@@ -514,7 +517,13 @@
impl AsRawFd for Tap {
fn as_raw_fd(&self) -> RawFd {
- self.tap_file.as_raw_fd()
+ self.tap_file.as_raw_descriptor()
+ }
+}
+
+impl AsRawDescriptor for Tap {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.tap_file.as_raw_descriptor()
}
}
@@ -617,7 +626,13 @@
impl AsRawFd for FakeTap {
fn as_raw_fd(&self) -> RawFd {
- self.tap_file.as_raw_fd()
+ self.tap_file.as_raw_descriptor()
+ }
+ }
+
+ impl AsRawDescriptor for FakeTap {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.tap_file.as_raw_descriptor()
}
}
volatile_impl!(FakeTap);
diff --git a/resources/Android.bp b/resources/Android.bp
index 037c1c3..416210c 100644
--- a/resources/Android.bp
+++ b/resources/Android.bp
@@ -53,6 +53,7 @@
// ../syscall_defines/src/lib.rs
// ../tempfile/src/lib.rs
// async-trait-0.1.42
+// base-0.1.0
// futures-0.3.8 "alloc,async-await,default,executor,futures-executor,std"
// futures-channel-0.3.8 "alloc,futures-sink,sink,std"
// futures-core-0.3.8 "alloc,std"
@@ -74,7 +75,7 @@
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// thiserror-1.0.22
// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/resources/src/gpu_allocator.rs b/resources/src/gpu_allocator.rs
index 05ff2ec..70c0752 100644
--- a/resources/src/gpu_allocator.rs
+++ b/resources/src/gpu_allocator.rs
@@ -5,6 +5,7 @@
use std::fmt::Debug;
use std::fs::File;
+use base::RawDescriptor;
#[cfg(feature = "wl-dmabuf")]
use libc::EINVAL;
diff --git a/resources/src/lib.rs b/resources/src/lib.rs
index 71a4d2e..97943d0 100644
--- a/resources/src/lib.rs
+++ b/resources/src/lib.rs
@@ -10,6 +10,7 @@
extern crate libc;
extern crate msg_socket;
+use base::RawDescriptor;
use msg_socket::MsgOnSocket;
use std::fmt::Display;
diff --git a/seccomp/aarch64/9p_device.policy b/seccomp/aarch64/9p_device.policy
index dcf6ffd..27c7908 100644
--- a/seccomp/aarch64/9p_device.policy
+++ b/seccomp/aarch64/9p_device.policy
@@ -6,11 +6,13 @@
@include /usr/share/policy/crosvm/common_device.policy
+fcntl: 1
pread64: 1
pwrite64: 1
statx: 1
fstat: 1
ioctl: arg1 == FIOCLEX
+lseek: 1
getdents64: 1
fdatasync: 1
fsync: 1
@@ -22,5 +24,5 @@
utimensat: 1
ftruncate: 1
fchown: arg1 == 0xffffffff && arg2 == 0xffffffff
-statfs: 1
+fstatfs: 1
newfstatat: 1
diff --git a/seccomp/aarch64/battery.policy b/seccomp/aarch64/battery.policy
new file mode 100644
index 0000000..a4fb9fc
--- /dev/null
+++ b/seccomp/aarch64/battery.policy
@@ -0,0 +1,5 @@
+# Copyright 2020 The Chromium OS 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/9p_device.policy b/seccomp/arm/9p_device.policy
index 1c26079..95d0b32 100644
--- a/seccomp/arm/9p_device.policy
+++ b/seccomp/arm/9p_device.policy
@@ -4,26 +4,27 @@
@include /usr/share/policy/crosvm/common_device.policy
+fcntl64: 1
pread64: 1
pwrite64: 1
-lstat64: 1
stat64: 1
statx: 1
fstat64: 1
ioctl: arg1 == FIOCLEX
+_llseek: 1
getdents64: 1
fdatasync: 1
fsync: 1
-mkdir: 1
+mkdirat: 1
open: 1
openat: 1
rmdir: 1
-rename: 1
-link: 1
-unlink: 1
+renameat: 1
+linkat: 1
+unlinkat: 1
socket: arg0 == AF_UNIX
utimensat: 1
ftruncate64: 1
fchown: arg1 == 0xffffffff && arg2 == 0xffffffff
-statfs64: 1
+fstatfs64: 1
fstatat64: 1
diff --git a/seccomp/arm/battery.policy b/seccomp/arm/battery.policy
new file mode 100644
index 0000000..a4fb9fc
--- /dev/null
+++ b/seccomp/arm/battery.policy
@@ -0,0 +1,5 @@
+# Copyright 2020 The Chromium OS 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/9p_device.policy b/seccomp/x86_64/9p_device.policy
index 114ea11..6f14c0a 100644
--- a/seccomp/x86_64/9p_device.policy
+++ b/seccomp/x86_64/9p_device.policy
@@ -7,23 +7,24 @@
@include /usr/share/policy/crosvm/common_device.policy
+fcntl: 1
pwrite64: 1
stat: 1
statx: 1
-lstat: 1
fstat: 1
ioctl: arg1 == FIOCLEX
-link: 1
-unlink: 1
-rename: 1
+linkat: 1
+unlinkat: 1
+renameat: 1
pread64: 1
-getdents: 1
-mkdir: 1
+lseek: 1
+getdents64: 1
+mkdirat: 1
rmdir: 1
fsync: 1
fdatasync: 1
utimensat: 1
ftruncate: 1
fchown: arg1 == 0xffffffff && arg2 == 0xffffffff
-statfs: 1
+fstatfs: 1
newfstatat: 1
diff --git a/seccomp/x86_64/battery.policy b/seccomp/x86_64/battery.policy
new file mode 100644
index 0000000..a4fb9fc
--- /dev/null
+++ b/seccomp/x86_64/battery.policy
@@ -0,0 +1,5 @@
+# Copyright 2020 The Chromium OS 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/src/crosvm.rs b/src/crosvm.rs
index 832257a..0260edb 100644
--- a/src/crosvm.rs
+++ b/src/crosvm.rs
@@ -6,7 +6,10 @@
//! configs.
pub mod argument;
-pub mod linux;
+#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+pub mod gdb;
+#[path = "linux.rs"]
+pub mod platform;
#[cfg(feature = "plugin")]
pub mod plugin;
@@ -23,6 +26,7 @@
#[cfg(feature = "audio")]
use devices::Ac97Parameters;
use libc::{getegid, geteuid};
+use vm_control::BatteryType;
static SECCOMP_POLICY_DIR: &str = "/usr/share/policy/crosvm";
@@ -142,7 +146,8 @@
pub kind: SharedDirKind,
pub uid_map: String,
pub gid_map: String,
- pub cfg: passthrough::Config,
+ pub fs_cfg: passthrough::Config,
+ pub p9_cfg: p9::Config,
}
impl Default for SharedDir {
@@ -153,7 +158,8 @@
kind: Default::default(),
uid_map: format!("0 {} 1", unsafe { geteuid() }),
gid_map: format!("0 {} 1", unsafe { getegid() }),
- cfg: Default::default(),
+ fs_cfg: Default::default(),
+ p9_cfg: Default::default(),
}
}
}
@@ -210,6 +216,9 @@
pub video_enc: bool,
pub acpi_tables: Vec<PathBuf>,
pub protected_vm: bool,
+ pub battery_type: Option<BatteryType>,
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ pub gdb: Option<u32>,
}
impl Default for Config {
@@ -265,6 +274,9 @@
video_enc: false,
acpi_tables: Vec::new(),
protected_vm: false,
+ battery_type: None,
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ gdb: None,
}
}
}
diff --git a/src/gdb.rs b/src/gdb.rs
new file mode 100644
index 0000000..65626f5
--- /dev/null
+++ b/src/gdb.rs
@@ -0,0 +1,343 @@
+// Copyright 2020 The Chromium OS 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::net::TcpListener;
+use std::sync::mpsc;
+use std::time::Duration;
+
+use base::{error, info};
+use msg_socket::{MsgReceiver, MsgSender};
+use sync::Mutex;
+use vm_control::{
+ VcpuControl, VcpuDebug, VcpuDebugStatus, VcpuDebugStatusMessage, VmControlRequestSocket,
+ VmRequest, VmResponse,
+};
+use vm_memory::GuestAddress;
+
+#[cfg(target_arch = "x86_64")]
+use gdbstub::arch::x86::X86_64_SSE as GdbArch;
+use gdbstub::arch::Arch;
+use gdbstub::target::ext::base::singlethread::{ResumeAction, SingleThreadOps, StopReason};
+use gdbstub::target::ext::base::BaseOps;
+use gdbstub::target::ext::breakpoints::{HwBreakpoint, HwBreakpointOps};
+use gdbstub::target::TargetError::NonFatal;
+use gdbstub::target::{Target, TargetResult};
+use gdbstub::Connection;
+use remain::sorted;
+use thiserror::Error as ThisError;
+
+#[cfg(target_arch = "x86_64")]
+type ArchUsize = u64;
+
+pub fn gdb_thread(mut gdbstub: GdbStub, port: u32) {
+ let addr = format!("0.0.0.0:{}", port);
+ let listener = match TcpListener::bind(addr.clone()) {
+ Ok(s) => s,
+ Err(e) => {
+ error!("Failed to create a TCP listener: {}", e);
+ return;
+ }
+ };
+ info!("Waiting for a GDB connection on {:?}...", addr);
+
+ let (stream, addr) = match listener.accept() {
+ Ok(v) => v,
+ Err(e) => {
+ error!("Failed to accept a connection from GDB: {}", e);
+ return;
+ }
+ };
+ info!("GDB connected from {}", addr);
+
+ let connection: Box<dyn Connection<Error = std::io::Error>> = Box::new(stream);
+ let mut gdb = gdbstub::GdbStub::new(connection);
+
+ match gdb.run(&mut gdbstub) {
+ Ok(reason) => {
+ info!("GDB session closed: {:?}", reason);
+ }
+ Err(e) => {
+ error!("error occurred in GDB session: {}", e);
+ }
+ }
+
+ // Resume the VM when GDB session is disconnected.
+ if let Err(e) = gdbstub.vm_request(VmRequest::Resume) {
+ error!("Failed to resume the VM after GDB disconnected: {}", e);
+ }
+}
+
+#[sorted]
+#[derive(ThisError, Debug)]
+enum Error {
+ /// Got an unexpected VM response.
+ #[error("Got an unexpected VM response: {0}")]
+ UnexpectedVmResponse(VmResponse),
+ /// Failed to send a vCPU request.
+ #[error("failed to send a vCPU request: {0}")]
+ VcpuRequest(mpsc::SendError<VcpuControl>),
+ /// Failed to receive a vCPU response.
+ #[error("failed to receive a vCPU response: {0}")]
+ VcpuResponse(mpsc::RecvTimeoutError),
+ /// Failed to send a VM request.
+ #[error("failed to send a VM request: {0}")]
+ VmRequest(msg_socket::MsgError),
+ /// Failed to receive a VM request.
+ #[error("failed to receive a VM response: {0}")]
+ VmResponse(msg_socket::MsgError),
+}
+type GdbResult<T> = std::result::Result<T, Error>;
+
+pub struct GdbStub {
+ vm_socket: Mutex<VmControlRequestSocket>,
+ vcpu_com: Vec<mpsc::Sender<VcpuControl>>,
+ from_vcpu: mpsc::Receiver<VcpuDebugStatusMessage>,
+
+ hw_breakpoints: Vec<GuestAddress>,
+}
+
+impl GdbStub {
+ pub fn new(
+ vm_socket: VmControlRequestSocket,
+ vcpu_com: Vec<mpsc::Sender<VcpuControl>>,
+ from_vcpu: mpsc::Receiver<VcpuDebugStatusMessage>,
+ ) -> Self {
+ GdbStub {
+ vm_socket: Mutex::new(vm_socket),
+ vcpu_com,
+ from_vcpu,
+ hw_breakpoints: Default::default(),
+ }
+ }
+
+ fn vcpu_request(&self, request: VcpuControl) -> GdbResult<VcpuDebugStatus> {
+ // We use the only one vCPU when GDB is enabled.
+ self.vcpu_com[0].send(request).map_err(Error::VcpuRequest)?;
+
+ match self.from_vcpu.recv_timeout(Duration::from_millis(500)) {
+ Ok(msg) => Ok(msg.msg),
+ Err(e) => Err(Error::VcpuResponse(e)),
+ }
+ }
+
+ fn vm_request(&self, request: VmRequest) -> GdbResult<()> {
+ let vm_socket = self.vm_socket.lock();
+ vm_socket.send(&request).map_err(Error::VmRequest)?;
+ match vm_socket.recv() {
+ Ok(VmResponse::Ok) => Ok(()),
+ Ok(r) => Err(Error::UnexpectedVmResponse(r)),
+ Err(e) => Err(Error::VmResponse(e)),
+ }
+ }
+}
+
+impl Target for GdbStub {
+ // TODO(keiichiw): Replace `()` with `X86_64CoreRegId` when we update the gdbstub crate.
+ type Arch = GdbArch<()>;
+ type Error = &'static str;
+
+ fn base_ops(&mut self) -> BaseOps<Self::Arch, Self::Error> {
+ BaseOps::SingleThread(self)
+ }
+
+ // TODO(keiichiw): sw_breakpoint, hw_watchpoint, extended_mode, monitor_cmd, section_offsets
+ fn hw_breakpoint(&mut self) -> Option<HwBreakpointOps<Self>> {
+ Some(self)
+ }
+}
+
+impl SingleThreadOps for GdbStub {
+ fn resume(
+ &mut self,
+ action: ResumeAction,
+ check_gdb_interrupt: &mut dyn FnMut() -> bool,
+ ) -> Result<StopReason<ArchUsize>, Self::Error> {
+ let single_step = ResumeAction::Step == action;
+
+ if single_step {
+ match self.vcpu_request(VcpuControl::Debug(VcpuDebug::EnableSinglestep)) {
+ Ok(VcpuDebugStatus::CommandComplete) => {}
+ Ok(s) => {
+ error!("Unexpected vCPU response for EnableSinglestep: {:?}", s);
+ return Err("Unexpected vCPU response for EnableSinglestep");
+ }
+ Err(e) => {
+ error!("Failed to request EnableSinglestep: {}", e);
+ return Err("Failed to request EnableSinglestep");
+ }
+ };
+ }
+
+ self.vm_request(VmRequest::Resume).map_err(|e| {
+ error!("Failed to resume the target: {}", e);
+ "Failed to resume the target"
+ })?;
+
+ // Polling
+ loop {
+ match self
+ .from_vcpu
+ .recv_timeout(std::time::Duration::from_millis(100))
+ {
+ Ok(msg) => match msg.msg {
+ VcpuDebugStatus::HitBreakPoint => {
+ if single_step {
+ return Ok(StopReason::DoneStep);
+ } else {
+ return Ok(StopReason::HwBreak);
+ }
+ }
+ status => {
+ error!("Unexpected VcpuDebugStatus: {:?}", status);
+ }
+ },
+ Err(_) => {} // TODO(keiichiw): handle error?
+ };
+
+ if check_gdb_interrupt() {
+ self.vm_request(VmRequest::Suspend).map_err(|e| {
+ error!("Failed to suspend the target: {}", e);
+ "Failed to suspend the target"
+ })?;
+ return Ok(StopReason::GdbInterrupt);
+ }
+ }
+ }
+
+ fn read_registers(
+ &mut self,
+ regs: &mut <Self::Arch as Arch>::Registers,
+ ) -> TargetResult<(), Self> {
+ match self.vcpu_request(VcpuControl::Debug(VcpuDebug::ReadRegs)) {
+ Ok(VcpuDebugStatus::RegValues(r)) => {
+ *regs = r;
+ Ok(())
+ }
+ Ok(s) => {
+ error!("Unexpected vCPU response for ReadRegs: {:?}", s);
+ Err(NonFatal)
+ }
+ Err(e) => {
+ error!("Failed to request ReadRegs: {}", e);
+ Err(NonFatal)
+ }
+ }
+ }
+
+ fn write_registers(
+ &mut self,
+ regs: &<Self::Arch as Arch>::Registers,
+ ) -> TargetResult<(), Self> {
+ match self.vcpu_request(VcpuControl::Debug(VcpuDebug::WriteRegs(Box::new(
+ regs.clone(),
+ )))) {
+ Ok(VcpuDebugStatus::CommandComplete) => Ok(()),
+ Ok(s) => {
+ error!("Unexpected vCPU response for WriteRegs: {:?}", s);
+ Err(NonFatal)
+ }
+ Err(e) => {
+ error!("Failed to request WriteRegs: {}", e);
+ Err(NonFatal)
+ }
+ }
+ }
+
+ fn read_addrs(
+ &mut self,
+ start_addr: <Self::Arch as Arch>::Usize,
+ data: &mut [u8],
+ ) -> TargetResult<(), Self> {
+ match self.vcpu_request(VcpuControl::Debug(VcpuDebug::ReadMem(
+ GuestAddress(start_addr),
+ data.len(),
+ ))) {
+ Ok(VcpuDebugStatus::MemoryRegion(r)) => {
+ for (dst, v) in data.iter_mut().zip(r.iter()) {
+ *dst = *v;
+ }
+ Ok(())
+ }
+ Ok(s) => {
+ error!("Unexpected vCPU response for ReadMem: {:?}", s);
+ Err(NonFatal)
+ }
+ Err(e) => {
+ error!("Failed to request ReadMem: {}", e);
+ Err(NonFatal)
+ }
+ }
+ }
+
+ fn write_addrs(
+ &mut self,
+ start_addr: <Self::Arch as Arch>::Usize,
+ data: &[u8],
+ ) -> TargetResult<(), Self> {
+ match self.vcpu_request(VcpuControl::Debug(VcpuDebug::WriteMem(
+ GuestAddress(start_addr),
+ data.to_owned(),
+ ))) {
+ Ok(VcpuDebugStatus::CommandComplete) => Ok(()),
+ Ok(s) => {
+ error!("Unexpected vCPU response for WriteMem: {:?}", s);
+ Err(NonFatal)
+ }
+ Err(e) => {
+ error!("Failed to request WriteMem: {}", e);
+ Err(NonFatal)
+ }
+ }
+ }
+}
+
+impl HwBreakpoint for GdbStub {
+ /// Add a new hardware breakpoint.
+ /// Return `Ok(false)` if the operation could not be completed.
+ fn add_hw_breakpoint(&mut self, addr: <Self::Arch as Arch>::Usize) -> TargetResult<bool, Self> {
+ // If we already have 4 breakpoints, we cannot set a new one.
+ if self.hw_breakpoints.len() >= 4 {
+ error!("Not allowed to set more than 4 HW breakpoints");
+ return Err(NonFatal);
+ }
+ self.hw_breakpoints.push(GuestAddress(addr));
+
+ match self.vcpu_request(VcpuControl::Debug(VcpuDebug::SetHwBreakPoint(
+ self.hw_breakpoints.clone(),
+ ))) {
+ Ok(VcpuDebugStatus::CommandComplete) => Ok(true),
+ Ok(s) => {
+ error!("Unexpected vCPU response for SetHwBreakPoint: {:?}", s);
+ Err(NonFatal)
+ }
+ Err(e) => {
+ error!("Failed to request SetHwBreakPoint: {}", e);
+ Err(NonFatal)
+ }
+ }
+ }
+
+ /// Remove an existing hardware breakpoint.
+ /// Return `Ok(false)` if the operation could not be completed.
+ fn remove_hw_breakpoint(
+ &mut self,
+ addr: <Self::Arch as Arch>::Usize,
+ ) -> TargetResult<bool, Self> {
+ self.hw_breakpoints.retain(|&b| b.0 != addr);
+
+ match self.vcpu_request(VcpuControl::Debug(VcpuDebug::SetHwBreakPoint(
+ self.hw_breakpoints.clone(),
+ ))) {
+ Ok(VcpuDebugStatus::CommandComplete) => Ok(true),
+ Ok(s) => {
+ error!("Unexpected vCPU response for SetHwBreakPoint: {:?}", s);
+ Err(NonFatal)
+ }
+ Err(e) => {
+ error!("Failed to request SetHwBreakPoint: {}", e);
+ Err(NonFatal)
+ }
+ }
+ }
+}
diff --git a/src/linux.rs b/src/linux.rs
index 8e5647b..8cfeef7 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -17,12 +17,13 @@
#[cfg(feature = "gpu")]
use std::num::NonZeroU8;
use std::num::ParseIntError;
-use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::os::unix::io::FromRawFd;
use std::os::unix::net::UnixStream;
use std::path::{Path, PathBuf};
use std::ptr;
use std::str;
-use std::sync::{Arc, Barrier};
+use std::sync::{mpsc, Arc, Barrier};
+
use std::thread;
use std::thread::JoinHandle;
use std::time::Duration;
@@ -38,8 +39,8 @@
#[cfg(feature = "audio")]
use devices::Ac97Dev;
use devices::{
- self, HostBackendDeviceProvider, KvmKernelIrqChip, PciDevice, VfioContainer, VfioDevice,
- VfioPciDevice, VirtioPciDevice, XhciController,
+ self, HostBackendDeviceProvider, IrqChip, IrqEventIndex, KvmKernelIrqChip, PciDevice,
+ VcpuRunState, VfioContainer, VfioDevice, VfioPciDevice, VirtioPciDevice, XhciController,
};
use hypervisor::kvm::{Kvm, KvmVcpu, KvmVm};
use hypervisor::{HypervisorCap, Vcpu, VcpuExit, VcpuRunHandle, Vm, VmCap};
@@ -48,25 +49,30 @@
use net_util::{Error as NetError, MacAddress, Tap};
use remain::sorted;
use resources::{Alloc, MmioType, SystemAllocator};
-use sync::{Condvar, Mutex};
+use sync::Mutex;
use base::{
self, block_signal, clear_signal, drop_capabilities, error, flock, get_blocked_signals,
get_group_id, get_user_id, getegid, geteuid, info, register_rt_signal_handler,
- set_cpu_affinity, set_rt_prio_limit, set_rt_round_robin, signal, validate_raw_fd, warn, Event,
- ExternalMapping, FlockOperation, Killable, MemoryMappingArena, PollContext, PollToken,
- Protection, ScopedEvent, SignalFd, Terminal, Timer, WatchingEvents, SIGRTMIN,
+ set_cpu_affinity, set_rt_prio_limit, set_rt_round_robin, signal, validate_raw_descriptor, warn,
+ AsRawDescriptor, Event, EventType, ExternalMapping, FlockOperation, FromRawDescriptor,
+ Killable, MemoryMappingArena, PollToken, Protection, RawDescriptor, ScopedEvent, SignalFd,
+ Terminal, Timer, WaitContext, SIGRTMIN,
};
use vm_control::{
BalloonControlCommand, BalloonControlRequestSocket, BalloonControlResponseSocket,
BalloonControlResult, DiskControlCommand, DiskControlRequestSocket, DiskControlResponseSocket,
- DiskControlResult, IrqSetup, UsbControlSocket, VmControlResponseSocket, VmIrqRequest,
- VmIrqRequestSocket, VmIrqResponse, VmIrqResponseSocket, VmMemoryControlRequestSocket,
- VmMemoryControlResponseSocket, VmMemoryRequest, VmMemoryResponse, VmMsyncRequest,
- VmMsyncRequestSocket, VmMsyncResponse, VmMsyncResponseSocket, VmRunMode,
+ DiskControlResult, IrqSetup, UsbControlSocket, VcpuControl, VmControlResponseSocket,
+ VmIrqRequest, VmIrqRequestSocket, VmIrqResponse, VmIrqResponseSocket,
+ VmMemoryControlRequestSocket, VmMemoryControlResponseSocket, VmMemoryRequest, VmMemoryResponse,
+ VmMsyncRequest, VmMsyncRequestSocket, VmMsyncResponse, VmMsyncResponseSocket, VmRunMode,
};
+#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+use vm_control::{VcpuDebug, VcpuDebugStatus, VcpuDebugStatusMessage, VmRequest, VmResponse};
use vm_memory::{GuestAddress, GuestMemory};
+#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+use crate::gdb::{gdb_thread, GdbStub};
use crate::{Config, DiskOption, Executable, SharedDir, SharedDirKind, TouchDeviceOption};
use arch::{
self, LinuxArch, RunnableLinuxVm, SerialHardware, SerialParameters, VcpuAffinity,
@@ -76,13 +82,13 @@
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
use {
aarch64::AArch64 as Arch,
- devices::{IrqChip, IrqChipAArch64 as IrqChipArch},
+ devices::IrqChipAArch64 as IrqChipArch,
hypervisor::{VcpuAArch64 as VcpuArch, VmAArch64 as VmArch},
};
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use {
- devices::{IrqChipX86_64, IrqChipX86_64 as IrqChipArch, KvmSplitIrqChip},
- hypervisor::{VcpuX86_64, VcpuX86_64 as VcpuArch, VmX86_64 as VmArch},
+ devices::{IrqChipX86_64 as IrqChipArch, KvmSplitIrqChip},
+ hypervisor::{VcpuX86_64 as VcpuArch, VmX86_64 as VmArch},
x86_64::X8664arch as Arch,
};
@@ -107,7 +113,6 @@
CreateConsole(arch::serial::Error),
CreateDiskError(disk::Error),
CreateEvent(base::Error),
- CreatePollContext(base::Error),
CreateSignalFd(base::SignalFdError),
CreateSocket(io::Error),
CreateTapDevice(NetError),
@@ -116,6 +121,7 @@
CreateUsbProvider(devices::usb::host_backend::error::Error),
CreateVcpu(base::Error),
CreateVfioDevice(devices::vfio::VfioError),
+ CreateWaitContext(base::Error),
DeviceJail(minijail::Error),
DevicePivotRoot(minijail::Error),
Disk(PathBuf, io::Error),
@@ -124,6 +130,8 @@
FsDeviceNew(virtio::fs::Error),
GetMaxOpenFiles(io::Error),
GetSignalMask(signal::Error),
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ HandleDebugCommand(<Arch as LinuxArch>::Error),
InputDeviceNew(virtio::InputError),
InputEventsOpen(std::io::Error),
InvalidFdPath,
@@ -143,8 +151,6 @@
PivotRootDoesntExist(&'static str),
PmemDeviceImageTooBig,
PmemDeviceNew(base::Error),
- PollContextAdd(base::Error),
- PollContextDelete(base::Error),
ReadMemAvailable(io::Error),
RegisterBalloon(arch::DeviceRegistrationError),
RegisterBlock(arch::DeviceRegistrationError),
@@ -160,17 +166,23 @@
ResetTimer(base::Error),
RngDeviceNew(virtio::RngError),
RunnableVcpu(base::Error),
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ SendDebugStatus(Box<mpsc::SendError<VcpuDebugStatusMessage>>),
SettingGidMap(minijail::Error),
SettingMaxOpenFiles(minijail::Error),
SettingSignalMask(base::Error),
SettingUidMap(minijail::Error),
SignalFd(base::SignalFdError),
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ SpawnGdbServer(io::Error),
SpawnVcpu(io::Error),
Timer(base::Error),
- ValidateRawFd(base::Error),
+ ValidateRawDescriptor(base::Error),
VhostNetDeviceNew(virtio::vhost::Error),
VhostVsockDeviceNew(virtio::vhost::Error),
VirtioPciDev(base::Error),
+ WaitContextAdd(base::Error),
+ WaitContextDelete(base::Error),
WaylandDeviceNew(base::Error),
}
@@ -201,7 +213,6 @@
CreateConsole(e) => write!(f, "failed to create console device: {}", e),
CreateDiskError(e) => write!(f, "failed to create virtual disk: {}", e),
CreateEvent(e) => write!(f, "failed to create event: {}", 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),
@@ -212,6 +223,7 @@
CreateUsbProvider(e) => write!(f, "failed to create usb provider: {}", e),
CreateVcpu(e) => write!(f, "failed to create vcpu: {}", e),
CreateVfioDevice(e) => write!(f, "Failed to create vfio device {}", e),
+ CreateWaitContext(e) => write!(f, "failed to create wait context: {}", e),
DeviceJail(e) => write!(f, "failed to jail device: {}", e),
DevicePivotRoot(e) => write!(f, "failed to pivot root device: {}", e),
Disk(p, e) => write!(f, "failed to load disk image {}: {}", p.display(), e),
@@ -220,6 +232,8 @@
FsDeviceNew(e) => write!(f, "failed to create fs device: {}", e),
GetMaxOpenFiles(e) => write!(f, "failed to get max number of open files: {}", e),
GetSignalMask(e) => write!(f, "failed to retrieve signal mask for vcpu: {}", e),
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ HandleDebugCommand(e) => write!(f, "failed to handle a gdb command: {}", 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/*"),
@@ -246,8 +260,6 @@
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),
ReadMemAvailable(e) => write!(f, "failed to read /proc/meminfo: {}", e),
RegisterBalloon(e) => write!(f, "error registering balloon device: {}", e),
RegisterBlock(e) => write!(f, "error registering block device: {}", e),
@@ -263,17 +275,25 @@
ResetTimer(e) => write!(f, "failed to reset Timer: {}", e),
RngDeviceNew(e) => write!(f, "failed to set up rng: {}", e),
RunnableVcpu(e) => write!(f, "failed to set thread id for vcpu: {}", e),
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ SendDebugStatus(e) => write!(f, "failed to send a debug status to GDB thread: {}", e),
SettingGidMap(e) => write!(f, "error setting GID map: {}", e),
SettingMaxOpenFiles(e) => write!(f, "error setting max open files: {}", e),
SettingSignalMask(e) => write!(f, "failed to set the signal mask for vcpu: {}", e),
SettingUidMap(e) => write!(f, "error setting UID map: {}", e),
SignalFd(e) => write!(f, "failed to read signal fd: {}", e),
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ SpawnGdbServer(e) => write!(f, "failed to spawn GDB thread: {}", e),
SpawnVcpu(e) => write!(f, "failed to spawn VCPU thread: {}", e),
Timer(e) => write!(f, "failed to read timer fd: {}", e),
- ValidateRawFd(e) => write!(f, "failed to validate raw fd: {}", e),
+ ValidateRawDescriptor(e) => write!(f, "failed to validate raw descriptor: {}", 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),
+ WaitContextAdd(e) => write!(f, "failed to add descriptor to wait context: {}", e),
+ WaitContextDelete(e) => {
+ write!(f, "failed to remove descriptor from wait context: {}", e)
+ }
WaylandDeviceNew(e) => write!(f, "failed to create wayland device: {}", e),
}
}
@@ -308,9 +328,9 @@
}
}
-impl AsRawFd for TaggedControlSocket {
- fn as_raw_fd(&self) -> RawFd {
- self.as_ref().as_raw_fd()
+impl AsRawDescriptor for TaggedControlSocket {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.as_ref().as_raw_descriptor()
}
}
@@ -442,7 +462,7 @@
// 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)?) }
+ unsafe { File::from_raw_descriptor(raw_descriptor_from_path(&disk.path)?) }
} else {
OpenOptions::new()
.read(true)
@@ -476,10 +496,8 @@
}
fn create_rng_device(cfg: &Config) -> DeviceResult {
- let dev = virtio::Rng::new(
- virtio::base_features(cfg.protected_vm)
- )
- .map_err(Error::RngDeviceNew)?;
+ let dev =
+ virtio::Rng::new(virtio::base_features(cfg.protected_vm)).map_err(Error::RngDeviceNew)?;
Ok(VirtioDeviceStub {
dev: Box::new(dev),
@@ -636,11 +654,13 @@
})
}
-fn create_tap_net_device(cfg: &Config, tap_fd: RawFd) -> DeviceResult {
+fn create_tap_net_device(cfg: &Config, tap_fd: RawDescriptor) -> 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)?
+ Tap::from_raw_descriptor(
+ validate_raw_descriptor(tap_fd).map_err(Error::ValidateRawDescriptor)?,
+ )
+ .map_err(Error::CreateTapDevice)?
};
let mut vq_pairs = cfg.net_vq_pairs.unwrap_or(1);
@@ -1024,6 +1044,7 @@
gid_map: &str,
src: &Path,
tag: &str,
+ mut p9_cfg: p9::Config,
) -> DeviceResult {
let max_open_files = get_max_open_files()?;
let (jail, root) = if cfg.sandbox {
@@ -1051,7 +1072,8 @@
};
let features = virtio::base_features(cfg.protected_vm);
- let dev = virtio::P9::new(features, root, tag).map_err(Error::P9DeviceNew)?;
+ p9_cfg.root = root.into();
+ let dev = virtio::P9::new(features, tag, p9_cfg).map_err(Error::P9DeviceNew)?;
Ok(VirtioDeviceStub {
dev: Box::new(dev),
@@ -1149,10 +1171,10 @@
}
fn create_console_device(cfg: &Config, param: &SerialParameters) -> DeviceResult {
- let mut keep_fds = Vec::new();
+ let mut keep_rds = Vec::new();
let evt = Event::new().map_err(Error::CreateEvent)?;
let dev = param
- .create_serial_device::<Console>(cfg.protected_vm, &evt, &mut keep_fds)
+ .create_serial_device::<Console>(cfg.protected_vm, &evt, &mut keep_rds)
.map_err(Error::CreateConsole)?;
let jail = match simple_jail(&cfg, "serial")? {
@@ -1380,12 +1402,13 @@
kind,
uid_map,
gid_map,
- cfg: fs_cfg,
+ fs_cfg,
+ p9_cfg,
} = shared_dir;
let dev = match kind {
SharedDirKind::FS => create_fs_device(cfg, uid_map, gid_map, src, tag, fs_cfg.clone())?,
- SharedDirKind::P9 => create_9p_device(cfg, uid_map, gid_map, src, tag)?,
+ SharedDirKind::P9 => create_9p_device(cfg, uid_map, gid_map, src, tag, p9_cfg.clone())?,
};
devs.push(dev);
}
@@ -1521,16 +1544,16 @@
})
}
-fn raw_fd_from_path(path: &Path) -> Result<RawFd> {
+fn raw_descriptor_from_path(path: &Path) -> Result<RawDescriptor> {
if !path.is_file() {
return Err(Error::InvalidFdPath);
}
- let raw_fd = path
+ let raw_descriptor = 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)
+ validate_raw_descriptor(raw_descriptor).map_err(Error::ValidateRawDescriptor)
}
trait IntoUnixStream {
@@ -1541,7 +1564,7 @@
fn into_unix_stream(self) -> Result<UnixStream> {
if self.parent() == Some(Path::new("/proc/self/fd")) {
// Safe because we will validate |raw_fd|.
- unsafe { Ok(UnixStream::from_raw_fd(raw_fd_from_path(self)?)) }
+ unsafe { Ok(UnixStream::from_raw_fd(raw_descriptor_from_path(self)?)) }
} else {
UnixStream::connect(self).map_err(Error::InputEventsOpen)
}
@@ -1580,19 +1603,6 @@
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();
- }
-}
-
// Sets up a vcpu and converts it into a runnable vcpu.
fn runnable_vcpu<V>(
cpu_id: usize,
@@ -1674,37 +1684,82 @@
Ok((vcpu, vcpu_run_handle))
}
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-fn inject_interrupt(irq_chip: &mut dyn IrqChipX86_64, vcpu: &dyn VcpuX86_64, vcpu_id: usize) {
- if !irq_chip.interrupt_requested(vcpu_id) || !vcpu.ready_for_interrupt() {
- return;
- }
-
- let vector = irq_chip
- .get_external_interrupt(vcpu_id)
- .unwrap_or_else(|e| {
- error!("get_external_interrupt failed on vcpu {}: {}", vcpu_id, e);
- None
- });
- if let Some(vector) = vector {
- if let Err(e) = vcpu.interrupt(vector as u32) {
- error!(
- "Failed to inject interrupt {} to vcpu {}: {}",
- vector, vcpu_id, e
- );
+#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+fn handle_debug_msg<V>(
+ cpu_id: usize,
+ vcpu: &V,
+ guest_mem: &GuestMemory,
+ d: VcpuDebug,
+ reply_channel: &mpsc::Sender<VcpuDebugStatusMessage>,
+) -> Result<()>
+where
+ V: VcpuArch + 'static,
+{
+ match d {
+ VcpuDebug::ReadRegs => {
+ let msg = VcpuDebugStatusMessage {
+ cpu: cpu_id as usize,
+ msg: VcpuDebugStatus::RegValues(
+ Arch::debug_read_registers(vcpu as &V).map_err(Error::HandleDebugCommand)?,
+ ),
+ };
+ reply_channel
+ .send(msg)
+ .map_err(|e| Error::SendDebugStatus(Box::new(e)))
+ }
+ VcpuDebug::WriteRegs(regs) => {
+ Arch::debug_write_registers(vcpu as &V, ®s).map_err(Error::HandleDebugCommand)?;
+ reply_channel
+ .send(VcpuDebugStatusMessage {
+ cpu: cpu_id as usize,
+ msg: VcpuDebugStatus::CommandComplete,
+ })
+ .map_err(|e| Error::SendDebugStatus(Box::new(e)))
+ }
+ VcpuDebug::ReadMem(vaddr, len) => {
+ let msg = VcpuDebugStatusMessage {
+ cpu: cpu_id as usize,
+ msg: VcpuDebugStatus::MemoryRegion(
+ Arch::debug_read_memory(vcpu as &V, guest_mem, vaddr, len)
+ .unwrap_or(Vec::new()),
+ ),
+ };
+ reply_channel
+ .send(msg)
+ .map_err(|e| Error::SendDebugStatus(Box::new(e)))
+ }
+ VcpuDebug::WriteMem(vaddr, buf) => {
+ Arch::debug_write_memory(vcpu as &V, guest_mem, vaddr, &buf)
+ .map_err(Error::HandleDebugCommand)?;
+ reply_channel
+ .send(VcpuDebugStatusMessage {
+ cpu: cpu_id as usize,
+ msg: VcpuDebugStatus::CommandComplete,
+ })
+ .map_err(|e| Error::SendDebugStatus(Box::new(e)))
+ }
+ VcpuDebug::EnableSinglestep => {
+ Arch::debug_enable_singlestep(vcpu as &V).map_err(Error::HandleDebugCommand)?;
+ reply_channel
+ .send(VcpuDebugStatusMessage {
+ cpu: cpu_id as usize,
+ msg: VcpuDebugStatus::CommandComplete,
+ })
+ .map_err(|e| Error::SendDebugStatus(Box::new(e)))
+ }
+ VcpuDebug::SetHwBreakPoint(addrs) => {
+ Arch::debug_set_hw_breakpoints(vcpu as &V, &addrs)
+ .map_err(Error::HandleDebugCommand)?;
+ reply_channel
+ .send(VcpuDebugStatusMessage {
+ cpu: cpu_id as usize,
+ msg: VcpuDebugStatus::CommandComplete,
+ })
+ .map_err(|e| Error::SendDebugStatus(Box::new(e)))
}
}
-
- // The second interrupt request should be handled immediately, so ask vCPU to exit as soon as
- // possible.
- if irq_chip.interrupt_requested(vcpu_id) {
- vcpu.request_interrupt_window();
- }
}
-#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
-fn inject_interrupt(_irq_chip: &mut dyn IrqChip, _vcpu: &dyn Vcpu, _vcpu_id: usize) {}
-
fn run_vcpu<V>(
cpu_id: usize,
vcpu: Option<V>,
@@ -1720,8 +1775,11 @@
mmio_bus: devices::Bus,
exit_evt: Event,
requires_pvclock_ctrl: bool,
- run_mode_arc: Arc<VcpuRunMode>,
+ from_main_channel: mpsc::Receiver<VcpuControl>,
use_hypervisor_signals: bool,
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))] to_gdb_channel: Option<
+ mpsc::Sender<VcpuDebugStatusMessage>,
+ >,
) -> Result<JoinHandle<()>>
where
V: VcpuArch + 'static,
@@ -1733,6 +1791,8 @@
// implementation accomplishes that.
let _scoped_exit_evt = ScopedEvent::from(exit_evt);
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ let guest_mem = vm.get_memory().clone();
let runnable_vcpu = runnable_vcpu(
cpu_id,
vcpu,
@@ -1756,70 +1816,193 @@
}
};
- loop {
- let mut interrupted_by_signal = false;
- match vcpu.run(&vcpu_run_handle) {
- 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);
+ let mut run_mode = VmRunMode::Running;
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ if to_gdb_channel.is_some() {
+ // Wait until a GDB client attaches
+ run_mode = VmRunMode::Breakpoint;
+ }
+
+ let mut interrupted_by_signal = false;
+
+ 'vcpu_loop: loop {
+ // Start by checking for messages to process and the run state of the CPU.
+ // An extra check here for Running so there isn't a need to call recv unless a
+ // message is likely to be ready because a signal was sent.
+ if interrupted_by_signal || run_mode != VmRunMode::Running {
+ 'state_loop: loop {
+ // Tries to get a pending message without blocking first.
+ let msg = match from_main_channel.try_recv() {
+ Ok(m) => m,
+ Err(mpsc::TryRecvError::Empty) if run_mode == VmRunMode::Running => {
+ // If the VM is running and no message is pending, the state won't
+ // change.
+ break 'state_loop;
+ }
+ Err(mpsc::TryRecvError::Empty) => {
+ // If the VM is not running, wait until a message is ready.
+ match from_main_channel.recv() {
+ Ok(m) => m,
+ Err(mpsc::RecvError) => {
+ error!("Failed to read from main channel in vcpu");
+ break 'vcpu_loop;
+ }
+ }
+ }
+ Err(mpsc::TryRecvError::Disconnected) => {
+ error!("Failed to read from main channel in vcpu");
+ break 'vcpu_loop;
+ }
+ };
+
+ // Collect all pending messages.
+ let mut messages = vec![msg];
+ messages.append(&mut from_main_channel.try_iter().collect());
+
+ for msg in messages {
+ match msg {
+ VcpuControl::RunState(new_mode) => {
+ run_mode = new_mode;
+ match run_mode {
+ VmRunMode::Running => break 'state_loop,
+ 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_pvclock_ctrl {
+ if let Err(e) = vcpu.pvclock_ctrl() {
+ error!(
+ "failed to tell hypervisor vcpu {} is suspending: {}",
+ cpu_id, e
+ );
+ }
+ }
+ }
+ VmRunMode::Breakpoint => {}
+ VmRunMode::Exiting => break 'vcpu_loop,
+ }
+ }
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ VcpuControl::Debug(d) => {
+ match &to_gdb_channel {
+ Some(ref ch) => {
+ if let Err(e) = handle_debug_msg(
+ cpu_id, &vcpu, &guest_mem, d, &ch,
+ ) {
+ error!("Failed to handle gdb message: {}", e);
+ }
+ },
+ None => {
+ error!("VcpuControl::Debug received while GDB feature is disabled: {:?}", d);
+ }
+ }
+ }
+ }
}
}
- Ok(VcpuExit::IoOut {
- port,
- mut size,
- data,
- }) => {
- if size > data.len() {
- error!("unsupported IoOut size of {} bytes", size);
- size = data.len();
+ }
+
+ interrupted_by_signal = false;
+
+ // Vcpus may have run a HLT instruction, which puts them into a state other than
+ // VcpuRunState::Runnable. In that case, this call to wait_until_runnable blocks
+ // until either the irqchip receives an interrupt for this vcpu, or until the main
+ // thread kicks this vcpu as a result of some VmControl operation. In most IrqChip
+ // implementations HLT instructions do not make it to crosvm, and thus this is a
+ // no-op that always returns VcpuRunState::Runnable.
+ match irq_chip.wait_until_runnable(&vcpu) {
+ Ok(VcpuRunState::Runnable) => {}
+ Ok(VcpuRunState::Interrupted) => interrupted_by_signal = true,
+ Err(e) => error!(
+ "error waiting for vcpu {} to become runnable: {}",
+ cpu_id, e
+ ),
+ }
+
+ if !interrupted_by_signal {
+ match vcpu.run(&vcpu_run_handle) {
+ 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);
+ }
}
- 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::IoapicEoi { vector }) => {
- if let Err(e) = irq_chip.broadcast_eoi(vector) {
- error!(
- "failed to broadcast eoi {} on vcpu {}: {}",
- vector, cpu_id, 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::Hlt) => break,
- Ok(VcpuExit::Shutdown) => break,
- Ok(VcpuExit::FailEntry {
- hardware_entry_failure_reason,
- }) => {
- error!("vcpu hw run failure: {:#x}", hardware_entry_failure_reason);
- 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);
+ 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::IoapicEoi { vector }) => {
+ if let Err(e) = irq_chip.broadcast_eoi(vector) {
+ error!(
+ "failed to broadcast eoi {} on vcpu {}: {}",
+ vector, cpu_id, e
+ );
+ }
+ }
+ Ok(VcpuExit::IrqWindowOpen) => {}
+ Ok(VcpuExit::Hlt) => irq_chip.halted(cpu_id),
+ Ok(VcpuExit::Shutdown) => break,
+ Ok(VcpuExit::FailEntry {
+ hardware_entry_failure_reason,
+ }) => {
+ error!("vcpu hw run failure: {:#x}", hardware_entry_failure_reason);
break;
}
- },
+ Ok(VcpuExit::SystemEvent(_, _)) => break,
+ Ok(VcpuExit::Debug { .. }) => {
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ {
+ let msg = VcpuDebugStatusMessage {
+ cpu: cpu_id as usize,
+ msg: VcpuDebugStatus::HitBreakPoint,
+ };
+ if let Some(ref ch) = to_gdb_channel {
+ if let Err(e) = ch.send(msg) {
+ error!("failed to notify breakpoint to GDB thread: {}", e);
+ break;
+ }
+ }
+ run_mode = VmRunMode::Breakpoint;
+ }
+ }
+ 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 {
@@ -1833,35 +2016,11 @@
} else {
vcpu.set_immediate_exit(false);
}
- 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_pvclock_ctrl {
- if let Err(e) = vcpu.pvclock_ctrl() {
- error!(
- "failed to tell hypervisor vcpu {} is suspending: {}",
- cpu_id, e
- );
- }
- }
- }
- VmRunMode::Exiting => return,
- }
- // 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);
- }
}
- inject_interrupt(&mut irq_chip, &vcpu, cpu_id);
+ if let Err(e) = irq_chip.inject_interrupts(&vcpu) {
+ error!("failed to inject interrupts for vcpu {}: {}", cpu_id, e);
+ }
}
})
.map_err(Error::SpawnVcpu)
@@ -1979,6 +2138,18 @@
_ => panic!("Did not receive a bios or kernel, should be impossible."),
};
+ let mut control_sockets = Vec::new();
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ let gdb_socket = if let Some(port) = cfg.gdb {
+ // GDB needs a control socket to interrupt vcpus.
+ let (gdb_host_socket, gdb_control_socket) =
+ msg_socket::pair::<VmResponse, VmRequest>().map_err(Error::CreateSocket)?;
+ control_sockets.push(TaggedControlSocket::Vm(gdb_host_socket));
+ Some((port, gdb_control_socket))
+ } else {
+ None
+ };
+
let components = VmComponents {
memory_size: cfg
.memory
@@ -2005,6 +2176,8 @@
.collect::<Result<Vec<SDT>>>()?,
rt_cpus: cfg.rt_cpus.clone(),
protected_vm: cfg.protected_vm,
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ gdb: gdb_socket,
};
let control_server_socket = match &cfg.socket_path {
@@ -2014,7 +2187,6 @@
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));
@@ -2052,12 +2224,19 @@
msg_socket::pair::<VmIrqResponse, VmIrqRequest>().map_err(Error::CreateSocket)?;
control_sockets.push(TaggedControlSocket::VmIrq(ioapic_host_socket));
+ let battery = if cfg.battery_type.is_some() {
+ (&cfg.battery_type, simple_jail(&cfg, "battery")?)
+ } else {
+ (&cfg.battery_type, None)
+ };
+
let map_request: Arc<Mutex<Option<ExternalMapping>>> = Arc::new(Mutex::new(None));
let linux: RunnableLinuxVm<_, Vcpu, _> = Arch::build_vm(
components,
&cfg.serial_parameters,
simple_jail(&cfg, "serial")?,
+ battery,
|mem, vm, sys_allocator, exit_evt| {
create_devices(
&cfg,
@@ -2093,6 +2272,24 @@
)
}
+/// Signals all running VCPUs to vmexit, sends VmRunMode message to each VCPU channel, and tells
+/// `irq_chip` to stop blocking halted VCPUs. The channel message is set first because both the
+/// signal and the irq_chip kick could cause the VCPU thread to continue through the VCPU run
+/// loop.
+fn kick_all_vcpus(
+ vcpu_handles: &[(JoinHandle<()>, mpsc::Sender<vm_control::VcpuControl>)],
+ irq_chip: &impl IrqChip,
+ run_mode: &VmRunMode,
+) {
+ for (handle, channel) in vcpu_handles {
+ if let Err(e) = channel.send(VcpuControl::RunState(run_mode.clone())) {
+ error!("failed to send VmRunMode: {}", e);
+ }
+ let _ = handle.kill(SIGRTMIN() + 0);
+ }
+ irq_chip.kick_halted_vcpus();
+}
+
fn run_control<V: VmArch + 'static, Vcpu: VcpuArch + 'static, I: IrqChipArch + 'static>(
mut linux: RunnableLinuxVm<V, Vcpu, I>,
control_server_socket: Option<UnlinkUnixSeqpacketListener>,
@@ -2111,7 +2308,7 @@
Exit,
Suspend,
ChildSignal,
- IrqFd { gsi: usize },
+ IrqFd { index: IrqEventIndex },
BalanceMemory,
BalloonResult,
VmControlServer,
@@ -2122,42 +2319,42 @@
.set_raw_mode()
.expect("failed to set terminal raw mode");
- let poll_ctx = PollContext::build_with(&[
+ let wait_ctx = WaitContext::build_with(&[
(&linux.exit_evt, Token::Exit),
(&linux.suspend_evt, Token::Suspend),
(&sigchld_fd, Token::ChildSignal),
])
- .map_err(Error::PollContextAdd)?;
+ .map_err(Error::WaitContextAdd)?;
if let Some(socket_server) = &control_server_socket {
- poll_ctx
+ wait_ctx
.add(socket_server, Token::VmControlServer)
- .map_err(Error::PollContextAdd)?;
+ .map_err(Error::WaitContextAdd)?;
}
for (index, socket) in control_sockets.iter().enumerate() {
- poll_ctx
+ wait_ctx
.add(socket.as_ref(), Token::VmControl { index })
- .map_err(Error::PollContextAdd)?;
+ .map_err(Error::WaitContextAdd)?;
}
let events = linux
.irq_chip
.irq_event_tokens()
- .map_err(Error::PollContextAdd)?;
+ .map_err(Error::WaitContextAdd)?;
- for (gsi, evt) in events {
- poll_ctx
- .add(&evt, Token::IrqFd { gsi: gsi as usize })
- .map_err(Error::PollContextAdd)?;
+ for (index, _gsi, evt) in events {
+ wait_ctx
+ .add(&evt, Token::IrqFd { index })
+ .map_err(Error::WaitContextAdd)?;
}
// Balance available memory between guest and host every second.
let mut balancemem_timer = Timer::new().map_err(Error::CreateTimer)?;
if Path::new(LOWMEM_AVAILABLE).exists() {
// Create timer request balloon stats every 1s.
- poll_ctx
+ wait_ctx
.add(&balancemem_timer, Token::BalanceMemory)
- .map_err(Error::PollContextAdd)?;
+ .map_err(Error::WaitContextAdd)?;
let balancemem_dur = Duration::from_secs(1);
let balancemem_int = Duration::from_secs(1);
balancemem_timer
@@ -2165,9 +2362,9 @@
.map_err(Error::ResetTimer)?;
// Listen for balloon statistics from the guest so we can balance.
- poll_ctx
+ wait_ctx
.add(&balloon_host_socket, Token::BalloonResult)
- .map_err(Error::PollContextAdd)?;
+ .map_err(Error::WaitContextAdd)?;
} else {
warn!("Unable to open low mem available, maybe not a chrome os kernel");
}
@@ -2177,9 +2374,17 @@
drop_capabilities().map_err(Error::DropCapabilities)?;
}
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ // Create a channel for GDB thread.
+ let (to_gdb_channel, from_vcpu_channel) = if linux.gdb.is_some() {
+ let (s, r) = mpsc::channel();
+ (Some(s), Some(r))
+ } else {
+ (None, None)
+ };
+
let mut vcpu_handles = Vec::with_capacity(linux.vcpu_count);
let vcpu_thread_barrier = Arc::new(Barrier::new(linux.vcpu_count + 1));
- let run_mode_arc = Arc::new(VcpuRunMode::default());
let use_hypervisor_signals = !linux
.vm
.get_hypervisor()
@@ -2191,6 +2396,7 @@
None => iter::repeat_with(|| None).take(linux.vcpu_count).collect(),
};
for (cpu_id, vcpu) in vcpus.into_iter().enumerate() {
+ let (to_vcpu_channel, from_main_channel) = mpsc::channel();
let vcpu_affinity = match linux.vcpu_affinity.clone() {
Some(VcpuAffinity::Global(v)) => v,
Some(VcpuAffinity::PerVcpu(mut m)) => m.remove(&cpu_id).unwrap_or_default(),
@@ -2211,17 +2417,37 @@
linux.mmio_bus.clone(),
linux.exit_evt.try_clone().map_err(Error::CloneEvent)?,
linux.vm.check_capability(VmCap::PvClockSuspend),
- run_mode_arc.clone(),
+ from_main_channel,
use_hypervisor_signals,
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ to_gdb_channel.clone(),
)?;
- vcpu_handles.push(handle);
+ vcpu_handles.push((handle, to_vcpu_channel));
}
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ // Spawn GDB thread.
+ if let Some((gdb_port_num, gdb_control_socket)) = linux.gdb.take() {
+ let to_vcpu_channels = vcpu_handles
+ .iter()
+ .map(|(_handle, channel)| channel.clone())
+ .collect();
+ let target = GdbStub::new(
+ gdb_control_socket,
+ to_vcpu_channels,
+ from_vcpu_channel.unwrap(), // Must succeed to unwrap()
+ );
+ thread::Builder::new()
+ .name("gdb".to_owned())
+ .spawn(move || gdb_thread(target, gdb_port_num))
+ .map_err(Error::SpawnGdbServer)?;
+ };
+
vcpu_thread_barrier.wait();
- 'poll: loop {
+ 'wait: loop {
let events = {
- match poll_ctx.wait() {
+ match wait_ctx.wait() {
Ok(v) => v,
Err(e) => {
error!("failed to poll: {}", e);
@@ -2235,19 +2461,16 @@
}
let mut vm_control_indices_to_remove = Vec::new();
- for event in events.iter_readable() {
- match event.token() {
+ for event in events.iter().filter(|e| e.is_readable) {
+ match event.token {
Token::Exit => {
info!("vcpu requested shutdown");
- break 'poll;
+ break 'wait;
}
Token::Suspend => {
info!("VM requested suspend");
linux.suspend_evt.read().unwrap();
- run_mode_arc.set_and_notify(VmRunMode::Suspending);
- for handle in &vcpu_handles {
- let _ = handle.kill(SIGRTMIN() + 0);
- }
+ kick_all_vcpus(&vcpu_handles, &linux.irq_chip, &VmRunMode::Suspending);
}
Token::ChildSignal => {
// Print all available siginfo structs, then exit the loop.
@@ -2262,11 +2485,11 @@
pid_label, siginfo.ssi_signo, siginfo.ssi_status, siginfo.ssi_code
);
}
- break 'poll;
+ break 'wait;
}
- Token::IrqFd { gsi } => {
- if let Err(e) = linux.irq_chip.service_irq_event(gsi as u32) {
- error!("failed to signal irq {}: {}", gsi, e);
+ Token::IrqFd { index } => {
+ if let Err(e) = linux.irq_chip.service_irq_event(index) {
+ error!("failed to signal irq {}: {}", index, e);
}
}
Token::BalanceMemory => {
@@ -2355,14 +2578,14 @@
if let Some(socket_server) = &control_server_socket {
match socket_server.accept() {
Ok(socket) => {
- poll_ctx
+ wait_ctx
.add(
&socket,
Token::VmControl {
index: control_sockets.len(),
},
)
- .map_err(Error::PollContextAdd)?;
+ .map_err(Error::WaitContextAdd)?;
control_sockets
.push(TaggedControlSocket::Vm(MsgSocket::new(socket)));
}
@@ -2381,6 +2604,7 @@
&balloon_host_socket,
disk_host_sockets,
&usb_control_socket,
+ &mut linux.bat_control,
);
if let Err(e) = socket.send(&response) {
error!("failed to send VmResponse: {}", e);
@@ -2389,24 +2613,17 @@
info!("control socket changed run mode to {}", run_mode);
match run_mode {
VmRunMode::Exiting => {
- break 'poll;
- }
- VmRunMode::Running => {
- if let VmRunMode::Suspending =
- *run_mode_arc.mtx.lock()
- {
- linux.io_bus.notify_resume();
- }
- run_mode_arc.set_and_notify(VmRunMode::Running);
- for handle in &vcpu_handles {
- let _ = handle.kill(SIGRTMIN() + 0);
- }
+ break 'wait;
}
other => {
- run_mode_arc.set_and_notify(other);
- for handle in &vcpu_handles {
- let _ = handle.kill(SIGRTMIN() + 0);
+ if other == VmRunMode::Running {
+ linux.io_bus.notify_resume();
}
+ kick_all_vcpus(
+ &vcpu_handles,
+ &linux.irq_chip,
+ &other,
+ );
}
}
}
@@ -2445,7 +2662,26 @@
request.execute(
|setup| match setup {
IrqSetup::Event(irq, ev) => {
- irq_chip.register_irq_event(irq, ev, None)
+ if let Some(event_index) = irq_chip
+ .register_irq_event(irq, ev, None)?
+ {
+ match wait_ctx.add(
+ ev,
+ Token::IrqFd {
+ index: event_index
+ },
+ ) {
+ Err(e) => {
+ warn!("failed to add IrqFd to poll context: {}", e);
+ Err(e)
+ },
+ Ok(_) => {
+ Ok(())
+ }
+ }
+ } else {
+ Ok(())
+ }
}
IrqSetup::Route(route) => irq_chip.route_irq(route),
},
@@ -2485,12 +2721,12 @@
}
}
- for event in events.iter_hungup() {
- match event.token() {
+ for event in events.iter().filter(|e| e.is_hungup) {
+ match event.token {
Token::Exit => {}
Token::Suspend => {}
Token::ChildSignal => {}
- Token::IrqFd { gsi: _ } => {}
+ Token::IrqFd { index: _ } => {}
Token::BalanceMemory => {}
Token::BalloonResult => {}
Token::VmControlServer => {}
@@ -2515,45 +2751,35 @@
vm_control_indices_to_remove.sort_unstable_by_key(|&k| Reverse(k));
vm_control_indices_to_remove.dedup();
for index in vm_control_indices_to_remove {
- // Delete the socket from the `poll_ctx` synchronously. Otherwise, the kernel will do
- // this automatically when the FD inserted into the `poll_ctx` is closed after this
+ // Delete the socket from the `wait_ctx` synchronously. Otherwise, the kernel will do
+ // this automatically when the FD inserted into the `wait_ctx` is closed after this
// if-block, but this removal can be deferred unpredictably. In some instances where the
- // system is under heavy load, we can even get events returned by `poll_ctx` for an FD
+ // system is under heavy load, we can even get events returned by `wait_ctx` for an FD
// that has already been closed. Because the token associated with that spurious event
// now belongs to a different socket, the control loop will start to interact with
// sockets that might not be ready to use. This can cause incorrect hangup detection or
// blocking on a socket that will never be ready. See also: crbug.com/1019986
if let Some(socket) = control_sockets.get(index) {
- poll_ctx.delete(socket).map_err(Error::PollContextDelete)?;
+ wait_ctx.delete(socket).map_err(Error::WaitContextDelete)?;
}
// This line implicitly drops the socket at `index` when it gets returned by
// `swap_remove`. After this line, the socket at `index` is not the one from
// `vm_control_indices_to_remove`. Because of this socket's change in index, we need to
- // use `poll_ctx.modify` to change the associated index in its `Token::VmControl`.
+ // use `wait_ctx.modify` to change the associated index in its `Token::VmControl`.
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)?;
+ wait_ctx
+ .modify(socket, EventType::Read, Token::VmControl { index })
+ .map_err(Error::WaitContextAdd)?;
}
}
}
- // 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),
+ kick_all_vcpus(&vcpu_handles, &linux.irq_chip, &VmRunMode::Exiting);
+ for (handle, _) in vcpu_handles {
+ if let Err(e) = handle.join() {
+ error!("failed to join vcpu thread: {:?}", e);
}
}
diff --git a/src/main.rs b/src/main.rs
index bf09f0f..4aab39a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -12,7 +12,6 @@
use std::fs::{File, OpenOptions};
use std::io::{BufRead, BufReader};
use std::num::ParseIntError;
-use std::os::unix::io::{FromRawFd, RawFd};
use std::path::{Path, PathBuf};
use std::string::String;
use std::thread::sleep;
@@ -24,11 +23,12 @@
};
use base::{
debug, error, getpid, info, kill_process_group, net::UnixSeqpacket, reap_child, syslog,
- validate_raw_fd, warn,
+ validate_raw_descriptor, warn, FromRawDescriptor, IntoRawDescriptor, RawDescriptor,
+ SafeDescriptor,
};
use crosvm::{
argument::{self, print_help, set_arguments, Argument},
- linux, BindMount, Config, DiskOption, Executable, GidMap, SharedDir, TouchDeviceOption,
+ platform, BindMount, Config, DiskOption, Executable, GidMap, SharedDir, TouchDeviceOption,
};
#[cfg(feature = "gpu")]
use devices::virtio::gpu::{GpuMode, GpuParameters};
@@ -37,15 +37,13 @@
use disk::QcowFile;
use msg_socket::{MsgReceiver, MsgSender, MsgSocket};
use vm_control::{
- BalloonControlCommand, DiskControlCommand, MaybeOwnedFd, UsbControlCommand, UsbControlResult,
- VmControlRequestSocket, VmRequest, VmResponse, USB_CONTROL_MAX_PORTS,
+ BalloonControlCommand, BatControlCommand, BatControlResult, BatteryType, DiskControlCommand,
+ MaybeOwnedDescriptor, UsbControlCommand, UsbControlResult, VmControlRequestSocket, VmRequest,
+ VmResponse, USB_CONTROL_MAX_PORTS,
};
fn executable_is_plugin(executable: &Option<Executable>) -> bool {
- match executable {
- Some(Executable::Plugin(_)) => true,
- _ => false,
- }
+ matches!(executable, Some(Executable::Plugin(_)))
}
// Wait for all children to exit. Return true if they have all exited, false
@@ -162,6 +160,8 @@
let mut vulkan_specified = false;
#[cfg(feature = "gfxstream")]
let mut syncfd_specified = false;
+ #[cfg(feature = "gfxstream")]
+ let mut angle_specified = false;
if let Some(s) = s {
let opts = s
@@ -283,6 +283,24 @@
}
}
#[cfg(feature = "gfxstream")]
+ "angle" => {
+ angle_specified = true;
+ match v {
+ "true" | "" => {
+ gpu_params.gfxstream_use_guest_angle = true;
+ }
+ "false" => {
+ gpu_params.gfxstream_use_guest_angle = false;
+ }
+ _ => {
+ return Err(argument::Error::InvalidValue {
+ value: v.to_string(),
+ expected: String::from("gpu parameter 'angle' should be a boolean"),
+ });
+ }
+ }
+ }
+ #[cfg(feature = "gfxstream")]
"vulkan" => {
vulkan_specified = true;
match v {
@@ -337,7 +355,7 @@
#[cfg(feature = "gfxstream")]
{
- if vulkan_specified || syncfd_specified {
+ if vulkan_specified || syncfd_specified || angle_specified {
match gpu_params.mode {
GpuMode::ModeGfxStream => {}
_ => {
@@ -574,6 +592,40 @@
})
}
+fn parse_battery_options(s: Option<&str>) -> argument::Result<BatteryType> {
+ let mut battery_type: BatteryType = Default::default();
+
+ if let Some(s) = s {
+ 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" => match v.parse::<BatteryType>() {
+ Ok(type_) => battery_type = type_,
+ Err(e) => {
+ return Err(argument::Error::InvalidValue {
+ value: v.to_string(),
+ expected: e.to_string(),
+ });
+ }
+ },
+ "" => {}
+ _ => {
+ return Err(argument::Error::UnknownArgument(format!(
+ "battery parameter {}",
+ k
+ )));
+ }
+ }
+ }
+ }
+
+ Ok(battery_type)
+}
+
fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::Result<()> {
match name {
"" => {
@@ -1109,8 +1161,8 @@
})?;
let dur = Duration::from_secs(seconds);
- shared_dir.cfg.entry_timeout = dur.clone();
- shared_dir.cfg.attr_timeout = dur;
+ shared_dir.fs_cfg.entry_timeout = dur.clone();
+ shared_dir.fs_cfg.attr_timeout = dur;
}
"cache" => {
let policy = value.parse().map_err(|_| argument::Error::InvalidValue {
@@ -1119,7 +1171,7 @@
"`cache` must be one of `never`, `always`, or `auto`",
),
})?;
- shared_dir.cfg.cache_policy = policy;
+ shared_dir.fs_cfg.cache_policy = policy;
}
"writeback" => {
let writeback =
@@ -1127,7 +1179,7 @@
value: value.to_owned(),
expected: String::from("`writeback` must be a boolean"),
})?;
- shared_dir.cfg.writeback = writeback;
+ shared_dir.fs_cfg.writeback = writeback;
}
"rewrite-security-xattrs" => {
let rewrite_security_xattrs =
@@ -1137,7 +1189,7 @@
"`rewrite-security-xattrs` must be a boolean",
),
})?;
- shared_dir.cfg.rewrite_security_xattrs = rewrite_security_xattrs;
+ shared_dir.fs_cfg.rewrite_security_xattrs = rewrite_security_xattrs;
}
"ascii_casefold" => {
let ascii_casefold =
@@ -1145,7 +1197,8 @@
value: value.to_owned(),
expected: String::from("`ascii_casefold` must be a boolean"),
})?;
- shared_dir.cfg.ascii_casefold = ascii_casefold;
+ shared_dir.fs_cfg.ascii_casefold = ascii_casefold;
+ shared_dir.p9_cfg.ascii_casefold = ascii_casefold;
}
_ => {
return Err(argument::Error::InvalidValue {
@@ -1381,7 +1434,21 @@
cfg.protected_vm = true;
cfg.params.push("swiotlb=force".to_string());
}
-
+ "battery" => {
+ let params = parse_battery_options(value)?;
+ cfg.battery_type = Some(params);
+ }
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ "gdb" => {
+ let port = value
+ .unwrap()
+ .parse()
+ .map_err(|_| argument::Error::InvalidValue {
+ value: value.unwrap().to_owned(),
+ expected: String::from("expected a valid port number"),
+ })?;
+ cfg.gdb = Some(port);
+ }
"help" => return Err(argument::Error::PrintHelp),
_ => unreachable!(),
}
@@ -1423,6 +1490,14 @@
}
}
}
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ if cfg.gdb.is_some() {
+ if cfg.vcpu_count.unwrap_or(1) != 1 {
+ return Err(argument::Error::ExpectedArgument(
+ "`gdb` requires the number of vCPU to be 1".to_owned(),
+ ));
+ }
+ }
set_default_serial_parameters(&mut cfg.serial_parameters);
Ok(())
}
@@ -1543,6 +1618,7 @@
egl[=true|=false] - If the virtio-gpu backend should use a EGL context for rendering.
glx[=true|=false] - If the virtio-gpu backend should use a GLX context for rendering.
surfaceless[=true|=false] - If the virtio-gpu backend should use a surfaceless context for rendering.
+ angle[=true|=false] - If the guest is using ANGLE (OpenGL on Vulkan) as its native OpenGL driver.
syncfd[=true|=false] - If the gfxstream backend should support EGL_ANDROID_native_fence_sync
vulkan[=true|=false] - If the gfxstream backend should support vulkan
"),
@@ -1563,6 +1639,13 @@
Argument::flag("video-encoder", "(EXPERIMENTAL) enable virtio-video encoder device"),
Argument::value("acpi-table", "PATH", "Path to user provided ACPI table"),
Argument::flag("protected-vm", "(EXPERIMENTAL) prevent host access to guest memory"),
+ Argument::flag_or_value("battery",
+ "[type=TYPE]",
+ "Comma separated key=value pairs for setting up battery device
+ Possible key values:
+ type=goldfish - type of battery emulation, defaults to goldfish
+ "),
+ Argument::value("gdb", "PORT", "(EXPERIMENTAL) gdb on the given port"),
Argument::short_flag('h', "help", "Print help message.")];
let mut cfg = Config::default();
@@ -1585,7 +1668,7 @@
}
}
}
- Ok(()) => match linux::run_config(cfg) {
+ Ok(()) => match platform::run_config(cfg) {
Ok(_) => {
info!("crosvm has exited normally");
Ok(())
@@ -1834,7 +1917,7 @@
ArgMissing(&'static str),
ArgParse(&'static str, String),
ArgParseInt(&'static str, String, ParseIntError),
- FailedFdValidate(base::Error),
+ FailedDescriptorValidate(base::Error),
PathDoesNotExist(PathBuf),
SocketFailed,
UnexpectedResponse(VmResponse),
@@ -1856,7 +1939,7 @@
"failed to parse integer argument {} value `{}`: {}",
name, value, e
),
- FailedFdValidate(e) => write!(f, "failed to validate file descriptor: {}", e),
+ FailedDescriptorValidate(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),
@@ -1892,11 +1975,11 @@
}
}
-fn raw_fd_from_path(path: &Path) -> ModifyUsbResult<RawFd> {
+fn raw_descriptor_from_path(path: &Path) -> ModifyUsbResult<RawDescriptor> {
if !path.exists() {
return Err(ModifyUsbError::PathDoesNotExist(path.to_owned()));
}
- let raw_fd = path
+ let raw_descriptor = path
.file_name()
.and_then(|fd_osstr| fd_osstr.to_str())
.map_or(
@@ -1910,7 +1993,7 @@
})
},
)?;
- validate_raw_fd(raw_fd).map_err(ModifyUsbError::FailedFdValidate)
+ validate_raw_descriptor(raw_descriptor).map_err(ModifyUsbError::FailedDescriptorValidate)
}
fn usb_attach(mut args: std::env::Args) -> ModifyUsbResult<UsbControlResult> {
@@ -1927,7 +2010,7 @@
} 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)?) })
+ Some(unsafe { File::from_raw_descriptor(raw_descriptor_from_path(&dev_path)?) })
} else {
Some(
OpenOptions::new()
@@ -1943,7 +2026,12 @@
addr,
vid,
pid,
- fd: usb_file.map(MaybeOwnedFd::Owned),
+ // Safe because we are transferring ownership to the rawdescriptor
+ descriptor: usb_file.map(|file| {
+ MaybeOwnedDescriptor::Owned(unsafe {
+ SafeDescriptor::from_raw_descriptor(file.into_raw_descriptor())
+ })
+ }),
});
let response = handle_request(&request, args).map_err(|_| ModifyUsbError::SocketFailed)?;
match response {
@@ -2030,6 +2118,55 @@
Ok(())
}
+enum ModifyBatError {
+ BatControlErr(BatControlResult),
+}
+
+impl fmt::Display for ModifyBatError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use self::ModifyBatError::*;
+
+ match self {
+ BatControlErr(e) => write!(f, "{}", e),
+ }
+ }
+}
+
+fn modify_battery(mut args: std::env::Args) -> std::result::Result<(), ()> {
+ if args.len() < 4 {
+ print_help("crosvm battery BATTERY_TYPE ",
+ "[status STATUS | present PRESENT | health HEALTH | capacity CAPACITY | aconline ACONLINE ] VM_SOCKET...", &[]);
+ return Err(());
+ }
+
+ // This unwrap will not panic because of the above length check.
+ let battery_type = args.next().unwrap();
+ let property = args.next().unwrap();
+ let target = args.next().unwrap();
+
+ let response = match battery_type.parse::<BatteryType>() {
+ Ok(type_) => match BatControlCommand::new(property, target) {
+ Ok(cmd) => {
+ let request = VmRequest::BatCommand(type_, cmd);
+ Ok(handle_request(&request, args)?)
+ }
+ Err(e) => Err(ModifyBatError::BatControlErr(e)),
+ },
+ Err(e) => Err(ModifyBatError::BatControlErr(e)),
+ };
+
+ match response {
+ Ok(response) => {
+ println!("{}", response);
+ Ok(())
+ }
+ Err(e) => {
+ println!("error {}", e);
+ Err(())
+ }
+ }
+}
+
fn crosvm_main() -> std::result::Result<(), ()> {
if let Err(e) = syslog::init() {
println!("failed to initialize syslog: {}", e);
@@ -2060,6 +2197,7 @@
Some("disk") => disk_cmd(args),
Some("usb") => modify_usb(args),
Some("version") => pkg_version(),
+ Some("battery") => modify_battery(args),
Some(c) => {
println!("invalid subcommand: {:?}", c);
print_usage();
@@ -2526,4 +2664,24 @@
assert!(parse_gpu_options(Some("backend=3d,syncfd=true")).is_err());
assert!(parse_gpu_options(Some("syncfd=true,backend=3d")).is_err());
}
+
+ #[test]
+ fn parse_battery_vaild() {
+ parse_battery_options(Some("type=goldfish")).expect("parse should have succeded");
+ }
+
+ #[test]
+ fn parse_battery_vaild_no_type() {
+ parse_battery_options(None).expect("parse should have succeded");
+ }
+
+ #[test]
+ fn parse_battery_invaild_parameter() {
+ parse_battery_options(Some("tyep=goldfish")).expect_err("parse should have failed");
+ }
+
+ #[test]
+ fn parse_battery_invaild_type_value() {
+ parse_battery_options(Some("type=xxx")).expect_err("parse should have failed");
+ }
}
diff --git a/src/panic_hook.rs b/src/panic_hook.rs
index d5cd6a2..f6625ef 100644
--- a/src/panic_hook.rs
+++ b/src/panic_hook.rs
@@ -5,12 +5,11 @@
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 base::error;
+use base::{error, FromRawDescriptor, IntoRawDescriptor};
use libc::{close, dup, dup2, pipe2, O_NONBLOCK, STDERR_FILENO};
// Opens a pipe and puts the write end into the stderr FD slot. On success, returns the read end of
@@ -38,16 +37,20 @@
// 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)))
+ Some((
+ File::from_raw_descriptor(fds[0]),
+ File::from_raw_descriptor(old_stderr),
+ ))
}
}
// Sets stderr to the given file. Returns true on success.
fn restore_stderr(stderr: File) -> bool {
- let fd = stderr.into_raw_fd();
+ let descriptor = stderr.into_raw_descriptor();
- // Safe because fd is guaranteed to be valid and replacing stderr should be an atomic operation.
- unsafe { dup2(fd, STDERR_FILENO) != -1 }
+ // Safe because descriptor is guaranteed to be valid and replacing stderr
+ // should be an atomic operation.
+ unsafe { dup2(descriptor, STDERR_FILENO) != -1 }
}
// Sends as much information about the panic as possible to syslog.
diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs
index 9c171fd..f900bf5 100644
--- a/src/plugin/mod.rs
+++ b/src/plugin/mod.rs
@@ -8,7 +8,6 @@
use std::fmt::{self, Display};
use std::fs::File;
use std::io;
-use std::os::unix::io::{AsRawFd, FromRawFd};
use std::os::unix::net::UnixDatagram;
use std::path::Path;
use std::result;
@@ -28,8 +27,9 @@
use base::{
block_signal, clear_signal, drop_capabilities, error, getegid, geteuid, info, pipe,
- register_rt_signal_handler, validate_raw_fd, warn, Error as SysError, Event, Killable,
- MmapError, PollContext, PollToken, Result as SysResult, SignalFd, SignalFdError, SIGRTMIN,
+ register_rt_signal_handler, validate_raw_descriptor, warn, AsRawDescriptor, Error as SysError,
+ Event, FromRawDescriptor, Killable, MmapError, PollToken, Result as SysResult, SignalFd,
+ SignalFdError, WaitContext, SIGRTMIN,
};
use kvm::{Cap, Datamatch, IoeventAddress, Kvm, Vcpu, VcpuExit, Vm};
use minijail::{self, Minijail};
@@ -54,13 +54,13 @@
CreateKvm(SysError),
CreateMainSocket(SysError),
CreatePIT(SysError),
- CreatePollContext(SysError),
CreateSignalFd(SignalFdError),
CreateSocketPair(io::Error),
CreateTapFd(TapError),
CreateVcpu(SysError),
CreateVcpuSocket(SysError),
CreateVm(SysError),
+ CreateWaitContext(SysError),
DecodeRequest(ProtobufError),
DropCapabilities(SysError),
EncodeResponse(ProtobufError),
@@ -87,7 +87,6 @@
PluginTimeout,
PluginWait(SysError),
Poll(SysError),
- PollContextAdd(SysError),
RootNotAbsolute,
RootNotDir,
SetGidMap(minijail::Error),
@@ -106,6 +105,7 @@
TapSetMacAddress(TapError),
TapSetNetmask(TapError),
ValidateTapFd(SysError),
+ WaitContextAdd(SysError),
}
impl Display for Error {
@@ -123,13 +123,13 @@
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),
+ CreateWaitContext(e) => write!(f, "failed to create wait context: {}", 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),
@@ -152,7 +152,6 @@
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),
@@ -175,6 +174,7 @@
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),
+ WaitContextAdd(e) => write!(f, "failed to add descriptor to wait context: {}", e),
}
}
}
@@ -188,8 +188,8 @@
if ret == 0 {
ioctl(fds[0], FIOCLEX);
Ok((
- UnixDatagram::from_raw_fd(fds[0]),
- UnixDatagram::from_raw_fd(fds[1]),
+ UnixDatagram::from_raw_descriptor(fds[0]),
+ UnixDatagram::from_raw_descriptor(fds[1]),
))
} else {
Err(SysError::last())
@@ -212,7 +212,7 @@
// though it's not necessary a hard requirement for things to work.
let flags = unsafe {
fcntl(
- to_crosvm.0.as_raw_fd(),
+ to_crosvm.0.as_raw_descriptor(),
F_SETPIPE_SZ,
MAX_VCPU_DATAGRAM_SIZE as c_int,
)
@@ -226,7 +226,7 @@
}
let flags = unsafe {
fcntl(
- to_plugin.0.as_raw_fd(),
+ to_plugin.0.as_raw_descriptor(),
F_SETPIPE_SZ,
MAX_VCPU_DATAGRAM_SIZE as c_int,
)
@@ -677,7 +677,7 @@
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)?)
+ Tap::from_raw_descriptor(validate_raw_descriptor(tap_fd).map_err(Error::ValidateTapFd)?)
.map_err(Error::CreateTapFd)?
};
tap_interfaces.push(tap);
@@ -710,17 +710,17 @@
let kill_signaled = Arc::new(AtomicBool::new(false));
let mut vcpu_handles = Vec::with_capacity(vcpu_count as usize);
- let poll_ctx =
- PollContext::build_with(&[(&exit_evt, Token::Exit), (&sigchld_fd, Token::ChildSignal)])
- .map_err(Error::PollContextAdd)?;
+ let wait_ctx =
+ WaitContext::build_with(&[(&exit_evt, Token::Exit), (&sigchld_fd, Token::ChildSignal)])
+ .map_err(Error::WaitContextAdd)?;
let mut sockets_to_drop = Vec::new();
- let mut redo_poll_ctx_sockets = true;
+ let mut redo_wait_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 {
+ 'wait: 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)
@@ -729,19 +729,19 @@
break;
}
- if redo_poll_ctx_sockets {
+ if redo_wait_ctx_sockets {
for (index, socket) in plugin.sockets().iter().enumerate() {
- poll_ctx
+ wait_ctx
.add(socket, Token::Plugin { index })
- .map_err(Error::PollContextAdd)?;
+ .map_err(Error::WaitContextAdd)?;
}
}
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(),
+ Some(inst) => wait_ctx.wait_timeout(duration_to_die - inst.elapsed()),
+ None => wait_ctx.wait(),
};
match poll_res {
Ok(v) => v,
@@ -754,11 +754,11 @@
}
}
};
- for event in events.iter_readable() {
- match event.token() {
+ for event in events.iter().filter(|e| e.is_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);
+ let _ = wait_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() {
@@ -773,7 +773,7 @@
// 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;
+ break 'wait;
}
// Because SIGCHLD is not expected from anything other than the
// plugin process, report it as an error.
@@ -840,7 +840,7 @@
}
}
- redo_poll_ctx_sockets =
+ redo_wait_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
@@ -848,9 +848,9 @@
plugin.drop_sockets(&mut sockets_to_drop);
sockets_to_drop.clear();
- if redo_poll_ctx_sockets {
+ if redo_wait_ctx_sockets {
for socket in plugin.sockets() {
- let _ = poll_ctx.delete(socket);
+ let _ = wait_ctx.delete(socket);
}
}
}
diff --git a/src/plugin/process.rs b/src/plugin/process.rs
index cb9bc21..9146256 100644
--- a/src/plugin/process.rs
+++ b/src/plugin/process.rs
@@ -7,7 +7,6 @@
use std::fs::File;
use std::io::{IoSlice, Write};
use std::mem::transmute;
-use std::os::unix::io::{IntoRawFd, RawFd};
use std::os::unix::net::UnixDatagram;
use std::path::Path;
use std::process::Command;
@@ -21,8 +20,9 @@
use protobuf::Message;
use base::{
- error, Error as SysError, Event, Killable, MemoryMappingBuilder, Result as SysResult,
- ScmSocket, SharedMemory, SharedMemoryUnix, SIGRTMIN,
+ error, AsRawDescriptor, Error as SysError, Event, IntoRawDescriptor, Killable,
+ MemoryMappingBuilder, RawDescriptor, Result as SysResult, ScmSocket, SharedMemory,
+ SharedMemoryUnix, SIGRTMIN,
};
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};
@@ -162,13 +162,19 @@
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)
+ set_var(
+ "CROSVM_SOCKET",
+ child_socket.as_raw_descriptor().to_string(),
+ );
+ jail.run(cmd, &[0, 1, 2, child_socket.as_raw_descriptor()], args)
.map_err(Error::PluginRunJail)?
}
None => Command::new(cmd)
.args(args)
- .env("CROSVM_SOCKET", child_socket.as_raw_fd().to_string())
+ .env(
+ "CROSVM_SOCKET",
+ child_socket.as_raw_descriptor().to_string(),
+ )
.spawn()
.map_err(Error::PluginSpawn)?
.id() as pid_t,
@@ -306,7 +312,7 @@
entry: VacantEntry<u32, PluginObject>,
vm: &mut Vm,
io_event: &MainRequest_Create_IoEvent,
- ) -> SysResult<RawFd> {
+ ) -> SysResult<RawDescriptor> {
let evt = Event::new()?;
let addr = match io_event.space {
AddressSpace::IOPORT => IoeventAddress::Pio(io_event.address),
@@ -327,7 +333,7 @@
_ => return Err(SysError::new(EINVAL)),
};
- let fd = evt.as_raw_fd();
+ let fd = evt.as_raw_descriptor();
entry.insert(PluginObject::IoEvent {
evt,
addr,
@@ -522,7 +528,7 @@
/// Use this to make it easier to stuff various kinds of File-like objects into the
/// `boxed_fds` list.
- fn box_owned_fd<F: IntoRawFd + 'static>(f: F) -> Box<dyn IntoRawFd> {
+ fn box_owned_fd<F: IntoRawDescriptor + 'static>(f: F) -> Box<dyn IntoRawDescriptor> {
Box::new(f)
}
@@ -567,8 +573,8 @@
irq_event.irq_id,
) {
Ok(()) => {
- response_fds.push(evt.as_raw_fd());
- response_fds.push(resample_evt.as_raw_fd());
+ response_fds.push(evt.as_raw_descriptor());
+ response_fds.push(resample_evt.as_raw_descriptor());
boxed_fds.push(box_owned_fd(resample_evt));
entry.insert(PluginObject::IrqEvent {
irq_id: irq_event.irq_id,
@@ -597,7 +603,7 @@
match new_seqpacket_pair() {
Ok((request_socket, child_socket)) => {
self.request_sockets.push(request_socket);
- response_fds.push(child_socket.as_raw_fd());
+ response_fds.push(child_socket.as_raw_descriptor());
boxed_fds.push(box_owned_fd(child_socket));
Ok(())
}
@@ -605,7 +611,7 @@
}
} else if request.has_get_shutdown_eventfd() {
response.mut_get_shutdown_eventfd();
- response_fds.push(self.kill_evt.as_raw_fd());
+ response_fds.push(self.kill_evt.as_raw_descriptor());
Ok(())
} else if request.has_check_extension() {
// Safe because the Cap enum is not read by the check_extension method. In that method,
@@ -650,8 +656,8 @@
} 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());
+ response_fds.push(pipe.plugin_write.as_raw_descriptor());
+ response_fds.push(pipe.plugin_read.as_raw_descriptor());
}
Ok(())
} else if request.has_start() {
@@ -667,7 +673,7 @@
Some(tap) => {
match Self::handle_get_net_config(tap, response.mut_get_net_config()) {
Ok(_) => {
- response_fds.push(tap.as_raw_fd());
+ response_fds.push(tap.as_raw_descriptor());
Ok(())
}
Err(e) => Err(e),
diff --git a/src/plugin/vcpu.rs b/src/plugin/vcpu.rs
index 022d990..9438bb2 100644
--- a/src/plugin/vcpu.rs
+++ b/src/plugin/vcpu.rs
@@ -322,10 +322,7 @@
impl<'a> VcpuRunData<'a> {
fn is_write(&self) -> bool {
- match self {
- VcpuRunData::Write(_) => true,
- _ => false,
- }
+ matches!(self, VcpuRunData::Write(_))
}
fn as_slice(&self) -> &[u8] {
diff --git a/sys_util/Android.bp b/sys_util/Android.bp
index a1499f2..5023be5 100644
--- a/sys_util/Android.bp
+++ b/sys_util/Android.bp
@@ -80,5 +80,5 @@
// libc-0.2.80 "default,std"
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// syn-1.0.53 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
// unicode-xid-0.2.1 "default"
diff --git a/sys_util/poll_token_derive/Android.bp b/sys_util/poll_token_derive/Android.bp
index f4efe20..4577dc1 100644
--- a/sys_util/poll_token_derive/Android.bp
+++ b/sys_util/poll_token_derive/Android.bp
@@ -31,5 +31,5 @@
// dependent_library ["feature_list"]
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// syn-1.0.53 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
// unicode-xid-0.2.1 "default"
diff --git a/sys_util/src/descriptor.rs b/sys_util/src/descriptor.rs
index 0eff3d0..5ee075a 100644
--- a/sys_util/src/descriptor.rs
+++ b/sys_util/src/descriptor.rs
@@ -3,11 +3,15 @@
// found in the LICENSE file.
use std::fs::File;
+use std::io::{Stderr, Stdin, Stdout};
use std::mem;
+use std::net::UdpSocket;
use std::ops::Drop;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use std::os::unix::net::{UnixDatagram, UnixStream};
-use crate::{errno_result, Result};
+use crate::net::UnlinkUnixSeqpacketListener;
+use crate::{errno_result, PollToken, Result};
pub type RawDescriptor = RawFd;
@@ -129,6 +133,17 @@
}
}
+/// Implement token for implementations that wish to use this struct as such
+impl PollToken for Descriptor {
+ fn as_raw_token(&self) -> u64 {
+ self.0 as u64
+ }
+
+ fn from_raw_token(data: u64) -> Self {
+ Descriptor(data as RawDescriptor)
+ }
+}
+
macro_rules! AsRawDescriptor {
($name:ident) => {
impl AsRawDescriptor for $name {
@@ -164,8 +179,42 @@
// descriptor container. That should go to either SafeDescriptor or another more
// relevant container type.
AsRawDescriptor!(File);
+AsRawDescriptor!(UnlinkUnixSeqpacketListener);
FromRawDescriptor!(File);
IntoRawDescriptor!(File);
+AsRawDescriptor!(Stdin);
+AsRawDescriptor!(Stdout);
+AsRawDescriptor!(Stderr);
+
+impl AsRawDescriptor for UdpSocket {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.as_raw_fd()
+ }
+}
+
+impl AsRawDescriptor for UnixStream {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.as_raw_fd()
+ }
+}
+
+impl AsRawDescriptor for UnixDatagram {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.as_raw_fd()
+ }
+}
+
+impl FromRawDescriptor for UnixDatagram {
+ unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
+ Self::from_raw_fd(descriptor)
+ }
+}
+
+impl IntoRawDescriptor for UnixDatagram {
+ fn into_raw_descriptor(self) -> RawDescriptor {
+ self.into_raw_fd()
+ }
+}
#[test]
fn clone_equality() {
diff --git a/sys_util/src/net.rs b/sys_util/src/net.rs
index 71ab3ee..5cc87f5 100644
--- a/sys_util/src/net.rs
+++ b/sys_util/src/net.rs
@@ -19,6 +19,7 @@
use libc::{recvfrom, MSG_PEEK, MSG_TRUNC};
use crate::sock_ctrl_msg::{ScmSocket, SCM_SOCKET_MAX_FD_COUNT};
+use crate::{AsRawDescriptor, RawDescriptor};
// Offset of sun_path in structure sockaddr_un.
fn sun_path_offset() -> usize {
@@ -338,6 +339,18 @@
}
}
+impl AsRawFd for &UnixSeqpacket {
+ fn as_raw_fd(&self) -> RawFd {
+ self.fd
+ }
+}
+
+impl AsRawDescriptor for UnixSeqpacket {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.fd
+ }
+}
+
/// Like a `UnixListener` but for accepting `UnixSeqpacket` type sockets.
pub struct UnixSeqpacketListener {
fd: RawFd,
diff --git a/sys_util/src/poll.rs b/sys_util/src/poll.rs
index 1b92c96..50af029 100644
--- a/sys_util/src/poll.rs
+++ b/sys_util/src/poll.rs
@@ -132,6 +132,11 @@
self.event.events & (EPOLLIN as u32) != 0
}
+ /// True if the `fd` associated with this token in `PollContext::add` is writable.
+ pub fn writable(&self) -> bool {
+ self.event.events & (EPOLLOUT 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
diff --git a/sys_util/src/signalfd.rs b/sys_util/src/signalfd.rs
index 0b50ea4..bdb94dd 100644
--- a/sys_util/src/signalfd.rs
+++ b/sys_util/src/signalfd.rs
@@ -12,8 +12,7 @@
use libc::{c_void, read, signalfd, signalfd_siginfo};
use libc::{EAGAIN, SFD_CLOEXEC, SFD_NONBLOCK};
-use crate::errno;
-use crate::signal;
+use crate::{errno, signal, AsRawDescriptor, RawDescriptor};
#[derive(Debug)]
pub enum Error {
@@ -135,6 +134,12 @@
}
}
+impl AsRawDescriptor for SignalFd {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.signalfd.as_raw_descriptor()
+ }
+}
+
impl Drop for SignalFd {
fn drop(&mut self) {
// This is thread-safe and safe in the sense that we're doing what
diff --git a/sys_util/src/syslog.rs b/sys_util/src/syslog.rs
index 8a80acc..3cb551a 100644
--- a/sys_util/src/syslog.rs
+++ b/sys_util/src/syslog.rs
@@ -21,6 +21,7 @@
//! ```
use crate::target_os::syslog::PlatformSyslog;
+use crate::RawDescriptor;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fmt::{self, Display};
@@ -308,6 +309,11 @@
fds.extend(state.file.iter().map(|f| f.as_raw_fd()));
}
+/// Does the same as push_fds, but using the RawDescriptorType
+pub fn push_descriptors(descriptors: &mut Vec<RawDescriptor>) {
+ push_fds(descriptors)
+}
+
/// Records a log message with the given details.
///
/// Note that this will fail silently if syslog was not initialized.
diff --git a/tests/boot.rs b/tests/boot.rs
index 4277072..5eab683 100644
--- a/tests/boot.rs
+++ b/tests/boot.rs
@@ -15,7 +15,7 @@
use arch::{set_default_serial_parameters, SerialHardware, SerialParameters, SerialType};
use base::syslog;
-use crosvm::{linux, Config, Executable};
+use crosvm::{platform, Config, Executable};
const CHROOT_KERNEL_PATH: &str = "/mnt/host/source/src/third_party/kernel/v4.19/";
const CONTAINER_VM_DEFCONFIG: &str = "arch/x86/configs/chromiumos-container-vm-x86_64_defconfig";
@@ -243,6 +243,6 @@
set_default_serial_parameters(&mut c.serial_parameters);
c.executable_path = Some(Executable::Kernel(kernel_path));
- let r = linux::run_config(c);
+ let r = platform::run_config(c);
r.expect("failed to run linux");
}
diff --git a/tests/plugins.rs b/tests/plugins.rs
index 054ce6a..e7c872e 100644
--- a/tests/plugins.rs
+++ b/tests/plugins.rs
@@ -8,7 +8,6 @@
use std::ffi::OsString;
use std::fs::remove_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;
@@ -127,7 +126,7 @@
run_plugin(&bin_path.0, true);
}
-fn keep_fd_on_exec<F: AsRawFd>(f: &F) {
+fn keep_fd_on_exec<F: AsRawDescriptor>(f: &F) {
unsafe {
ioctl(f, 0x5450 /* FIONCLEX */);
}
diff --git a/usb_sys/Android.bp b/usb_sys/Android.bp
index 960736b..2583e50 100644
--- a/usb_sys/Android.bp
+++ b/usb_sys/Android.bp
@@ -38,14 +38,31 @@
// dependent_library ["feature_list"]
// ../assertions/src/lib.rs
// ../base/src/lib.rs
+// ../cros_async/src/lib.rs
// ../data_model/src/lib.rs
+// ../io_uring/src/lib.rs
// ../sync/src/lib.rs
// ../sys_util/poll_token_derive/poll_token_derive.rs
// ../sys_util/src/lib.rs
// ../syscall_defines/src/lib.rs
// ../tempfile/src/lib.rs
+// async-trait-0.1.42
+// futures-0.3.8 "alloc"
+// futures-channel-0.3.8 "alloc,futures-sink,sink"
+// futures-core-0.3.8 "alloc"
+// futures-io-0.3.8
+// futures-sink-0.3.8 "alloc"
+// futures-task-0.3.8 "alloc"
+// futures-util-0.3.8 "alloc,futures-sink,sink"
// libc-0.2.80 "default,std"
+// paste-1.0.3
+// pin-project-1.0.2
+// pin-project-internal-1.0.2
+// pin-utils-0.1.0
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// slab-0.4.2
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// thiserror-1.0.22
+// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/usb_util/Android.bp b/usb_util/Android.bp
index a9b4f04..4b9afc5 100644
--- a/usb_util/Android.bp
+++ b/usb_util/Android.bp
@@ -48,16 +48,33 @@
// dependent_library ["feature_list"]
// ../assertions/src/lib.rs
// ../base/src/lib.rs
+// ../cros_async/src/lib.rs
// ../data_model/src/lib.rs
+// ../io_uring/src/lib.rs
// ../sync/src/lib.rs
// ../sys_util/poll_token_derive/poll_token_derive.rs
// ../sys_util/src/lib.rs
// ../syscall_defines/src/lib.rs
// ../tempfile/src/lib.rs
// ../usb_sys/src/lib.rs
+// async-trait-0.1.42
+// futures-0.3.8 "alloc"
+// futures-channel-0.3.8 "alloc,futures-sink,sink"
+// futures-core-0.3.8 "alloc"
+// futures-io-0.3.8
+// futures-sink-0.3.8 "alloc"
+// futures-task-0.3.8 "alloc"
+// futures-util-0.3.8 "alloc,futures-sink,sink"
// libc-0.2.80 "default,std"
+// paste-1.0.3
+// pin-project-1.0.2
+// pin-project-internal-1.0.2
+// pin-utils-0.1.0
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
// remain-0.2.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// slab-0.4.2
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// thiserror-1.0.22
+// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/vfio_sys/Android.bp b/vfio_sys/Android.bp
index f3d0701..17c4a1a 100644
--- a/vfio_sys/Android.bp
+++ b/vfio_sys/Android.bp
@@ -38,14 +38,31 @@
// dependent_library ["feature_list"]
// ../assertions/src/lib.rs
// ../base/src/lib.rs
+// ../cros_async/src/lib.rs
// ../data_model/src/lib.rs
+// ../io_uring/src/lib.rs
// ../sync/src/lib.rs
// ../sys_util/poll_token_derive/poll_token_derive.rs
// ../sys_util/src/lib.rs
// ../syscall_defines/src/lib.rs
// ../tempfile/src/lib.rs
+// async-trait-0.1.42
+// futures-0.3.8 "alloc"
+// futures-channel-0.3.8 "alloc,futures-sink,sink"
+// futures-core-0.3.8 "alloc"
+// futures-io-0.3.8
+// futures-sink-0.3.8 "alloc"
+// futures-task-0.3.8 "alloc"
+// futures-util-0.3.8 "alloc,futures-sink,sink"
// libc-0.2.80 "default,std"
+// paste-1.0.3
+// pin-project-1.0.2
+// pin-project-internal-1.0.2
+// pin-utils-0.1.0
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// slab-0.4.2
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// thiserror-1.0.22
+// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/vhost/Android.bp b/vhost/Android.bp
index 6da545d..9c393eb 100644
--- a/vhost/Android.bp
+++ b/vhost/Android.bp
@@ -76,7 +76,7 @@
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// thiserror-1.0.22
// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/vhost/src/lib.rs b/vhost/src/lib.rs
index bc750d6..1af9af6 100644
--- a/vhost/src/lib.rs
+++ b/vhost/src/lib.rs
@@ -13,12 +13,11 @@
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 base::{ioctl, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref};
-use base::{Event, LayoutAllocation};
+use base::{AsRawDescriptor, Event, LayoutAllocation};
use vm_memory::{GuestAddress, GuestMemory, GuestMemoryError};
#[derive(Debug)]
@@ -64,7 +63,7 @@
/// 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 {
+pub trait Vhost: AsRawDescriptor + std::marker::Sized {
/// Get the guest memory mapping.
fn mem(&self) -> &GuestMemory;
@@ -298,11 +297,11 @@
///
/// # Arguments
/// * `queue_index` - Index of the queue to modify.
- /// * `fd` - Event to trigger.
- fn set_vring_call(&self, queue_index: usize, fd: &Event) -> Result<()> {
+ /// * `event` - Event to trigger.
+ fn set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()> {
let vring_file = virtio_sys::vhost_vring_file {
index: queue_index as u32,
- fd: fd.as_raw_fd(),
+ event: event.as_raw_descriptor(),
};
// This ioctl is called on a valid vhost_net fd and has its
@@ -320,10 +319,10 @@
/// # Arguments
/// * `queue_index` - Index of the queue to modify.
/// * `fd` - Event that will be signaled from guest.
- fn set_vring_kick(&self, queue_index: usize, fd: &Event) -> Result<()> {
+ fn set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()> {
let vring_file = virtio_sys::vhost_vring_file {
index: queue_index as u32,
- fd: fd.as_raw_fd(),
+ event: event.as_raw_descriptor(),
};
// This ioctl is called on a valid vhost_net fd and has its
diff --git a/vhost/src/net.rs b/vhost/src/net.rs
index 3263efb..df6de95 100644
--- a/vhost/src/net.rs
+++ b/vhost/src/net.rs
@@ -6,9 +6,8 @@
use std::fs::{File, OpenOptions};
use std::marker::PhantomData;
use std::os::unix::fs::OpenOptionsExt;
-use std::os::unix::io::{AsRawFd, RawFd};
-use base::ioctl_with_ref;
+use base::{ioctl_with_ref, AsRawDescriptor, RawDescriptor};
use vm_memory::GuestMemory;
use super::{ioctl_result, Error, Result, Vhost};
@@ -20,14 +19,14 @@
/// 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
+ // descriptor must be dropped first, which will stop and tear down the
// vhost-net worker before GuestMemory can potentially be unmapped.
- fd: File,
+ descriptor: File,
mem: GuestMemory,
phantom: PhantomData<T>,
}
-pub trait NetT<T: TapT>: Vhost + AsRawFd + Send + Sized {
+pub trait NetT<T: TapT>: Vhost + AsRawDescriptor + Send + Sized {
/// Create a new NetT instance
fn new(mem: &GuestMemory) -> Result<Self>;
@@ -36,8 +35,8 @@
///
/// # 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: Option<&T>) -> Result<()>;
+ /// * `descriptor` - Tap interface that will be used as the backend.
+ fn set_backend(&self, queue_index: usize, descriptor: Option<&T>) -> Result<()>;
}
impl<T> NetT<T> for Net<T>
@@ -50,7 +49,7 @@
/// * `mem` - Guest memory mapping.
fn new(mem: &GuestMemory) -> Result<Net<T>> {
Ok(Net::<T> {
- fd: OpenOptions::new()
+ descriptor: OpenOptions::new()
.read(true)
.write(true)
.custom_flags(libc::O_CLOEXEC | libc::O_NONBLOCK)
@@ -61,16 +60,21 @@
})
}
- fn set_backend(&self, queue_index: usize, fd: Option<&T>) -> Result<()> {
+ fn set_backend(&self, queue_index: usize, event: Option<&T>) -> Result<()> {
let vring_file = virtio_sys::vhost_vring_file {
index: queue_index as u32,
- fd: fd.map_or(-1, |fd| fd.as_raw_fd()),
+ event: event.map_or(-1, |event| event.as_raw_descriptor()),
};
- // This ioctl is called on a valid vhost_net fd and has its
+ // This ioctl is called on a valid vhost_net descriptor and has its
// return value checked.
- let ret =
- unsafe { ioctl_with_ref(&self.fd, virtio_sys::VHOST_NET_SET_BACKEND(), &vring_file) };
+ let ret = unsafe {
+ ioctl_with_ref(
+ &self.descriptor,
+ virtio_sys::VHOST_NET_SET_BACKEND(),
+ &vring_file,
+ )
+ };
if ret < 0 {
return ioctl_result();
}
@@ -84,9 +88,9 @@
}
}
-impl<T> AsRawFd for Net<T> {
- fn as_raw_fd(&self) -> RawFd {
- self.fd.as_raw_fd()
+impl<T> AsRawDescriptor for Net<T> {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.descriptor.as_raw_descriptor()
}
}
@@ -98,7 +102,7 @@
const TMP_FILE: &str = "/tmp/crosvm_vhost_test_file";
pub struct FakeNet<T> {
- fd: File,
+ descriptor: File,
mem: GuestMemory,
phantom: PhantomData<T>,
}
@@ -115,7 +119,7 @@
{
fn new(mem: &GuestMemory) -> Result<FakeNet<T>> {
Ok(FakeNet::<T> {
- fd: OpenOptions::new()
+ descriptor: OpenOptions::new()
.read(true)
.append(true)
.create(true)
@@ -137,9 +141,9 @@
}
}
- impl<T> AsRawFd for FakeNet<T> {
- fn as_raw_fd(&self) -> RawFd {
- self.fd.as_raw_fd()
+ impl<T> AsRawDescriptor for FakeNet<T> {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.descriptor.as_raw_descriptor()
}
}
}
diff --git a/vhost/src/vsock.rs b/vhost/src/vsock.rs
index e4b24fe..95fbb72 100644
--- a/vhost/src/vsock.rs
+++ b/vhost/src/vsock.rs
@@ -4,9 +4,8 @@
use std::fs::{File, OpenOptions};
use std::os::unix::fs::OpenOptionsExt;
-use std::os::unix::io::{AsRawFd, RawFd};
-use base::ioctl_with_ref;
+use base::{ioctl_with_ref, AsRawDescriptor, RawDescriptor};
use virtio_sys::{VHOST_VSOCK_SET_GUEST_CID, VHOST_VSOCK_SET_RUNNING};
use vm_memory::GuestMemory;
@@ -16,7 +15,7 @@
/// Handle for running VHOST_VSOCK ioctls.
pub struct Vsock {
- fd: File,
+ descriptor: File,
mem: GuestMemory,
}
@@ -24,7 +23,7 @@
/// Open a handle to a new VHOST_VSOCK instance.
pub fn new(mem: &GuestMemory) -> Result<Vsock> {
Ok(Vsock {
- fd: OpenOptions::new()
+ descriptor: OpenOptions::new()
.read(true)
.write(true)
.custom_flags(libc::O_CLOEXEC | libc::O_NONBLOCK)
@@ -41,7 +40,7 @@
/// # 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) };
+ let ret = unsafe { ioctl_with_ref(&self.descriptor, VHOST_VSOCK_SET_GUEST_CID(), &cid) };
if ret < 0 {
return ioctl_result();
}
@@ -60,7 +59,7 @@
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) };
+ let ret = unsafe { ioctl_with_ref(&self.descriptor, VHOST_VSOCK_SET_RUNNING(), &on) };
if ret < 0 {
return ioctl_result();
@@ -75,8 +74,8 @@
}
}
-impl AsRawFd for Vsock {
- fn as_raw_fd(&self) -> RawFd {
- self.fd.as_raw_fd()
+impl AsRawDescriptor for Vsock {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ self.descriptor.as_raw_descriptor()
}
}
diff --git a/virtio_sys/Android.bp b/virtio_sys/Android.bp
index 97899e4..2b96727 100644
--- a/virtio_sys/Android.bp
+++ b/virtio_sys/Android.bp
@@ -38,14 +38,31 @@
// dependent_library ["feature_list"]
// ../assertions/src/lib.rs
// ../base/src/lib.rs
+// ../cros_async/src/lib.rs
// ../data_model/src/lib.rs
+// ../io_uring/src/lib.rs
// ../sync/src/lib.rs
// ../sys_util/poll_token_derive/poll_token_derive.rs
// ../sys_util/src/lib.rs
// ../syscall_defines/src/lib.rs
// ../tempfile/src/lib.rs
+// async-trait-0.1.42
+// futures-0.3.8 "alloc"
+// futures-channel-0.3.8 "alloc,futures-sink,sink"
+// futures-core-0.3.8 "alloc"
+// futures-io-0.3.8
+// futures-sink-0.3.8 "alloc"
+// futures-task-0.3.8 "alloc"
+// futures-util-0.3.8 "alloc,futures-sink,sink"
// libc-0.2.80 "default,std"
+// paste-1.0.3
+// pin-project-1.0.2
+// pin-project-internal-1.0.2
+// pin-utils-0.1.0
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.50 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// slab-0.4.2
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// thiserror-1.0.22
+// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/virtio_sys/src/vhost.rs b/virtio_sys/src/vhost.rs
index 70d2db6..020d43c 100644
--- a/virtio_sys/src/vhost.rs
+++ b/virtio_sys/src/vhost.rs
@@ -574,7 +574,7 @@
#[derive(Debug, Default, Copy)]
pub struct vhost_vring_file {
pub index: ::std::os::raw::c_uint,
- pub fd: ::std::os::raw::c_int,
+ pub event: ::std::os::raw::c_int,
}
#[test]
fn bindgen_test_layout_vhost_vring_file() {
@@ -599,7 +599,7 @@
)
);
assert_eq!(
- unsafe { &(*(0 as *const vhost_vring_file)).fd as *const _ as usize },
+ unsafe { &(*(0 as *const vhost_vring_file)).event as *const _ as usize },
4usize,
concat!(
"Alignment of field: ",
diff --git a/vm_control/Android.bp b/vm_control/Android.bp
index cf0ad82..032beb0 100644
--- a/vm_control/Android.bp
+++ b/vm_control/Android.bp
@@ -71,6 +71,7 @@
// ../tempfile/src/lib.rs
// ../vm_memory/src/lib.rs
// async-trait-0.1.42
+// base-0.1.0
// downcast-rs-1.2.0 "default,std"
// futures-0.3.8 "alloc,async-await,default,executor,futures-executor,std"
// futures-channel-0.3.8 "alloc,futures-sink,sink,std"
@@ -93,7 +94,7 @@
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// thiserror-1.0.22
// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/vm_control/Cargo.toml b/vm_control/Cargo.toml
index e383679..2382059 100644
--- a/vm_control/Cargo.toml
+++ b/vm_control/Cargo.toml
@@ -4,8 +4,12 @@
authors = ["The Chromium OS Authors"]
edition = "2018"
+[features]
+gdb = ["gdbstub"]
+
[dependencies]
data_model = { path = "../data_model" }
+gdbstub = { version = "0.4.0", optional = true }
hypervisor = { path = "../hypervisor" }
libc = "*"
msg_socket = { path = "../msg_socket" }
diff --git a/vm_control/src/gdb.rs b/vm_control/src/gdb.rs
new file mode 100644
index 0000000..cf1cf6d
--- /dev/null
+++ b/vm_control/src/gdb.rs
@@ -0,0 +1,35 @@
+// Copyright 2020 The Chromium OS 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")]
+use gdbstub::arch::x86::reg::X86_64CoreRegs as CoreRegs;
+use vm_memory::GuestAddress;
+
+/// Messages that can be sent to a vCPU to set/get its state from the debugger.
+#[derive(Debug)]
+pub enum VcpuDebug {
+ ReadMem(GuestAddress, usize),
+ ReadRegs,
+ WriteRegs(Box<CoreRegs>),
+ WriteMem(GuestAddress, Vec<u8>),
+ EnableSinglestep,
+ SetHwBreakPoint(Vec<GuestAddress>),
+}
+
+/// Messages that can be sent from a vCPU to update the state to the debugger.
+#[derive(Debug)]
+pub enum VcpuDebugStatus {
+ RegValues(CoreRegs),
+ MemoryRegion(Vec<u8>),
+ CommandComplete,
+ HitBreakPoint,
+}
+
+/// Pair of a vCPU ID and messages that can be sent from the vCPU to update the state to the
+/// debugger.
+#[derive(Debug)]
+pub struct VcpuDebugStatusMessage {
+ pub cpu: usize,
+ pub msg: VcpuDebugStatus,
+}
diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs
index 92bf35a..311ad7e 100644
--- a/vm_control/src/lib.rs
+++ b/vm_control/src/lib.rs
@@ -10,18 +10,23 @@
//! The wire message format is a little-endian C-struct of fixed size, along with a file descriptor
//! if the request type expects one.
+#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+pub mod gdb;
+
use std::fmt::{self, Display};
use std::fs::File;
use std::io::{Seek, SeekFrom};
use std::mem::ManuallyDrop;
-use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::result::Result as StdResult;
+use std::str::FromStr;
use std::sync::Arc;
use libc::{EINVAL, EIO, ENODEV};
use base::{
- error, AsRawDescriptor, Error as SysError, Event, ExternalMapping, MappedRegion,
- MemoryMappingBuilder, MmapError, RawDescriptor, Result,
+ error, AsRawDescriptor, Error as SysError, Event, ExternalMapping, FromRawDescriptor,
+ IntoRawDescriptor, MappedRegion, MemoryMappingBuilder, MmapError, RawDescriptor, Result,
+ SafeDescriptor,
};
use hypervisor::{IrqRoute, IrqSource, Vm};
use msg_socket::{MsgError, MsgOnSocket, MsgReceiver, MsgResult, MsgSender, MsgSocket};
@@ -29,60 +34,80 @@
use sync::Mutex;
use vm_memory::GuestAddress;
+#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+pub use crate::gdb::*;
pub use hypervisor::MemSlot;
+/// Control the state of a particular VM CPU.
+#[derive(Debug)]
+pub enum VcpuControl {
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ Debug(VcpuDebug),
+ RunState(VmRunMode),
+}
+
/// A file descriptor either borrowed or owned by this.
#[derive(Debug)]
-pub enum MaybeOwnedFd {
+pub enum MaybeOwnedDescriptor {
/// Owned by this enum variant, and will be destructed automatically if not moved out.
- Owned(File),
+ Owned(SafeDescriptor),
/// A file descriptor borrwed by this enum.
Borrowed(RawDescriptor),
}
-impl AsRawDescriptor for MaybeOwnedFd {
+impl AsRawDescriptor for MaybeOwnedDescriptor {
fn as_raw_descriptor(&self) -> RawDescriptor {
match self {
- MaybeOwnedFd::Owned(f) => f.as_raw_descriptor(),
- MaybeOwnedFd::Borrowed(descriptor) => *descriptor,
+ MaybeOwnedDescriptor::Owned(f) => f.as_raw_descriptor(),
+ MaybeOwnedDescriptor::Borrowed(descriptor) => *descriptor,
}
}
}
-// TODO(mikehoyle): Remove this in favor of just AsRawDescriptor
-impl AsRawFd for MaybeOwnedFd {
- fn as_raw_fd(&self) -> RawFd {
- self.as_raw_descriptor()
+impl AsRawDescriptor for &MaybeOwnedDescriptor {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
+ match self {
+ MaybeOwnedDescriptor::Owned(f) => f.as_raw_descriptor(),
+ MaybeOwnedDescriptor::Borrowed(descriptor) => *descriptor,
+ }
}
}
// When sent, it could be owned or borrowed. On the receiver end, it always owned.
-impl MsgOnSocket for MaybeOwnedFd {
- fn uses_fd() -> bool {
+impl MsgOnSocket for MaybeOwnedDescriptor {
+ fn uses_descriptor() -> bool {
true
}
fn fixed_size() -> Option<usize> {
Some(0)
}
- fn fd_count(&self) -> usize {
+ fn descriptor_count(&self) -> usize {
1usize
}
- unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
- let (file, size) = File::read_from_buffer(buffer, fds)?;
- Ok((MaybeOwnedFd::Owned(file), size))
+ unsafe fn read_from_buffer(
+ buffer: &[u8],
+ descriptors: &[RawDescriptor],
+ ) -> MsgResult<(Self, usize)> {
+ let (file, size) = File::read_from_buffer(buffer, descriptors)?;
+ let safe_descriptor = SafeDescriptor::from_raw_descriptor(file.into_raw_descriptor());
+ Ok((MaybeOwnedDescriptor::Owned(safe_descriptor), size))
}
- fn write_to_buffer(&self, _buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
- if fds.is_empty() {
- return Err(MsgError::WrongFdBufferSize);
+ fn write_to_buffer(
+ &self,
+ _buffer: &mut [u8],
+ descriptors: &mut [RawDescriptor],
+ ) -> MsgResult<usize> {
+ if descriptors.is_empty() {
+ return Err(MsgError::WrongDescriptorBufferSize);
}
- fds[0] = self.as_raw_fd();
+ descriptors[0] = self.as_raw_descriptor();
Ok(1)
}
}
/// Mode of execution for the VM.
-#[derive(Debug)]
+#[derive(Debug, Clone, PartialEq)]
pub enum VmRunMode {
/// The default run mode indicating the VCPUs are running.
Running,
@@ -90,6 +115,8 @@
Suspending,
/// Indicates that the VM is exiting all processes.
Exiting,
+ /// Indicates that the VM is in a breakpoint waiting for the debugger to do continue.
+ Breakpoint,
}
impl Display for VmRunMode {
@@ -100,6 +127,7 @@
Running => write!(f, "running"),
Suspending => write!(f, "suspending"),
Exiting => write!(f, "exiting"),
+ Breakpoint => write!(f, "breakpoint"),
}
}
}
@@ -215,7 +243,7 @@
addr: u8,
vid: u16,
pid: u16,
- fd: Option<MaybeOwnedFd>,
+ descriptor: Option<MaybeOwnedDescriptor>,
},
DetachDevice {
port: u8,
@@ -271,12 +299,12 @@
#[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),
+ /// Register shared memory represented by the given descriptor into guest address space.
+ /// The response variant is `VmResponse::RegisterMemory`.
+ RegisterMemory(MaybeOwnedDescriptor, usize),
/// Similiar to `VmMemoryRequest::RegisterMemory`, but doesn't allocate new address space.
/// Useful for cases where the address space is already allocated (PCI regions).
- RegisterFdAtPciBarOffset(Alloc, MaybeOwnedFd, usize, u64),
+ RegisterFdAtPciBarOffset(Alloc, MaybeOwnedDescriptor, usize, u64),
/// Similar to RegisterFdAtPciBarOffset, but is for buffers in the current address space.
RegisterHostPointerAtPciBarOffset(Alloc, u64),
/// Unregister the given memory slot that was previously registered with `RegisterMemory*`.
@@ -290,7 +318,7 @@
},
/// Register mmaped memory into the hypervisor's EPT.
RegisterMmapMemory {
- fd: MaybeOwnedFd,
+ descriptor: MaybeOwnedDescriptor,
size: usize,
offset: u64,
gpa: u64,
@@ -315,14 +343,14 @@
) -> VmMemoryResponse {
use self::VmMemoryRequest::*;
match *self {
- RegisterMemory(ref fd, size) => {
- match register_memory(vm, sys_allocator, fd, size, None) {
+ RegisterMemory(ref descriptor, size) => {
+ match register_memory(vm, sys_allocator, descriptor, size, None) {
Ok((pfn, slot)) => VmMemoryResponse::RegisterMemory { pfn, slot },
Err(e) => VmMemoryResponse::Err(e),
}
}
- RegisterFdAtPciBarOffset(alloc, ref fd, size, offset) => {
- match register_memory(vm, sys_allocator, fd, size, Some((alloc, offset))) {
+ RegisterFdAtPciBarOffset(alloc, ref descriptor, size, offset) => {
+ match register_memory(vm, sys_allocator, descriptor, size, Some((alloc, offset))) {
Ok((pfn, slot)) => VmMemoryResponse::RegisterMemory { pfn, slot },
Err(e) => VmMemoryResponse::Err(e),
}
@@ -363,7 +391,11 @@
};
match register_memory(vm, sys_allocator, &fd, size as usize, None) {
Ok((pfn, slot)) => VmMemoryResponse::AllocateAndRegisterGpuMemory {
- fd: MaybeOwnedFd::Owned(fd),
+ // Safe because ownership is transferred to SafeDescriptor via
+ // into_raw_descriptor
+ descriptor: MaybeOwnedDescriptor::Owned(unsafe {
+ SafeDescriptor::from_raw_descriptor(fd.into_raw_descriptor())
+ }),
pfn,
slot,
desc,
@@ -372,13 +404,13 @@
}
}
RegisterMmapMemory {
- ref fd,
+ ref descriptor,
size,
offset,
gpa,
} => {
let mmap = match MemoryMappingBuilder::new(size)
- .from_descriptor(fd)
+ .from_descriptor(descriptor)
.offset(offset as u64)
.build()
{
@@ -405,7 +437,7 @@
/// 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,
+ descriptor: MaybeOwnedDescriptor,
pfn: u64,
slot: MemSlot,
desc: GpuMemoryDesc,
@@ -417,7 +449,7 @@
#[derive(MsgOnSocket, Debug)]
pub enum VmIrqRequest {
/// Allocate one gsi, and associate gsi to irqfd with register_irqfd()
- AllocateOneMsi { irqfd: MaybeOwnedFd },
+ AllocateOneMsi { irqfd: MaybeOwnedDescriptor },
/// Add one msi route entry into the IRQ chip.
AddMsiRoute {
gsi: u32,
@@ -451,15 +483,17 @@
match *self {
AllocateOneMsi { ref irqfd } => {
if let Some(irq_num) = sys_allocator.allocate_irq() {
- // Beacuse of the limitation of `MaybeOwnedFd` not fitting into `register_irqfd`
- // which expects an `&Event`, we use the unsafe `from_raw_fd` to assume that
- // the fd given is an `Event`, and we ignore the ownership question using
- // `ManuallyDrop`. This is safe because `ManuallyDrop` prevents any Drop
- // implementation from triggering on `irqfd` which already has an owner, and the
- // `Event` methods are never called. The underlying fd is merely passed to the
- // kernel which doesn't care about ownership and deals with incorrect FDs, in
- // the case of bugs on our part.
- let evt = unsafe { ManuallyDrop::new(Event::from_raw_fd(irqfd.as_raw_fd())) };
+ // Because of the limitation of `MaybeOwnedDescriptor` not fitting into
+ // `register_irqfd` which expects an `&Event`, we use the unsafe `from_raw_fd`
+ // to assume that the descriptor given is an `Event`, and we ignore the
+ // ownership question using `ManuallyDrop`. This is safe because `ManuallyDrop`
+ // prevents any Drop implementation from triggering on `irqfd` which already has
+ // an owner, and the `Event` methods are never called. The underlying descriptor
+ // is merely passed to the kernel which doesn't care about ownership and deals
+ // with incorrect FDs, in the case of bugs on our part.
+ let evt = unsafe {
+ ManuallyDrop::new(Event::from_raw_descriptor(irqfd.as_raw_descriptor()))
+ };
match set_up_irq(IrqSetup::Event(irq_num, &evt)) {
Ok(_) => VmIrqResponse::AllocateOneMsi { gsi: irq_num },
@@ -536,9 +570,208 @@
}
}
+#[derive(MsgOnSocket, Debug)]
+pub enum BatControlResult {
+ Ok,
+ NoBatDevice,
+ NoSuchHealth,
+ NoSuchProperty,
+ NoSuchStatus,
+ NoSuchBatType,
+ StringParseIntErr,
+}
+
+impl Display for BatControlResult {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use self::BatControlResult::*;
+
+ match self {
+ Ok => write!(f, "Setting battery property successfully"),
+ NoBatDevice => write!(f, "No battery device created"),
+ NoSuchHealth => write!(f, "Invalid Battery health setting. Only support: unknown/good/overheat/dead/overvoltage/unexpectedfailure/cold/watchdogtimerexpire/safetytimerexpire/overcurrent"),
+ NoSuchProperty => write!(f, "Battery doesn't have such property. Only support: status/health/present/capacity/aconline"),
+ NoSuchStatus => write!(f, "Invalid Battery status setting. Only support: unknown/charging/discharging/notcharging/full"),
+ NoSuchBatType => write!(f, "Invalid Battery type setting. Only support: goldfish"),
+ StringParseIntErr => write!(f, "Battery property target ParseInt error"),
+ }
+ }
+}
+
+#[derive(MsgOnSocket, Copy, Clone, Debug, PartialEq)]
+pub enum BatteryType {
+ Goldfish,
+}
+
+impl Default for BatteryType {
+ fn default() -> Self {
+ BatteryType::Goldfish
+ }
+}
+
+impl FromStr for BatteryType {
+ type Err = BatControlResult;
+
+ fn from_str(s: &str) -> StdResult<Self, Self::Err> {
+ match s {
+ "goldfish" => Ok(BatteryType::Goldfish),
+ _ => Err(BatControlResult::NoSuchBatType),
+ }
+ }
+}
+
+#[derive(MsgOnSocket, Debug)]
+pub enum BatProperty {
+ Status,
+ Health,
+ Present,
+ Capacity,
+ ACOnline,
+}
+
+impl FromStr for BatProperty {
+ type Err = BatControlResult;
+
+ fn from_str(s: &str) -> StdResult<Self, Self::Err> {
+ match s {
+ "status" => Ok(BatProperty::Status),
+ "health" => Ok(BatProperty::Health),
+ "present" => Ok(BatProperty::Present),
+ "capacity" => Ok(BatProperty::Capacity),
+ "aconline" => Ok(BatProperty::ACOnline),
+ _ => Err(BatControlResult::NoSuchProperty),
+ }
+ }
+}
+
+#[derive(MsgOnSocket, Debug)]
+pub enum BatStatus {
+ Unknown,
+ Charging,
+ DisCharging,
+ NotCharging,
+ Full,
+}
+
+impl BatStatus {
+ pub fn new(status: String) -> std::result::Result<Self, BatControlResult> {
+ match status.as_str() {
+ "unknown" => Ok(BatStatus::Unknown),
+ "charging" => Ok(BatStatus::Charging),
+ "discharging" => Ok(BatStatus::DisCharging),
+ "notcharging" => Ok(BatStatus::NotCharging),
+ "full" => Ok(BatStatus::Full),
+ _ => Err(BatControlResult::NoSuchStatus),
+ }
+ }
+}
+
+impl FromStr for BatStatus {
+ type Err = BatControlResult;
+
+ fn from_str(s: &str) -> StdResult<Self, Self::Err> {
+ match s {
+ "unknown" => Ok(BatStatus::Unknown),
+ "charging" => Ok(BatStatus::Charging),
+ "discharging" => Ok(BatStatus::DisCharging),
+ "notcharging" => Ok(BatStatus::NotCharging),
+ "full" => Ok(BatStatus::Full),
+ _ => Err(BatControlResult::NoSuchStatus),
+ }
+ }
+}
+
+impl From<BatStatus> for u32 {
+ fn from(status: BatStatus) -> Self {
+ status as u32
+ }
+}
+
+#[derive(MsgOnSocket, Debug)]
+pub enum BatHealth {
+ Unknown,
+ Good,
+ Overheat,
+ Dead,
+ OverVoltage,
+ UnexpectedFailure,
+ Cold,
+ WatchdogTimerExpire,
+ SafetyTimerExpire,
+ OverCurrent,
+}
+
+impl FromStr for BatHealth {
+ type Err = BatControlResult;
+
+ fn from_str(s: &str) -> StdResult<Self, Self::Err> {
+ match s {
+ "unknown" => Ok(BatHealth::Unknown),
+ "good" => Ok(BatHealth::Good),
+ "overheat" => Ok(BatHealth::Overheat),
+ "dead" => Ok(BatHealth::Dead),
+ "overvoltage" => Ok(BatHealth::OverVoltage),
+ "unexpectedfailure" => Ok(BatHealth::UnexpectedFailure),
+ "cold" => Ok(BatHealth::Cold),
+ "watchdogtimerexpire" => Ok(BatHealth::WatchdogTimerExpire),
+ "safetytimerexpire" => Ok(BatHealth::SafetyTimerExpire),
+ "overcurrent" => Ok(BatHealth::OverCurrent),
+ _ => Err(BatControlResult::NoSuchHealth),
+ }
+ }
+}
+
+impl From<BatHealth> for u32 {
+ fn from(status: BatHealth) -> Self {
+ status as u32
+ }
+}
+
+#[derive(MsgOnSocket, Debug)]
+pub enum BatControlCommand {
+ SetStatus(BatStatus),
+ SetHealth(BatHealth),
+ SetPresent(u32),
+ SetCapacity(u32),
+ SetACOnline(u32),
+}
+
+impl BatControlCommand {
+ pub fn new(property: String, target: String) -> std::result::Result<Self, BatControlResult> {
+ let cmd = property.parse::<BatProperty>()?;
+ match cmd {
+ BatProperty::Status => Ok(BatControlCommand::SetStatus(target.parse::<BatStatus>()?)),
+ BatProperty::Health => Ok(BatControlCommand::SetHealth(target.parse::<BatHealth>()?)),
+ BatProperty::Present => Ok(BatControlCommand::SetPresent(
+ target
+ .parse::<u32>()
+ .map_err(|_| BatControlResult::StringParseIntErr)?,
+ )),
+ BatProperty::Capacity => Ok(BatControlCommand::SetCapacity(
+ target
+ .parse::<u32>()
+ .map_err(|_| BatControlResult::StringParseIntErr)?,
+ )),
+ BatProperty::ACOnline => Ok(BatControlCommand::SetACOnline(
+ target
+ .parse::<u32>()
+ .map_err(|_| BatControlResult::StringParseIntErr)?,
+ )),
+ }
+ }
+}
+
+/// Used for VM to control battery properties.
+pub struct BatControl {
+ pub type_: BatteryType,
+ pub control_socket: BatControlRequestSocket,
+}
+
pub type BalloonControlRequestSocket = MsgSocket<BalloonControlCommand, BalloonControlResult>;
pub type BalloonControlResponseSocket = MsgSocket<BalloonControlResult, BalloonControlCommand>;
+pub type BatControlRequestSocket = MsgSocket<BatControlCommand, BatControlResult>;
+pub type BatControlResponseSocket = MsgSocket<BatControlResult, BatControlCommand>;
+
pub type DiskControlRequestSocket = MsgSocket<DiskControlCommand, DiskControlResult>;
pub type DiskControlResponseSocket = MsgSocket<DiskControlResult, DiskControlCommand>;
@@ -577,16 +810,21 @@
},
/// Command to use controller.
UsbCommand(UsbControlCommand),
+ /// Command to set battery.
+ BatCommand(BatteryType, BatControlCommand),
}
fn register_memory(
vm: &mut impl Vm,
allocator: &mut SystemAllocator,
- fd: &dyn AsRawDescriptor,
+ descriptor: &dyn AsRawDescriptor,
size: usize,
pci_allocation: Option<(Alloc, u64)>,
) -> Result<(u64, MemSlot)> {
- let mmap = match MemoryMappingBuilder::new(size).from_descriptor(fd).build() {
+ let mmap = match MemoryMappingBuilder::new(size)
+ .from_descriptor(descriptor)
+ .build()
+ {
Ok(v) => v,
Err(MmapError::SystemCallFailed(e)) => return Err(e),
_ => return Err(SysError::new(EINVAL)),
@@ -638,6 +876,7 @@
balloon_host_socket: &BalloonControlRequestSocket,
disk_host_sockets: &[DiskControlRequestSocket],
usb_control_socket: &UsbControlSocket,
+ bat_control: &mut Option<BatControl>,
) -> VmResponse {
match *self {
VmRequest::Exit => {
@@ -713,6 +952,31 @@
}
}
}
+ VmRequest::BatCommand(type_, ref cmd) => {
+ match bat_control {
+ Some(battery) => {
+ if battery.type_ != type_ {
+ error!("ignored battery command due to battery type: expected {:?}, got {:?}", battery.type_, type_);
+ return VmResponse::Err(SysError::new(EINVAL));
+ }
+
+ let res = battery.control_socket.send(cmd);
+ if let Err(e) = res {
+ error!("fail to send command to bat control socket: {}", e);
+ return VmResponse::Err(SysError::new(EIO));
+ }
+
+ match battery.control_socket.recv() {
+ Ok(response) => VmResponse::BatResponse(response),
+ Err(e) => {
+ error!("fail to recv command from bat control socket: {}", e);
+ VmResponse::Err(SysError::new(EIO))
+ }
+ }
+ }
+ None => VmResponse::BatResponse(BatControlResult::NoBatDevice),
+ }
+ }
}
}
}
@@ -732,7 +996,7 @@
/// 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,
+ descriptor: MaybeOwnedDescriptor,
pfn: u64,
slot: u32,
desc: GpuMemoryDesc,
@@ -744,6 +1008,8 @@
},
/// Results of usb control commands.
UsbResponse(UsbControlResult),
+ /// Results of battery control commands.
+ BatResponse(BatControlResult),
}
impl Display for VmResponse {
@@ -772,6 +1038,7 @@
balloon_actual, stats
),
UsbResponse(result) => write!(f, "usb control request get result {:?}", result),
+ BatResponse(result) => write!(f, "{}", result),
}
}
}
diff --git a/vm_memory/Android.bp b/vm_memory/Android.bp
index a9463bb..5d35372 100644
--- a/vm_memory/Android.bp
+++ b/vm_memory/Android.bp
@@ -70,7 +70,7 @@
// proc-macro2-1.0.24 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// thiserror-1.0.22
// thiserror-impl-1.0.22
// unicode-xid-0.2.1 "default"
diff --git a/vm_memory/src/guest_memory.rs b/vm_memory/src/guest_memory.rs
index 8a1640b..a7b9d53 100644
--- a/vm_memory/src/guest_memory.rs
+++ b/vm_memory/src/guest_memory.rs
@@ -8,7 +8,6 @@
use std::convert::TryFrom;
use std::fmt::{self, Display};
use std::mem::size_of;
-use std::os::unix::io::{AsRawFd, RawFd};
use std::result;
use std::sync::Arc;
@@ -16,7 +15,7 @@
use base::{pagesize, Error as SysError};
use base::{
AsRawDescriptor, MappedRegion, MemfdSeals, MemoryMapping, MemoryMappingBuilder, MmapError,
- SharedMemory, SharedMemoryUnix,
+ RawDescriptor, SharedMemory, SharedMemoryUnix,
};
use cros_async::{
uring_mem::{self, BorrowedIoVec},
@@ -115,8 +114,8 @@
memfd: Arc<SharedMemory>,
}
-impl AsRawFd for GuestMemory {
- fn as_raw_fd(&self) -> RawFd {
+impl AsRawDescriptor for GuestMemory {
+ fn as_raw_descriptor(&self) -> RawDescriptor {
self.memfd.as_raw_descriptor()
}
}
diff --git a/x86_64/Android.bp b/x86_64/Android.bp
index 8677080..d78feaa 100644
--- a/x86_64/Android.bp
+++ b/x86_64/Android.bp
@@ -26,6 +26,7 @@
"libvm_memory",
],
proc_macros: ["libremain"],
+ // Exclude arm family manually
arch: {
arm: {
enabled: false,
@@ -62,6 +63,7 @@
"libvm_memory",
],
proc_macros: ["libremain"],
+ // Exclude arm family manually
arch: {
arm: {
enabled: false,
@@ -88,6 +90,7 @@
// ../../adhd/cras/client/libcras/src/libcras.rs
// ../../minijail/rust/minijail-sys/lib.rs
// ../../minijail/rust/minijail/src/lib.rs
+// ../../rust/crates/libchromeos-rs/src/lib.rs
// ../../vm_tools/p9/src/lib.rs
// ../../vm_tools/p9/wire_format_derive/wire_format_derive.rs
// ../acpi_tables/src/lib.rs
@@ -101,6 +104,7 @@
// ../devices/src/lib.rs
// ../disk/src/disk.rs
// ../enumn/src/lib.rs
+// ../fuse/src/lib.rs
// ../hypervisor/src/lib.rs
// ../io_uring/src/lib.rs
// ../kernel_cmdline/src/kernel_cmdline.rs
@@ -127,6 +131,8 @@
// ../vm_control/src/lib.rs
// ../vm_memory/src/lib.rs
// async-trait-0.1.42
+// autocfg-1.0.1
+// base-0.1.0
// bitflags-1.2.1 "default"
// cfg-if-0.1.10
// downcast-rs-1.2.0 "default,std"
@@ -139,9 +145,13 @@
// futures-sink-0.3.8 "alloc,std"
// futures-task-0.3.8 "alloc,once_cell,std"
// futures-util-0.3.8 "alloc,async-await,async-await-macro,channel,futures-channel,futures-io,futures-macro,futures-sink,io,memchr,proc-macro-hack,proc-macro-nested,sink,slab,std"
+// getopts-0.2.21
// getrandom-0.1.15 "std"
+// intrusive-collections-0.9.0 "alloc,default"
// libc-0.2.80 "default,std"
+// log-0.4.11
// memchr-2.3.4 "default,std"
+// memoffset-0.5.6 "default"
// once_cell-1.5.2 "alloc,std"
// paste-1.0.3
// pin-project-1.0.2
@@ -152,6 +162,7 @@
// proc-macro-hack-0.5.19
// proc-macro-nested-0.1.6
// proc-macro2-1.0.24 "default,proc-macro"
+// protobuf-2.18.1
// quote-1.0.7 "default,proc-macro"
// rand-0.7.3 "alloc,default,getrandom,getrandom_package,libc,std"
// rand_chacha-0.2.2 "std"
@@ -159,8 +170,9 @@
// remain-0.2.2
// remove_dir_all-0.5.3
// slab-0.4.2
-// syn-1.0.50 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+// syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
// tempfile-3.1.0
// thiserror-1.0.22
// thiserror-impl-1.0.22
+// unicode-width-0.1.8 "default"
// unicode-xid-0.2.1 "default"
diff --git a/x86_64/Cargo.toml b/x86_64/Cargo.toml
index 7ed07cf..21e019d 100644
--- a/x86_64/Cargo.toml
+++ b/x86_64/Cargo.toml
@@ -4,16 +4,21 @@
authors = ["The Chromium OS Authors"]
edition = "2018"
+[features]
+gdb = ["gdbstub", "msg_socket", "arch/gdb"]
+
[dependencies]
arch = { path = "../arch" }
assertions = { path = "../assertions" }
data_model = { path = "../data_model" }
devices = { path = "../devices" }
+gdbstub = { version = "0.4.0", optional = true }
hypervisor = { path = "../hypervisor" }
kernel_cmdline = { path = "../kernel_cmdline" }
kernel_loader = { path = "../kernel_loader" }
libc = "*"
minijail = { path = "../../minijail/rust/minijail" } # ignored by ebuild
+msg_socket = { path = "../msg_socket", optional = true }
remain = "*"
resources = { path = "../resources" }
sync = { path = "../sync" }
diff --git a/x86_64/src/cpuid.rs b/x86_64/src/cpuid.rs
index 38d2a89..f8cd977 100644
--- a/x86_64/src/cpuid.rs
+++ b/x86_64/src/cpuid.rs
@@ -6,7 +6,8 @@
use std::fmt::{self, Display};
use std::result;
-use hypervisor::{HypervisorCap, HypervisorX86_64, VcpuX86_64};
+use devices::{IrqChipCap, IrqChipX86_64};
+use hypervisor::{HypervisorX86_64, VcpuX86_64};
#[derive(Debug, PartialEq)]
pub enum Error {
@@ -34,7 +35,8 @@
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_TSC_DEADLINE_TIMER_SHIFT: u32 = 24; // TSC deadline mode of APIC timer
+const ECX_X2APIC_SHIFT: u32 = 21; // APIC supports extended xAPIC (x2APIC) standard.
+const ECX_TSC_DEADLINE_TIMER_SHIFT: u32 = 24; // TSC deadline mode of APIC timer.
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.
const ECX_TOPO_TYPE_SHIFT: u32 = 8; // Topology Level type.
@@ -45,7 +47,7 @@
vcpu_id: usize,
cpu_count: usize,
cpuid: &mut hypervisor::CpuId,
- hypervisor: &dyn HypervisorX86_64,
+ irq_chip: &dyn IrqChipX86_64,
no_smt: bool,
) -> Result<()> {
let entries = &mut cpuid.cpu_id_entries;
@@ -57,7 +59,12 @@
if entry.index == 0 {
entry.ecx |= 1 << ECX_HYPERVISOR_SHIFT;
}
- if hypervisor.check_capability(&HypervisorCap::TscDeadlineTimer) {
+ if irq_chip.check_capability(IrqChipCap::X2Apic) {
+ entry.ecx |= 1 << ECX_X2APIC_SHIFT;
+ } else {
+ entry.ecx &= !(1 << ECX_X2APIC_SHIFT);
+ }
+ if irq_chip.check_capability(IrqChipCap::TscDeadlineTimer) {
entry.ecx |= 1 << ECX_TSC_DEADLINE_TIMER_SHIFT;
}
entry.ebx = (vcpu_id << EBX_CPUID_SHIFT) as u32
@@ -129,6 +136,7 @@
/// * `nrcpus` - The number of vcpus being used by this VM.
pub fn setup_cpuid(
hypervisor: &dyn HypervisorX86_64,
+ irq_chip: &dyn IrqChipX86_64,
vcpu: &dyn VcpuX86_64,
vcpu_id: usize,
nrcpus: usize,
@@ -138,7 +146,7 @@
.get_supported_cpuid()
.map_err(Error::GetSupportedCpusFailed)?;
- filter_cpuid(vcpu_id, nrcpus, &mut cpuid, hypervisor, no_smt)?;
+ filter_cpuid(vcpu_id, nrcpus, &mut cpuid, irq_chip, no_smt)?;
vcpu.set_cpuid(&cpuid)
.map_err(Error::SetSupportedCpusFailed)
@@ -165,7 +173,11 @@
#[test]
fn feature_and_vendor_name() {
let mut cpuid = hypervisor::CpuId::new(2);
- let hypervisor = hypervisor::kvm::Kvm::new().unwrap();
+ let guest_mem =
+ vm_memory::GuestMemory::new(&[(vm_memory::GuestAddress(0), 0x10000)]).unwrap();
+ let kvm = hypervisor::kvm::Kvm::new().unwrap();
+ let vm = hypervisor::kvm::KvmVm::new(&kvm, guest_mem).unwrap();
+ let irq_chip = devices::KvmKernelIrqChip::new(vm, 1).unwrap();
let entries = &mut cpuid.cpu_id_entries;
entries.push(CpuIdEntry {
@@ -178,7 +190,7 @@
edx: 0,
..Default::default()
});
- assert_eq!(Ok(()), filter_cpuid(1, 2, &mut cpuid, &hypervisor, false));
+ assert_eq!(Ok(()), filter_cpuid(1, 2, &mut cpuid, &irq_chip, false));
let entries = &mut cpuid.cpu_id_entries;
assert_eq!(entries[0].function, 0);
diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs
index ef44adc..cc00a79 100644
--- a/x86_64/src/lib.rs
+++ b/x86_64/src/lib.rs
@@ -67,7 +67,13 @@
use remain::sorted;
use resources::SystemAllocator;
use sync::Mutex;
+use vm_control::{BatControl, BatteryType};
use vm_memory::{GuestAddress, GuestMemory, GuestMemoryError};
+#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+use {
+ gdbstub::arch::x86::reg::X86_64CoreRegs,
+ hypervisor::x86_64::{Regs, Sregs},
+};
#[sorted]
#[derive(Debug)]
@@ -77,6 +83,7 @@
CloneEvent(base::Error),
Cmdline(kernel_cmdline::Error),
ConfigureSystem,
+ CreateBatDevices(arch::DeviceRegistrationError),
CreateDevices(Box<dyn StdError>),
CreateEvent(base::Error),
CreateFdt(arch::fdt::Error),
@@ -90,6 +97,7 @@
CreateVcpu(base::Error),
CreateVm(Box<dyn StdError>),
E820Configuration,
+ EnableSinglestep(base::Error),
EnableSplitIrqchip(base::Error),
GetSerialCmdline(GetSerialCmdlineError),
KernelOffsetPastEnd,
@@ -98,9 +106,13 @@
LoadCmdline(kernel_loader::Error),
LoadInitrd(arch::LoadImageError),
LoadKernel(kernel_loader::Error),
+ PageNotPresent,
Pstore(arch::pstore::Error),
+ ReadingGuestMemory(vm_memory::GuestMemoryError),
+ ReadRegs(base::Error),
RegisterIrqfd(base::Error),
RegisterVsock(arch::DeviceRegistrationError),
+ SetHwBreakpoint(base::Error),
SetLint(interrupts::Error),
SetTssAddr(base::Error),
SetupCpuid(cpuid::Error),
@@ -111,6 +123,9 @@
SetupRegs(regs::Error),
SetupSmbios(smbios::Error),
SetupSregs(regs::Error),
+ TranslatingVirtAddr,
+ WriteRegs(base::Error),
+ WritingGuestMemory(GuestMemoryError),
ZeroPagePastRamEnd,
ZeroPageSetup,
}
@@ -127,6 +142,7 @@
CloneEvent(e) => write!(f, "unable to clone an Event: {}", e),
Cmdline(e) => write!(f, "the given kernel command line was invalid: {}", e),
ConfigureSystem => write!(f, "error configuring the system"),
+ CreateBatDevices(e) => write!(f, "unable to create battery devices: {}", e),
CreateDevices(e) => write!(f, "error creating devices: {}", e),
CreateEvent(e) => write!(f, "unable to make an Event: {}", e),
CreateFdt(e) => write!(f, "failed to create fdt: {}", e),
@@ -140,6 +156,7 @@
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"),
+ EnableSinglestep(e) => write!(f, "failed to enable singlestep execution: {}", e),
EnableSplitIrqchip(e) => write!(f, "failed to enable split irqchip: {}", e),
GetSerialCmdline(e) => write!(f, "failed to get serial cmdline: {}", e),
KernelOffsetPastEnd => write!(f, "the kernel extends past the end of RAM"),
@@ -148,9 +165,13 @@
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),
+ PageNotPresent => write!(f, "error translating address: Page not present"),
Pstore(e) => write!(f, "failed to allocate pstore region: {}", e),
+ ReadingGuestMemory(e) => write!(f, "error reading guest memory {}", e),
+ ReadRegs(e) => write!(f, "error reading CPU registers {}", e),
RegisterIrqfd(e) => write!(f, "error registering an IrqFd: {}", e),
RegisterVsock(e) => write!(f, "error registering virtual socket device: {}", e),
+ SetHwBreakpoint(e) => write!(f, "failed to set a hardware breakpoint: {}", 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),
@@ -161,6 +182,9 @@
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),
+ TranslatingVirtAddr => write!(f, "failed to translate virtual address"),
+ WriteRegs(e) => write!(f, "error writing CPU registers {}", e),
+ WritingGuestMemory(e) => write!(f, "error writing guest memory {}", 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"),
}
@@ -325,6 +349,7 @@
mut components: VmComponents,
serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
serial_jail: Option<Minijail>,
+ battery: (&Option<BatteryType>, Option<Minijail>),
create_devices: FD,
create_vm: FV,
create_irq_chip: FI,
@@ -345,10 +370,7 @@
E2: StdError + 'static,
E3: StdError + 'static,
{
- let has_bios = match components.vm_image {
- VmImage::Bios(_) => true,
- _ => false,
- };
+ let has_bios = matches!(components.vm_image, VmImage::Bios(_));
let mem = Self::setup_memory(components.memory_size, has_bios)?;
let mut resources = Self::get_resource_allocator(&mem, components.wayland_dmabuf);
@@ -395,11 +417,15 @@
serial_jail,
)?;
- let acpi_dev_resource = Self::setup_acpi_devices(
+ let (acpi_dev_resource, bat_control) = Self::setup_acpi_devices(
&mut io_bus,
&mut resources,
suspend_evt.try_clone().map_err(Error::CloneEvent)?,
+ exit_evt.try_clone().map_err(Error::CloneEvent)?,
components.acpi_sdts,
+ &mut irq_chip,
+ battery,
+ &mut mmio_bus,
)?;
let ramoops_region = match components.pstore {
@@ -489,6 +515,9 @@
pid_debug_label_map,
suspend_evt,
rt_cpus: components.rt_cpus,
+ bat_control,
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ gdb: components.gdb,
})
}
@@ -502,7 +531,7 @@
has_bios: bool,
no_smt: bool,
) -> Result<()> {
- cpuid::setup_cpuid(hypervisor, vcpu, vcpu_id, num_cpus, no_smt)
+ cpuid::setup_cpuid(hypervisor, irq_chip, vcpu, vcpu_id, num_cpus, no_smt)
.map_err(Error::SetupCpuid)?;
if has_bios {
@@ -527,6 +556,234 @@
Ok(())
}
+
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ fn debug_read_registers<T: VcpuX86_64>(vcpu: &T) -> Result<X86_64CoreRegs> {
+ // General registers: RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, r8-r15
+ let gregs = vcpu.get_regs().map_err(Error::ReadRegs)?;
+ let regs = [
+ gregs.rax, gregs.rbx, gregs.rcx, gregs.rdx, gregs.rsi, gregs.rdi, gregs.rbp, gregs.rsp,
+ gregs.r8, gregs.r9, gregs.r10, gregs.r11, gregs.r12, gregs.r13, gregs.r14, gregs.r15,
+ ];
+
+ // GDB exposes 32-bit eflags instead of 64-bit rflags.
+ // https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/64bit-core.xml
+ let eflags = gregs.rflags as u32;
+ let rip = gregs.rip;
+
+ // Segment registers: CS, SS, DS, ES, FS, GS
+ let sregs = vcpu.get_sregs().map_err(Error::ReadRegs)?;
+ let sgs = [sregs.cs, sregs.ss, sregs.ds, sregs.es, sregs.fs, sregs.gs];
+ let mut segments = [0u32; 6];
+ // GDB uses only the selectors.
+ for i in 0..sgs.len() {
+ segments[i] = sgs[i].selector as u32;
+ }
+
+ // TODO(keiichiw): Other registers such as FPU, xmm and mxcsr.
+
+ Ok(X86_64CoreRegs {
+ regs,
+ eflags,
+ rip,
+ segments,
+ ..Default::default()
+ })
+ }
+
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ fn debug_write_registers<T: VcpuX86_64>(vcpu: &T, regs: &X86_64CoreRegs) -> Result<()> {
+ // General purpose registers (RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, r8-r15) + RIP + rflags
+ let orig_gregs = vcpu.get_regs().map_err(Error::ReadRegs)?;
+ let gregs = Regs {
+ rax: regs.regs[0],
+ rbx: regs.regs[1],
+ rcx: regs.regs[2],
+ rdx: regs.regs[3],
+ rsi: regs.regs[4],
+ rdi: regs.regs[5],
+ rbp: regs.regs[6],
+ rsp: regs.regs[7],
+ r8: regs.regs[8],
+ r9: regs.regs[9],
+ r10: regs.regs[10],
+ r11: regs.regs[11],
+ r12: regs.regs[12],
+ r13: regs.regs[13],
+ r14: regs.regs[14],
+ r15: regs.regs[15],
+ rip: regs.rip,
+ // Update the lower 32 bits of rflags.
+ rflags: (orig_gregs.rflags & !(u32::MAX as u64)) | (regs.eflags as u64),
+ };
+ vcpu.set_regs(&gregs).map_err(Error::WriteRegs)?;
+
+ // Segment registers: CS, SS, DS, ES, FS, GS
+ // Since GDB care only selectors, we call get_sregs() first.
+ let mut sregs = vcpu.get_sregs().map_err(Error::ReadRegs)?;
+ sregs.cs.selector = regs.segments[0] as u16;
+ sregs.ss.selector = regs.segments[1] as u16;
+ sregs.ds.selector = regs.segments[2] as u16;
+ sregs.es.selector = regs.segments[3] as u16;
+ sregs.fs.selector = regs.segments[4] as u16;
+ sregs.gs.selector = regs.segments[5] as u16;
+
+ vcpu.set_sregs(&sregs).map_err(Error::WriteRegs)?;
+
+ // TODO(keiichiw): Other registers such as FPU, xmm and mxcsr.
+
+ Ok(())
+ }
+
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ fn debug_read_memory<T: VcpuX86_64>(
+ vcpu: &T,
+ guest_mem: &GuestMemory,
+ vaddr: GuestAddress,
+ len: usize,
+ ) -> Result<Vec<u8>> {
+ let sregs = vcpu.get_sregs().map_err(Error::ReadRegs)?;
+ let mut buf = vec![0; len];
+ let mut total_read = 0u64;
+ // Handle reads across page boundaries.
+
+ while total_read < len as u64 {
+ let (paddr, psize) = phys_addr(guest_mem, vaddr.0 + total_read, &sregs)?;
+ let read_len = std::cmp::min(len as u64 - total_read, psize - (paddr & (psize - 1)));
+ guest_mem
+ .get_slice_at_addr(GuestAddress(paddr), read_len as usize)
+ .map_err(Error::ReadingGuestMemory)?
+ .copy_to(&mut buf[total_read as usize..]);
+ total_read += read_len;
+ }
+ Ok(buf)
+ }
+
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ fn debug_write_memory<T: VcpuX86_64>(
+ vcpu: &T,
+ guest_mem: &GuestMemory,
+ vaddr: GuestAddress,
+ buf: &[u8],
+ ) -> Result<()> {
+ let sregs = vcpu.get_sregs().map_err(Error::ReadRegs)?;
+ let mut total_written = 0u64;
+ // Handle writes across page boundaries.
+ while total_written < buf.len() as u64 {
+ let (paddr, psize) = phys_addr(guest_mem, vaddr.0 + total_written, &sregs)?;
+ let write_len = std::cmp::min(
+ buf.len() as u64 - total_written,
+ psize - (paddr & (psize - 1)),
+ );
+
+ guest_mem
+ .write_all_at_addr(
+ &buf[total_written as usize..(total_written as usize + write_len as usize)],
+ GuestAddress(paddr),
+ )
+ .map_err(Error::WritingGuestMemory)?;
+ total_written += write_len;
+ }
+ Ok(())
+ }
+
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ fn debug_enable_singlestep<T: VcpuX86_64>(vcpu: &T) -> Result<()> {
+ vcpu.set_guest_debug(&[], true /* enable_singlestep */)
+ .map_err(Error::EnableSinglestep)
+ }
+
+ #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+ fn debug_set_hw_breakpoints<T: VcpuX86_64>(
+ vcpu: &T,
+ breakpoints: &[GuestAddress],
+ ) -> Result<()> {
+ vcpu.set_guest_debug(&breakpoints, false /* enable_singlestep */)
+ .map_err(Error::SetHwBreakpoint)
+ }
+}
+
+#[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+// return the translated address and the size of the page it resides in.
+fn phys_addr(mem: &GuestMemory, vaddr: u64, sregs: &Sregs) -> Result<(u64, u64)> {
+ const CR0_PG_MASK: u64 = 1 << 31;
+ const CR4_PAE_MASK: u64 = 1 << 5;
+ const CR4_LA57_MASK: u64 = 1 << 12;
+ const MSR_EFER_LMA: u64 = 1 << 10;
+ // bits 12 through 51 are the address in a PTE.
+ const PTE_ADDR_MASK: u64 = ((1 << 52) - 1) & !0x0fff;
+ const PAGE_PRESENT: u64 = 0x1;
+ const PAGE_PSE_MASK: u64 = 0x1 << 7;
+
+ const PAGE_SIZE_4K: u64 = 4 * 1024;
+ const PAGE_SIZE_2M: u64 = 2 * 1024 * 1024;
+ const PAGE_SIZE_1G: u64 = 1024 * 1024 * 1024;
+
+ fn next_pte(mem: &GuestMemory, curr_table_addr: u64, vaddr: u64, level: usize) -> Result<u64> {
+ let ent: u64 = mem
+ .read_obj_from_addr(GuestAddress(
+ (curr_table_addr & PTE_ADDR_MASK) + page_table_offset(vaddr, level),
+ ))
+ .map_err(|_| Error::TranslatingVirtAddr)?;
+ /* TODO - convert to a trace
+ println!(
+ "level {} vaddr {:x} table-addr {:x} mask {:x} ent {:x} offset {:x}",
+ level,
+ vaddr,
+ curr_table_addr,
+ PTE_ADDR_MASK,
+ ent,
+ page_table_offset(vaddr, level)
+ );
+ */
+ if ent & PAGE_PRESENT == 0 {
+ return Err(Error::PageNotPresent);
+ }
+ Ok(ent)
+ }
+
+ // Get the offset in to the page of `vaddr`.
+ fn page_offset(vaddr: u64, page_size: u64) -> u64 {
+ vaddr & (page_size - 1)
+ }
+
+ // Get the offset in to the page table of the given `level` specified by the virtual `address`.
+ // `level` is 1 through 5 in x86_64 to handle the five levels of paging.
+ fn page_table_offset(addr: u64, level: usize) -> u64 {
+ let offset = (level - 1) * 9 + 12;
+ ((addr >> offset) & 0x1ff) << 3
+ }
+
+ if sregs.cr0 & CR0_PG_MASK == 0 {
+ return Ok((vaddr, PAGE_SIZE_4K));
+ }
+
+ if sregs.cr4 & CR4_PAE_MASK == 0 {
+ return Err(Error::TranslatingVirtAddr);
+ }
+
+ if sregs.efer & MSR_EFER_LMA != 0 {
+ // TODO - check LA57
+ if sregs.cr4 & CR4_LA57_MASK != 0 {}
+ let p4_ent = next_pte(mem, sregs.cr3, vaddr, 4)?;
+ let p3_ent = next_pte(mem, p4_ent, vaddr, 3)?;
+ // TODO check if it's a 1G page with the PSE bit in p2_ent
+ if p3_ent & PAGE_PSE_MASK != 0 {
+ // It's a 1G page with the PSE bit in p3_ent
+ let paddr = p3_ent & PTE_ADDR_MASK | page_offset(vaddr, PAGE_SIZE_1G);
+ return Ok((paddr, PAGE_SIZE_1G));
+ }
+ let p2_ent = next_pte(mem, p3_ent, vaddr, 2)?;
+ if p2_ent & PAGE_PSE_MASK != 0 {
+ // It's a 2M page with the PSE bit in p2_ent
+ let paddr = p2_ent & PTE_ADDR_MASK | page_offset(vaddr, PAGE_SIZE_2M);
+ return Ok((paddr, PAGE_SIZE_2M));
+ }
+ let p1_ent = next_pte(mem, p2_ent, vaddr, 1)?;
+ let paddr = p1_ent & PTE_ADDR_MASK | page_offset(vaddr, PAGE_SIZE_4K);
+ return Ok((paddr, PAGE_SIZE_4K));
+ }
+ Err(Error::TranslatingVirtAddr)
}
impl X8664arch {
@@ -736,7 +993,6 @@
Arc::new(Mutex::new(devices::Cmos::new(mem_below_4g, mem_above_4g))),
0x70,
0x2,
- false,
)
.unwrap();
@@ -746,25 +1002,19 @@
)));
if pit_uses_speaker_port {
- io_bus.insert(i8042, 0x062, 0x3, true).unwrap();
+ io_bus.insert(i8042, 0x062, 0x3).unwrap();
} else {
- io_bus.insert(i8042, 0x061, 0x4, true).unwrap();
+ io_bus.insert(i8042, 0x061, 0x4).unwrap();
}
- 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
+ io_bus.insert(nul_device.clone(), 0x0ed, 0x1).unwrap(); // most likely this one does nothing
+ io_bus.insert(nul_device.clone(), 0x0f0, 0x2).unwrap(); // ignore fpu
if let Some(pci_root) = pci {
- io_bus.insert(pci_root, 0xcf8, 0x8, false).unwrap();
+ io_bus.insert(pci_root, 0xcf8, 0x8).unwrap();
} else {
// ignore pci.
- io_bus
- .insert(nul_device.clone(), 0xcf8, 0x8, false)
- .unwrap();
+ io_bus.insert(nul_device.clone(), 0xcf8, 0x8).unwrap();
}
Ok(io_bus)
@@ -778,13 +1028,21 @@
/// * - `io_bus` the I/O bus to add the devices to
/// * - `resources` the SystemAllocator to allocate IO and MMIO for acpi
/// devices.
- /// * - `suspend_evt` - the event object which used to suspend the vm
+ /// * - `suspend_evt` the event object which used to suspend the vm
+ /// * - `sdts` ACPI system description tables
+ /// * - `irq_chip` the IrqChip object for registering irq events
+ /// * - `battery` indicate whether to create the battery
+ /// * - `mmio_bus` the MMIO bus to add the devices to
fn setup_acpi_devices(
io_bus: &mut devices::Bus,
resources: &mut SystemAllocator,
suspend_evt: Event,
+ exit_evt: Event,
sdts: Vec<SDT>,
- ) -> Result<acpi::ACPIDevResource> {
+ irq_chip: &mut impl IrqChip,
+ battery: (&Option<BatteryType>, Option<Minijail>),
+ mmio_bus: &mut devices::Bus,
+ ) -> Result<(acpi::ACPIDevResource, Option<BatControl>)> {
// The AML data for the acpi devices
let mut amls = Vec::new();
@@ -801,7 +1059,7 @@
None => 0x600,
};
- let pmresource = devices::ACPIPMResource::new(suspend_evt);
+ let pmresource = devices::ACPIPMResource::new(suspend_evt, exit_evt);
Aml::to_aml_bytes(&pmresource, &mut amls);
let pm = Arc::new(Mutex::new(pmresource));
io_bus
@@ -809,16 +1067,40 @@
pm.clone(),
pm_iobase as u64,
devices::acpi::ACPIPM_RESOURCE_LEN as u64,
- false,
)
.unwrap();
io_bus.notify_on_resume(pm);
- Ok(acpi::ACPIDevResource {
- amls,
- pm_iobase,
- sdts,
- })
+ let bat_control = if let Some(battery_type) = battery.0 {
+ match battery_type {
+ BatteryType::Goldfish => {
+ let control_socket = arch::add_goldfish_battery(
+ &mut amls,
+ battery.1,
+ mmio_bus,
+ irq_chip,
+ X86_64_SCI_IRQ,
+ resources,
+ )
+ .map_err(Error::CreateBatDevices)?;
+ Some(BatControl {
+ type_: BatteryType::Goldfish,
+ control_socket,
+ })
+ }
+ }
+ } else {
+ None
+ };
+
+ Ok((
+ acpi::ACPIDevResource {
+ amls,
+ pm_iobase,
+ sdts,
+ },
+ bat_control,
+ ))
}
/// Sets up the serial devices for this platform. Returns the serial port number and serial
diff --git a/x86_64/src/mptable.rs b/x86_64/src/mptable.rs
index 0354b4f..548ea33 100644
--- a/x86_64/src/mptable.rs
+++ b/x86_64/src/mptable.rs
@@ -268,7 +268,7 @@
base_mp = base_mp.unchecked_add(size as u64);
checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
}
- let pci_irq_base = super::X86_64_IRQ_BASE as u8;
+
// Insert PCI interrupts after platform IRQs.
for (address, irq_num, irq_pin) in pci_irqs.iter() {
let size = mem::size_of::<mpc_intsrc>();
@@ -285,8 +285,14 @@
base_mp = base_mp.unchecked_add(size as u64);
checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
}
+
+ let starting_isa_irq_num = pci_irqs
+ .into_iter()
+ .map(|(_, irq_num, _)| irq_num + 1)
+ .fold(super::X86_64_IRQ_BASE, u32::max) as u8;
+
// Finally insert ISA interrupts.
- for i in pci_irq_base + pci_irqs.len() as u8..16 {
+ for i in starting_isa_irq_num..16 {
let size = mem::size_of::<mpc_intsrc>();
let mut mpc_intsrc = mpc_intsrc::default();
mpc_intsrc.type_ = MP_INTSRC as u8;