-
Notifications
You must be signed in to change notification settings - Fork 1.9k
WIP: Refactor device managers, preparing for PCIe devices #5174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feature/pcie
Are you sure you want to change the base?
WIP: Refactor device managers, preparing for PCIe devices #5174
Conversation
503fa5d
to
a7ec377
Compare
903e15a
to
564c7c0
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## feature/pcie #5174 +/- ##
================================================
+ Coverage 82.93% 83.23% +0.29%
================================================
Files 251 253 +2
Lines 27073 27172 +99
================================================
+ Hits 22454 22617 +163
+ Misses 4619 4555 -64
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
f84229f
to
e6560c9
Compare
src/vmm/src/device_manager/mmio.rs
Outdated
match &self.serial { | ||
Some(device) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be an assert, as the serial is registered right before this call. Otherwise maybe just remove this function and to the addition inline in the attach_legacy_devices_aarch64
? (like we do for block devices)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
balloon.process_virtio_queues(); | ||
} | ||
let _: Result<(), MmioError> = self.for_each_virtio_device(|virtio_type, id, device| { | ||
let mmio_transport_locked = device.inner.lock().expect("Poisoned locked"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/locked/lock/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mmio_transport_locked
now is essentially a reference to the actual MMIO transport (after being locked). So... semantics.
impl MmioTransport { | ||
pub fn bus_read(&mut self, offset: u64, data: &mut [u8]) { | ||
impl vm_device::BusDevice for MmioTransport { | ||
fn read(&mut self, base: u64, offset: u64, data: &mut [u8]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that the base
arg is never used, so maybe it is worth removing it from a trait definition?
And same question about Option<Arc<Barrier>>
return type in write
function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These come from the external crate. So I assume they are used somewhere even if we don't use them today in Firecracker.
src/vmm/src/builder.rs
Outdated
let i8042 = Arc::new(Mutex::new(I8042Device::new( | ||
reset_evt, | ||
EventFd::new(libc::EFD_NONBLOCK).map_err(VmmError::EventFd)?, | ||
))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: the I8042Device::new
can be simplified by moving EventFd
creation inside and asserting on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
although, I didn't assert. I'm still returning an Error. This code is in the InstanceStart API call path.
src/vm-device/Cargo.toml
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are the gaps between the rust-vmm vm-devices
create and this one? Is there any possibility of upstreaming these changes to the crate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They have diverged significantly, but I think nobody is actually using the rust-vmm one, so in theory we should be able to upstream the CH one.
src/vmm/src/builder.rs
Outdated
}))); | ||
let serial = Arc::new(Mutex::new(BusDevice::Serial( | ||
SerialDevice::new(Some(std::io::stdin()), SerialOut::Stdout(std::io::stdout())) | ||
.map_err(VmmError::EventFd)?, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can this fail only due to EventFd
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, it essentially fails only when we can't create the EventFd
.
src/vmm/src/arch/aarch64/fdt.rs
Outdated
device_info: &HashMap<(DeviceType, String), MMIODeviceInfo>, | ||
virtio_devices: Vec<&MMIODeviceInfo>, | ||
rtc: Option<&MMIODeviceInfo>, | ||
serial: Option<&MMIODeviceInfo>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can this be simplified by passing the DeviceManager
as we do in ACPI?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to do that, but that breaks hopelessly unit tests. It's gonna be a mess fixing it.
src/vmm/src/builder.rs
Outdated
@@ -615,7 +615,11 @@ fn attach_legacy_devices_aarch64( | |||
if cmdline_contains_console { | |||
// Make stdout non-blocking. | |||
set_stdout_nonblocking(); | |||
let serial = setup_serial_device(event_manager)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't follow why we're inlining the function here for arm but not for x86. Also, this could be moved to the earlier commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this commit, the setup_serial_device
still returns the old BusDevice
thingy. The serial device on ARM is a MMIO device so it is not part of BusDevice
any more, because it's an MMIO device, so it temporarily diverge. We revert to unifying them again when IO devices become vm_device::Bus
as well.
#[cfg(target_arch = "x86_64")] | ||
pub(crate) dsdt_data: Vec<u8>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason to leave this in in ARM?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cfg
just moved above the comment.
let _: Result<(), MmioError> = self.for_each_virtio_device(|virtio_type, id, device| { | ||
let mmio_transport_locked = device.inner.lock().expect("Poisoned locked"); | ||
let mut virtio = mmio_transport_locked.locked_device(); | ||
match *virtio_type { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unrelated to the scope of this PR, but I'm wondering if the "kick" can become a trait function that we call on every device, rather than having this combination of downcast and device-specific logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup, that's not such a bad idea.
src/vmm/src/device_manager/mmio.rs
Outdated
self.bus | ||
.insert(device.clone(), device_info.addr, device_info.len)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does the "register" function no longer actually register the device with the bus?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, good catch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
src/vmm/src/device_manager/mod.rs
Outdated
let boot_timer = Arc::new(Mutex::new(BootTimer::new(request_ts))); | ||
|
||
self.mmio_devices | ||
.register_mmio_boot_timer(&mut self.resource_allocator, boot_timer)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this not get registered with the Bus?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
Ok(serial) | ||
} | ||
|
||
#[cfg_attr(target_arch = "aarch64", allow(unused))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: why allow(unused)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
event_manager
and vcpu_exit_evt
are only used by the Port IO initialization code.
c6e5fcd
to
0a85b66
Compare
Bring in the vm-device crate from CloudHypervisor. We will be using it for adding PCIe support. Signed-off-by: Babis Chalios <[email protected]>
We use `SerialDevice` with Stdin as the input source. Encode this in the type so that we don't spill the generic all over the place. Signed-off-by: Babis Chalios <[email protected]> Co-authored-by: Egor Lazarchuk <[email protected]> Signed-off-by: Egor Lazarchuk <[email protected]> Signed-off-by: Babis Chalios <[email protected]>
Use the vm_device::Bus bus for all MMIO devices. This mainly to prepare for using it for PCIe devices. Also, sepate VirtIO devices from other MMIO devices inside the MMIODeviceManager struct. This makes iterating over VirtIO devices since we don't need to access two data structures as to get a reference to a VirtIO device any more. Signed-off-by: Babis Chalios <[email protected]>
We were always constructing RTCDevice using a set of metrics that were defined in the RTC module itself. Don't leak the metrics to other modules. Instead, create a new() function that always constructs it the correct way. Signed-off-by: Babis Chalios <[email protected]>
Use the vm_device::Bus bus for PortIO devices on x86. PCIe devices will use this as well. Signed-off-by: Babis Chalios <[email protected]>
PCIe spec mandates that software can access the configuration space of PCIe devices both via MMIO and Port IO accesses. As a result, PCIe devices will need to register to both buses (on x86). Change the organization of devices, so that MMIO and PIO device managers do not own the buses. Instead, introduce a DeviceManager object which holds the buses, the resource allocator and includes also all types of device managers (at the moment MMIO, PIO and ACPI). Signed-off-by: Babis Chalios <[email protected]>
We always create anew the keyboard interrupt event. Just create it inside `I8042Device::new()` and return an error if that fails. Signed-off-by: Babis Chalios <[email protected]>
To see if we the memory increase increases. Signed-off-by: Babis Chalios <[email protected]>
Changes
Group all device managers in a single top-level device manager, which now becomes the owner of the MMIO and Port IO buses along with the resource allocator. Also, it gets rid of the our
Bus
implementation in favour of thevm-device
one from Cloud Hypervisor.Reason
PCIe devices also need to be registered to the MMIO and Port IO buses. So, it makes more sense to keep the buses outside of MMIO and PortIO device managers.
Regarding switching to using
vm_devices::Bus
, PCIe implementation is using it and it was quite simpler to switch our own implementation to the upstream type rather than the other way around.License Acceptance
By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache 2.0 license. For more information on following Developer
Certificate of Origin and signing off your commits, please check
CONTRIBUTING.md
.PR Checklist
tools/devtool checkstyle
to verify that the PR passes theautomated style checks.
how they are solving the problem in a clear and encompassing way.
in the PR.
CHANGELOG.md
.Runbook for Firecracker API changes.
integration tests.
TODO
.rust-vmm
.