Replace our memory manager implementation with vm-memory.

This is a large intrusive refactor but it will make it easier
to adopt other components from rust-vmm ecosystem in the future.

Our old implementation was also potentially problematic due to
an API which directly hands out [u8] slices to guest memory.

(See VolatileSlice and 'volatile_memory' module in vm-memory for
discussion about this issue)

Since the old memory manager also handled graphics memory buffers
this was rewritten into a separate component and moved into 'io'
module.

Uses of FileDesc class were removed and replaced by use of the
standard File type instead which accomplishes most of the same
goals.

MemoryFd was removed and replaced with memfd crate.
This commit is contained in:
Bruce Leidl 2024-01-11 08:53:48 -05:00
parent d426b8e749
commit 53a5bce2a2
53 changed files with 1087 additions and 1338 deletions

249
Cargo.lock generated
View File

@ -14,6 +14,12 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1a1eca3195b729bbd64e292ef2f5fff6b1c28504fed762ce2b1013dde4d8e92" checksum = "f1a1eca3195b729bbd64e292ef2f5fff6b1c28504fed762ce2b1013dde4d8e92"
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.37" version = "0.3.37"
@ -48,9 +54,15 @@ dependencies = [
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.1.0" version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
@ -89,6 +101,16 @@ dependencies = [
"libdbus-sys", "libdbus-sys",
] ]
[[package]]
name = "errno"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
dependencies = [
"libc",
"windows-sys",
]
[[package]] [[package]]
name = "failure" name = "failure"
version = "0.1.5" version = "0.1.5"
@ -135,7 +157,7 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24e40d6fd5d64e2082e0c796495c8ef5ad667a96d03e5aaa0becfd9d47bcbfb8" checksum = "24e40d6fd5d64e2082e0c796495c8ef5ad667a96d03e5aaa0becfd9d47bcbfb8"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
"inotify-sys", "inotify-sys",
"libc", "libc",
] ]
@ -177,9 +199,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.62" version = "0.2.151"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
[[package]] [[package]]
name = "libcitadel" name = "libcitadel"
@ -223,6 +245,33 @@ dependencies = [
"take_mut", "take_mut",
] ]
[[package]]
name = "libpulse-binding"
version = "2.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3557a2dfc380c8f061189a01c6ae7348354e0c9886038dc6c171219c08eaff"
dependencies = [
"bitflags 1.3.2",
"libc",
"libpulse-sys",
"num-derive",
"num-traits",
"winapi",
]
[[package]]
name = "libpulse-sys"
version = "1.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc19e110fbf42c17260d30f6d3dc545f58491c7830d38ecb9aaca96e26067a9b"
dependencies = [
"libc",
"num-derive",
"num-traits",
"pkg-config",
"winapi",
]
[[package]] [[package]]
name = "libsodium-sys" name = "libsodium-sys"
version = "0.2.4" version = "0.2.4"
@ -237,19 +286,54 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "linux-raw-sys"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
[[package]]
name = "memfd"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64"
dependencies = [
"rustix",
]
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.12.1" version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "319fffb13b63c0f4ff5a4e1c97566e7e741561ff5d03bf8bbf11653454bbd70b" checksum = "319fffb13b63c0f4ff5a4e1c97566e7e741561ff5d03bf8bbf11653454bbd70b"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
"cc", "cc",
"cfg-if", "cfg-if",
"libc", "libc",
"void", "void",
] ]
[[package]]
name = "num-derive"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
dependencies = [
"proc-macro2 1.0.69",
"quote 1.0.33",
"syn 1.0.107",
]
[[package]]
name = "num-traits"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "ph" name = "ph"
version = "0.1.0" version = "0.1.0"
@ -260,17 +344,21 @@ dependencies = [
"lazy_static", "lazy_static",
"libc", "libc",
"libcitadel", "libcitadel",
"libpulse-binding",
"memfd",
"signal-hook", "signal-hook",
"termios", "termios",
"thiserror", "thiserror",
"vm-allocator",
"vm-memory",
"vmm-sys-util", "vmm-sys-util",
] ]
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.16" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
@ -283,9 +371,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.50" version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -301,11 +389,11 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.2" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [ dependencies = [
"proc-macro2 1.0.50", "proc-macro2 1.0.69",
] ]
[[package]] [[package]]
@ -326,6 +414,19 @@ version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
[[package]]
name = "rustix"
version = "0.38.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
dependencies = [
"bitflags 2.4.1",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]] [[package]]
name = "same-file" name = "same-file"
version = "1.0.5" version = "1.0.5"
@ -347,8 +448,8 @@ version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" checksum = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
dependencies = [ dependencies = [
"proc-macro2 1.0.50", "proc-macro2 1.0.69",
"quote 1.0.2", "quote 1.0.33",
"syn 1.0.107", "syn 1.0.107",
] ]
@ -400,8 +501,19 @@ version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [ dependencies = [
"proc-macro2 1.0.50", "proc-macro2 1.0.69",
"quote 1.0.2", "quote 1.0.33",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
dependencies = [
"proc-macro2 1.0.69",
"quote 1.0.33",
"unicode-ident", "unicode-ident",
] ]
@ -446,22 +558,22 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.38" version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.38" version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
dependencies = [ dependencies = [
"proc-macro2 1.0.50", "proc-macro2 1.0.69",
"quote 1.0.2", "quote 1.0.33",
"syn 1.0.107", "syn 2.0.38",
] ]
[[package]] [[package]]
@ -491,13 +603,34 @@ version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95" checksum = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95"
[[package]]
name = "vm-allocator"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "565b6886b7dd1b3bf34ec9243d90a97db4f2a83c2416caa52fcc95fd255d45e4"
dependencies = [
"libc",
"thiserror",
]
[[package]]
name = "vm-memory"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5376c9ee5ebe2103a310d8241936cfb93c946734b0479a4fa5bdf7a64abbacd8"
dependencies = [
"libc",
"thiserror",
"winapi",
]
[[package]] [[package]]
name = "vmm-sys-util" name = "vmm-sys-util"
version = "0.11.1" version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd64fe09d8e880e600c324e7d664760a17f56e9672b7495a86381b49e4f72f46" checksum = "dd64fe09d8e880e600c324e7d664760a17f56e9672b7495a86381b49e4f72f46"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
"libc", "libc",
] ]
@ -549,6 +682,72 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]] [[package]]
name = "xattr" name = "xattr"
version = "0.2.2" version = "0.2.2"

View File

@ -14,7 +14,10 @@ lazy_static = "1.4.0"
signal-hook = "0.1.10" signal-hook = "0.1.10"
thiserror = "1.0" thiserror = "1.0"
vmm-sys-util = "0.11.1" vmm-sys-util = "0.11.1"
vm-memory = { version = "0.13.1", features = ["backend-mmap"] }
vm-allocator = "0.1.0"
kvm-ioctls = "0.12.0" kvm-ioctls = "0.12.0"
kvm-bindings = "0.6.0" kvm-bindings = "0.6.0"
memfd = "0.6.4"
pulse = { version = "2.27.1", package = "libpulse-binding" } pulse = { version = "2.27.1", package = "libpulse-binding" }
libcitadel = { git = "https://github.com/brl/citadel-tools", rev="44d5ce660f1f5cf8a3ad1060b143926a99be5148" } libcitadel = { git = "https://github.com/brl/citadel-tools", rev="44d5ce660f1f5cf8a3ad1060b143926a99be5148" }

View File

@ -1,27 +1,30 @@
use std::sync::mpsc; use std::sync::mpsc;
use std::thread; use std::thread;
use pulse::sample::{Format, Spec}; use pulse::sample::{Format, Spec};
use vm_memory::GuestMemoryMmap;
use crate::audio::pulse::context::PulseContext; use crate::audio::pulse::context::PulseContext;
use crate::audio::pulse::message::PulseMessageChannel; use crate::audio::pulse::message::PulseMessageChannel;
use crate::audio::pulse::Result; use crate::audio::pulse::Result;
use crate::audio::{SampleFormat, StreamDirection}; use crate::audio::{SampleFormat, StreamDirection};
use crate::audio::shm_streams::{GenericResult, NullShmStream, ShmStream, ShmStreamSource}; use crate::audio::shm_streams::{GenericResult, NullShmStream, ShmStream, ShmStreamSource};
use crate::memory::GuestRam;
pub struct PulseClient { pub struct PulseClient {
channel: PulseMessageChannel, channel: PulseMessageChannel,
} }
impl PulseClient { impl PulseClient {
pub fn connect(guest_ram: GuestRam) -> Result<Self> { pub fn connect(guest_memory: &GuestMemoryMmap) -> Result<Self> {
let (tx,rx) = mpsc::channel(); let (tx,rx) = mpsc::channel();
let _ = thread::spawn(move || { let _ = thread::spawn({
let mut ctx = PulseContext::new(guest_ram); let guest_memory = guest_memory.clone();
if let Err(err) = ctx.connect() { move || {
warn!("PulseAudio Error: {}", err); let mut ctx = PulseContext::new(guest_memory);
} else { if let Err(err) = ctx.connect() {
ctx.run(rx); warn!("PulseAudio Error: {}", err);
} else {
ctx.run(rx);
}
} }
}); });
Ok(PulseClient { Ok(PulseClient {

View File

@ -7,12 +7,12 @@ use pulse::mainloop::threaded::Mainloop;
use pulse::proplist::{properties, Proplist}; use pulse::proplist::{properties, Proplist};
use pulse::sample::Spec; use pulse::sample::Spec;
use pulse::stream::Stream; use pulse::stream::Stream;
use crate::memory::GuestRam; use vm_memory::GuestMemoryMmap;
use crate::audio::pulse::{Result, PulseError, PulseStream}; use crate::audio::pulse::{Result, PulseError, PulseStream};
use crate::audio::pulse::message::{PulseContextMessage, PulseContextRequest, PulseMessageChannel}; use crate::audio::pulse::message::{PulseContextMessage, PulseContextRequest, PulseMessageChannel};
pub struct PulseContext { pub struct PulseContext {
guest_ram: GuestRam, guest_memory: GuestMemoryMmap,
mainloop: Rc<RefCell<Mainloop>>, mainloop: Rc<RefCell<Mainloop>>,
context: Rc<RefCell<Context>>, context: Rc<RefCell<Context>>,
} }
@ -34,7 +34,7 @@ impl PulseContext {
self.mainloop.clone() self.mainloop.clone()
} }
pub fn new(guest_ram: GuestRam) -> Self { pub fn new(guest_memory: GuestMemoryMmap) -> Self {
let mainloop = Mainloop::new() let mainloop = Mainloop::new()
.expect("Failed to create a pulseaudio mainloop"); .expect("Failed to create a pulseaudio mainloop");
@ -51,7 +51,7 @@ impl PulseContext {
).expect("Failed to create a pulseaudio context"); ).expect("Failed to create a pulseaudio context");
PulseContext { PulseContext {
guest_ram, guest_memory,
mainloop: Rc::new(RefCell::new(mainloop)), mainloop: Rc::new(RefCell::new(mainloop)),
context: Rc::new(RefCell::new(context)), context: Rc::new(RefCell::new(context)),
} }
@ -111,7 +111,7 @@ impl PulseContext {
None) None)
.expect("Failed to create pulseaudio stream"); .expect("Failed to create pulseaudio stream");
let ps = PulseStream::new_playback(stream, self.guest_ram.clone(), spec, buffer_size, channel); let ps = PulseStream::new_playback(stream, self.guest_memory.clone(), spec, buffer_size, channel);
self.mainloop_unlock(); self.mainloop_unlock();
ps ps
} }

View File

@ -2,12 +2,11 @@ use std::sync::{Arc, Condvar, Mutex, MutexGuard};
use std::time::Duration; use std::time::Duration;
use pulse::sample::Spec; use pulse::sample::Spec;
use pulse::stream::{FlagSet, SeekMode, State, Stream}; use pulse::stream::{FlagSet, SeekMode, State, Stream};
use vm_memory::{Bytes, GuestAddress, GuestMemoryMmap};
use crate::audio::pulse::{PulseError,Result}; use crate::audio::pulse::{PulseError,Result};
use crate::audio::pulse::context::PulseContext; use crate::audio::pulse::context::PulseContext;
use crate::audio::pulse::message::PulseMessageChannel; use crate::audio::pulse::message::PulseMessageChannel;
use crate::audio::shm_streams::{BufferSet, GenericResult, ServerRequest, ShmStream}; use crate::audio::shm_streams::{BufferSet, GenericResult, ServerRequest, ShmStream};
use crate::memory::GuestRam;
struct Available { struct Available {
byte_count: Mutex<usize>, byte_count: Mutex<usize>,
cond: Condvar, cond: Condvar,
@ -52,7 +51,7 @@ impl Available {
pub struct PulseStream { pub struct PulseStream {
spec: Spec, spec: Spec,
buffer_size: usize, buffer_size: usize,
guest_ram: GuestRam, guest_memory: GuestMemoryMmap,
stream: Arc<Mutex<Stream>>, stream: Arc<Mutex<Stream>>,
avail: Arc<Available>, avail: Arc<Available>,
channel: PulseMessageChannel, channel: PulseMessageChannel,
@ -105,7 +104,7 @@ impl PulseStream {
result result
} }
pub fn new_playback(mut stream: Stream, guest_ram: GuestRam, spec: Spec, buffer_size: usize, channel: PulseMessageChannel) -> Self { pub fn new_playback(mut stream: Stream, guest_memory: GuestMemoryMmap, spec: Spec, buffer_size: usize, channel: PulseMessageChannel) -> Self {
let avail = Arc::new(Available::new()); let avail = Arc::new(Available::new());
stream.set_write_callback(Some(Box::new({ stream.set_write_callback(Some(Box::new({
@ -119,7 +118,7 @@ impl PulseStream {
PulseStream { PulseStream {
spec, spec,
buffer_size, buffer_size,
guest_ram, guest_memory,
avail, avail,
stream, stream,
channel, channel,
@ -166,12 +165,13 @@ impl ShmStream for PulseStream {
impl BufferSet for PulseStream { impl BufferSet for PulseStream {
fn callback(&self, address: u64, frames: usize) -> GenericResult<()> { fn callback(&self, address: u64, frames: usize) -> GenericResult<()> {
self.uncork()?; self.uncork()?;
let bytes = self.guest_ram.slice(address, frames * self.frame_size())?; let mut buffer = vec![0u8; frames * self.frame_size()];
self.guest_memory.read_slice(&mut buffer, GuestAddress(address))?;
self.channel.send_mainloop_lock()?; self.channel.send_mainloop_lock()?;
self.stream().write_copy(bytes, 0, SeekMode::Relative)?; self.stream().write_copy(&buffer, 0, SeekMode::Relative)?;
self.channel.send_mainloop_unlock()?; self.channel.send_mainloop_unlock()?;
self.avail.decrement(bytes.len()); self.avail.decrement(buffer.len());
Ok(()) Ok(())
} }

View File

@ -5,13 +5,13 @@
use std::io; use std::io;
use thiserror::Error; use thiserror::Error;
use vm_memory::GuestMemoryMmap;
use crate::audio::pulse::{PulseClient, PulseError}; use crate::audio::pulse::{PulseClient, PulseError};
use crate::devices::ac97::ac97_bus_master::{Ac97BusMaster, AudioStreamSource}; use crate::devices::ac97::ac97_bus_master::{Ac97BusMaster, AudioStreamSource};
use crate::devices::ac97::ac97_mixer::Ac97Mixer; use crate::devices::ac97::ac97_mixer::Ac97Mixer;
use crate::devices::ac97::ac97_regs::{MASTER_REGS_SIZE, MIXER_REGS_SIZE}; use crate::devices::ac97::ac97_regs::{MASTER_REGS_SIZE, MIXER_REGS_SIZE};
use crate::devices::irq_event::IrqLevelEvent; use crate::devices::irq_event::IrqLevelEvent;
use crate::io::pci::{PciBar, PciBarAllocation, PciConfiguration, PciDevice}; use crate::io::pci::{PciBar, PciBarAllocation, PciConfiguration, PciDevice};
use crate::memory::GuestRam;
use crate::vm::KvmVm; use crate::vm::KvmVm;
@ -48,7 +48,7 @@ impl Ac97Dev {
/// default values. /// default values.
pub fn new( pub fn new(
irq: u8, irq: u8,
mem: GuestRam, mem: &GuestMemoryMmap,
audio_server: AudioStreamSource, audio_server: AudioStreamSource,
) -> Self { ) -> Self {
let pci_config = PciConfiguration::new(irq, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_5, PCI_CLASS_MULTIMEDIA_AUDIO); let pci_config = PciConfiguration::new(irq, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_5, PCI_CLASS_MULTIMEDIA_AUDIO);
@ -57,7 +57,7 @@ impl Ac97Dev {
irq, irq,
pci_config, pci_config,
bus_master: Ac97BusMaster::new( bus_master: Ac97BusMaster::new(
mem, mem.clone(),
audio_server, audio_server,
), ),
mixer: Ac97Mixer::new(), mixer: Ac97Mixer::new(),
@ -69,7 +69,7 @@ impl Ac97Dev {
pub fn try_new( pub fn try_new(
kvm_vm: &KvmVm, kvm_vm: &KvmVm,
irq: u8, irq: u8,
mem: GuestRam, mem: &GuestMemoryMmap,
) -> Result<Self, Ac97Error> { ) -> Result<Self, Ac97Error> {
let mut ac97 = Self::initialize_pulseaudio(irq, mem)?; let mut ac97 = Self::initialize_pulseaudio(irq, mem)?;
let irq_event = IrqLevelEvent::register(kvm_vm, irq) let irq_event = IrqLevelEvent::register(kvm_vm, irq)
@ -78,8 +78,8 @@ impl Ac97Dev {
Ok(ac97) Ok(ac97)
} }
fn initialize_pulseaudio(irq: u8, mem: GuestRam) -> Result<Self, Ac97Error> { fn initialize_pulseaudio(irq: u8, mem: &GuestMemoryMmap) -> Result<Self, Ac97Error> {
let server = PulseClient::connect(mem.clone()) let server = PulseClient::connect(mem)
.map_err(Ac97Error::PulseError)?; .map_err(Ac97Error::PulseError)?;
Ok(Self::new( Ok(Self::new(
irq, irq,

View File

@ -13,13 +13,12 @@ use std::fmt::{Debug, Formatter};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use thiserror::Error; use thiserror::Error;
use vm_memory::{Bytes, guest_memory, GuestAddress, GuestMemoryMmap};
use crate::audio::shm_streams::{ShmStream, ShmStreamSource}; use crate::audio::shm_streams::{ShmStream, ShmStreamSource};
use crate::audio::{BoxError, SampleFormat, StreamControl, StreamDirection}; use crate::audio::{BoxError, SampleFormat, StreamControl, StreamDirection};
use crate::devices::ac97::ac97_mixer::Ac97Mixer; use crate::devices::ac97::ac97_mixer::Ac97Mixer;
use crate::devices::ac97::ac97_regs::*; use crate::devices::ac97::ac97_regs::*;
use crate::devices::irq_event::IrqLevelEvent; use crate::devices::irq_event::IrqLevelEvent;
use crate::memory::GuestRam;
use crate::system;
const INPUT_SAMPLE_RATE: u32 = 48000; const INPUT_SAMPLE_RATE: u32 = 48000;
const DEVICE_INPUT_CHANNEL_COUNT: usize = 2; const DEVICE_INPUT_CHANNEL_COUNT: usize = 2;
@ -100,7 +99,7 @@ impl Ac97BusMasterRegs {
pub(crate) enum GuestMemoryError { pub(crate) enum GuestMemoryError {
// Failure getting the address of the audio buffer. // Failure getting the address of the audio buffer.
#[error("Failed to get the address of the audio buffer: {0}.")] #[error("Failed to get the address of the audio buffer: {0}.")]
ReadingGuestBufferAddress(system::Error), ReadingGuestBufferAddress(guest_memory::Error),
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -178,7 +177,7 @@ impl AudioThreadInfo {
/// interface compliant with the ICH bus master. /// interface compliant with the ICH bus master.
pub struct Ac97BusMaster { pub struct Ac97BusMaster {
// Keep guest memory as each function will use it for buffer descriptors. // Keep guest memory as each function will use it for buffer descriptors.
mem: GuestRam, mem: GuestMemoryMmap,
regs: Arc<Mutex<Ac97BusMasterRegs>>, regs: Arc<Mutex<Ac97BusMasterRegs>>,
acc_sema: u8, acc_sema: u8,
@ -198,7 +197,7 @@ impl Ac97BusMaster {
/// Creates an Ac97BusMaster` object that plays audio from `mem` to streams provided by /// Creates an Ac97BusMaster` object that plays audio from `mem` to streams provided by
/// `audio_server`. /// `audio_server`.
pub fn new(mem: GuestRam, audio_server: AudioStreamSource) -> Self { pub fn new(mem: GuestMemoryMmap, audio_server: AudioStreamSource) -> Self {
Ac97BusMaster { Ac97BusMaster {
mem, mem,
regs: Arc::new(Mutex::new(Ac97BusMasterRegs::new())), regs: Arc::new(Mutex::new(Ac97BusMasterRegs::new())),
@ -597,12 +596,12 @@ impl Ac97BusMaster {
fn get_buffer_samples( fn get_buffer_samples(
func_regs: &Ac97FunctionRegs, func_regs: &Ac97FunctionRegs,
mem: &GuestRam, mem: &GuestMemoryMmap,
index: u8, index: u8,
) -> GuestMemoryResult<usize> { ) -> GuestMemoryResult<usize> {
let descriptor_addr = func_regs.bdbar + u32::from(index) * DESCRIPTOR_LENGTH as u32; let descriptor_addr = func_regs.bdbar + u32::from(index) * DESCRIPTOR_LENGTH as u32;
let control_reg: u32 = mem let control_reg: u32 = mem
.read_int(u64::from(descriptor_addr) + 4) .read_obj(GuestAddress(u64::from(descriptor_addr) + 4))
.map_err(GuestMemoryError::ReadingGuestBufferAddress)?; .map_err(GuestMemoryError::ReadingGuestBufferAddress)?;
let buffer_samples = control_reg as usize & 0x0000_ffff; let buffer_samples = control_reg as usize & 0x0000_ffff;
Ok(buffer_samples) Ok(buffer_samples)
@ -612,14 +611,14 @@ fn get_buffer_samples(
// function and registers. // function and registers.
fn buffer_completed( fn buffer_completed(
regs: &mut Ac97BusMasterRegs, regs: &mut Ac97BusMasterRegs,
mem: &GuestRam, mem: &GuestMemoryMmap,
func: Ac97Function, func: Ac97Function,
) -> AudioResult<()> { ) -> AudioResult<()> {
// check if the completed descriptor wanted an interrupt on completion. // check if the completed descriptor wanted an interrupt on completion.
let civ = regs.func_regs(func).civ; let civ = regs.func_regs(func).civ;
let descriptor_addr = regs.func_regs(func).bdbar + u32::from(civ) * DESCRIPTOR_LENGTH as u32; let descriptor_addr = regs.func_regs(func).bdbar + u32::from(civ) * DESCRIPTOR_LENGTH as u32;
let control_reg: u32 = mem let control_reg: u32 = mem
.read_int(u64::from(descriptor_addr) + 4) .read_obj(GuestAddress(u64::from(descriptor_addr) + 4))
.map_err(GuestMemoryError::ReadingGuestBufferAddress)?; .map_err(GuestMemoryError::ReadingGuestBufferAddress)?;
let mut new_sr = regs.func_regs(func).sr & !SR_CELV; let mut new_sr = regs.func_regs(func).sr & !SR_CELV;
@ -688,7 +687,7 @@ fn update_sr(regs: &mut Ac97BusMasterRegs, func: Ac97Function, val: u16) {
// Returns the size in samples of the buffer pointed to by the CIV register. // Returns the size in samples of the buffer pointed to by the CIV register.
fn current_buffer_size( fn current_buffer_size(
func_regs: &Ac97FunctionRegs, func_regs: &Ac97FunctionRegs,
mem: &GuestRam, mem: &GuestMemoryMmap,
) -> GuestMemoryResult<usize> { ) -> GuestMemoryResult<usize> {
let civ = func_regs.civ; let civ = func_regs.civ;
get_buffer_samples(func_regs, mem, civ) get_buffer_samples(func_regs, mem, civ)
@ -747,12 +746,12 @@ impl Debug for GuestBuffer {
fn get_buffer_address( fn get_buffer_address(
func_regs: &Ac97FunctionRegs, func_regs: &Ac97FunctionRegs,
mem: &GuestRam, mem: &GuestMemoryMmap,
index: u8, index: u8,
) -> GuestMemoryResult<u64> { ) -> GuestMemoryResult<u64> {
let descriptor_addr = func_regs.bdbar + u32::from(index) * DESCRIPTOR_LENGTH as u32; let descriptor_addr = func_regs.bdbar + u32::from(index) * DESCRIPTOR_LENGTH as u32;
let buffer_addr_reg: u32 = mem let buffer_addr_reg: u32 = mem
.read_int(u64::from(descriptor_addr)) .read_obj(GuestAddress(u64::from(descriptor_addr)))
.map_err(GuestMemoryError::ReadingGuestBufferAddress)?; .map_err(GuestMemoryError::ReadingGuestBufferAddress)?;
let buffer_addr = (buffer_addr_reg & !0x03u32) as u64; // The address must be aligned to four bytes. let buffer_addr = (buffer_addr_reg & !0x03u32) as u64; // The address must be aligned to four bytes.
Ok(buffer_addr) Ok(buffer_addr)
@ -765,7 +764,7 @@ fn get_buffer_address(
// `civ + offset == LVI and the CELV flag is set. // `civ + offset == LVI and the CELV flag is set.
fn next_guest_buffer( fn next_guest_buffer(
regs: &Ac97BusMasterRegs, regs: &Ac97BusMasterRegs,
mem: &GuestRam, mem: &GuestMemoryMmap,
func: Ac97Function, func: Ac97Function,
offset: usize, offset: usize,
) -> AudioResult<Option<GuestBuffer>> { ) -> AudioResult<Option<GuestBuffer>> {
@ -812,7 +811,7 @@ fn next_guest_buffer(
struct AudioWorker { struct AudioWorker {
func: Ac97Function, func: Ac97Function,
regs: Arc<Mutex<Ac97BusMasterRegs>>, regs: Arc<Mutex<Ac97BusMasterRegs>>,
mem: GuestRam, mem: GuestMemoryMmap,
thread_run: Arc<AtomicBool>, thread_run: Arc<AtomicBool>,
lvi_semaphore: Arc<Condvar>, lvi_semaphore: Arc<Condvar>,
message_interval: Duration, message_interval: Duration,

View File

@ -5,13 +5,13 @@ use std::path::{Path, PathBuf, Component};
use std::fs::{Metadata, File}; use std::fs::{Metadata, File};
use std::os::unix::io::{RawFd,AsRawFd}; use std::os::unix::io::{RawFd,AsRawFd};
use std::os::linux::fs::MetadataExt; use std::os::linux::fs::MetadataExt;
use std::os::unix::fs::FileExt;
use crate::devices::virtio_9p::{ use crate::devices::virtio_9p::{
pdu::PduParser, directory::Directory, filesystem::FileSystemOps, pdu::PduParser, directory::Directory, filesystem::FileSystemOps,
}; };
use std::io::{Cursor, SeekFrom, Seek, Read}; use std::io::{Cursor, SeekFrom, Seek};
use std::sync::{RwLock, Arc}; use std::sync::{RwLock, Arc};
use vm_memory::{ReadVolatile, VolatileSlice, WriteVolatile};
pub const P9_DOTL_RDONLY: u32 = 0o00000000; pub const P9_DOTL_RDONLY: u32 = 0o00000000;
pub const P9_DOTL_WRONLY: u32 = 0o00000001; pub const P9_DOTL_WRONLY: u32 = 0o00000001;
@ -59,12 +59,14 @@ impl <T: AsRef<[u8]>> Buffer <T> {
Buffer(Arc::new(RwLock::new(Cursor::new(bytes)))) Buffer(Arc::new(RwLock::new(Cursor::new(bytes))))
} }
pub fn read_at(&self, buffer: &mut [u8], offset: u64) -> io::Result<usize> { pub fn read_at(&self, buffer: &mut VolatileSlice, offset: u64) -> io::Result<usize> {
let mut lock = self.0.write().unwrap(); let mut lock = self.0.write().unwrap();
lock.seek(SeekFrom::Start(offset))?; lock.seek(SeekFrom::Start(offset))?;
lock.read(buffer) lock.read_volatile(buffer)
.map_err(io::Error::other)
} }
pub fn write_at(&self, _buffer: &[u8], _offset: u64) -> io::Result<usize> {
pub fn write_at(&self, _buffer: &VolatileSlice, _offset: u64) -> io::Result<usize> {
return Err(io::Error::from_raw_os_error(libc::EPERM)) return Err(io::Error::from_raw_os_error(libc::EPERM))
} }
@ -121,17 +123,31 @@ impl P9File {
} }
} }
pub fn read_at(&self, buffer: &mut [u8], offset: u64) -> io::Result<usize> { pub fn read_at(&mut self, buffer: &mut VolatileSlice, offset: u64) -> io::Result<usize> {
match self.file { match self.file {
FileObject::File(ref f) => f.read_at(buffer,offset), FileObject::File(ref mut f) => {
let pos = f.stream_position()?;
f.seek(SeekFrom::Start(offset))?;
let result = f.read_volatile(buffer)
.map_err(io::Error::other);
f.seek(SeekFrom::Start(pos))?;
result
},
FileObject::BufferFile(ref f) => f.read_at(buffer, offset), FileObject::BufferFile(ref f) => f.read_at(buffer, offset),
FileObject::NotAFile => Ok(0), FileObject::NotAFile => Ok(0),
} }
} }
pub fn write_at(&self, buffer: &[u8], offset: u64) -> io::Result<usize> { pub fn write_at(&mut self, buffer: &VolatileSlice, offset: u64) -> io::Result<usize> {
match self.file { match self.file {
FileObject::File(ref f) => f.write_at(buffer,offset), FileObject::File(ref mut f) => {
let pos = f.stream_position()?;
f.seek(SeekFrom::Start(offset))?;
let result = f.write_volatile(buffer)
.map_err(io::Error::other);
f.seek(SeekFrom::Start(pos))?;
result
},
FileObject::BufferFile(ref f) => f.write_at(buffer, offset), FileObject::BufferFile(ref f) => f.write_at(buffer, offset),
FileObject::NotAFile => Ok(0), FileObject::NotAFile => Ok(0),
} }
@ -328,6 +344,11 @@ impl <T: FileSystemOps> Fids<T> {
self.fid(id) self.fid(id)
} }
pub fn read_fid_mut(&mut self, pp: &mut PduParser) -> io::Result<&mut Fid<T>> {
let id = pp.r32()?;
self.fid_mut(id)
}
pub fn read_new_path(&self, pp: &mut PduParser) -> io::Result<PathBuf> { pub fn read_new_path(&self, pp: &mut PduParser) -> io::Result<PathBuf> {
let fid = self.read_fid(pp)?; let fid = self.read_fid(pp)?;
let name = pp.read_string()?; let name = pp.read_string()?;
@ -435,6 +456,13 @@ impl <T: FileSystemOps> Fid<T> {
} }
} }
pub fn file_mut(&mut self) -> io::Result<&mut P9File> {
match self.file.as_mut() {
Some(file) => Ok(file),
None => system_error(libc::EBADF),
}
}
pub fn join_name(&self, root: &Path, name: &str) -> io::Result<PathBuf> { pub fn join_name(&self, root: &Path, name: &str) -> io::Result<PathBuf> {
Self::path_join_name(self.qid, self.path(), root, name) Self::path_join_name(self.qid, self.path(), root, name)
} }

View File

@ -1,8 +1,8 @@
use std::thread; use std::thread;
use std::path::{PathBuf, Path}; use std::path::{PathBuf, Path};
use vm_memory::GuestMemoryMmap;
use crate::memory::GuestRam;
use crate::devices::virtio_9p::server::Server; use crate::devices::virtio_9p::server::Server;
use crate::devices::virtio_9p::filesystem::{FileSystem, FileSystemOps}; use crate::devices::virtio_9p::filesystem::{FileSystem, FileSystemOps};
use self::pdu::PduParser; use self::pdu::PduParser;
@ -85,13 +85,13 @@ impl <T: FileSystemOps+'static> VirtioDevice for VirtioP9<T> {
let vq = queues.get_queue(0); let vq = queues.get_queue(0);
let root_dir = self.root_dir.clone(); let root_dir = self.root_dir.clone();
let filesystem = self.filesystem.clone(); let filesystem = self.filesystem.clone();
let ram = queues.memory().guest_ram().clone(); let memory = queues.guest_memory().clone();
let debug = self.debug; let debug = self.debug;
thread::spawn(move || run_device(ram, vq, &root_dir, filesystem, debug)); thread::spawn(move || run_device(memory, vq, &root_dir, filesystem, debug));
} }
} }
fn run_device<T: FileSystemOps>(memory: GuestRam, vq: VirtQueue, root_dir: &Path, filesystem: T, debug: bool) { fn run_device<T: FileSystemOps>(memory: GuestMemoryMmap, vq: VirtQueue, root_dir: &Path, filesystem: T, debug: bool) {
let mut server = Server::new(&root_dir, filesystem); let mut server = Server::new(&root_dir, filesystem);
if debug { if debug {

View File

@ -4,16 +4,16 @@ use std::ffi::OsStr;
use libc; use libc;
use byteorder::{LittleEndian,ReadBytesExt,WriteBytesExt}; use byteorder::{LittleEndian,ReadBytesExt,WriteBytesExt};
use vm_memory::{Bytes, GuestAddress, GuestMemoryMmap};
use crate::devices::virtio_9p::file::Qid; use crate::devices::virtio_9p::file::Qid;
use crate::io::Chain; use crate::io::Chain;
use crate::memory::GuestRam;
const P9_HEADER_LEN: usize = 7; const P9_HEADER_LEN: usize = 7;
const P9_RLERROR: u8 = 7; const P9_RLERROR: u8 = 7;
pub struct PduParser<'a> { pub struct PduParser<'a> {
memory: GuestRam, memory: GuestMemoryMmap,
pub chain: &'a mut Chain, pub chain: &'a mut Chain,
size: u32, size: u32,
@ -107,7 +107,7 @@ impl P9Attr {
} }
impl <'a> PduParser<'a> { impl <'a> PduParser<'a> {
pub fn new(chain: &'a mut Chain, memory: GuestRam) -> PduParser<'a> { pub fn new(chain: &'a mut Chain, memory: GuestMemoryMmap) -> PduParser<'a> {
PduParser{ memory, chain, size: 0, cmd: 0, tag: 0, reply_start_addr: 0 } PduParser{ memory, chain, size: 0, cmd: 0, tag: 0, reply_start_addr: 0 }
} }
@ -180,7 +180,7 @@ impl <'a> PduParser<'a> {
} }
pub fn _w8_at(&self, offset: usize, val: u8) { pub fn _w8_at(&self, offset: usize, val: u8) {
self.memory.write_int::<u8>(self.reply_start_addr + offset as u64, val).unwrap(); self.memory.write_obj::<u8>(val, GuestAddress(self.reply_start_addr + offset as u64)).unwrap();
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -189,7 +189,7 @@ impl <'a> PduParser<'a> {
} }
pub fn _w16_at(&self, offset: usize, val: u16) { pub fn _w16_at(&self, offset: usize, val: u16) {
self.memory.write_int::<u16>(self.reply_start_addr + offset as u64, val).unwrap(); self.memory.write_obj::<u16>(val, GuestAddress(self.reply_start_addr + offset as u64)).unwrap();
} }
pub fn w32_at(&self, offset: usize, val: u32) { pub fn w32_at(&self, offset: usize, val: u32) {
@ -197,7 +197,7 @@ impl <'a> PduParser<'a> {
} }
pub fn _w32_at(&self, offset: usize, val: u32) { pub fn _w32_at(&self, offset: usize, val: u32) {
self.memory.write_int::<u32>(self.reply_start_addr + offset as u64, val).unwrap(); self.memory.write_obj::<u32>(val, GuestAddress(self.reply_start_addr + offset as u64)).unwrap();
} }
pub fn write_done(&mut self) -> io::Result<()> { pub fn write_done(&mut self) -> io::Result<()> {

View File

@ -633,8 +633,8 @@ impl <T: FileSystemOps> Server<T> {
pp.write_done() pp.write_done()
} }
fn p9_read_args(&self, pp: &mut PduParser) -> io::Result<(&Fid<T>, u64, u32)> { fn p9_read_args(&mut self, pp: &mut PduParser) -> io::Result<(&mut Fid<T>, u64, u32)> {
let fid = self.read_fid(pp)?; let fid = self.fids.read_fid_mut(pp)?;
let offset = pp.r64()?; let offset = pp.r64()?;
let count = pp.r32()?; let count = pp.r32()?;
pp.read_done()?; pp.read_done()?;
@ -642,13 +642,14 @@ impl <T: FileSystemOps> Server<T> {
} }
fn p9_read(&mut self, pp: &mut PduParser) -> io::Result<()> { fn p9_read(&mut self, pp: &mut PduParser) -> io::Result<()> {
let debug = self.debug;
let (fid, offset, count) = self.p9_read_args(pp)?; let (fid, offset, count) = self.p9_read_args(pp)?;
if self.debug { if debug {
notify!("p9_read({}, offset={}, count={})", fid, offset, count); notify!("p9_read({}, offset={}, count={})", fid, offset, count);
} }
let file = fid.file()?; let file = fid.file_mut()?;
// space for size field // space for size field
pp.w32(0)?; pp.w32(0)?;
@ -660,7 +661,8 @@ impl <T: FileSystemOps> Server<T> {
break; break;
} }
let rlen = cmp::min(current.len(), count as usize); let rlen = cmp::min(current.len(), count as usize);
let n = file.read_at(&mut current[..rlen], offset + nread as u64)?; let mut subslice = current.subslice(0, rlen).map_err(io::Error::other)?;
let n = file.read_at(&mut subslice, offset + nread as u64)?;
if n == 0 { if n == 0 {
break; break;
} }
@ -671,24 +673,26 @@ impl <T: FileSystemOps> Server<T> {
pp.write_done() pp.write_done()
} }
fn p9_write_args(&self, pp: &mut PduParser) -> io::Result<(&Fid<T>, u64, u32)> { fn p9_write_args(&mut self, pp: &mut PduParser) -> io::Result<(&mut Fid<T>, u64, u32)> {
let fid = self.read_fid(pp)?; let fid = self.fids.read_fid_mut(pp)?;
let offset = pp.r64()?; let offset = pp.r64()?;
let count = pp.r32()?; let count = pp.r32()?;
Ok((fid, offset, count)) Ok((fid, offset, count))
} }
fn p9_write(&mut self, pp: &mut PduParser) -> io::Result<()> { fn p9_write(&mut self, pp: &mut PduParser) -> io::Result<()> {
let debug = self.debug;
let (fid, offset, count) = self.p9_write_args(pp)?; let (fid, offset, count) = self.p9_write_args(pp)?;
if self.debug { if debug {
notify!("p9_write({}, offset={}, count={})", fid, offset, count); notify!("p9_write({}, offset={}, count={})", fid, offset, count);
} }
let file = fid.file()?; let file = fid.file_mut()?;
let mut nread = 0; let mut nread = 0;
while nread < count { while nread < count {
let n = file.write_at(pp.chain.current_read_slice(), offset + nread as u64)?; let buffer = pp.chain.current_read_slice();
let n = file.write_at(&buffer, offset + nread as u64)?;
if n == 0 { if n == 0 {
break; break;
} }

View File

@ -199,9 +199,10 @@ impl <'a,'b, D: DiskImage> MessageHandler<'a,'b, D> {
return Ok(()) return Ok(())
} }
let len = nsectors << SECTOR_SHIFT; let len = nsectors << SECTOR_SHIFT;
let buffer = &mut current[..len]; let mut buffer = current.subslice(0, len)
.map_err(io::Error::other)?;
self.disk.read_sectors(self.sector, buffer) self.disk.read_sectors(self.sector, &mut buffer)
.map_err(Error::DiskRead)?; .map_err(Error::DiskRead)?;
self.chain.inc_write_offset(len); self.chain.inc_write_offset(len);
self.sector += nsectors as u64; self.sector += nsectors as u64;
@ -218,7 +219,7 @@ impl <'a,'b, D: DiskImage> MessageHandler<'a,'b, D> {
if nsectors == 0 { if nsectors == 0 {
return Ok(()) return Ok(())
} }
self.disk.write_sectors(self.sector, current) self.disk.write_sectors(self.sector, &current)
.map_err(Error::DiskWrite)?; .map_err(Error::DiskWrite)?;
self.chain.inc_read_offset(nsectors << SECTOR_SHIFT); self.chain.inc_read_offset(nsectors << SECTOR_SHIFT);

View File

@ -16,12 +16,12 @@ impl VirtioRandom {
} }
fn run(q: VirtQueue) { fn run(q: VirtQueue) {
let random = File::open("/dev/urandom").unwrap(); let mut random = File::open("/dev/urandom").unwrap();
loop { loop {
q.on_each_chain(|mut chain| { q.on_each_chain(|mut chain| {
while !chain.is_end_of_chain() { while !chain.is_end_of_chain() {
let _ = chain.copy_from_reader(&random, 256).unwrap(); let _ = chain.copy_from_reader(&mut random, 256).unwrap();
} }
}); });
} }

View File

@ -3,13 +3,14 @@ use std::thread;
use crate::system; use crate::system;
use crate::system::EPoll; use crate::system::EPoll;
use crate::memory::{MemoryManager, DrmDescriptor}; use crate::system::drm::DrmDescriptor;
use crate::devices::virtio_wl::{vfd::VfdManager, consts::*, Error, Result, VfdObject}; use crate::devices::virtio_wl::{vfd::VfdManager, consts::*, Error, Result, VfdObject};
use crate::system::ioctl::ioctl_with_ref; use crate::system::ioctl::ioctl_with_ref;
use std::os::raw::{c_ulong, c_uint, c_ulonglong}; use std::os::raw::{c_ulong, c_uint, c_ulonglong};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
use crate::io::{Chain, FeatureBits, Queues, VirtioDevice, VirtioDeviceType, VirtQueue}; use crate::io::{Chain, FeatureBits, Queues, VirtioDevice, VirtioDeviceType, VirtQueue};
use crate::io::shm_mapper::DeviceSharedMemoryManager;
#[repr(C)] #[repr(C)]
struct dma_buf_sync { struct dma_buf_sync {
@ -19,14 +20,16 @@ const DMA_BUF_IOCTL_BASE: c_uint = 0x62;
const DMA_BUF_IOCTL_SYNC: c_ulong = iow!(DMA_BUF_IOCTL_BASE, 0, ::std::mem::size_of::<dma_buf_sync>() as i32); const DMA_BUF_IOCTL_SYNC: c_ulong = iow!(DMA_BUF_IOCTL_BASE, 0, ::std::mem::size_of::<dma_buf_sync>() as i32);
pub struct VirtioWayland { pub struct VirtioWayland {
dev_shm_manager: Option<DeviceSharedMemoryManager>,
features: FeatureBits, features: FeatureBits,
enable_dmabuf: bool, enable_dmabuf: bool,
} }
impl VirtioWayland { impl VirtioWayland {
pub fn new(enable_dmabuf: bool) -> Self { pub fn new(enable_dmabuf: bool , dev_shm_manager: DeviceSharedMemoryManager) -> Self {
let features = FeatureBits::new_default(VIRTIO_WL_F_TRANS_FLAGS as u64); let features = FeatureBits::new_default(VIRTIO_WL_F_TRANS_FLAGS as u64);
VirtioWayland { VirtioWayland {
dev_shm_manager: Some(dev_shm_manager),
features, features,
enable_dmabuf enable_dmabuf
} }
@ -36,9 +39,9 @@ impl VirtioWayland {
self.features.has_guest_bit(VIRTIO_WL_F_TRANS_FLAGS as u64) self.features.has_guest_bit(VIRTIO_WL_F_TRANS_FLAGS as u64)
} }
fn create_device(memory: MemoryManager, in_vq: VirtQueue, out_vq: VirtQueue, transition: bool, enable_dmabuf: bool) -> Result<WaylandDevice> { fn create_device(in_vq: VirtQueue, out_vq: VirtQueue, transition: bool, enable_dmabuf: bool, dev_shm_manager: DeviceSharedMemoryManager) -> Result<WaylandDevice> {
let kill_evt = EventFd::new(0).map_err(Error::EventFdCreate)?; let kill_evt = EventFd::new(0).map_err(Error::EventFdCreate)?;
let dev = WaylandDevice::new(memory, in_vq, out_vq, kill_evt, transition, enable_dmabuf)?; let dev = WaylandDevice::new(in_vq, out_vq, kill_evt, transition, enable_dmabuf, dev_shm_manager)?;
Ok(dev) Ok(dev)
} }
} }
@ -60,11 +63,11 @@ impl VirtioDevice for VirtioWayland {
thread::spawn({ thread::spawn({
let transition = self.transition_flags(); let transition = self.transition_flags();
let enable_dmabuf = self.enable_dmabuf; let enable_dmabuf = self.enable_dmabuf;
let dev_shm_manager = self.dev_shm_manager.take().expect("No dev_shm_manager");
let in_vq = queues.get_queue(0); let in_vq = queues.get_queue(0);
let out_vq = queues.get_queue(1); let out_vq = queues.get_queue(1);
let memory = queues.memory().clone();
move || { move || {
let mut dev = match Self::create_device(memory, in_vq, out_vq,transition, enable_dmabuf) { let mut dev = match Self::create_device(in_vq, out_vq,transition, enable_dmabuf, dev_shm_manager) {
Err(e) => { Err(e) => {
warn!("Error creating virtio wayland device: {}", e); warn!("Error creating virtio wayland device: {}", e);
return; return;
@ -92,8 +95,9 @@ impl WaylandDevice {
const KILL_TOKEN: u64 = 2; const KILL_TOKEN: u64 = 2;
const VFDS_TOKEN: u64 = 3; const VFDS_TOKEN: u64 = 3;
fn new(mm: MemoryManager, in_vq: VirtQueue, out_vq: VirtQueue, kill_evt: EventFd, use_transition: bool, enable_dmabuf: bool) -> Result<Self> { fn new(in_vq: VirtQueue, out_vq: VirtQueue, kill_evt: EventFd, use_transition: bool, enable_dmabuf: bool, dev_shm_manager: DeviceSharedMemoryManager) -> Result<Self> {
let vfd_manager = VfdManager::new(mm, use_transition, in_vq, "/run/user/1000/wayland-0")?; let vfd_manager = VfdManager::new(dev_shm_manager, use_transition, in_vq, "/run/user/1000/wayland-0")?;
Ok(WaylandDevice { Ok(WaylandDevice {
vfd_manager, vfd_manager,
out_vq, out_vq,
@ -219,7 +223,7 @@ impl <'a> MessageHandler<'a> {
self.chain.w32(id)?; self.chain.w32(id)?;
self.chain.w32(flags)?; self.chain.w32(flags)?;
self.chain.w64(pfn)?; self.chain.w64(pfn)?;
self.chain.w32(size as u32)?; self.chain.w32(size)?;
self.responded = true; self.responded = true;
Ok(()) Ok(())
} }
@ -306,9 +310,9 @@ impl <'a> MessageHandler<'a> {
}; };
if let Some(fds) = send_fds.as_ref() { if let Some(fds) = send_fds.as_ref() {
vfd.send_with_fds(data, fds)?; vfd.send_with_fds(&data, fds)?;
} else { } else {
vfd.send(data)?; vfd.send(&data)?;
} }
self.send_ok() self.send_ok()
} }

View File

@ -1,11 +1,11 @@
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
use std::{result, io}; use std::{result, io};
use std::fs::File;
use thiserror::Error; use thiserror::Error;
use vm_memory::{VolatileMemoryError, VolatileSlice};
use crate::system; use crate::system;
use crate::memory::Error as MemError;
use crate::system::FileDesc;
mod vfd; mod vfd;
mod shm; mod shm;
@ -52,18 +52,21 @@ mod consts {
} }
pub use device::VirtioWayland; pub use device::VirtioWayland;
use crate::devices::virtio_wl::shm_mapper::SharedMemoryAllocation;
use crate::io::shm_mapper;
pub type Result<T> = result::Result<T, Error>; pub type Result<T> = result::Result<T, Error>;
pub struct VfdRecv { pub struct VfdRecv {
buf: Vec<u8>, buf: Vec<u8>,
fds: Option<Vec<FileDesc>>, fds: Option<Vec<File>>,
} }
impl VfdRecv { impl VfdRecv {
fn new(buf: Vec<u8>) -> Self { fn new(buf: Vec<u8>) -> Self {
VfdRecv { buf, fds: None } VfdRecv { buf, fds: None }
} }
fn new_with_fds(buf: Vec<u8>, fds: Vec<FileDesc>) -> Self { fn new_with_fds(buf: Vec<u8>, fds: Vec<File>) -> Self {
VfdRecv { buf, fds: Some(fds) } VfdRecv { buf, fds: Some(fds) }
} }
} }
@ -73,11 +76,11 @@ pub trait VfdObject {
fn send_fd(&self) -> Option<RawFd> { None } fn send_fd(&self) -> Option<RawFd> { None }
fn poll_fd(&self) -> Option<RawFd> { None } fn poll_fd(&self) -> Option<RawFd> { None }
fn recv(&mut self) -> Result<Option<VfdRecv>> { Ok(None) } fn recv(&mut self) -> Result<Option<VfdRecv>> { Ok(None) }
fn send(&mut self, _data: &[u8]) -> Result<()> { Err(Error::InvalidSendVfd) } fn send(&mut self, _data: &VolatileSlice) -> Result<()> { Err(Error::InvalidSendVfd) }
fn send_with_fds(&mut self, _data: &[u8], _fds: &[RawFd]) -> Result<()> { Err(Error::InvalidSendVfd) } fn send_with_fds(&mut self, _data: &VolatileSlice, _fds: &[RawFd]) -> Result<()> { Err(Error::InvalidSendVfd) }
fn flags(&self) -> u32; fn flags(&self) -> u32;
fn pfn_and_size(&self) -> Option<(u64, u64)> { None } fn shared_memory(&self) -> Option<SharedMemoryAllocation> { None }
fn close(&mut self) -> Result<()>; fn close(&mut self) -> Result<()> { Ok(()) }
} }
@ -92,9 +95,9 @@ pub enum Error {
#[error("unexpected virtio wayland command: {0}")] #[error("unexpected virtio wayland command: {0}")]
UnexpectedCommand(u32), UnexpectedCommand(u32),
#[error("failed to allocate shared memory: {0}")] #[error("failed to allocate shared memory: {0}")]
ShmAllocFailed(system::Error), ShmAllocFailed(shm_mapper::Error),
#[error("failed to register memory with hypervisor: {0}")] #[error("failed to free shared memory allocation: {0}")]
RegisterMemoryFailed(MemError), ShmFreeFailed(shm_mapper::Error),
#[error("failed to create pipes: {0}")] #[error("failed to create pipes: {0}")]
CreatePipesFailed(system::Error), CreatePipesFailed(system::Error),
#[error("error reading from socket: {0}")] #[error("error reading from socket: {0}")]
@ -105,6 +108,8 @@ pub enum Error {
PipeReceive(io::Error), PipeReceive(io::Error),
#[error("error writing to vfd: {0}")] #[error("error writing to vfd: {0}")]
SendVfd(io::Error), SendVfd(io::Error),
#[error("error writing volatile memory to vfd: {0}")]
VolatileSendVfd(VolatileMemoryError),
#[error("attempt to send to incorrect vfd type")] #[error("attempt to send to incorrect vfd type")]
InvalidSendVfd, InvalidSendVfd,
#[error("message has too many vfd ids: {0}")] #[error("message has too many vfd ids: {0}")]
@ -115,8 +120,4 @@ pub enum Error {
FailedPollAdd(system::Error), FailedPollAdd(system::Error),
#[error("error calling dma sync: {0}")] #[error("error calling dma sync: {0}")]
DmaSync(system::ErrnoError), DmaSync(system::ErrnoError),
#[error("failed creating DMA buf: {0}")]
DmaBuf(MemError),
#[error("failed creating DMA buf: {0}")]
DmaBufSize(system::Error),
} }

View File

@ -1,6 +1,10 @@
use std::os::unix::io::{AsRawFd,RawFd}; use std::fs::File;
use std::io::Read;
use std::os::fd::FromRawFd;
use std::os::unix::io::{AsRawFd, RawFd};
use vm_memory::{VolatileSlice, WriteVolatile};
use crate::system::{self,FileDesc}; use crate::system;
use crate::devices::virtio_wl::{ use crate::devices::virtio_wl::{
consts::{VIRTIO_WL_VFD_WRITE, VIRTIO_WL_VFD_READ, IN_BUFFER_LEN}, consts::{VIRTIO_WL_VFD_WRITE, VIRTIO_WL_VFD_READ, IN_BUFFER_LEN},
@ -11,13 +15,13 @@ use crate::devices::virtio_wl::{
pub struct VfdPipe { pub struct VfdPipe {
vfd_id: u32, vfd_id: u32,
flags: u32, flags: u32,
local: Option<FileDesc>, local: Option<File>,
remote: Option<FileDesc>, remote: Option<File>,
} }
impl VfdPipe { impl VfdPipe {
pub fn new(vfd_id: u32, read_pipe: FileDesc, write_pipe: FileDesc, local_write: bool) -> Self { pub fn new(vfd_id: u32, read_pipe: File, write_pipe: File, local_write: bool) -> Self {
if local_write { if local_write {
VfdPipe { vfd_id, local: Some(write_pipe), remote: Some(read_pipe), flags: VIRTIO_WL_VFD_WRITE } VfdPipe { vfd_id, local: Some(write_pipe), remote: Some(read_pipe), flags: VIRTIO_WL_VFD_WRITE }
} else { } else {
@ -25,7 +29,7 @@ impl VfdPipe {
} }
} }
pub fn local_only(vfd_id: u32, local_pipe: FileDesc, flags: u32) -> Self { pub fn local_only(vfd_id: u32, local_pipe: File, flags: u32) -> Self {
VfdPipe { vfd_id, local: Some(local_pipe), remote: None, flags } VfdPipe { vfd_id, local: Some(local_pipe), remote: None, flags }
} }
@ -35,8 +39,8 @@ impl VfdPipe {
if libc::pipe2(pipe_fds.as_mut_ptr(), libc::O_CLOEXEC) < 0 { if libc::pipe2(pipe_fds.as_mut_ptr(), libc::O_CLOEXEC) < 0 {
return Err(Error::CreatePipesFailed(system::Error::last_os_error())); return Err(Error::CreatePipesFailed(system::Error::last_os_error()));
} }
let read_pipe = FileDesc::new(pipe_fds[0]); let read_pipe = File::from_raw_fd(pipe_fds[0]);
let write_pipe = FileDesc::new(pipe_fds[1]); let write_pipe = File::from_raw_fd(pipe_fds[1]);
Ok(Self::new(vfd_id, read_pipe, write_pipe, local_write)) Ok(Self::new(vfd_id, read_pipe, write_pipe, local_write))
} }
} }
@ -58,7 +62,7 @@ impl VfdObject for VfdPipe {
fn recv(&mut self) -> Result<Option<VfdRecv>> { fn recv(&mut self) -> Result<Option<VfdRecv>> {
if let Some(pipe) = self.local.take() { if let Some(pipe) = self.local.take() {
let mut buf = vec![0; IN_BUFFER_LEN]; let mut buf = vec![0; IN_BUFFER_LEN];
let len = pipe.read(&mut buf[..IN_BUFFER_LEN]) let len = (&pipe).read(&mut buf[..IN_BUFFER_LEN])
.map_err(Error::PipeReceive)?; .map_err(Error::PipeReceive)?;
buf.truncate(len); buf.truncate(len);
if buf.len() > 0 { if buf.len() > 0 {
@ -69,9 +73,9 @@ impl VfdObject for VfdPipe {
Ok(None) Ok(None)
} }
fn send(&mut self, data: &[u8]) -> Result<()> { fn send(&mut self, data: &VolatileSlice) -> Result<()> {
if let Some(pipe) = self.local.as_ref() { if let Some(pipe) = self.local.as_mut() {
pipe.write_all(data).map_err(Error::SendVfd) pipe.write_all_volatile(data).map_err(Error::VolatileSendVfd)
} else { } else {
Err(Error::InvalidSendVfd) Err(Error::InvalidSendVfd)
} }

View File

@ -1,20 +1,15 @@
use std::os::unix::io::{AsRawFd,RawFd}; use std::os::unix::io::RawFd;
use crate::memory::{MemoryManager, DrmDescriptor};
use crate::system::MemoryFd;
use crate::devices::virtio_wl::{ use crate::devices::virtio_wl::{
consts::{VIRTIO_WL_VFD_MAP, VIRTIO_WL_VFD_WRITE}, consts::{VIRTIO_WL_VFD_MAP, VIRTIO_WL_VFD_WRITE},
Error, Result, VfdObject Error, Result, VfdObject
}; };
use crate::io::shm_mapper::{DeviceSharedMemoryManager, SharedMemoryAllocation};
pub struct VfdSharedMemory { pub struct VfdSharedMemory {
vfd_id: u32, vfd_id: u32,
flags: u32, flags: u32,
mm: MemoryManager, shm: SharedMemoryAllocation,
memfd: Option<MemoryFd>,
slot: u32,
pfn: u64,
} }
impl VfdSharedMemory { impl VfdSharedMemory {
@ -23,28 +18,22 @@ impl VfdSharedMemory {
(n + mask) & !mask (n + mask) & !mask
} }
pub fn new(vfd_id: u32, transition_flags: bool, mm: MemoryManager, memfd: MemoryFd, slot: u32, pfn: u64) -> Self { pub fn new(vfd_id: u32, transition_flags: bool, shm: SharedMemoryAllocation) -> Self {
let flags = if transition_flags { 0 } else { VIRTIO_WL_VFD_WRITE | VIRTIO_WL_VFD_MAP}; let flags = if transition_flags { 0 } else { VIRTIO_WL_VFD_WRITE | VIRTIO_WL_VFD_MAP};
let memfd = Some(memfd); VfdSharedMemory { vfd_id, flags, shm }
VfdSharedMemory { vfd_id, flags, mm, memfd, slot, pfn }
} }
pub fn create(vfd_id: u32, transition_flags: bool, size: u32, mm: &MemoryManager) -> Result<Self> { pub fn create(vfd_id: u32, transition_flags: bool, size: u32, dev_shm_manager: &DeviceSharedMemoryManager) -> Result<Self> {
let size = Self::round_to_page_size(size as usize); let size = Self::round_to_page_size(size as usize);
let memfd = MemoryFd::new_memfd(size, true) let shm = dev_shm_manager.allocate_buffer(size)
.map_err(Error::ShmAllocFailed)?; .map_err(Error::ShmAllocFailed)?;
let (pfn, slot) = mm.register_device_memory(memfd.as_raw_fd(), size) Ok(Self::new(vfd_id, transition_flags, shm))
.map_err(Error::RegisterMemoryFailed)?;
Ok(Self::new(vfd_id, transition_flags, mm.clone(), memfd, slot, pfn))
} }
pub fn create_dmabuf(vfd_id: u32, tflags: bool, width: u32, height: u32, format: u32, mm: &MemoryManager) -> Result<(Self, DrmDescriptor)> { pub fn create_dmabuf(vfd_id: u32, tflags: bool, width: u32, height: u32, format: u32, dev_shm_manager: &DeviceSharedMemoryManager) -> Result<Self> {
let (pfn, slot, fd, desc) = mm.allocate_drm_buffer(width, height, format) let shm = dev_shm_manager.allocate_drm_buffer(width, height, format)
.map_err(Error::DmaBuf)?; .map_err(Error::ShmAllocFailed)?;
let memfd = MemoryFd::from_filedesc(fd) Ok(Self::new(vfd_id, tflags, shm))
.map_err(Error::DmaBufSize)?;
let vfd = Self::new(vfd_id, tflags, mm.clone(), memfd, slot, pfn);
Ok((vfd, desc))
} }
} }
@ -54,26 +43,14 @@ impl VfdObject for VfdSharedMemory {
} }
fn send_fd(&self) -> Option<RawFd> { fn send_fd(&self) -> Option<RawFd> {
self.memfd.as_ref().map(AsRawFd::as_raw_fd) Some(self.shm.raw_fd())
} }
fn flags(&self) -> u32 { fn flags(&self) -> u32 {
self.flags self.flags
} }
fn pfn_and_size(&self) -> Option<(u64, u64)> { fn shared_memory(&self) -> Option<SharedMemoryAllocation> {
if let Some(memfd) = self.memfd.as_ref() { Some(self.shm)
Some((self.pfn, memfd.size() as u64))
} else {
None
}
}
fn close(&mut self) -> Result<()> {
if let Some(_) = self.memfd.take() {
self.mm.unregister_device_memory(self.slot)
.map_err(Error::RegisterMemoryFailed)?;
}
Ok(())
} }
} }

View File

@ -1,8 +1,11 @@
use std::io::{self,Write}; use std::fs::File;
use std::io;
use std::os::fd::FromRawFd;
use std::path::Path; use std::path::Path;
use std::os::unix::{net::UnixStream, io::{AsRawFd, RawFd}}; use std::os::unix::{net::UnixStream, io::{AsRawFd, RawFd}};
use vm_memory::{VolatileSlice, WriteVolatile};
use crate::system::{FileDesc,ScmSocket}; use crate::system::ScmSocket;
use crate::devices::virtio_wl::{consts:: *, Error, Result, VfdObject, VfdRecv}; use crate::devices::virtio_wl::{consts:: *, Error, Result, VfdObject, VfdRecv};
pub struct VfdSocket { pub struct VfdSocket {
@ -29,14 +32,16 @@ impl VfdSocket {
socket: Some(socket), socket: Some(socket),
}) })
} }
fn socket_recv(socket: &mut UnixStream) -> Result<(Vec<u8>, Vec<FileDesc>)> { fn socket_recv(socket: &mut UnixStream) -> Result<(Vec<u8>, Vec<File>)> {
let mut buf = vec![0; IN_BUFFER_LEN]; let mut buf = vec![0; IN_BUFFER_LEN];
let mut fd_buf = [0; VIRTWL_SEND_MAX_ALLOCS]; let mut fd_buf = [0; VIRTWL_SEND_MAX_ALLOCS];
let (len, fd_len) = socket.recv_with_fds(&mut buf, &mut fd_buf) let (len, fd_len) = socket.recv_with_fds(&mut buf, &mut fd_buf)
.map_err(Error::SocketReceive)?; .map_err(Error::SocketReceive)?;
buf.truncate(len); buf.truncate(len);
let files = fd_buf[..fd_len].iter() let files = fd_buf[..fd_len].iter()
.map(|&fd| FileDesc::new(fd)).collect(); .map(|&fd| unsafe {
File::from_raw_fd(fd)
}).collect();
Ok((buf, files)) Ok((buf, files))
} }
} }
@ -58,27 +63,29 @@ impl VfdObject for VfdSocket {
let (buf,files) = Self::socket_recv(&mut sock)?; let (buf,files) = Self::socket_recv(&mut sock)?;
if !(buf.is_empty() && files.is_empty()) { if !(buf.is_empty() && files.is_empty()) {
self.socket.replace(sock); self.socket.replace(sock);
if files.is_empty() { return if files.is_empty() {
return Ok(Some(VfdRecv::new(buf))); Ok(Some(VfdRecv::new(buf)))
} else { } else {
return Ok(Some(VfdRecv::new_with_fds(buf, files))); Ok(Some(VfdRecv::new_with_fds(buf, files)))
} }
} }
} }
Ok(None) Ok(None)
} }
fn send(&mut self, data: &[u8]) -> Result<()> { fn send(&mut self, data: &VolatileSlice) -> Result<()> {
if let Some(s) = self.socket.as_mut() { if let Some(s) = self.socket.as_mut() {
s.write_all(data).map_err(Error::SendVfd) s.write_all_volatile(data).map_err(Error::VolatileSendVfd)
} else { } else {
Err(Error::InvalidSendVfd) Err(Error::InvalidSendVfd)
} }
} }
fn send_with_fds(&mut self, data: &[u8], fds: &[RawFd]) -> Result<()> { fn send_with_fds(&mut self, data: &VolatileSlice, fds: &[RawFd]) -> Result<()> {
if let Some(s) = self.socket.as_mut() { if let Some(s) = self.socket.as_mut() {
s.send_with_fds(data, fds) let mut buffer = vec![0u8; data.len()];
data.copy_to(&mut buffer);
s.send_with_fds(&buffer, fds)
.map_err(|_| Error::SendVfd(io::Error::last_os_error()))?; .map_err(|_| Error::SendVfd(io::Error::last_os_error()))?;
Ok(()) Ok(())
} else { } else {
@ -98,5 +105,3 @@ impl VfdObject for VfdSocket {
Ok(()) Ok(())
} }
} }

View File

@ -1,20 +1,24 @@
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use std::io::{Write, SeekFrom}; use std::fs::File;
use std::io;
use std::io::{Write, SeekFrom, Seek};
use std::os::unix::io::{AsRawFd,RawFd}; use std::os::unix::io::{AsRawFd,RawFd};
use std::path::PathBuf; use std::path::PathBuf;
use std::time::Duration; use std::time::Duration;
use crate::memory::{MemoryManager, DrmDescriptor}; use crate::system::drm::DrmDescriptor;
use crate::system::{FileDesc, FileFlags,EPoll,MemoryFd}; use crate::system::EPoll;
use crate::devices::virtio_wl::{ use crate::devices::virtio_wl::{
consts::*, Error, Result, shm::VfdSharedMemory, pipe::VfdPipe, socket::VfdSocket, VfdObject consts::*, Error, Result, shm::VfdSharedMemory, pipe::VfdPipe, socket::VfdSocket, VfdObject
}; };
use crate::io::{Chain, VirtQueue}; use crate::io::{Chain, VirtQueue};
use crate::io::shm_mapper::DeviceSharedMemoryManager;
use crate::system::errno::cvt;
pub struct VfdManager { pub struct VfdManager {
wayland_path: PathBuf, wayland_path: PathBuf,
mm: MemoryManager, dev_shm_manager: DeviceSharedMemoryManager,
use_transition_flags: bool, use_transition_flags: bool,
vfd_map: HashMap<u32, Box<dyn VfdObject>>, vfd_map: HashMap<u32, Box<dyn VfdObject>>,
next_vfd_id: u32, next_vfd_id: u32,
@ -24,16 +28,12 @@ pub struct VfdManager {
} }
impl VfdManager { impl VfdManager {
fn round_to_page_size(n: usize) -> usize { pub fn new<P: Into<PathBuf>>(dev_shm_manager: DeviceSharedMemoryManager, use_transition_flags: bool, in_vq: VirtQueue, wayland_path: P) -> Result<Self> {
let mask = 4096 - 1;
(n + mask) & !mask
}
pub fn new<P: Into<PathBuf>>(mm: MemoryManager, use_transition_flags: bool, in_vq: VirtQueue, wayland_path: P) -> Result<Self> {
let poll_ctx = EPoll::new().map_err(Error::FailedPollContextCreate)?; let poll_ctx = EPoll::new().map_err(Error::FailedPollContextCreate)?;
Ok(VfdManager { Ok(VfdManager {
wayland_path: wayland_path.into(), wayland_path: wayland_path.into(),
mm, use_transition_flags, dev_shm_manager,
use_transition_flags,
vfd_map: HashMap::new(), vfd_map: HashMap::new(),
next_vfd_id: NEXT_VFD_ID_BASE, next_vfd_id: NEXT_VFD_ID_BASE,
poll_ctx, poll_ctx,
@ -61,18 +61,18 @@ impl VfdManager {
Ok(()) Ok(())
} }
pub fn create_shm(&mut self, vfd_id: u32, size: u32) -> Result<(u64,u64)> { pub fn create_shm(&mut self, vfd_id: u32, size: u32) -> Result<(u64,usize)> {
let shm = VfdSharedMemory::create(vfd_id, self.use_transition_flags, size, &self.mm)?; let vfd = VfdSharedMemory::create(vfd_id, self.use_transition_flags, size, &self.dev_shm_manager)?;
let (pfn,size) = shm.pfn_and_size().unwrap(); let shm = vfd.shared_memory().unwrap();
self.vfd_map.insert(vfd_id, Box::new(shm)); self.vfd_map.insert(vfd_id, Box::new(vfd));
Ok((pfn,size)) Ok((shm.pfn(),shm.size()))
} }
pub fn create_dmabuf(&mut self, vfd_id: u32, width: u32, height: u32, format: u32) -> Result<(u64, u64, DrmDescriptor)> { pub fn create_dmabuf(&mut self, vfd_id: u32, width: u32, height: u32, format: u32) -> Result<(u64, usize, DrmDescriptor)> {
let (vfd, desc) = VfdSharedMemory::create_dmabuf(vfd_id, self.use_transition_flags, width, height, format, &self.mm)?; let vfd = VfdSharedMemory::create_dmabuf(vfd_id, self.use_transition_flags, width, height, format, &self.dev_shm_manager)?;
let (pfn, size) = vfd.pfn_and_size().unwrap(); let shm = vfd.shared_memory().unwrap();
self.vfd_map.insert(vfd_id, Box::new(vfd)); self.vfd_map.insert(vfd_id, Box::new(vfd));
Ok((pfn, size, desc)) Ok((shm.pfn(), shm.size(), shm.drm_descriptor().unwrap()))
} }
pub fn create_socket(&mut self, vfd_id: u32) -> Result<u32> { pub fn create_socket(&mut self, vfd_id: u32) -> Result<u32> {
@ -195,30 +195,35 @@ impl VfdManager {
Ok(()) Ok(())
} }
fn vfd_from_file(&self, vfd_id: u32, fd: FileDesc) -> Result<Box<dyn VfdObject>> { fn vfd_from_file(&self, vfd_id: u32, fd: File) -> Result<Box<dyn VfdObject>> {
match fd.seek(SeekFrom::End(0)) { fn has_size(mut fd: &File) -> bool {
Ok(size) => { fd.seek(SeekFrom::End(0)).is_ok()
let size = Self::round_to_page_size(size as usize) as u64; }
let (pfn,slot) = self.mm.register_device_memory(fd.as_raw_fd(), size as usize)
.map_err(Error::RegisterMemoryFailed)?;
if has_size(&fd) {
let shm = self.dev_shm_manager.allocate_buffer_from_file(fd)
.map_err(Error::ShmAllocFailed)?;
Ok(Box::new(VfdSharedMemory::new(vfd_id, self.use_transition_flags,shm)))
} else {
let flags = match FileFlags::file_flags(fd.as_raw_fd()) {
Ok(FileFlags::Read) => VIRTIO_WL_VFD_READ,
Ok(FileFlags::Write) => VIRTIO_WL_VFD_WRITE,
Ok(FileFlags::ReadWrite) =>VIRTIO_WL_VFD_READ | VIRTIO_WL_VFD_WRITE,
_ => 0,
};
Ok(Box::new(VfdPipe::local_only(vfd_id, fd, flags)))
let memfd = MemoryFd::from_filedesc(fd).map_err(Error::ShmAllocFailed)?;
return Ok(Box::new(VfdSharedMemory::new(vfd_id, self.use_transition_flags,self.mm.clone(), memfd, slot, pfn)));
}
_ => {
let flags = match fd.flags() {
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,
};
return Ok(Box::new(VfdPipe::local_only(vfd_id, fd, flags)));
}
} }
} }
pub fn close_vfd(&mut self, vfd_id: u32) -> Result<()> { pub fn close_vfd(&mut self, vfd_id: u32) -> Result<()> {
if let Some(mut vfd) = self.vfd_map.remove(&vfd_id) { if let Some(mut vfd) = self.vfd_map.remove(&vfd_id) {
if let Some(shm) = vfd.shared_memory() {
self.dev_shm_manager.free_buffer(shm.slot())
.map_err(Error::ShmFreeFailed)?;
}
vfd.close()?; vfd.close()?;
} }
// XXX remove any matching fds from in_queue_pending // XXX remove any matching fds from in_queue_pending
@ -290,9 +295,9 @@ impl PendingInput {
chain.w32(0)?; chain.w32(0)?;
chain.w32(vfd.id())?; chain.w32(vfd.id())?;
chain.w32(vfd.flags())?; chain.w32(vfd.flags())?;
let (pfn, size) = match vfd.pfn_and_size() { let (pfn, size) = match vfd.shared_memory() {
Some(vals) => vals, Some(shm) => (shm.pfn(), shm.size()),
None => (0,0), None => (0, 0),
}; };
chain.w64(pfn)?; chain.w64(pfn)?;
chain.w32(size as u32)?; chain.w32(size as u32)?;
@ -319,3 +324,23 @@ impl PendingInput {
} }
} }
#[derive(Copy,Clone,Debug,Eq,PartialEq)]
pub enum FileFlags {
Read,
Write,
ReadWrite,
}
impl FileFlags {
fn file_flags(fd: RawFd) -> io::Result<FileFlags> {
let flags = unsafe { cvt(libc::fcntl(fd, libc::F_GETFL))? };
match flags & libc::O_ACCMODE {
libc::O_RDONLY => Ok(FileFlags::Read),
libc::O_WRONLY => Ok(FileFlags::Write),
libc::O_RDWR => Ok(FileFlags::ReadWrite),
_ => Err(io::Error::from_raw_os_error(libc::EINVAL)),
}
}
}

View File

@ -1,32 +1,40 @@
use crate::system::MemoryFd; use std::fs::File;
use std::io;
use crate::util::BitSet; use crate::util::BitSet;
use crate::disk::{Result, Error, SECTOR_SIZE, DiskImage}; use crate::disk::{Result, Error, SECTOR_SIZE, DiskImage};
use std::io::SeekFrom; use std::io::{Seek, SeekFrom};
use memfd::MemfdOptions;
use vm_memory::{ReadVolatile, VolatileSlice, WriteVolatile};
pub struct MemoryOverlay { pub struct MemoryOverlay {
memory: MemoryFd, memory: File,
written_sectors: BitSet, written_sectors: BitSet,
} }
impl MemoryOverlay { impl MemoryOverlay {
pub fn new() -> Result<Self> { pub fn new() -> Result<Self> {
let memory = MemoryFd::new_memfd(0, false) let memory = MemfdOptions::new()
.allow_sealing(true)
.create("disk-overlay-memfd")
.map_err(Error::MemoryOverlayCreate)?; .map_err(Error::MemoryOverlayCreate)?;
let memory = memory.into_file();
let written_sectors = BitSet::new(); let written_sectors = BitSet::new();
Ok(MemoryOverlay { memory, written_sectors }) Ok(MemoryOverlay { memory, written_sectors })
} }
pub fn write_sectors(&mut self, start: u64, buffer: &[u8]) -> Result<()> { pub fn write_sectors(&mut self, start: u64, buffer: &VolatileSlice) -> Result<()> {
let sector_count = buffer.len() / SECTOR_SIZE; let sector_count = buffer.len() / SECTOR_SIZE;
let len = sector_count * SECTOR_SIZE; let len = sector_count * SECTOR_SIZE;
let seek_offset = SeekFrom::Start(start * SECTOR_SIZE as u64); let seek_offset = SeekFrom::Start(start * SECTOR_SIZE as u64);
self.memory.fd_mut() self.memory.seek(seek_offset)
.seek(seek_offset)
.map_err(Error::DiskSeek)?; .map_err(Error::DiskSeek)?;
self.memory.fd_mut() let slice = buffer.subslice(0, len)
.write_all(&buffer[..len]) .expect("Out of bounds in MemoryOverlay::write_sectors()");
self.memory.write_all_volatile(&slice)
.map_err(io::Error::other)
.map_err(Error::DiskWrite)?; .map_err(Error::DiskWrite)?;
for n in 0..sector_count { for n in 0..sector_count {
@ -36,7 +44,7 @@ impl MemoryOverlay {
Ok(()) Ok(())
} }
pub fn read_sectors<D: DiskImage>(&mut self, disk: &mut D, start: u64, buffer: &mut [u8]) -> Result<()> { pub fn read_sectors<D: DiskImage>(&mut self, disk: &mut D, start: u64, buffer: &mut VolatileSlice) -> Result<()> {
let sector_count = buffer.len() / SECTOR_SIZE; let sector_count = buffer.len() / SECTOR_SIZE;
if (0..sector_count).all(|i| !self.written_sectors.get(i)) { if (0..sector_count).all(|i| !self.written_sectors.get(i)) {
return disk.read_sectors(start, buffer); return disk.read_sectors(start, buffer);
@ -45,22 +53,23 @@ impl MemoryOverlay {
for n in 0..sector_count { for n in 0..sector_count {
let sector = start + n as u64; let sector = start + n as u64;
let offset = n * SECTOR_SIZE; let offset = n * SECTOR_SIZE;
let sector_buffer = &mut buffer[offset..offset+SECTOR_SIZE]; let mut sector_buffer = buffer.subslice(offset, SECTOR_SIZE)
.expect("Out of bounds in MemoryOverlay::read_sectors()");
if self.written_sectors.get(sector as usize) { if self.written_sectors.get(sector as usize) {
self.read_single_sector(sector, sector_buffer)?; self.read_single_sector(sector, &mut sector_buffer)?;
} else { } else {
disk.read_sectors(sector, sector_buffer)?; disk.read_sectors(sector, &mut sector_buffer)?;
} }
} }
Ok(()) Ok(())
} }
fn read_single_sector(&mut self, sector: u64, buffer: &mut [u8]) -> Result<()> { fn read_single_sector(&mut self, sector: u64, buffer: &mut VolatileSlice) -> Result<()> {
assert_eq!(buffer.len(), SECTOR_SIZE); assert_eq!(buffer.len(), SECTOR_SIZE);
let offset = SeekFrom::Start(sector * SECTOR_SIZE as u64); let offset = SeekFrom::Start(sector * SECTOR_SIZE as u64);
self.memory.fd_mut().seek(offset) self.memory.seek(offset)
.map_err(Error::DiskSeek)?; .map_err(Error::DiskSeek)?;
self.memory.fd_mut().read_exact(buffer) self.memory.read_exact_volatile(buffer).map_err(io::Error::other)
.map_err(Error::DiskRead)?; .map_err(Error::DiskRead)?;
Ok(()) Ok(())
} }

View File

@ -3,8 +3,6 @@ use std::fs::File;
use std::os::linux::fs::MetadataExt; use std::os::linux::fs::MetadataExt;
use std::io::{SeekFrom, Seek}; use std::io::{SeekFrom, Seek};
use crate::system;
mod realmfs; mod realmfs;
mod raw; mod raw;
mod memory; mod memory;
@ -13,6 +11,7 @@ pub use raw::RawDiskImage;
pub use realmfs::RealmFSImage; pub use realmfs::RealmFSImage;
use std::path::PathBuf; use std::path::PathBuf;
use thiserror::Error; use thiserror::Error;
use vm_memory::VolatileSlice;
const SECTOR_SIZE: usize = 512; const SECTOR_SIZE: usize = 512;
@ -39,8 +38,8 @@ pub trait DiskImage: Sync+Send {
.map_err(Error::DiskSeek)?; .map_err(Error::DiskSeek)?;
Ok(()) Ok(())
} }
fn write_sectors(&mut self, start_sector: u64, buffer: &[u8]) -> Result<()>; fn write_sectors(&mut self, start_sector: u64, buffer: &VolatileSlice) -> Result<()>;
fn read_sectors(&mut self, start_sector: u64, buffer: &mut [u8]) -> Result<()>; fn read_sectors(&mut self, start_sector: u64, buffer: &mut VolatileSlice) -> Result<()>;
fn flush(&mut self) -> Result<()> { Ok(()) } fn flush(&mut self) -> Result<()> { Ok(()) }
fn disk_image_id(&self) -> &[u8]; fn disk_image_id(&self) -> &[u8];
@ -79,7 +78,7 @@ pub enum Error {
#[error("attempt to access invalid sector offset {0}")] #[error("attempt to access invalid sector offset {0}")]
BadSectorOffset(u64), BadSectorOffset(u64),
#[error("failed to create memory overlay: {0}")] #[error("failed to create memory overlay: {0}")]
MemoryOverlayCreate(system::Error), MemoryOverlayCreate(memfd::Error),
#[error("disk not open")] #[error("disk not open")]
NotOpen, NotOpen,
} }

View File

@ -1,10 +1,11 @@
use crate::disk::{Result, Error, DiskImage, SECTOR_SIZE, generate_disk_image_id, OpenType}; use crate::disk::{Result, Error, DiskImage, SECTOR_SIZE, generate_disk_image_id, OpenType};
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::io::{Write, Read, SeekFrom, Seek}; use std::io;
use std::io::{SeekFrom, Seek};
use crate::disk::Error::DiskRead; use crate::disk::Error::DiskRead;
use crate::disk::memory::MemoryOverlay; use crate::disk::memory::MemoryOverlay;
use std::path::{PathBuf, Path}; use std::path::{PathBuf, Path};
use vm_memory::{ReadVolatile, VolatileSlice, WriteVolatile};
pub struct RawDiskImage { pub struct RawDiskImage {
path: PathBuf, path: PathBuf,
@ -94,7 +95,7 @@ impl DiskImage for RawDiskImage {
Ok(()) Ok(())
} }
fn write_sectors(&mut self, start_sector: u64, buffer: &[u8]) -> Result<()> { fn write_sectors(&mut self, start_sector: u64, buffer: &VolatileSlice) -> Result<()> {
if let Some(ref mut overlay) = self.overlay { if let Some(ref mut overlay) = self.overlay {
return overlay.write_sectors(start_sector, buffer); return overlay.write_sectors(start_sector, buffer);
} }
@ -104,12 +105,15 @@ impl DiskImage for RawDiskImage {
self.seek_to_sector(start_sector)?; self.seek_to_sector(start_sector)?;
let len = (buffer.len() / SECTOR_SIZE) * SECTOR_SIZE; let len = (buffer.len() / SECTOR_SIZE) * SECTOR_SIZE;
let file = self.disk_file()?; let file = self.disk_file()?;
file.write_all(&buffer[..len]) let buffer = buffer.subslice(0, len)
.expect("Out of bounds in RawDiskImage::write_sectors()");
file.write_all_volatile(&buffer)
.map_err(io::Error::other)
.map_err(Error::DiskWrite)?; .map_err(Error::DiskWrite)?;
Ok(()) Ok(())
} }
fn read_sectors(&mut self, start_sector: u64, buffer: &mut [u8]) -> Result<()> { fn read_sectors(&mut self, start_sector: u64, buffer: &mut VolatileSlice) -> Result<()> {
if let Some(mut overlay) = self.overlay.take() { if let Some(mut overlay) = self.overlay.take() {
let ret = overlay.read_sectors(self, start_sector, buffer); let ret = overlay.read_sectors(self, start_sector, buffer);
self.overlay.replace(overlay); self.overlay.replace(overlay);
@ -119,7 +123,10 @@ impl DiskImage for RawDiskImage {
self.seek_to_sector(start_sector)?; self.seek_to_sector(start_sector)?;
let len = (buffer.len() / SECTOR_SIZE) * SECTOR_SIZE; let len = (buffer.len() / SECTOR_SIZE) * SECTOR_SIZE;
let file = self.disk_file()?; let file = self.disk_file()?;
file.read_exact(&mut buffer[..len]) let mut buffer = buffer.subslice(0, len)
.expect("Out of bounds in RawDiskImage::read_sectors()");
file.read_exact_volatile(&mut buffer)
.map_err(io::Error::other)
.map_err(DiskRead)?; .map_err(DiskRead)?;
Ok(()) Ok(())
} }

View File

@ -1,6 +1,7 @@
use crate::disk::{Result, DiskImage, SECTOR_SIZE, RawDiskImage, OpenType}; use crate::disk::{Result, DiskImage, SECTOR_SIZE, RawDiskImage, OpenType};
use std::fs::File; use std::fs::File;
use std::path::PathBuf; use std::path::PathBuf;
use vm_memory::VolatileSlice;
// skip 4096 byte realmfs header // skip 4096 byte realmfs header
const HEADER_SECTOR_COUNT: usize = 8; const HEADER_SECTOR_COUNT: usize = 8;
@ -35,11 +36,11 @@ impl DiskImage for RealmFSImage {
self.raw.disk_file() self.raw.disk_file()
} }
fn write_sectors(&mut self, start_sector: u64, buffer: &[u8]) -> Result<()> { fn write_sectors(&mut self, start_sector: u64, buffer: &VolatileSlice) -> Result<()> {
self.raw.write_sectors(start_sector, buffer) self.raw.write_sectors(start_sector, buffer)
} }
fn read_sectors(&mut self, start_sector: u64, buffer: &mut [u8]) -> Result<()> { fn read_sectors(&mut self, start_sector: u64, buffer: &mut VolatileSlice) -> Result<()> {
self.raw.read_sectors(start_sector, buffer) self.raw.read_sectors(start_sector, buffer)
} }

View File

@ -1,14 +1,16 @@
use std::sync::{Arc, Mutex, MutexGuard}; use std::sync::{Arc, Mutex, MutexGuard};
use vm_allocator::{AddressAllocator, AllocPolicy, IdAllocator, RangeInclusive}; use vm_allocator::{AddressAllocator, AllocPolicy, IdAllocator, RangeInclusive};
use vm_memory::GuestMemoryMmap;
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
use crate::devices::rtc::Rtc; use crate::devices::rtc::Rtc;
use crate::devices::serial::{SerialDevice, SerialPort}; use crate::devices::serial::{SerialDevice, SerialPort};
use crate::io::bus::{Bus, BusDevice}; use crate::io::bus::{Bus, BusDevice};
use crate::io::pci::{MmioHandler, PciBarAllocation, PciBus, PciDevice}; use crate::io::pci::{MmioHandler, PciBarAllocation, PciBus, PciDevice};
use crate::io::{PciIrq, virtio}; use crate::io::{PciIrq, virtio};
use crate::io::address::AddressRange;
use crate::io::shm_mapper::DeviceSharedMemoryManager;
use crate::io::virtio::{VirtioDeviceState,VirtioDevice}; use crate::io::virtio::{VirtioDeviceState,VirtioDevice};
use crate::memory::{AddressRange, MemoryManager}; use crate::vm::{arch, KvmVm};
use crate::vm::arch;
#[derive(Clone)] #[derive(Clone)]
pub struct IoAllocator { pub struct IoAllocator {
@ -41,7 +43,9 @@ impl IoAllocator {
#[derive(Clone)] #[derive(Clone)]
pub struct IoManager { pub struct IoManager {
memory: MemoryManager, kvm_vm: KvmVm,
memory: GuestMemoryMmap,
dev_shm_manager: DeviceSharedMemoryManager,
pio_bus: Bus, pio_bus: Bus,
mmio_bus: Bus, mmio_bus: Bus,
pci_bus: Arc<Mutex<PciBus>>, pci_bus: Arc<Mutex<PciBus>>,
@ -49,13 +53,18 @@ pub struct IoManager {
} }
impl IoManager { impl IoManager {
pub fn new(memory: MemoryManager) -> IoManager { pub fn new(kvm_vm: KvmVm, memory: GuestMemoryMmap) -> IoManager {
let pci_bus = Arc::new(Mutex::new(PciBus::new())); let pci_bus = Arc::new(Mutex::new(PciBus::new()));
let mut pio_bus = Bus::new(); let mut pio_bus = Bus::new();
pio_bus.insert(pci_bus.clone(), PciBus::PCI_CONFIG_ADDRESS as u64, 8) pio_bus.insert(pci_bus.clone(), PciBus::PCI_CONFIG_ADDRESS as u64, 8)
.expect("Failed to add PCI configuration to PIO"); .expect("Failed to add PCI configuration to PIO");
let dev_shm_manager = DeviceSharedMemoryManager::new(&kvm_vm, &memory);
IoManager { IoManager {
kvm_vm,
memory, memory,
dev_shm_manager,
pio_bus, pio_bus,
mmio_bus: Bus::new(), mmio_bus: Bus::new(),
pci_bus, pci_bus,
@ -72,7 +81,7 @@ impl IoManager {
} }
pub fn register_serial_port(&mut self, port: SerialPort) { pub fn register_serial_port(&mut self, port: SerialPort) {
let serial = SerialDevice::new(self.memory.kvm_vm().clone(), port.irq()); let serial = SerialDevice::new(self.kvm_vm.clone(), port.irq());
let serial = Arc::new(Mutex::new(serial)); let serial = Arc::new(Mutex::new(serial));
self.pio_bus.insert(serial, port.io_port() as u64, 8).unwrap(); self.pio_bus.insert(serial, port.io_port() as u64, 8).unwrap();
@ -135,29 +144,15 @@ impl IoManager {
} }
pub fn add_virtio_device<D: VirtioDevice+'static>(&mut self, dev: D) -> virtio::Result<()> { pub fn add_virtio_device<D: VirtioDevice+'static>(&mut self, dev: D) -> virtio::Result<()> {
//let devtype = dev.device_type();
//let dev = Arc::new(Mutex::new(dev));
//let devstate = VirtioDeviceState::new(dev.clone(), self.memory.clone(), self.allocator.clone())?;
let irq = self.allocator.allocate_irq(); let irq = self.allocator.allocate_irq();
//let devstate = VirtioDeviceState::new(dev, self.memory.clone(), self.allocator.clone())?; let devstate = VirtioDeviceState::new(dev, self.kvm_vm.clone(), self.memory.clone(), irq)?;
let devstate = VirtioDeviceState::new(dev, self.memory.clone(), irq)?;
self.add_pci_device(Arc::new(Mutex::new(devstate))); self.add_pci_device(Arc::new(Mutex::new(devstate)));
// let mmio_range = devstate.mmio_range();
//let mut pci = self.pci_bus.lock().unwrap();
//pci.add_device(devstate);
// let mut pci_device = pci.new_device(devstate.irq() as u8, PCI_VENDOR_ID_REDHAT, devtype.device_id(), devtype.class_id());
// XXX add mmio bar
//pci_device.set_mmio_bar(0, AddressRange::new(mmio_range.start(), mmio_range.len() as usize));
// devstate.add_pci_capabilities(&mut pci_device);
// XXX add devstate to mmio bus
//self.mmio_bus.insert(Arc::new(Mutex::new(devstate)), mmio_range.start(), mmio_range.len())?;
//pci.add_device(pci_device);
Ok(()) Ok(())
} }
pub fn dev_shm_manager(&self) -> &DeviceSharedMemoryManager {
&self.dev_shm_manager
}
} }
pub struct I8042Device { pub struct I8042Device {

View File

@ -3,10 +3,14 @@ pub mod busdata;
pub mod pci; pub mod pci;
pub mod manager; pub mod manager;
pub mod virtio; pub mod virtio;
mod address;
pub mod shm_mapper;
pub use virtio::{VirtioDevice,FeatureBits,VirtioDeviceType,VirtQueue,Chain,Queues}; pub use virtio::{VirtioDevice,FeatureBits,VirtioDeviceType,VirtQueue,Chain,Queues};
pub use virtio::Error as VirtioError; pub use virtio::Error as VirtioError;
pub use busdata::{ReadableInt,WriteableInt}; pub use busdata::ReadableInt;
pub use pci::PciIrq; pub use pci::PciIrq;
// PCI Vendor id for Virtio devices // PCI Vendor id for Virtio devices
pub const PCI_VENDOR_ID_REDHAT: u16 = 0x1af4; pub const PCI_VENDOR_ID_REDHAT: u16 = 0x1af4;

View File

@ -1,7 +1,7 @@
use crate::io::address::AddressRange;
use crate::io::pci::address::PciAddress; use crate::io::pci::address::PciAddress;
use crate::io::pci::consts::{PCI_BAR0, PCI_BAR5, PCI_CACHE_LINE_SIZE, PCI_CAP_BASE_OFFSET, PCI_CAP_ID_VENDOR, PCI_CAPABILITY_LIST, PCI_CLASS_DEVICE, PCI_CLASS_REVISION, PCI_COMMAND, PCI_COMMAND_IO, PCI_COMMAND_MEMORY, PCI_DEVICE_ID, PCI_INTERRUPT_LINE, PCI_INTERRUPT_PIN, PCI_STATUS, PCI_STATUS_CAP_LIST, PCI_SUBSYSTEM_ID, PCI_VENDOR_ID}; use crate::io::pci::consts::{PCI_BAR0, PCI_BAR5, PCI_CACHE_LINE_SIZE, PCI_CAP_BASE_OFFSET, PCI_CAP_ID_VENDOR, PCI_CAPABILITY_LIST, PCI_CLASS_DEVICE, PCI_CLASS_REVISION, PCI_COMMAND, PCI_COMMAND_IO, PCI_COMMAND_MEMORY, PCI_DEVICE_ID, PCI_INTERRUPT_LINE, PCI_INTERRUPT_PIN, PCI_STATUS, PCI_STATUS_CAP_LIST, PCI_SUBSYSTEM_ID, PCI_VENDOR_ID};
use crate::io::pci::device::PciBar; use crate::io::pci::device::PciBar;
use crate::memory::AddressRange;
use crate::util::{ByteBuffer,Writeable}; use crate::util::{ByteBuffer,Writeable};
const PCI_CONFIG_SPACE_SIZE: usize = 256; const PCI_CONFIG_SPACE_SIZE: usize = 256;
@ -227,22 +227,3 @@ impl PciConfiguration {
} }
} }
} }
/*
impl BusDevice for PciConfiguration {
fn read(&mut self, offset: u64, data: &mut [u8]) {
if Self::is_valid_access(offset, data.len()) {
self.read_bytes(offset as usize, data)
} else {
data.fill(0xff)
}
}
fn write(&mut self, offset: u64, data: &[u8]) {
if Self::is_valid_access(offset, data.len()) {
self.write_config(offset as usize, data);
}
}
}
*/

View File

@ -5,6 +5,5 @@ mod config;
mod consts; mod consts;
mod device; mod device;
pub use bus::{PciBus,PciIrq}; pub use bus::{PciBus,PciIrq};
pub use config::{PciCapability,PciConfiguration}; pub use config::PciConfiguration;
pub use address::PciAddress;
pub use device::{PciDevice,PciBar,PciBarAllocation,MmioHandler}; pub use device::{PciDevice,PciBar,PciBarAllocation,MmioHandler};

341
src/io/shm_mapper.rs Normal file
View File

@ -0,0 +1,341 @@
use std::collections::HashMap;
use std::fs::File;
use std::os::fd::{AsRawFd, RawFd};
use std::result;
use std::sync::{Arc, Mutex, MutexGuard};
use vm_allocator::{AddressAllocator, AllocPolicy, RangeInclusive};
use vm_memory::{Address, FileOffset, GuestAddress, GuestMemory, GuestMemoryMmap, GuestMemoryRegion, MmapRegion};
use crate::system::drm::{DrmBufferAllocator, DrmDescriptor};
use crate::system::drm;
use crate::util::BitSet;
use crate::vm::KvmVm;
use thiserror::Error;
use std::io::{Seek, SeekFrom};
use memfd::{FileSeal, MemfdOptions};
use crate::system;
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug,Error)]
pub enum Error {
#[error("failed to create SharedMemory: {0}")]
SharedMemoryCreation(system::Error),
#[error("failed to allocate DRM buffer: {0}")]
DrmAllocateFailed(drm::Error),
#[error("no DRM memory allocator")]
NoDrmAllocator,
#[error("failed to register memory with hypervisor: {0}")]
RegisterMemoryFailed(kvm_ioctls::Error),
#[error("failed to unregister memory with hypervisor: {0}")]
UnregisterMemoryFailed(kvm_ioctls::Error),
#[error("failed to allocate memory for device")]
DeviceMemoryAllocFailed,
}
/// Tracks graphic buffer memory allocations shared between host and guest.
///
/// The allocated buffers are opaque to the hypervisor and are referred to only
/// by file descriptor. These memory regions are passed to or received from the
/// wayland compositor (ie GNOME Shell) and are mapped into guest memory space so
/// that a device driver in the guest can make the shared memory available for
/// rendering application windows.
///
#[derive(Clone)]
pub struct DeviceSharedMemoryManager {
device_memory: Arc<Mutex<DeviceSharedMemory>>,
}
impl DeviceSharedMemoryManager {
pub fn new(kvm_vm: &KvmVm, memory: &GuestMemoryMmap) -> Self {
let device_memory = DeviceSharedMemory::new(kvm_vm.clone(), memory);
DeviceSharedMemoryManager {
device_memory: Arc::new(Mutex::new(device_memory)),
}
}
pub fn free_buffer(&self, slot: u32) -> Result<()> {
self.dev_memory().unregister(slot)
}
pub fn allocate_buffer_from_file(&self, fd: File) -> Result<SharedMemoryAllocation> {
let memory = SharedMemoryMapping::from_file(fd)
.map_err(Error::SharedMemoryCreation)?;
self.dev_memory().register(memory)
}
pub fn allocate_buffer(&self, size: usize) -> Result<SharedMemoryAllocation> {
let memory = SharedMemoryMapping::create_memfd(size, "ph-dev-shm")
.map_err(Error::SharedMemoryCreation)?;
self.dev_memory().register(memory)
}
pub fn allocate_drm_buffer(&self, width: u32, height: u32, format: u32) -> Result<SharedMemoryAllocation> {
self.dev_memory().allocate_drm_buffer(width, height, format)
}
fn dev_memory(&self) -> MutexGuard<DeviceSharedMemory> {
self.device_memory.lock().unwrap()
}
}
#[derive(Copy,Clone)]
pub struct SharedMemoryAllocation {
pfn: u64,
size: usize,
slot: u32,
raw_fd: RawFd,
drm_descriptor: Option<DrmDescriptor>,
}
impl SharedMemoryAllocation {
fn new(pfn: u64, size: usize, slot: u32, raw_fd: RawFd) -> Self {
SharedMemoryAllocation {
pfn, size, slot, raw_fd,
drm_descriptor: None,
}
}
fn set_drm_descriptor(&mut self, drm_descriptor: DrmDescriptor) {
self.drm_descriptor.replace(drm_descriptor);
}
pub fn pfn(&self) -> u64 {
self.pfn
}
pub fn size(&self) -> usize {
self.size
}
pub fn slot(&self) -> u32 {
self.slot
}
pub fn raw_fd(&self) -> RawFd {
self.raw_fd
}
pub fn drm_descriptor(&self) -> Option<DrmDescriptor> {
self.drm_descriptor
}
}
struct DeviceSharedMemory {
kvm_vm: KvmVm,
slots: BitSet,
mappings: HashMap<u32, SharedMemoryMapping>,
allocator: AddressAllocator,
drm_allocator: Option<DrmBufferAllocator>
}
impl DeviceSharedMemory {
const WL_SHM_SIZE: u64 = 1 << 32;
fn create_allocator(memory: &GuestMemoryMmap) -> AddressAllocator {
let device_memory_base = || -> GuestAddress {
// Put device memory at a 2MB boundary after physical memory or at 4GB,
// whichever is higher.
const ONE_MB: u64 = 1 << 20;
const FOUR_GB: u64 = 4 * 1024 * ONE_MB;
memory.iter()
.map(|addr| addr.last_addr().unchecked_align_up(2 * ONE_MB))
.max()
.map(|top| std::cmp::max(top, GuestAddress(FOUR_GB)))
.expect("Failed to compute device memory base")
};
let base = device_memory_base();
AddressAllocator::new(base.raw_value(), Self::WL_SHM_SIZE)
.expect("Failed to create wayland shared memory allocator")
}
fn new(kvm_vm: KvmVm, memory: &GuestMemoryMmap) -> Self {
let allocator = Self::create_allocator(memory);
let mut slots = BitSet::new();
for idx in 0..memory.num_regions() {
slots.insert(idx);
}
DeviceSharedMemory {
kvm_vm,
slots,
mappings: HashMap::new(),
allocator,
drm_allocator: None,
}
}
fn is_drm_enabled(&self) -> bool {
self.drm_allocator.is_some()
}
fn enable_drm_allocator(&mut self) {
if !self.is_drm_enabled() {
match DrmBufferAllocator::open() {
Ok(allocator) => { self.drm_allocator.replace(allocator); },
Err(err) => {
warn!("failed to open DRM buffer allocator: {}", err);
},
};
}
}
fn allocate_drm_buffer(&mut self, width: u32, height: u32, format: u32) -> Result<SharedMemoryAllocation> {
if !self.is_drm_enabled() {
self.enable_drm_allocator();
}
if let Some(drm_allocator) = self.drm_allocator.as_ref() {
let (fd, desc) = drm_allocator.allocate(width, height, format)
.map_err(Error::DrmAllocateFailed)?;
let memory = SharedMemoryMapping::from_file(fd)
.map_err(Error::SharedMemoryCreation)?;
let mut registration = self.register(memory)?;
registration.set_drm_descriptor(desc);
Ok(registration)
} else {
Err(Error::NoDrmAllocator)
}
}
fn register(&mut self, mut memory: SharedMemoryMapping) -> Result<SharedMemoryAllocation> {
fn round_to_page_size(n: usize) -> usize {
let mask = 4096 - 1;
(n + mask) & !mask
}
let size = round_to_page_size(memory.size());
let (range, slot) = self.allocate_addr_and_slot(size)?;
memory.set_guest_range(range.clone());
if let Err(e) = self.kvm_vm.add_memory_region(slot, range.start(), memory.mapping_host_address(), size) {
self.free_range_and_slot(&range, slot);
Err(Error::RegisterMemoryFailed(e))
} else {
let pfn = range.start() >> 12;
let size = memory.size();
let raw_fd = memory.raw_fd();
self.mappings.insert(slot, memory);
Ok(SharedMemoryAllocation::new(pfn, size, slot, raw_fd))
}
}
fn unregister(&mut self, slot: u32) -> Result<()> {
if let Some(registration) = self.mappings.remove(&slot) {
self.kvm_vm.remove_memory_region(slot)
.map_err(Error::UnregisterMemoryFailed)?;
if let Some(range) = registration.guest_range() {
self.free_range_and_slot(range, slot);
} else {
// XXX
}
}
Ok(())
}
fn allocate_addr_and_slot(&mut self, size: usize) -> Result<(RangeInclusive, u32)> {
let range = self.allocator.allocate(
size as u64,
4096,
AllocPolicy::FirstMatch
).map_err(|_| Error::DeviceMemoryAllocFailed)?;
Ok((range, self.allocate_slot()))
}
fn free_range_and_slot(&mut self, range: &RangeInclusive, slot: u32) {
if let Err(err) = self.allocator.free(range) {
warn!("Error freeing memory range from allocator: {}", err);
}
self.free_slot(slot);
}
fn allocate_slot(&mut self) -> u32 {
for i in 0.. {
if !self.slots.get(i) {
self.slots.insert(i);
return i as u32;
}
}
unreachable!()
}
fn free_slot(&mut self, slot: u32) {
self.slots.remove(slot as usize)
}
}
struct SharedMemoryMapping {
mapping: MmapRegion,
guest_range: Option<RangeInclusive>,
}
impl SharedMemoryMapping {
fn from_file(fd: File) -> system::Result<Self> {
let size = (&fd).seek(SeekFrom::End(0))? as usize;
let file_offset = FileOffset::new(fd, 0);
let mapping = MmapRegion::from_file(file_offset, size)
.map_err(system::Error::MmapRegionCreate)?;
Ok(SharedMemoryMapping {
mapping,
guest_range: None,
})
}
fn create_memfd(size: usize, name: &str) -> system::Result<Self> {
let memfd = MemfdOptions::default()
.allow_sealing(true)
.create(name)
.map_err(system::Error::ShmAllocFailed)?;
memfd.as_file().set_len(size as u64)?;
memfd.add_seals(&[
FileSeal::SealShrink,
FileSeal::SealGrow,
]).map_err(system::Error::ShmAllocFailed)?;
memfd.add_seal(FileSeal::SealSeal)
.map_err(system::Error::ShmAllocFailed)?;
let fd = memfd.into_file();
let file_offset = FileOffset::new(fd, 0);
let mapping = MmapRegion::from_file(file_offset, size)
.map_err(system::Error::MmapRegionCreate)?;
Ok(SharedMemoryMapping {
mapping,
guest_range: None,
})
}
fn size(&self) -> usize {
self.mapping.size()
}
fn mapping_host_address(&self) -> u64 {
self.mapping.as_ptr() as u64
}
fn set_guest_range(&mut self, range: RangeInclusive) {
self.guest_range.replace(range);
}
fn guest_range(&self) -> Option<&RangeInclusive> {
self.guest_range.as_ref()
}
fn raw_fd(&self) -> RawFd {
self.mapping.file_offset()
.expect("SharedMemory mapping does not have a file!")
.file()
.as_raw_fd()
}
}

View File

@ -1,6 +1,8 @@
use std::ops::Range; use std::ops::Range;
use std::sync::{Arc, Mutex, MutexGuard}; use std::sync::{Arc, Mutex, MutexGuard};
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use vm_memory::GuestMemoryMmap;
use crate::io::address::AddressRange;
use crate::io::busdata::{ReadableInt, WriteableInt}; use crate::io::busdata::{ReadableInt, WriteableInt};
use crate::io::pci::{PciBar, PciBarAllocation, PciConfiguration, PciDevice}; use crate::io::pci::{PciBar, PciBarAllocation, PciConfiguration, PciDevice};
@ -9,7 +11,7 @@ use crate::io::virtio::features::FeatureBits;
use crate::io::virtio::queues::Queues; use crate::io::virtio::queues::Queues;
use crate::io::virtio::Result; use crate::io::virtio::Result;
use crate::io::PCI_VENDOR_ID_REDHAT; use crate::io::PCI_VENDOR_ID_REDHAT;
use crate::memory::{AddressRange, MemoryManager}; use crate::vm::KvmVm;
pub trait VirtioDevice: Send { pub trait VirtioDevice: Send {
@ -41,12 +43,12 @@ pub struct VirtioDeviceState {
impl VirtioDeviceState { impl VirtioDeviceState {
pub fn new<T: VirtioDevice+'static>(device: T, memory: MemoryManager, irq: u8) -> Result<Self> { pub fn new<T: VirtioDevice+'static>(device: T, kvm_vm: KvmVm, guest_memory: GuestMemoryMmap, irq: u8) -> Result<Self> {
let devtype = device.device_type(); let devtype = device.device_type();
let config_size = device.config_size(); let config_size = device.config_size();
let device = Arc::new(Mutex::new(device)); let device = Arc::new(Mutex::new(device));
let queues = Queues::new(memory, irq)?; let queues = Queues::new(kvm_vm, guest_memory, irq)?;
let mut pci_config = PciConfiguration::new(queues.irq(), PCI_VENDOR_ID_REDHAT, devtype.device_id(), devtype.class_id()); let mut pci_config = PciConfiguration::new(queues.irq(), PCI_VENDOR_ID_REDHAT, devtype.device_id(), devtype.class_id());
Self::add_pci_capabilities::<T>(&mut pci_config, config_size); Self::add_pci_capabilities::<T>(&mut pci_config, config_size);

View File

@ -1,8 +1,8 @@
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use kvm_ioctls::{IoEventAddress, NoDatamatch}; use kvm_ioctls::{IoEventAddress, NoDatamatch};
use vm_memory::GuestMemoryMmap;
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
use crate::memory::MemoryManager;
use crate::io::virtio::{Error, Result}; use crate::io::virtio::{Error, Result};
use crate::io::virtio::consts::VIRTIO_MMIO_OFFSET_NOTIFY; use crate::io::virtio::consts::VIRTIO_MMIO_OFFSET_NOTIFY;
use crate::io::VirtQueue; use crate::io::VirtQueue;
@ -49,17 +49,19 @@ impl InterruptLine {
} }
pub struct Queues { pub struct Queues {
memory: MemoryManager, kvm_vm: KvmVm,
guest_memory: GuestMemoryMmap,
selected_queue: u16, selected_queue: u16,
queues: Vec<VirtQueue>, queues: Vec<VirtQueue>,
interrupt: Arc<InterruptLine>, interrupt: Arc<InterruptLine>,
} }
impl Queues { impl Queues {
pub fn new(memory: MemoryManager, irq: u8) -> Result<Self> { pub fn new(kvm_vm: KvmVm, guest_memory: GuestMemoryMmap, irq: u8) -> Result<Self> {
let interrupt = InterruptLine::new(memory.kvm_vm(), irq)?; let interrupt = InterruptLine::new(&kvm_vm, irq)?;
let queues = Queues { let queues = Queues {
memory, kvm_vm,
guest_memory,
selected_queue: 0, selected_queue: 0,
queues: Vec::new(), queues: Vec::new(),
interrupt: Arc::new(interrupt), interrupt: Arc::new(interrupt),
@ -78,8 +80,12 @@ impl Queues {
self.queues.clone() self.queues.clone()
} }
pub fn memory(&self) -> &MemoryManager { pub fn guest_memory(&self) -> &GuestMemoryMmap{
&self.memory &self.guest_memory
}
pub fn kvm_vm(&self) -> &KvmVm {
&self.kvm_vm
} }
pub fn configure_queues(&self, features: u64) -> Result<()> { pub fn configure_queues(&self, features: u64) -> Result<()> {
@ -113,7 +119,7 @@ impl Queues {
let mut idx = 0; let mut idx = 0;
for &sz in queue_sizes { for &sz in queue_sizes {
let ioevent = self.create_ioevent(idx, mmio_base)?; let ioevent = self.create_ioevent(idx, mmio_base)?;
let vq = VirtQueue::new(self.memory.guest_ram().clone(), sz, self.interrupt.clone(), ioevent); let vq = VirtQueue::new(self.guest_memory.clone(), sz, self.interrupt.clone(), ioevent);
self.queues.push(vq); self.queues.push(vq);
idx += 1; idx += 1;
} }
@ -130,7 +136,7 @@ impl Queues {
let addr = IoEventAddress::Mmio(notify_address); let addr = IoEventAddress::Mmio(notify_address);
self.memory.kvm_vm().vm_fd().register_ioevent(&evt, &addr, NoDatamatch) self.kvm_vm.vm_fd().register_ioevent(&evt, &addr, NoDatamatch)
.map_err(Error::CreateIoEventFd)?; .map_err(Error::CreateIoEventFd)?;
Ok(Arc::new(evt)) Ok(Arc::new(evt))

View File

@ -1,12 +1,12 @@
use std::{fmt, io}; use std::{fmt, io};
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use vm_memory::{GuestAddress, GuestMemory, GuestMemoryMmap, ReadVolatile, VolatileSlice};
use crate::io::virtio::vq::descriptor::Descriptor; use crate::io::virtio::vq::descriptor::Descriptor;
use crate::io::virtio::vq::virtqueue::QueueBackend; use crate::io::virtio::vq::virtqueue::QueueBackend;
use crate::memory::GuestRam;
pub struct DescriptorList { pub struct DescriptorList {
memory: GuestRam, memory: GuestMemoryMmap,
descriptors: Vec<Descriptor>, descriptors: Vec<Descriptor>,
offset: usize, offset: usize,
total_size: usize, total_size: usize,
@ -14,7 +14,7 @@ pub struct DescriptorList {
} }
impl DescriptorList { impl DescriptorList {
pub fn new(memory: GuestRam) -> Self { pub fn new(memory: GuestMemoryMmap) -> Self {
DescriptorList { DescriptorList {
memory, memory,
descriptors: Vec::new(), descriptors: Vec::new(),
@ -96,8 +96,8 @@ impl DescriptorList {
0 0
} }
fn write_from_reader<R>(&mut self, reader: R, size: usize) -> io::Result<usize> fn write_from_reader<R>(&mut self, reader: &mut R, size: usize) -> io::Result<usize>
where R: Read+Sized where R: ReadVolatile+Sized
{ {
if let Some(d) = self.current() { if let Some(d) = self.current() {
let n = d.write_from_reader(&self.memory, self.offset, reader, size)?; let n = d.write_from_reader(&self.memory, self.offset, reader, size)?;
@ -108,23 +108,20 @@ impl DescriptorList {
} }
} }
fn current_slice(&self) -> &[u8] { fn empty_slice() -> VolatileSlice<'static> {
if let Some(d) = self.current() { unsafe {
let size = d.remaining(self.offset); VolatileSlice::new(0 as *mut u8, 0)
let addr = d.address() + self.offset as u64;
self.memory.slice(addr, size).unwrap_or(&[])
} else {
&[]
} }
} }
fn current_mut_slice(&self) -> &mut [u8] { fn current_slice(&self) -> VolatileSlice {
if let Some(d) = self.current() { if let Some(d) = self.current() {
let size = d.remaining(self.offset); let size = d.remaining(self.offset);
let addr = d.address() + self.offset as u64; let addr = d.address() + self.offset as u64;
self.memory.mut_slice(addr, size).unwrap_or(&mut []) self.memory.get_slice(GuestAddress(addr), size)
.unwrap_or(Self::empty_slice())
} else { } else {
&mut [] Self::empty_slice()
} }
} }
@ -224,7 +221,7 @@ impl Chain {
self.readable.is_empty() && self.writeable.is_empty() self.readable.is_empty() && self.writeable.is_empty()
} }
pub fn current_read_slice(&self) -> &[u8] { pub fn current_read_slice(&self) -> VolatileSlice {
self.readable.current_slice() self.readable.current_slice()
} }
@ -239,12 +236,12 @@ impl Chain {
self.writeable.inc(sz); self.writeable.inc(sz);
} }
pub fn current_write_slice(&mut self) -> &mut [u8] { pub fn current_write_slice(&mut self) -> VolatileSlice {
self.writeable.current_mut_slice() self.writeable.current_slice()
} }
pub fn copy_from_reader<R>(&mut self, r: R, size: usize) -> io::Result<usize> pub fn copy_from_reader<R>(&mut self, r: &mut R, size: usize) -> io::Result<usize>
where R: Read+Sized where R: ReadVolatile+Sized
{ {
self.writeable.write_from_reader(r, size) self.writeable.write_from_reader(r, size)
} }

View File

@ -1,6 +1,5 @@
use std::{cmp, io}; use std::{cmp, io};
use std::io::Read; use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap, ReadVolatile};
use crate::memory::GuestRam;
#[repr(u16)] #[repr(u16)]
enum DescriptorFlag { enum DescriptorFlag {
@ -83,29 +82,32 @@ impl Descriptor {
(used != avail) && (avail == wrap_counter) (used != avail) && (avail == wrap_counter)
} }
pub fn read_from(&self, memory: &GuestRam, offset: usize, buf: &mut[u8]) -> usize { pub fn read_from(&self, memory: &GuestMemoryMmap, offset: usize, buf: &mut[u8]) -> usize {
let sz = cmp::min(buf.len(), self.remaining(offset)); let sz = cmp::min(buf.len(), self.remaining(offset));
if sz > 0 { if sz > 0 {
memory.read_bytes(self.address + offset as u64, &mut buf[..sz]).unwrap(); let address = GuestAddress(self.address).checked_add(offset as u64).unwrap();
memory.read_slice(&mut buf[..sz], address).unwrap();
} }
sz sz
} }
pub fn write_to(&self, memory: &GuestRam, offset: usize, buf: &[u8]) -> usize { pub fn write_to(&self, memory: &GuestMemoryMmap, offset: usize, buf: &[u8]) -> usize {
let sz = cmp::min(buf.len(), self.remaining(offset)); let sz = cmp::min(buf.len(), self.remaining(offset));
if sz > 0 { if sz > 0 {
memory.write_bytes(self.address + offset as u64, &buf[..sz]).unwrap(); let address = GuestAddress(self.address).checked_add(offset as u64).unwrap();
memory.write_slice(&buf[..sz], address).unwrap();
} }
sz sz
} }
pub fn write_from_reader<R: Read+Sized>(&self, memory: &GuestRam, offset: usize, mut r: R, size: usize) -> io::Result<usize> { pub fn write_from_reader<R: ReadVolatile+Sized>(&self, memory: &GuestMemoryMmap, offset: usize, r: &mut R, size: usize) -> io::Result<usize> {
let sz = cmp::min(size, self.remaining(offset)); let sz = cmp::min(size, self.remaining(offset));
if sz > 0 { if sz > 0 {
let slice = memory.mut_slice(self.address + offset as u64, sz).unwrap(); let address = GuestAddress(self.address).checked_add(offset as u64).unwrap();
return r.read(slice); let mut slice = memory.get_slice(address, sz).unwrap();
let sz = r.read_volatile(&mut slice).unwrap();
return Ok(sz)
} }
Ok(0) Ok(0)
} }
} }

View File

@ -1,5 +1,6 @@
use std::sync::{Arc, atomic}; use std::sync::{Arc, atomic};
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use vm_memory::{Bytes, GuestAddress, GuestMemory, GuestMemoryMmap};
use crate::io::virtio::Error; use crate::io::virtio::Error;
use crate::io::virtio::features::ReservedFeatureBit; use crate::io::virtio::features::ReservedFeatureBit;
use crate::io::virtio::queues::InterruptLine; use crate::io::virtio::queues::InterruptLine;
@ -7,11 +8,10 @@ use crate::io::virtio::vq::chain::DescriptorList;
use crate::io::virtio::vq::descriptor::Descriptor; use crate::io::virtio::vq::descriptor::Descriptor;
use crate::io::virtio::vq::SharedIndex; use crate::io::virtio::vq::SharedIndex;
use crate::io::virtio::vq::virtqueue::QueueBackend; use crate::io::virtio::vq::virtqueue::QueueBackend;
use crate::memory::GuestRam;
pub struct SplitQueue { pub struct SplitQueue {
memory: GuestRam, memory: GuestMemoryMmap,
interrupt: Arc<InterruptLine>, interrupt: Arc<InterruptLine>,
queue_size: u16, queue_size: u16,
@ -29,7 +29,7 @@ pub struct SplitQueue {
} }
impl SplitQueue { impl SplitQueue {
pub fn new(memory: GuestRam, interrupt: Arc<InterruptLine>) -> Self { pub fn new(memory: GuestMemoryMmap, interrupt: Arc<InterruptLine>) -> Self {
SplitQueue { SplitQueue {
memory, memory,
interrupt, interrupt,
@ -54,12 +54,12 @@ impl SplitQueue {
} }
let head = self.descriptor_base + (idx as u64 * 16); let head = self.descriptor_base + (idx as u64 * 16);
let addr = self.memory.read_int::<u64>(head).unwrap(); let addr = self.memory.read_obj::<u64>(GuestAddress(head)).ok()?;
let len= self.memory.read_int::<u32>(head + 8).unwrap(); let len= self.memory.read_obj::<u32>(GuestAddress(head + 8)).ok()?;
let flags = self.memory.read_int::<u16>(head + 12).unwrap(); let flags = self.memory.read_obj::<u16>(GuestAddress(head + 12)).ok()?;
let next = self.memory.read_int::<u16>(head + 14).unwrap(); let next = self.memory.read_obj::<u16>(GuestAddress(head + 14)).ok()?;
if self.memory.is_valid_range(addr, len as usize) && next < self.queue_size { if self.memory.check_range(GuestAddress(addr), len as usize) && next < self.queue_size {
return Some(Descriptor::new(addr, len, flags, next)); return Some(Descriptor::new(addr, len, flags, next));
} }
None None
@ -101,7 +101,7 @@ impl SplitQueue {
/// Load `avail_ring.idx` from guest memory and store it in `cached_avail_idx`. /// Load `avail_ring.idx` from guest memory and store it in `cached_avail_idx`.
/// ///
fn load_avail_idx(&self) -> u16 { fn load_avail_idx(&self) -> u16 {
let avail_idx = self.memory.read_int::<u16>(self.avail_base + 2).unwrap(); let avail_idx = self.memory.read_obj::<u16>(GuestAddress(self.avail_base + 2)).unwrap();
self.cached_avail_idx.set(avail_idx); self.cached_avail_idx.set(avail_idx);
avail_idx avail_idx
} }
@ -112,21 +112,7 @@ impl SplitQueue {
/// ///
fn load_avail_entry(&self, ring_idx: u16) -> u16 { fn load_avail_entry(&self, ring_idx: u16) -> u16 {
let offset = (4 + (ring_idx % self.queue_size) * 2) as u64; let offset = (4 + (ring_idx % self.queue_size) * 2) as u64;
self.memory.read_int(self.avail_base + offset).unwrap() self.memory.read_obj(GuestAddress(self.avail_base + offset)).unwrap()
}
/// Queue is empty if `next_avail` is same value as
/// `avail_ring.idx` value in guest memory If `cached_avail_idx`
/// currently matches `next_avail` it is reloaded from
/// memory in case guest has updated field since last
/// time it was loaded.
///
fn is_empty(&self) -> bool {
let next_avail = self.next_avail.get();
if self.cached_avail_idx.get() != next_avail {
return false;
}
next_avail == self.load_avail_idx()
} }
/// ///
@ -147,7 +133,7 @@ impl SplitQueue {
} }
fn read_avail_flags(&self) -> u16 { fn read_avail_flags(&self) -> u16 {
self.memory.read_int::<u16>(self.avail_base).unwrap() self.memory.read_obj::<u16>(GuestAddress(self.avail_base)).unwrap()
} }
/// ///
@ -166,14 +152,14 @@ impl SplitQueue {
let used_idx = (self.next_used_idx.get() % self.queue_size) as u64; let used_idx = (self.next_used_idx.get() % self.queue_size) as u64;
let elem_addr = self.used_base + (4 + used_idx * 8); let elem_addr = self.used_base + (4 + used_idx * 8);
// write descriptor index to 'next used' slot in used ring // write descriptor index to 'next used' slot in used ring
self.memory.write_int(elem_addr, idx as u32).unwrap(); self.memory.write_obj(idx as u32, GuestAddress(elem_addr)).unwrap();
// write length to 'next used' slot in ring // write length to 'next used' slot in ring
self.memory.write_int(elem_addr + 4, len as u32).unwrap(); self.memory.write_obj(len, GuestAddress(elem_addr + 4)).unwrap();
self.next_used_idx.inc(); self.next_used_idx.inc();
atomic::fence(Ordering::Release); atomic::fence(Ordering::Release);
// write updated next_used // write updated next_used
self.memory.write_int(self.used_base + 2, self.next_used_idx.get()).unwrap(); self.memory.write_obj(self.next_used_idx.get(), GuestAddress(self.used_base + 2)).unwrap();
} }
/// ///
@ -187,7 +173,8 @@ impl SplitQueue {
return; return;
} }
let addr = self.used_base + 4 + (self.queue_size as u64 * 8); let addr = self.used_base + 4 + (self.queue_size as u64 * 8);
self.memory.write_int::<u16>(addr, val).unwrap(); self.memory.write_obj::<u16>( val, GuestAddress(addr)).unwrap();
atomic::fence(Ordering::Release); atomic::fence(Ordering::Release);
} }
@ -199,7 +186,7 @@ impl SplitQueue {
/// Read and return the `used_event` field from the Avail ring /// Read and return the `used_event` field from the Avail ring
fn read_used_event(&self) -> u16 { fn read_used_event(&self) -> u16 {
let addr = self.avail_base + 4 + (self.queue_size as u64 * 2); let addr = self.avail_base + 4 + (self.queue_size as u64 * 2);
self.memory.read_int::<u16>(addr).unwrap() self.memory.read_obj::<u16>(GuestAddress(addr)).unwrap()
} }
fn need_interrupt(&self, first_used: u16) -> bool { fn need_interrupt(&self, first_used: u16) -> bool {
@ -217,13 +204,13 @@ impl QueueBackend for SplitQueue {
let avail_ring_sz = 6 + 2 * size as usize; let avail_ring_sz = 6 + 2 * size as usize;
let used_ring_sz = 6 + 8 * size as usize; let used_ring_sz = 6 + 8 * size as usize;
if !self.memory.is_valid_range(descriptor_area, desc_table_sz) { if !self.memory.check_range(GuestAddress(descriptor_area), desc_table_sz) {
return Err(Error::RangeInvalid(descriptor_area)); return Err(Error::RangeInvalid(descriptor_area));
} }
if !self.memory.is_valid_range(driver_area, avail_ring_sz) { if !self.memory.check_range(GuestAddress(driver_area), avail_ring_sz) {
return Err(Error::AvailInvalid(driver_area)); return Err(Error::AvailInvalid(driver_area));
} }
if !self.memory.is_valid_range(device_area, used_ring_sz) { if !self.memory.check_range(GuestAddress(device_area), used_ring_sz) {
return Err(Error::UsedInvalid(device_area)); return Err(Error::UsedInvalid(device_area));
} }

View File

@ -1,4 +1,5 @@
use std::sync::{Arc, Mutex, MutexGuard}; use std::sync::{Arc, Mutex, MutexGuard};
use vm_memory::GuestMemoryMmap;
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
@ -7,7 +8,6 @@ use crate::io::virtio::consts::MAX_QUEUE_SIZE;
use crate::io::virtio::queues::InterruptLine; use crate::io::virtio::queues::InterruptLine;
use crate::io::virtio::vq::chain::{Chain, DescriptorList}; use crate::io::virtio::vq::chain::{Chain, DescriptorList};
use crate::io::virtio::vq::splitqueue::SplitQueue; use crate::io::virtio::vq::splitqueue::SplitQueue;
use crate::memory::GuestRam;
pub trait QueueBackend: Send { pub trait QueueBackend: Send {
@ -44,7 +44,7 @@ pub struct VirtQueue {
impl VirtQueue { impl VirtQueue {
pub const DEFAULT_QUEUE_SIZE: u16 = 128; pub const DEFAULT_QUEUE_SIZE: u16 = 128;
pub fn new(memory: GuestRam, default_size: u16, interrupt: Arc<InterruptLine>, ioeventfd: Arc<EventFd>) -> Self { pub fn new(memory: GuestMemoryMmap, default_size: u16, interrupt: Arc<InterruptLine>, ioeventfd: Arc<EventFd>) -> Self {
let backend = Arc::new(Mutex::new(SplitQueue::new(memory, interrupt))); let backend = Arc::new(Mutex::new(SplitQueue::new(memory, interrupt)));
VirtQueue { VirtQueue {
ioeventfd, ioeventfd,

View File

@ -5,7 +5,6 @@ mod system;
#[macro_use] #[macro_use]
pub mod util; pub mod util;
mod vm; mod vm;
mod memory;
mod devices; mod devices;
mod disk; mod disk;
mod io; mod io;

View File

@ -1,93 +0,0 @@
use crate::memory::AddressRange;
use std::collections::BTreeMap;
use std::sync::{Mutex, Arc};
#[derive(Clone)]
pub struct SystemAllocator {
device_memory: AddressAllocator,
}
impl SystemAllocator {
pub fn new(device_range: AddressRange) -> Self {
let device_memory = AddressAllocator::new(device_range, 4096);
SystemAllocator { device_memory }
}
pub fn free_device_memory(&self, base: u64) -> bool {
self.device_memory.free(base)
}
pub fn allocate_device_memory(&self, size: usize) -> Option<u64> {
self.device_memory.allocate(size)
}
}
#[derive(Clone)]
struct AddressAllocator {
range: AddressRange,
default_alignment: usize,
allocations: Arc<Mutex<BTreeMap<u64, AddressRange>>>,
}
impl AddressAllocator {
fn new(range: AddressRange, default_alignment: usize) -> Self {
let allocations = Arc::new(Mutex::new(BTreeMap::new()));
AddressAllocator { range, default_alignment, allocations }
}
fn align_addr_to(addr: u64, alignment: u64) -> u64 {
let adjust = if addr % alignment != 0 {
alignment - (addr % alignment)
} else {
0
};
addr + adjust
}
fn allocate(&self, size: usize) -> Option<u64> {
self.allocate_aligned(size, self.default_alignment)
}
fn allocate_aligned(&self, size: usize, alignment: usize) -> Option<u64> {
self.first_available(size, alignment)
}
fn free(&self, base: u64) -> bool {
let mut map = self.allocations.lock().unwrap();
map.remove(&base).is_some()
}
fn first_available(&self, size: usize, alignment: usize) -> Option<u64> {
if size == 0 {
return None;
}
let mut map = self.allocations.lock().unwrap();
let base = self.first_available_base_addr(&map, size, alignment);
let size = size as usize;
if self.range.contains(base, size) {
map.insert(base, AddressRange::new(base, size));
return Some(base);
}
None
}
// Return lowest base address of requested alignment which does not
// conflict with any currently allocated range
fn first_available_base_addr(&self, map: &BTreeMap<u64, AddressRange>, size: usize, alignment: usize) -> u64 {
let mut base = Self::align_addr_to(self.range.base(), alignment as u64);
for alloc in map.values() {
// Alignment adjustment may have placed address beyond start of next
// allocation.
if let Some(gap_size) = alloc.base().checked_sub(base) {
if (gap_size as usize) >= size {
return base;
}
}
if base < alloc.end() {
base = Self::align_addr_to(alloc.end(), alignment as u64);
}
}
base
}
}

View File

@ -1,159 +0,0 @@
use std::collections::HashMap;
use std::os::unix::io::{AsRawFd,RawFd};
use std::sync::{Arc, RwLock};
use crate::memory::{GuestRam, SystemAllocator, Mapping, Error, Result};
use crate::system::FileDesc;
use crate::util::BitSet;
use crate::memory::drm::{DrmBufferAllocator, DrmDescriptor};
use std::io::SeekFrom;
use crate::memory::ram::MemoryRegion;
use crate::vm::KvmVm;
#[derive(Clone)]
pub struct MemoryManager {
kvm_vm: KvmVm,
ram: GuestRam,
device_memory: Arc<RwLock<DeviceMemory>>,
drm_allocator: Option<DrmBufferAllocator>,
}
impl MemoryManager {
pub fn new(kvm_vm: KvmVm, ram: GuestRam, allocator: SystemAllocator, use_drm: bool) -> Result<Self> {
let device_memory = RwLock::new(DeviceMemory::new(ram.region_count(), allocator)).into();
let drm_allocator = if use_drm {
DrmBufferAllocator::open().ok()
} else {
None
};
Ok(MemoryManager {
kvm_vm, ram, device_memory,
drm_allocator,
})
}
pub fn guest_ram(&self) -> &GuestRam {
&self.ram
}
pub fn kvm_vm(&self) -> &KvmVm {
&self.kvm_vm
}
pub fn set_ram_regions(&mut self, regions: Vec<MemoryRegion>) {
let mut devmem = self.device_memory.write().unwrap();
devmem.set_slots_occupied(0, regions.len());
self.ram.set_regions(regions);
}
pub fn register_device_memory(&self, fd: RawFd, size: usize) -> Result<(u64, u32)> {
let mut devmem = self.device_memory.write().unwrap();
devmem.register(self.kvm_vm(), fd, size)
}
pub fn unregister_device_memory(&self, slot: u32) -> Result<()> {
let mut devmem = self.device_memory.write().unwrap();
devmem.unregister(self.kvm_vm(), slot)
}
pub fn drm_available(&self) -> bool {
self.drm_allocator.is_some()
}
pub fn allocate_drm_buffer(&self, width: u32, height: u32, format: u32) -> Result<(u64, u32, FileDesc, DrmDescriptor)> {
if let Some(drm_allocator) = self.drm_allocator.as_ref() {
let (fd, desc) = drm_allocator.allocate(width, height, format)?;
let size = fd.seek(SeekFrom::End(0)).map_err(Error::CreateBuffer)?;
let (pfn, slot) = self.register_device_memory(fd.as_raw_fd(), size as usize)?;
Ok((pfn, slot, fd, desc))
} else {
Err(Error::NoDrmAllocator)
}
}
}
pub struct MemoryRegistration {
guest_addr: u64,
_mapping: Mapping,
}
impl MemoryRegistration {
fn new(guest_addr: u64, mapping: Mapping)-> Self {
MemoryRegistration { guest_addr, _mapping: mapping }
}
}
struct DeviceMemory {
slots: BitSet,
mappings: HashMap<u32, MemoryRegistration>,
allocator: SystemAllocator,
}
impl DeviceMemory {
fn new(ram_region_count: usize, allocator: SystemAllocator) -> DeviceMemory {
let mut devmem = DeviceMemory {
slots: BitSet::new(),
mappings: HashMap::new(),
allocator
};
devmem.set_slots_occupied(0, ram_region_count);
devmem
}
fn set_slots_occupied(&mut self, first: usize, count: usize) {
for i in first..first+count {
self.slots.insert(i)
}
}
fn register(&mut self, kvm_vm: &KvmVm, fd: RawFd, size: usize) -> Result<(u64, u32)> {
let mapping = Mapping::new_from_fd(fd, size)
.map_err(Error::MappingFailed)?;
let (addr, slot) = self.allocate_addr_and_slot(size)?;
if let Err(e) = kvm_vm.add_memory_region(slot, addr, mapping.address(), size) {
self.free_addr_and_slot(addr, slot);
Err(Error::RegisterMemoryFailed(e))
} else {
self.mappings.insert(slot, MemoryRegistration::new(addr, mapping));
Ok((addr >> 12, slot))
}
}
fn unregister(&mut self, kvm_vm: &KvmVm, slot: u32) -> Result<()> {
if let Some(registration) = self.mappings.remove(&slot) {
kvm_vm.remove_memory_region(slot)
.map_err(Error::UnregisterMemoryFailed)?;
self.free_addr_and_slot(registration.guest_addr, slot);
}
Ok(())
}
fn allocate_addr_and_slot(&mut self, size: usize) -> Result<(u64, u32)> {
let addr = self.allocator.allocate_device_memory(size)
.ok_or(Error::DeviceMemoryAllocFailed)?;
Ok((addr, self.allocate_slot()))
}
fn free_addr_and_slot(&mut self, addr: u64, slot: u32) {
self.allocator.free_device_memory(addr);
self.free_slot(slot);
}
fn allocate_slot(&mut self) -> u32 {
for i in 0.. {
if !self.slots.get(i) {
self.slots.insert(i);
return i as u32;
}
}
unreachable!()
}
fn free_slot(&mut self, slot: u32) {
self.slots.remove(slot as usize)
}
}

View File

@ -1,172 +0,0 @@
use libc;
use std::ptr;
use std::slice;
use std::mem;
use std::io::Write;
use std::os::unix::io::RawFd;
use crate::system::{Result,Error};
pub struct Mapping {
ptr: *mut u8,
size: usize,
}
/// Marks types that can be passed to `write_int` and returned from `read_int`
pub unsafe trait Serializable: Copy+Send+Sync {}
unsafe impl Serializable for u8 {}
unsafe impl Serializable for u16 {}
unsafe impl Serializable for u32 {}
unsafe impl Serializable for u64 {}
unsafe impl Send for Mapping {}
unsafe impl Sync for Mapping {}
/// A block of memory returned from the mmap() system call. Provides safe access to the raw
/// memory region.
impl Mapping {
/// Creates a new anonymous mapping of `size` bytes.
///
/// # Errors
/// Returns [`Err`] if the `mmap()` system call fails and returns an `Error` representing
/// the system error which occurred.
///
pub fn new(size: usize) -> Result<Mapping> {
Mapping::_new(size,libc::MAP_ANONYMOUS | libc::MAP_SHARED | libc::MAP_NORESERVE, -1)
}
/// Creates a new mapping of `size` bytes from the object referenced by file descriptor `fd`
///
/// # Errors
/// Returns [`Err`] if the `mmap()` system call fails and returns an `Error` representing
/// the system error which occurred.
///
pub fn new_from_fd(fd: RawFd, size: usize) -> Result<Mapping> {
Mapping::_new(size, libc::MAP_SHARED, fd)
}
fn _new(size: usize, flags: libc::c_int, fd: RawFd) -> Result<Mapping> {
let p = unsafe { mmap_allocate(size, flags, fd)? };
Ok(Mapping {
ptr: p,
size
})
}
/// Ensure that `offset` is not larger than this allocation.
///
/// # Errors
///
/// Returns [`Err`] of kind `InvalidMappingOffset` if passed an
/// illegal `offset`
///
fn check_offset(&self, offset: usize) -> Result<()> {
if offset > self.size {
Err(Error::InvalidOffset)
} else {
Ok(())
}
}
/// Return the pointer address of this allocation.
pub fn address(&self) -> u64 {
self.ptr as u64
}
/// Read and return an integer value in native byte order from `offset` into the memory allocation
///
/// # Errors
/// Returns [`Err`] of kind `InvalidMappingOffset` if passed an
/// illegal `offset`
///
pub fn read_int<T: Serializable>(&self, offset: usize) -> Result<T> {
self.check_offset(offset + mem::size_of::<T>())?;
unsafe {
Ok(ptr::read_volatile(&self.as_slice()[offset..] as *const _ as *const T))
}
}
/// Write the integer `val` in native byte order at `offset` into the memory allocation
///
/// # Errors
/// Returns [`Err`] of kind `InvalidMappingOffset` if passed an
/// illegal `offset`
///
pub fn write_int<T: Serializable>(&self, offset: usize, val: T) -> Result<()> {
self.check_offset(offset + mem::size_of::<T>())?;
unsafe { ptr::write_volatile(&mut self.as_mut_slice()[offset..] as *mut _ as *mut T, val); }
Ok(())
}
pub fn write_bytes(&self, offset: usize, bytes: &[u8]) -> Result<()> {
self.check_offset(offset + bytes.len())?;
unsafe {
let mut slice: &mut [u8] = &mut self.as_mut_slice()[offset..];
slice.write_all(bytes).map_err(|_| Error::InvalidOffset)
}
}
pub fn read_bytes(&self, offset: usize, mut bytes: &mut [u8]) -> Result<()> {
self.check_offset(offset + bytes.len())?;
unsafe {
let slice: &[u8] = &self.as_slice()[offset..];
bytes.write(slice).unwrap();
Ok(())
}
}
pub fn slice(&self, offset: usize, size: usize) -> Result<&[u8]> {
self.check_offset(offset + size)?;
unsafe {
let x = &self.as_slice()[offset..offset+size];
Ok(x)
}
}
pub fn mut_slice(&self, offset: usize, size: usize) -> Result<&mut [u8]> {
self.check_offset(offset + size)?;
unsafe {
let x = &mut self.as_mut_slice()[offset..offset+size];
Ok(x)
}
}
#[allow(dead_code)]
pub fn set_mergeable(&self) -> Result<()> {
unsafe {
if libc::madvise(self.ptr as *mut libc::c_void, self.size, libc::MADV_MERGEABLE) == -1 {
return Err(Error::last_os_error());
}
}
Ok(())
}
unsafe fn as_slice(&self) -> &[u8] {
slice::from_raw_parts(self.ptr, self.size)
}
unsafe fn as_mut_slice(&self) -> &mut [u8] {
slice::from_raw_parts_mut(self.ptr, self.size)
}
}
impl Drop for Mapping {
fn drop(&mut self) {
unsafe {
libc::munmap(self.ptr as *mut libc::c_void, self.size);
}
}
}
unsafe fn mmap_allocate(size: usize, flags: libc::c_int, fd: libc::c_int) -> Result<*mut u8> {
let p = libc::mmap(ptr::null_mut(),
size, libc::PROT_READ|libc::PROT_WRITE,
flags, fd, 0);
if p.is_null() || p == libc::MAP_FAILED {
return Err(Error::last_os_error());
}
Ok(p as *mut u8)
}

View File

@ -1,47 +0,0 @@
mod ram;
mod drm;
mod manager;
mod mmap;
mod address;
mod allocator;
pub use self::allocator::SystemAllocator;
pub use self::address::AddressRange;
pub use self::mmap::Mapping;
pub use self::ram::{GuestRam,MemoryRegion};
pub use manager::MemoryManager;
pub use drm::{DrmDescriptor,DrmPlaneDescriptor};
use std::{result, io};
use crate::system;
use thiserror::Error;
#[derive(Debug,Error)]
pub enum Error {
#[error("failed to allocate memory for device")]
DeviceMemoryAllocFailed,
#[error("failed to create memory mapping for device memory: {0}")]
MappingFailed(system::Error),
#[error("failed to register memory for device memory: {0}")]
RegisterMemoryFailed(kvm_ioctls::Error),
#[error("failed to unregister memory for device memory: {0}")]
UnregisterMemoryFailed(kvm_ioctls::Error),
#[error("failed to open device with libgbm: {0}")]
GbmCreateDevice(system::Error),
#[error("failed to allocate buffer with libgbm: {0}")]
GbmCreateBuffer(system::Error),
#[error("error opening render node: {0}")]
OpenRenderNode(io::Error),
#[error("exporting prime handle to fd failed: {0}")]
PrimeHandleToFD(system::ErrnoError),
#[error("failed to create buffer: {0}")]
CreateBuffer(io::Error),
#[error("no DRM allocator is available")]
NoDrmAllocator,
}
pub type Result<T> = result::Result<T, Error>;

View File

@ -1,145 +0,0 @@
use std::sync::Arc;
use std::mem;
use crate::memory::{Mapping,AddressRange};
use crate::memory::mmap::Serializable;
use crate::system::{Result, Error};
use crate::util::ByteBuffer;
#[derive(Clone)]
pub struct GuestRam {
ram_size: usize,
regions: Arc<Vec<MemoryRegion>>,
}
impl GuestRam {
pub fn new(ram_size: usize) -> GuestRam {
GuestRam {
ram_size,
regions: Vec::new().into(),
}
}
pub fn ram_size(&self) -> usize {
self.ram_size
}
pub fn region_count(&self) -> usize {
self.regions.len()
}
pub fn write_bytes(&self, guest_address: u64, bytes: &[u8]) -> Result<()> {
let region = self.find_region(guest_address, bytes.len())?;
region.write_bytes(guest_address, bytes)
}
pub fn read_bytes(&self, guest_address: u64, bytes: &mut [u8]) -> Result<()> {
let region = self.find_region(guest_address, bytes.len())?;
region.read_bytes(guest_address, bytes)
}
pub fn slice(&self, guest_address: u64, size: usize) -> Result<&[u8]> {
let region = self.find_region(guest_address, size)?;
region.slice(guest_address, size)
}
pub fn mut_buffer(&self, guest_address: u64, size: usize) -> Result<ByteBuffer<&mut [u8]>> {
let bytes = self.mut_slice(guest_address, size)?;
Ok(ByteBuffer::from_bytes_mut(bytes))
}
pub fn mut_slice(&self, guest_address: u64, size: usize) -> Result<&mut[u8]> {
let region = self.find_region(guest_address, size)?;
region.mut_slice(guest_address, size)
}
pub fn write_int<T: Serializable>(&self, guest_address: u64, val: T) -> Result<()> {
let region = self.find_region(guest_address, mem::size_of::<T>())?;
region.write_int(guest_address, val)
}
pub fn read_int<T: Serializable>(&self, guest_address: u64) -> Result<T> {
let region = self.find_region(guest_address, mem::size_of::<T>())?;
region.read_int(guest_address)
}
pub fn set_regions(&mut self, regions: Vec<MemoryRegion>) {
self.regions = regions.into();
}
#[allow(dead_code)]
pub fn end_addr(&self) -> u64 {
self.regions.iter()
.max_by_key(|r| r.guest_range.end())
.map_or(0, |r| r.guest_range.end())
}
pub fn is_valid_range(&self, guest_address: u64, size: usize) -> bool {
self.find_region(guest_address, size).is_ok()
}
fn find_region(&self, guest_address: u64, size: usize) -> Result<&MemoryRegion> {
self.regions.iter()
.find(|r| r.contains(guest_address, size))
.ok_or(Error::InvalidAddress(guest_address))
}
}
pub struct MemoryRegion {
guest_range: AddressRange,
mapping: Mapping,
}
impl MemoryRegion {
pub fn new(guest_base: u64, size: usize) -> Result<MemoryRegion> {
Ok(MemoryRegion{
guest_range: AddressRange::new(guest_base, size),
mapping: Mapping::new(size)?,
})
}
pub fn base_address(&self) -> u64 {
self.mapping.address()
}
fn contains(&self, guest_addr: u64, size: usize) -> bool { self.guest_range.contains(guest_addr, size) }
fn checked_offset(&self, guest_addr: u64, size: usize) -> Result<usize> {
if self.contains(guest_addr, size) {
Ok(self.guest_range.offset_of(guest_addr))
} else {
Err(Error::InvalidAddress(guest_addr))
}
}
pub fn write_bytes(&self, guest_address: u64, bytes: &[u8]) -> Result<()> {
let offset = self.checked_offset(guest_address, bytes.len())?;
self.mapping.write_bytes(offset, bytes)
}
pub fn read_bytes(&self, guest_address: u64, bytes: &mut [u8]) -> Result<()> {
let offset = self.checked_offset(guest_address, bytes.len())?;
self.mapping.read_bytes(offset, bytes)
}
pub fn slice(&self, guest_address: u64, size: usize) -> Result<&[u8]> {
let offset = self.checked_offset(guest_address, size)?;
self.mapping.slice(offset, size)
}
pub fn mut_slice(&self, guest_address: u64, size: usize) -> Result<&mut [u8]> {
let offset = self.checked_offset(guest_address, size)?;
self.mapping.mut_slice(offset, size)
}
pub fn write_int<T: Serializable>(&self, guest_address: u64, val: T) -> Result<()> {
let offset = self.checked_offset(guest_address, mem::size_of::<T>())?;
self.mapping.write_int(offset, val)
}
pub fn read_int<T: Serializable>(&self, guest_address: u64) -> Result<T> {
let offset = self.checked_offset(guest_address, mem::size_of::<T>())?;
self.mapping.read_int(offset)
}
}

View File

@ -1,19 +1,37 @@
use std::fs::{OpenOptions, File}; use std::fs::{OpenOptions, File};
use std::os::fd::FromRawFd;
use std::os::raw::{c_ulong, c_int, c_uint}; use std::os::raw::{c_ulong, c_int, c_uint};
use std::os::unix::io::{RawFd,AsRawFd}; use std::os::unix::io::{RawFd,AsRawFd};
use std::path::Path; use std::path::Path;
use std::{io, result};
use std::sync::Arc; use std::sync::Arc;
use crate::system::{self, ioctl::ioctl_with_mut_ref, FileDesc }; use crate::system::{self, ioctl::ioctl_with_mut_ref};
use crate::memory::{Error,Result};
#[derive(Default,Debug)] use thiserror::Error;
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug,Error)]
pub enum Error {
#[error("failed to open device with libgbm: {0}")]
GbmCreateDevice(system::Error),
#[error("failed to allocate buffer with libgbm: {0}")]
GbmCreateBuffer(system::Error),
#[error("error opening render node: {0}")]
OpenRenderNode(io::Error),
#[error("exporting prime handle to fd failed: {0}")]
PrimeHandleToFD(system::ErrnoError),
}
#[derive(Default,Debug,Copy,Clone)]
pub struct DrmPlaneDescriptor { pub struct DrmPlaneDescriptor {
pub stride: u32, pub stride: u32,
pub offset: u32, pub offset: u32,
} }
#[derive(Default,Debug)] #[derive(Default,Debug,Copy,Clone)]
pub struct DrmDescriptor { pub struct DrmDescriptor {
pub planes: [DrmPlaneDescriptor; 3] pub planes: [DrmPlaneDescriptor; 3]
} }
@ -32,7 +50,7 @@ impl DrmBufferAllocator {
}) })
} }
pub fn allocate(&self, width: u32, height: u32, format: u32) -> Result<(FileDesc, DrmDescriptor)> { pub fn allocate(&self, width: u32, height: u32, format: u32) -> Result<(File, DrmDescriptor)> {
const GBM_BO_USE_LINEAR: u32 = 16; const GBM_BO_USE_LINEAR: u32 = 16;
let buffer = self.create_buffer(width, height, format, GBM_BO_USE_LINEAR)?; let buffer = self.create_buffer(width, height, format, GBM_BO_USE_LINEAR)?;
@ -131,7 +149,7 @@ impl DrmBuffer {
unsafe { gbm_bo_get_stride_for_plane(self.bo, plane) } unsafe { gbm_bo_get_stride_for_plane(self.bo, plane) }
} }
fn buffer_fd(&self) -> Result<FileDesc> { fn buffer_fd(&self) -> Result<File> {
const DRM_CLOEXEC: u32 = libc::O_CLOEXEC as u32; const DRM_CLOEXEC: u32 = libc::O_CLOEXEC as u32;
const DRM_RDWR: u32 = libc::O_RDWR as u32; const DRM_RDWR: u32 = libc::O_RDWR as u32;
let mut prime = DrmPrimeHandle { let mut prime = DrmPrimeHandle {
@ -143,8 +161,8 @@ impl DrmBuffer {
unsafe { unsafe {
ioctl_with_mut_ref(self.dev.as_raw_fd(), DRM_IOCTL_PRIME_HANDLE_TO_FD, &mut prime) ioctl_with_mut_ref(self.dev.as_raw_fd(), DRM_IOCTL_PRIME_HANDLE_TO_FD, &mut prime)
.map_err(Error::PrimeHandleToFD)?; .map_err(Error::PrimeHandleToFD)?;
Ok(File::from_raw_fd(prime.fd))
} }
Ok(FileDesc::new(prime.fd))
} }
} }

View File

@ -1,143 +0,0 @@
use std::os::unix::io::{IntoRawFd,AsRawFd,RawFd};
use std::{mem, io};
use crate::system::errno::cvt;
use std::os::raw::c_void;
use libc::c_int;
use std::io::SeekFrom;
#[derive(Debug)]
pub struct FileDesc {
fd: RawFd,
}
#[derive(Copy,Clone,Debug,Eq,PartialEq)]
pub enum FileFlags {
Read,
Write,
ReadWrite,
}
#[allow(dead_code)]
impl FileDesc {
pub fn new(fd: RawFd) -> Self {
FileDesc { fd }
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, buf.len())
})?;
Ok(ret as usize)
}
pub fn read_exact(&mut self, mut buf: &mut [u8]) -> io::Result<()> {
while !buf.is_empty() {
match self.read(buf) {
Ok(0) => break,
Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; }
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
if !buf.is_empty() {
Err(io::Error::new(io::ErrorKind::UnexpectedEof,
"failed to fill whole buffer"))
} else {
Ok(())
}
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
unsafe {
let v = nonblocking as c_int;
cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?;
Ok(())
}
}
pub fn set_cloexec(&self) -> io::Result<()> {
unsafe {
cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
Ok(())
}
}
pub fn flags(&self) -> io::Result<FileFlags> {
let flags = unsafe { cvt(libc::fcntl(self.fd, libc::F_GETFL))? };
match flags & libc::O_ACCMODE {
libc::O_RDONLY => Ok(FileFlags::Read),
libc::O_WRONLY => Ok(FileFlags::Write),
libc::O_RDWR => Ok(FileFlags::ReadWrite),
_ => Err(io::Error::from_raw_os_error(libc::EINVAL)),
}
}
pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
let (whence, pos) = match pos {
// Casting to `i64` is fine, too large values will end up as
// negative which will cause an error in `lseek64`.
SeekFrom::Start(off) => (libc::SEEK_SET, off as i64),
SeekFrom::End(off) => (libc::SEEK_END, off),
SeekFrom::Current(off) => (libc::SEEK_CUR, off),
};
let n = cvt(unsafe { libc::lseek64(self.fd, pos, whence) })?;
Ok(n as u64)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
libc::write(self.fd,
buf.as_ptr() as *const c_void,
buf.len())
})?;
Ok(ret as usize)
}
pub fn write_all(&self, buf: &[u8]) -> io::Result<()> {
let mut buf = buf;
while !buf.is_empty() {
match self.write(buf) {
Ok(0) => return Err(io::Error::new(io::ErrorKind::WriteZero,
"failed to write whole buffer")),
Ok(n) => {
buf = &buf[n..];
}
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
Ok(())
}
pub fn set_size(&self, size: usize) -> io::Result<()> {
unsafe {
if libc::ftruncate64(self.fd, size as libc::off64_t) < 0 {
Err(io::Error::last_os_error())
} else {
Ok(())
}
}
}
pub fn flush(&self) -> io::Result<()> {
Ok(())
}
}
impl Drop for FileDesc {
fn drop(&mut self) {
let _ = unsafe { libc::close(self.fd) };
}
}
impl AsRawFd for FileDesc {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
impl IntoRawFd for FileDesc {
fn into_raw_fd(self) -> RawFd {
let fd = self.fd;
mem::forget(self);
fd
}
}

View File

@ -1,76 +0,0 @@
use std::ffi::CString;
use std::io::SeekFrom;
use std::os::unix::io::{RawFd,AsRawFd};
use crate::system::{Error,Result, FileDesc};
use libc::{
self, c_char, c_uint, c_int, c_long,SYS_memfd_create,
MFD_CLOEXEC, MFD_ALLOW_SEALING, F_SEAL_GROW,F_SEAL_SHRINK, F_SEAL_SEAL
};
#[derive(Debug)]
pub struct MemoryFd {
fd: FileDesc,
size: usize,
}
impl MemoryFd {
pub fn from_filedesc(fd: FileDesc) -> Result<MemoryFd> {
let size = fd.seek(SeekFrom::End(0))? as usize;
Ok(MemoryFd { fd, size })
}
pub fn new_memfd(size: usize, sealed: bool) -> Result<MemoryFd> {
Self::new_memfd_with_name(size, sealed, "pH-memfd")
}
pub fn new_memfd_with_name(size: usize, sealed: bool, name: &str) -> Result<MemoryFd> {
let fd = Self::memfd_create(name, MFD_CLOEXEC | MFD_ALLOW_SEALING)?;
fd.set_size(size)?;
let memfd = MemoryFd { fd, size };
if sealed {
memfd.add_seals(F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL)?;
}
Ok(memfd)
}
pub fn size(&self) -> usize {
self.size
}
pub fn fd_mut(&mut self) -> &mut FileDesc {
&mut self.fd
}
fn memfd_create(name: &str, flags: c_uint) -> Result<FileDesc> {
let name = CString::new(name).expect("Cstring from &str");
let name = name.as_ptr() as *const c_char;
let fd = unsafe { libc::syscall(SYS_memfd_create as c_long, name, flags) } as c_int;
if fd < 0 {
Err(Error::last_os_error())
} else {
Ok(FileDesc::new(fd))
}
}
fn add_seals(&self, flags: c_int) -> Result<()> {
let ret = unsafe { libc::fcntl(self.fd.as_raw_fd(), libc::F_ADD_SEALS, flags) };
if ret < 0 {
Err(Error::last_os_error())
} else {
Ok(())
}
}
}
impl AsRawFd for MemoryFd {
fn as_raw_fd(&self) -> RawFd {
self.fd.as_raw_fd()
}
}

View File

@ -1,15 +1,11 @@
#[macro_use]pub mod ioctl; #[macro_use]pub mod ioctl;
mod epoll; mod epoll;
mod errno; pub mod errno;
mod socket; mod socket;
mod filedesc;
mod memfd;
mod tap; mod tap;
//pub mod priority;
pub mod netlink; pub mod netlink;
pub mod drm;
pub use filedesc::{FileDesc, FileFlags};
pub use memfd::MemoryFd;
pub use epoll::{EPoll,Event}; pub use epoll::{EPoll,Event};
pub use socket::ScmSocket; pub use socket::ScmSocket;
pub use netlink::NetlinkSocket; pub use netlink::NetlinkSocket;
@ -19,6 +15,8 @@ use std::{result, io};
pub use errno::Error as ErrnoError; pub use errno::Error as ErrnoError;
use thiserror::Error; use thiserror::Error;
use vm_memory::guest_memory;
use vm_memory::mmap::MmapRegionError;
pub type Result<T> = result::Result<T, Error>; pub type Result<T> = result::Result<T, Error>;
@ -38,6 +36,12 @@ pub enum Error {
EventFdWrite, EventFdWrite,
#[error("failed reading from eventfd")] #[error("failed reading from eventfd")]
EventFdRead, EventFdRead,
#[error("guest memory error: {0}")]
GuestMemory(guest_memory::Error),
#[error("failed to allocate shared memory: {0}")]
ShmAllocFailed(memfd::Error),
#[error("failed to create mmap region: {0}")]
MmapRegionCreate(MmapRegionError)
} }
@ -70,6 +74,12 @@ impl Error {
} }
} }
impl From<guest_memory::Error> for Error {
fn from(err: guest_memory::Error) -> Error {
Error::GuestMemory(err)
}
}
impl From<errno::Error> for Error { impl From<errno::Error> for Error {
fn from(err: errno::Error) -> Error { fn from(err: errno::Error) -> Error {
Error::Errno(err) Error::Errno(err)

View File

@ -1,13 +1,14 @@
use crate::{system, memory}; use crate::system;
use crate::system::ErrnoError; use crate::system::ErrnoError;
use std::result; use std::result;
use kvm_ioctls::Cap; use kvm_ioctls::Cap;
use thiserror::Error; use thiserror::Error;
use vm_memory::guest_memory;
#[derive(Debug,Error)] #[derive(Debug,Error)]
pub enum Error { pub enum Error {
#[error("failed to create memory manager: {0}")] #[error("failed to create memory manager: {0}")]
MemoryManagerCreate(memory::Error), MemoryManagerCreate(vm_memory::Error),
#[error("failed to register memory region: {0}")] #[error("failed to register memory region: {0}")]
MemoryRegister(kvm_ioctls::Error), MemoryRegister(kvm_ioctls::Error),
#[error("failed to create memory region: {0}")] #[error("failed to create memory region: {0}")]
@ -24,6 +25,8 @@ pub enum Error {
IoctlError(&'static str, ErrnoError), IoctlError(&'static str, ErrnoError),
#[error("error setting up vm: {0}")] #[error("error setting up vm: {0}")]
SetupError(kvm_ioctls::Error), SetupError(kvm_ioctls::Error),
#[error("guest memory error: {0}")]
GuestMemory(guest_memory::Error),
} }
pub type Result<T> = result::Result<T, Error>; pub type Result<T> = result::Result<T, Error>;

View File

@ -1,7 +1,7 @@
use kvm_bindings::CpuId; use kvm_bindings::CpuId;
use kvm_ioctls::VcpuFd; use kvm_ioctls::VcpuFd;
use vm_memory::GuestMemoryMmap;
pub use crate::vm::arch::x86::X86ArchSetup; pub use crate::vm::arch::x86::X86ArchSetup;
use crate::memory::MemoryManager;
mod error; mod error;
mod x86; mod x86;
@ -20,7 +20,7 @@ pub fn create_setup(config: &VmConfig) -> X86ArchSetup {
} }
pub trait ArchSetup { pub trait ArchSetup {
fn create_memory(&mut self, kvm_vm: KvmVm) -> Result<MemoryManager>; fn create_memory(&mut self, kvm_vm: KvmVm) -> Result<GuestMemoryMmap>;
fn setup_memory(&mut self, cmdline: &KernelCmdLine, pci_irqs: &[PciIrq]) -> Result<()>; fn setup_memory(&mut self, cmdline: &KernelCmdLine, pci_irqs: &[PciIrq]) -> Result<()>;
fn setup_vcpu(&self, vcpu: &VcpuFd, cpuid: CpuId) -> Result<()>; fn setup_vcpu(&self, vcpu: &VcpuFd, cpuid: CpuId) -> Result<()>;
} }

View File

@ -1,6 +1,6 @@
use std::io; use std::io;
use vm_memory::{Bytes, GuestAddress, GuestMemoryMmap};
use crate::memory::GuestRam;
use crate::system; use crate::system;
use crate::util::ByteBuffer; use crate::util::ByteBuffer;
use crate::vm::arch::PCI_MMIO_RESERVED_BASE; use crate::vm::arch::PCI_MMIO_RESERVED_BASE;
@ -33,8 +33,8 @@ const KERNEL_MIN_ALIGNMENT_BYTES: u32 = 0x1000000;
const E820_RAM: u32 = 1; const E820_RAM: u32 = 1;
fn setup_e820(memory: &GuestRam, mut zero: ByteBuffer<&mut [u8]>) -> system::Result<()> { fn setup_e820(ram_size: usize, zero: &mut ByteBuffer<Vec<u8>>) -> system::Result<()> {
let ram_size = memory.ram_size() as u64; let ram_size = ram_size as u64;
let mut e820_ranges = Vec::new(); let mut e820_ranges = Vec::new();
e820_ranges.push((0u64, EBDA_START)); e820_ranges.push((0u64, EBDA_START));
@ -56,8 +56,8 @@ fn setup_e820(memory: &GuestRam, mut zero: ByteBuffer<&mut [u8]>) -> system::Res
Ok(()) Ok(())
} }
fn setup_zero_page(memory: &GuestRam, cmdline_addr: u64, cmdline_size: usize) -> system::Result<()> { fn setup_zero_page(ram_size: usize, memory: &GuestMemoryMmap, cmdline_addr: u64, cmdline_size: usize) -> system::Result<()> {
let mut zero = memory.mut_buffer(KERNEL_ZERO_PAGE, 4096)?; let mut zero = ByteBuffer::new(4096);
zero.write_at(HDR_BOOT_FLAG, KERNEL_BOOT_FLAG_MAGIC) zero.write_at(HDR_BOOT_FLAG, KERNEL_BOOT_FLAG_MAGIC)
.write_at(HDR_HEADER, KERNEL_HDR_MAGIC) .write_at(HDR_HEADER, KERNEL_HDR_MAGIC)
.write_at(HDR_TYPE_LOADER, KERNEL_LOADER_OTHER) .write_at(HDR_TYPE_LOADER, KERNEL_LOADER_OTHER)
@ -65,24 +65,27 @@ fn setup_zero_page(memory: &GuestRam, cmdline_addr: u64, cmdline_size: usize) ->
.write_at(HDR_CMDLINE_SIZE, cmdline_size as u32) .write_at(HDR_CMDLINE_SIZE, cmdline_size as u32)
.write_at(HDR_KERNEL_ALIGNMENT, KERNEL_MIN_ALIGNMENT_BYTES); .write_at(HDR_KERNEL_ALIGNMENT, KERNEL_MIN_ALIGNMENT_BYTES);
setup_e820(memory, zero) setup_e820(ram_size, &mut zero)?;
memory.write_slice(zero.as_ref(), GuestAddress(KERNEL_ZERO_PAGE))?;
Ok(())
} }
pub fn load_pm_kernel(memory: &GuestRam, cmdline_addr: u64, cmdline_size: usize) -> system::Result<()> { pub fn load_pm_kernel(ram_size: usize, memory: &GuestMemoryMmap, cmdline_addr: u64, cmdline_size: usize) -> system::Result<()> {
load_elf_kernel(memory)?; load_elf_kernel(memory)?;
setup_zero_page(memory, cmdline_addr, cmdline_size) setup_zero_page(ram_size, memory, cmdline_addr, cmdline_size)
} }
fn load_elf_segment(memory: &GuestRam, hdr: ElfPhdr) { fn load_elf_segment(memory: &GuestMemoryMmap, hdr: ElfPhdr) {
let addr = hdr.p_paddr + KVM_KERNEL_LOAD_ADDRESS; let addr = hdr.p_paddr + KVM_KERNEL_LOAD_ADDRESS;
let size = hdr.p_filesz as usize; let size = hdr.p_filesz as usize;
let off = hdr.p_offset as usize; let off = hdr.p_offset as usize;
let dst = memory.mut_slice(addr, size).unwrap();
let src = &KERNEL[off..off+size]; let src = &KERNEL[off..off+size];
dst.copy_from_slice(src); memory.write_slice(src, GuestAddress(addr)).unwrap();
} }
pub fn load_elf_kernel(memory: &GuestRam) -> io::Result<()> { pub fn load_elf_kernel(memory: &GuestMemoryMmap) -> io::Result<()> {
let mut k = ByteBuffer::from_bytes(KERNEL); let mut k = ByteBuffer::from_bytes(KERNEL);
let phoff = k.read_at::<u64>(32); let phoff = k.read_at::<u64>(32);
let phnum = k.read_at::<u16>(56); let phnum = k.read_at::<u16>(56);

View File

@ -1,12 +1,10 @@
use crate::memory::{MemoryManager, MemoryRegion, GuestRam};
use crate::vm::arch::{Error, Result}; use crate::vm::arch::{Error, Result};
use std::cmp; use vm_memory::{Bytes, GuestAddress, GuestMemoryMmap};
use crate::io::PciIrq; use crate::io::PciIrq;
use crate::vm::kernel_cmdline::KernelCmdLine; use crate::vm::kernel_cmdline::KernelCmdLine;
use crate::vm::arch::x86::kernel::{load_pm_kernel, KERNEL_CMDLINE_ADDRESS}; use crate::vm::arch::x86::kernel::{load_pm_kernel, KERNEL_CMDLINE_ADDRESS};
use crate::system; use crate::system;
use crate::vm::arch::x86::mptable::setup_mptable; use crate::vm::arch::x86::mptable::setup_mptable;
use crate::vm::KvmVm;
pub const HIMEM_BASE: u64 = 1 << 32; pub const HIMEM_BASE: u64 = 1 << 32;
pub const PCI_MMIO_RESERVED_SIZE: usize = 512 << 20; pub const PCI_MMIO_RESERVED_SIZE: usize = 512 << 20;
@ -14,28 +12,6 @@ pub const PCI_MMIO_RESERVED_BASE: u64 = HIMEM_BASE - PCI_MMIO_RESERVED_SIZE as u
pub const IRQ_BASE: u32 = 5; pub const IRQ_BASE: u32 = 5;
pub const IRQ_MAX: u32 = 23; pub const IRQ_MAX: u32 = 23;
pub fn x86_setup_memory_regions(memory: &mut MemoryManager, ram_size: usize) -> Result<()> {
let mut regions = Vec::new();
let lowmem_sz = cmp::min(ram_size, PCI_MMIO_RESERVED_BASE as usize);
regions.push(create_region(memory.kvm_vm(), 0, lowmem_sz, 0)?);
if lowmem_sz < ram_size {
let himem_sz = ram_size - lowmem_sz;
regions.push(create_region(memory.kvm_vm(), HIMEM_BASE, himem_sz, 1)?);
}
memory.set_ram_regions(regions);
Ok(())
}
fn create_region(kvm_vm: &KvmVm, base: u64, size: usize, slot: u32) -> Result<MemoryRegion> {
let mr = MemoryRegion::new(base, size)
.map_err(Error::MemoryRegionCreate)?;
kvm_vm.add_memory_region(slot, base, mr.base_address(), size)
.map_err(Error::MemoryRegister)?;
Ok(mr)
}
const BOOT_GDT_OFFSET: usize = 0x500; const BOOT_GDT_OFFSET: usize = 0x500;
const BOOT_IDT_OFFSET: usize = 0x520; const BOOT_IDT_OFFSET: usize = 0x520;
@ -43,29 +19,29 @@ const BOOT_PML4: u64 = 0x9000;
const BOOT_PDPTE: u64 = 0xA000; const BOOT_PDPTE: u64 = 0xA000;
const BOOT_PDE: u64 = 0xB000; const BOOT_PDE: u64 = 0xB000;
pub fn x86_setup_memory(memory: &mut MemoryManager, cmdline: &KernelCmdLine, ncpus: usize, pci_irqs: &[PciIrq]) -> Result<()> { pub fn x86_setup_memory(ram_size: usize, memory: &GuestMemoryMmap, cmdline: &KernelCmdLine, ncpus: usize, pci_irqs: &[PciIrq]) -> Result<()> {
load_pm_kernel(memory.guest_ram(), KERNEL_CMDLINE_ADDRESS, cmdline.size()) load_pm_kernel(ram_size, memory, KERNEL_CMDLINE_ADDRESS, cmdline.size())
.map_err(Error::LoadKernel)?; .map_err(Error::LoadKernel)?;
setup_gdt(memory.guest_ram())?; setup_gdt(memory)?;
setup_boot_pagetables(memory.guest_ram()).map_err(Error::SystemError)?; setup_boot_pagetables(memory).map_err(Error::SystemError)?;
setup_mptable(memory.guest_ram(), ncpus, pci_irqs).map_err(Error::SystemError)?; setup_mptable(memory, ncpus, pci_irqs).map_err(Error::SystemError)?;
write_cmdline(memory.guest_ram(), cmdline).map_err(Error::SystemError)?; write_cmdline(memory, cmdline).map_err(Error::SystemError)?;
Ok(()) Ok(())
} }
fn setup_boot_pagetables(memory: &GuestRam) -> system::Result<()> { fn setup_boot_pagetables(memory: &GuestMemoryMmap) -> system::Result<()> {
memory.write_int::<u64>(BOOT_PML4, BOOT_PDPTE | 0x3)?; memory.write_obj(BOOT_PDPTE | 0x3, GuestAddress(BOOT_PML4))?;
memory.write_int::<u64>(BOOT_PDPTE, BOOT_PDE | 0x3)?; memory.write_obj(BOOT_PDE | 0x3, GuestAddress(BOOT_PDPTE))?;
for i in 0..512_u64 { for i in 0..512_u64 {
let entry = (i << 21) | 0x83; let entry = (i << 21) | 0x83;
memory.write_int::<u64>(BOOT_PDE + (i * 8), entry)?; memory.write_obj(entry, GuestAddress(BOOT_PDE + (i * 8)))?;
} }
Ok(()) Ok(())
} }
fn write_gdt_table(table: &[u64], memory: &GuestRam) -> system::Result<()> { fn write_gdt_table(table: &[u64], memory: &GuestMemoryMmap) -> system::Result<()> {
for i in 0..table.len() { for i in 0..table.len() {
memory.write_int((BOOT_GDT_OFFSET + i * 8) as u64, table[i])?; memory.write_obj(table[i], GuestAddress((BOOT_GDT_OFFSET + i * 8) as u64))?;
} }
Ok(()) Ok(())
} }
@ -76,7 +52,7 @@ pub fn gdt_entry(flags: u16, base: u32, limit: u32) -> u64 {
(((base as u64) & 0x00ffffffu64) << 16) | ((limit as u64) & 0x0000ffffu64) (((base as u64) & 0x00ffffffu64) << 16) | ((limit as u64) & 0x0000ffffu64)
} }
pub fn setup_gdt(memory: &GuestRam) -> Result<()> { pub fn setup_gdt(memory: &GuestMemoryMmap) -> Result<()> {
let table = [ let table = [
gdt_entry(0,0,0), gdt_entry(0,0,0),
gdt_entry(0xa09b,0,0xfffff), gdt_entry(0xa09b,0,0xfffff),
@ -86,16 +62,16 @@ pub fn setup_gdt(memory: &GuestRam) -> Result<()> {
write_gdt_table(&table, memory) write_gdt_table(&table, memory)
.map_err(Error::SystemError)?; .map_err(Error::SystemError)?;
memory.write_int::<u64>(BOOT_IDT_OFFSET as u64, 0u64) memory.write_obj(0u64, GuestAddress(BOOT_IDT_OFFSET as u64))
.map_err(Error::SystemError)?; .map_err(Error::GuestMemory)?;
Ok(()) Ok(())
} }
fn write_cmdline(memory: &GuestRam, cmdline: &KernelCmdLine) -> system::Result<()> { fn write_cmdline(memory: &GuestMemoryMmap, cmdline: &KernelCmdLine) -> system::Result<()> {
let bytes = cmdline.as_bytes(); let bytes = cmdline.as_bytes();
let len = bytes.len() as u64; let len = bytes.len() as u64;
memory.write_bytes(KERNEL_CMDLINE_ADDRESS, bytes)?; memory.write_slice(bytes, GuestAddress(KERNEL_CMDLINE_ADDRESS))?;
memory.write_int(KERNEL_CMDLINE_ADDRESS + len, 0u8)?; memory.write_obj(0u8, GuestAddress(KERNEL_CMDLINE_ADDRESS + len))?;
Ok(()) Ok(())
} }

View File

@ -1,7 +1,7 @@
use std::iter; use std::iter;
use vm_memory::{Bytes, GuestAddress, GuestMemoryMmap};
use crate::io::PciIrq; use crate::io::PciIrq;
use crate::memory::GuestRam;
use crate::system::Result; use crate::system::Result;
use crate::util::ByteBuffer; use crate::util::ByteBuffer;
@ -201,7 +201,7 @@ fn align(sz: usize, n: usize) -> usize {
(sz + (n - 1)) & !(n - 1) (sz + (n - 1)) & !(n - 1)
} }
pub fn setup_mptable(memory: &GuestRam, ncpus: usize, pci_irqs: &[PciIrq]) -> Result<()> { pub fn setup_mptable(memory: &GuestMemoryMmap, ncpus: usize, pci_irqs: &[PciIrq]) -> Result<()> {
let ioapicid = (ncpus + 1) as u8; let ioapicid = (ncpus + 1) as u8;
let mut buffer = Buffer::new(); let mut buffer = Buffer::new();
let address = MPTABLE_START; let address = MPTABLE_START;
@ -217,5 +217,6 @@ pub fn setup_mptable(memory: &GuestRam, ncpus: usize, pci_irqs: &[PciIrq]) -> Re
.write_mpc_lintsrc(MP_IRQ_SRC_NMI, 1) .write_mpc_lintsrc(MP_IRQ_SRC_NMI, 1)
.write_mpc_table(MPF_INTEL_SIZE); .write_mpc_table(MPF_INTEL_SIZE);
memory.write_bytes(address, buffer.buffer.as_ref()) memory.write_slice(buffer.buffer.as_ref(), GuestAddress(address))?;
Ok(())
} }

View File

@ -1,11 +1,11 @@
use kvm_bindings::CpuId; use kvm_bindings::CpuId;
use kvm_ioctls::VcpuFd; use kvm_ioctls::VcpuFd;
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryMmap, GuestMemoryRegion};
use crate::io::PciIrq; use crate::io::PciIrq;
use crate::memory::{MemoryManager, GuestRam, SystemAllocator, AddressRange};
use crate::vm::VmConfig; use crate::vm::VmConfig;
use crate::vm::arch::{ArchSetup, Error, PCI_MMIO_RESERVED_BASE, Result}; use crate::vm::arch::{ArchSetup, Error, PCI_MMIO_RESERVED_BASE, Result};
use crate::vm::kernel_cmdline::KernelCmdLine; use crate::vm::kernel_cmdline::KernelCmdLine;
use crate::vm::arch::x86::memory::{x86_setup_memory_regions, x86_setup_memory, HIMEM_BASE}; use crate::vm::arch::x86::memory::{x86_setup_memory, HIMEM_BASE};
use crate::vm::arch::x86::cpuid::setup_cpuid; use crate::vm::arch::x86::cpuid::setup_cpuid;
use crate::vm::arch::x86::registers::{setup_pm_sregs, setup_pm_regs, setup_fpu, setup_msrs}; use crate::vm::arch::x86::registers::{setup_pm_sregs, setup_pm_regs, setup_fpu, setup_msrs};
use crate::vm::arch::x86::interrupts::setup_lapic; use crate::vm::arch::x86::interrupts::setup_lapic;
@ -14,65 +14,52 @@ use crate::vm::kvm_vm::KvmVm;
pub struct X86ArchSetup { pub struct X86ArchSetup {
ram_size: usize, ram_size: usize,
use_drm: bool,
ncpus: usize, ncpus: usize,
memory: Option<MemoryManager>, memory: Option<GuestMemoryMmap>,
} }
impl X86ArchSetup { impl X86ArchSetup {
pub fn create(config: &VmConfig) -> Self { pub fn create(config: &VmConfig) -> Self {
let ram_size = config.ram_size(); let ram_size = config.ram_size();
let use_drm = config.is_wayland_enabled() && config.is_dmabuf_enabled();
X86ArchSetup { X86ArchSetup {
ram_size, ram_size,
use_drm,
ncpus: config.ncpus(), ncpus: config.ncpus(),
memory: None, memory: None,
} }
} }
} }
fn arch_memory_regions(mem_size: usize) -> Vec<(u64, usize)> { fn x86_memory_ranges(mem_size: usize) -> Vec<(GuestAddress, usize)> {
match mem_size.checked_sub(PCI_MMIO_RESERVED_BASE as usize) { match mem_size.checked_sub(PCI_MMIO_RESERVED_BASE as usize) {
None | Some(0) => vec![(0, mem_size)], None | Some(0) => vec![(GuestAddress(0), mem_size)],
Some(remaining) => vec![ Some(remaining) => vec![
(0, PCI_MMIO_RESERVED_BASE as usize), (GuestAddress(0), PCI_MMIO_RESERVED_BASE as usize),
(HIMEM_BASE, remaining), (GuestAddress(HIMEM_BASE), remaining),
], ],
} }
} }
fn device_memory_start(regions: &[(u64, usize)]) -> u64 {
let top = regions.last().map(|&(base, size)| {
base + size as u64
}).unwrap();
// Put device memory at a 2MB boundary after physical memory or 4gb, whichever is greater.
const MB: u64 = 1 << 20;
const TWO_MB: u64 = 2 * MB;
const FOUR_GB: u64 = 4 * 1024 * MB;
let dev_base_round_2mb = (top + TWO_MB - 1) & !(TWO_MB - 1);
std::cmp::max(dev_base_round_2mb, FOUR_GB)
}
impl ArchSetup for X86ArchSetup { impl ArchSetup for X86ArchSetup {
fn create_memory(&mut self, kvm_vm: KvmVm) -> Result<MemoryManager> { fn create_memory(&mut self, kvm_vm: KvmVm) -> Result<GuestMemoryMmap> {
let ram = GuestRam::new(self.ram_size); let ranges = x86_memory_ranges(self.ram_size);
let regions = arch_memory_regions(self.ram_size); let guest_memory = GuestMemoryMmap::from_ranges(&ranges)
let dev_addr_start = device_memory_start(&regions);
let dev_addr_size = u64::MAX - dev_addr_start;
let allocator = SystemAllocator::new(AddressRange::new(dev_addr_start,dev_addr_size as usize));
let mut mm = MemoryManager::new(kvm_vm, ram, allocator, self.use_drm)
.map_err(Error::MemoryManagerCreate)?; .map_err(Error::MemoryManagerCreate)?;
x86_setup_memory_regions(&mut mm, self.ram_size)?;
self.memory = Some(mm.clone()); for (i, r) in guest_memory.iter().enumerate() {
Ok(mm) let slot = i as u32;
let guest_address = r.start_addr().raw_value();
let size = r.len() as usize;
let host_address = guest_memory.get_host_address(r.start_addr()).unwrap() as u64;
kvm_vm.add_memory_region(slot, guest_address, host_address, size).map_err(Error::MemoryRegister)?;
}
self.memory = Some(guest_memory.clone());
Ok(guest_memory)
} }
fn setup_memory(&mut self, cmdline: &KernelCmdLine, pci_irqs: &[PciIrq]) -> Result<()> { fn setup_memory(&mut self, cmdline: &KernelCmdLine, pci_irqs: &[PciIrq]) -> Result<()> {
let memory = self.memory.as_mut().expect("No memory created"); let memory = self.memory.as_mut().expect("No memory created");
x86_setup_memory(memory, cmdline, self.ncpus, pci_irqs)?; x86_setup_memory(self.ram_size, memory, cmdline, self.ncpus, pci_irqs)?;
Ok(()) Ok(())
} }

View File

@ -15,6 +15,6 @@ pub use setup::VmSetup;
pub use kvm_vm::KvmVm; pub use kvm_vm::KvmVm;
pub use self::error::{Result,Error}; pub use self::error::{Result,Error};
pub use arch::{ArchSetup,create_setup}; pub use arch::ArchSetup;

View File

@ -7,9 +7,9 @@ use std::{env, fs, thread};
use crate::system::{Tap, NetlinkSocket}; use crate::system::{Tap, NetlinkSocket};
use crate::disk::DiskImage; use crate::disk::DiskImage;
use std::sync::{Arc, Barrier, Mutex}; use std::sync::{Arc, Barrier, Mutex};
use crate::memory::MemoryManager;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use kvm_ioctls::VmFd; use kvm_ioctls::VmFd;
use vm_memory::GuestMemoryMmap;
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
use crate::devices::ac97::Ac97Dev; use crate::devices::ac97::Ac97Dev;
use crate::devices::serial::SerialPort; use crate::devices::serial::SerialPort;
@ -21,7 +21,7 @@ use crate::vm::vcpu::Vcpu;
pub struct Vm { pub struct Vm {
kvm_vm: KvmVm, kvm_vm: KvmVm,
vcpus: Vec<Vcpu>, vcpus: Vec<Vcpu>,
memory: MemoryManager, memory: GuestMemoryMmap,
io_manager: IoManager, io_manager: IoManager,
termios: Option<Termios>, termios: Option<Termios>,
} }
@ -36,7 +36,7 @@ impl Vm {
let memory = arch.create_memory(kvm_vm.clone()) let memory = arch.create_memory(kvm_vm.clone())
.map_err(Error::ArchError)?; .map_err(Error::ArchError)?;
let io_manager = IoManager::new(memory.clone()); let io_manager = IoManager::new(kvm_vm.clone(), memory.clone());
Ok(Vm { Ok(Vm {
kvm_vm, kvm_vm,
@ -75,6 +75,10 @@ impl Vm {
self.kvm_vm.vm_fd() self.kvm_vm.vm_fd()
} }
pub fn guest_memory(&self) -> &GuestMemoryMmap {
&self.memory
}
} }
pub struct VmSetup <T: ArchSetup> { pub struct VmSetup <T: ArchSetup> {
@ -111,7 +115,7 @@ impl <T: ArchSetup> VmSetup <T> {
if self.config.rootshell() { if self.config.rootshell() {
self.cmdline.push("phinit.rootshell"); self.cmdline.push("phinit.rootshell");
} }
if vm.memory.drm_available() && self.config.is_dmabuf_enabled() { if self.config.is_wayland_enabled() && self.config.is_dmabuf_enabled() {
self.cmdline.push("phinit.virtwl_dmabuf"); self.cmdline.push("phinit.virtwl_dmabuf");
} }
@ -134,9 +138,8 @@ impl <T: ArchSetup> VmSetup <T> {
env::set_var("HOME", "/home/citadel"); env::set_var("HOME", "/home/citadel");
env::set_var("XDG_RUNTIME_DIR", "/run/user/1000"); env::set_var("XDG_RUNTIME_DIR", "/run/user/1000");
let irq = vm.io_manager.allocator().allocate_irq(); let irq = vm.io_manager.allocator().allocate_irq();
let mem = vm.memory.guest_ram().clone();
// XXX expect() // XXX expect()
let ac97 = Ac97Dev::try_new(&vm.kvm_vm, irq, mem).expect("audio initialize error"); let ac97 = Ac97Dev::try_new(&vm.kvm_vm, irq, vm.guest_memory()).expect("audio initialize error");
vm.io_manager.add_pci_device(Arc::new(Mutex::new(ac97))); vm.io_manager.add_pci_device(Arc::new(Mutex::new(ac97)));
} }
@ -162,7 +165,8 @@ impl <T: ArchSetup> VmSetup <T> {
io_manager.add_virtio_device(VirtioRandom::new())?; io_manager.add_virtio_device(VirtioRandom::new())?;
if self.config.is_wayland_enabled() { if self.config.is_wayland_enabled() {
io_manager.add_virtio_device(VirtioWayland::new(self.config.is_dmabuf_enabled()))?; let dev_shm_manager = io_manager.dev_shm_manager().clone();
io_manager.add_virtio_device(VirtioWayland::new(self.config.is_dmabuf_enabled(), dev_shm_manager))?;
} }
let homedir = self.config.homedir(); let homedir = self.config.homedir();