Skip to content

Commit bc97921

Browse files
author
Jonathan Woollett-Light
committed
fix: Update Arm logging
For Arm specific code, adds additional `std::fmt::Debug` implementations, reduces dynamic dispatch and removes the `GICDevice` trait. Signed-off-by: Jonathan Woollett-Light <jcawl@amazon.co.uk>
1 parent 2b61dfb commit bc97921

File tree

13 files changed

+311
-201
lines changed

13 files changed

+311
-201
lines changed

src/logger/src/metrics.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,17 @@ impl RtcEvents for RTCDeviceMetrics {
894894
}
895895
}
896896

897+
#[cfg(target_arch = "aarch64")]
898+
impl RtcEvents for &'static RTCDeviceMetrics {
899+
fn invalid_read(&self) {
900+
RTCDeviceMetrics::invalid_read(self);
901+
}
902+
903+
fn invalid_write(&self) {
904+
RTCDeviceMetrics::invalid_write(self);
905+
}
906+
}
907+
897908
/// Metrics for the seccomp filtering.
898909
#[derive(Debug, Default, Serialize)]
899910
pub struct SeccompMetrics {

src/vmm/src/arch/aarch64/fdt.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ pub fn create_fdt<T: DeviceInfoForFDT + Clone + Debug, S: std::hash::BuildHasher
7171
vcpu_mpidr: Vec<u64>,
7272
cmdline: CString,
7373
device_info: &HashMap<(DeviceType, String), T, S>,
74-
gic_device: &dyn GICDevice,
74+
gic_device: &GICDevice,
7575
initrd: &Option<InitrdConfig>,
7676
) -> Result<Vec<u8>> {
7777
// Allocate stuff necessary for storing the blob.
@@ -257,7 +257,7 @@ fn create_chosen_node(
257257
Ok(())
258258
}
259259

260-
fn create_gic_node(fdt: &mut FdtWriter, gic_device: &dyn GICDevice) -> Result<()> {
260+
fn create_gic_node(fdt: &mut FdtWriter, gic_device: &GICDevice) -> Result<()> {
261261
let interrupt = fdt.begin_node("intc")?;
262262
fdt.property_string("compatible", gic_device.fdt_compatibility())?;
263263
fdt.property_null("interrupt-controller")?;
@@ -490,7 +490,7 @@ mod tests {
490490
vec![0],
491491
CString::new("console=tty0").unwrap(),
492492
&dev_info,
493-
gic.as_ref(),
493+
&gic,
494494
&None,
495495
)
496496
.is_ok())
@@ -516,7 +516,7 @@ mod tests {
516516
vec![0],
517517
CString::new("console=tty0").unwrap(),
518518
&HashMap::<(DeviceType, std::string::String), MMIODeviceInfo>::new(),
519-
gic.as_ref(),
519+
&gic,
520520
&None,
521521
)
522522
.unwrap();
@@ -579,7 +579,7 @@ mod tests {
579579
vec![0],
580580
CString::new("console=tty0").unwrap(),
581581
&HashMap::<(DeviceType, std::string::String), MMIODeviceInfo>::new(),
582-
gic.as_ref(),
582+
&gic,
583583
&Some(initrd),
584584
)
585585
.unwrap();

src/vmm/src/arch/aarch64/gic/gicv2/mod.rs

Lines changed: 91 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33

44
mod regs;
55

6-
use std::boxed::Box;
76
use std::result;
87

9-
use kvm_ioctls::DeviceFd;
8+
use kvm_ioctls::{DeviceFd, VmFd};
109

11-
use crate::arch::aarch64::gic::{Error, GICDevice, GicState};
10+
use crate::arch::aarch64::gic::{Error, GicState};
1211

1312
type Result<T> = result::Result<T, Error>;
1413

1514
/// Represent a GIC v2 device
15+
#[derive(Debug)]
1616
pub struct GICv2 {
1717
/// The file descriptor for the KVM device
1818
fd: DeviceFd,
@@ -54,33 +54,32 @@ impl GICv2 {
5454
}
5555
}
5656

57-
impl GICDevice for GICv2 {
58-
fn version() -> u32 {
59-
kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2
60-
}
57+
impl GICv2 {
58+
pub const VERSION: u32 = kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2;
6159

62-
fn device_fd(&self) -> &DeviceFd {
60+
pub fn device_fd(&self) -> &DeviceFd {
6361
&self.fd
6462
}
6563

66-
fn device_properties(&self) -> &[u64] {
64+
pub fn device_properties(&self) -> &[u64] {
6765
&self.properties
6866
}
6967

70-
fn vcpu_count(&self) -> u64 {
68+
pub fn vcpu_count(&self) -> u64 {
7169
self.vcpu_count
7270
}
7371

74-
fn fdt_compatibility(&self) -> &str {
72+
pub fn fdt_compatibility(&self) -> &str {
7573
"arm,gic-400"
7674
}
7775

78-
fn fdt_maint_irq(&self) -> u32 {
76+
pub fn fdt_maint_irq(&self) -> u32 {
7977
GICv2::ARCH_GIC_V2_MAINT_IRQ
8078
}
8179

82-
fn create_device(fd: DeviceFd, vcpu_count: u64) -> Box<dyn GICDevice> {
83-
Box::new(GICv2 {
80+
/// Create the GIC device object
81+
pub fn create_device(fd: DeviceFd, vcpu_count: u64) -> Self {
82+
GICv2 {
8483
fd,
8584
properties: [
8685
GICv2::get_dist_addr(),
@@ -89,18 +88,18 @@ impl GICDevice for GICv2 {
8988
GICv2::get_cpu_size(),
9089
],
9190
vcpu_count,
92-
})
91+
}
9392
}
9493

95-
fn save_device(&self, mpidrs: &[u64]) -> Result<GicState> {
94+
pub fn save_device(&self, mpidrs: &[u64]) -> Result<GicState> {
9695
regs::save_state(&self.fd, mpidrs)
9796
}
9897

99-
fn restore_device(&self, mpidrs: &[u64], state: &GicState) -> Result<()> {
98+
pub fn restore_device(&self, mpidrs: &[u64], state: &GicState) -> Result<()> {
10099
regs::restore_state(&self.fd, mpidrs, state)
101100
}
102101

103-
fn init_device_attributes(gic_device: &dyn GICDevice) -> Result<()> {
102+
pub fn init_device_attributes(gic_device: &Self) -> Result<()> {
104103
// Setting up the distributor attribute.
105104
// We are placing the GIC below 1GB so we need to substract the size of the distributor.
106105
Self::set_device_attribute(
@@ -122,4 +121,78 @@ impl GICDevice for GICv2 {
122121

123122
Ok(())
124123
}
124+
125+
/// Initialize a GIC device
126+
pub fn init_device(vm: &VmFd) -> Result<DeviceFd> {
127+
let mut gic_device = kvm_bindings::kvm_create_device {
128+
type_: Self::VERSION,
129+
fd: 0,
130+
flags: 0,
131+
};
132+
133+
vm.create_device(&mut gic_device).map_err(Error::CreateGIC)
134+
}
135+
136+
/// Method to initialize the GIC device
137+
pub fn create(vm: &VmFd, vcpu_count: u64) -> Result<Self> {
138+
let vgic_fd = Self::init_device(vm)?;
139+
140+
let device = Self::create_device(vgic_fd, vcpu_count);
141+
142+
Self::init_device_attributes(&device)?;
143+
144+
Self::finalize_device(&device)?;
145+
146+
Ok(device)
147+
}
148+
149+
/// Finalize the setup of a GIC device
150+
pub fn finalize_device(gic_device: &Self) -> Result<()> {
151+
// On arm there are 3 types of interrupts: SGI (0-15), PPI (16-31), SPI (32-1020).
152+
// SPIs are used to signal interrupts from various peripherals accessible across
153+
// the whole system so these are the ones that we increment when adding a new virtio device.
154+
// KVM_DEV_ARM_VGIC_GRP_NR_IRQS sets the highest SPI number. Consequently, we will have a
155+
// total of `super::layout::IRQ_MAX - 32` usable SPIs in our microVM.
156+
let nr_irqs: u32 = super::layout::IRQ_MAX;
157+
let nr_irqs_ptr = &nr_irqs as *const u32;
158+
Self::set_device_attribute(
159+
gic_device.device_fd(),
160+
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
161+
0,
162+
nr_irqs_ptr as u64,
163+
0,
164+
)?;
165+
166+
// Finalize the GIC.
167+
// See https://code.woboq.org/linux/linux/virt/kvm/arm/vgic/vgic-kvm-device.c.html#211.
168+
Self::set_device_attribute(
169+
gic_device.device_fd(),
170+
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
171+
u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
172+
0,
173+
0,
174+
)?;
175+
176+
Ok(())
177+
}
178+
179+
/// Set a GIC device attribute
180+
pub fn set_device_attribute(
181+
fd: &DeviceFd,
182+
group: u32,
183+
attr: u64,
184+
addr: u64,
185+
flags: u32,
186+
) -> Result<()> {
187+
let attr = kvm_bindings::kvm_device_attr {
188+
flags,
189+
group,
190+
attr,
191+
addr,
192+
};
193+
fd.set_device_attr(&attr)
194+
.map_err(|err| Error::DeviceAttribute(err, true, group))?;
195+
196+
Ok(())
197+
}
125198
}

src/vmm/src/arch/aarch64/gic/gicv3/mod.rs

Lines changed: 92 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33

44
mod regs;
55

6-
use std::boxed::Box;
76
use std::result;
87

9-
use kvm_ioctls::DeviceFd;
8+
use kvm_ioctls::{DeviceFd, VmFd};
109

11-
use crate::arch::aarch64::gic::{Error, GICDevice, GicState};
10+
use crate::arch::aarch64::gic::{Error, GicState};
1211

1312
type Result<T> = result::Result<T, Error>;
1413

15-
pub(crate) struct GICv3 {
14+
#[derive(Debug)]
15+
pub struct GICv3 {
1616
/// The file descriptor for the KVM device
1717
fd: DeviceFd,
1818

@@ -54,33 +54,32 @@ impl GICv3 {
5454
}
5555
}
5656

57-
impl GICDevice for GICv3 {
58-
fn version() -> u32 {
59-
kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3
60-
}
57+
impl GICv3 {
58+
pub const VERSION: u32 = kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3;
6159

62-
fn device_fd(&self) -> &DeviceFd {
60+
pub fn device_fd(&self) -> &DeviceFd {
6361
&self.fd
6462
}
6563

66-
fn device_properties(&self) -> &[u64] {
64+
pub fn device_properties(&self) -> &[u64] {
6765
&self.properties
6866
}
6967

70-
fn vcpu_count(&self) -> u64 {
68+
pub fn vcpu_count(&self) -> u64 {
7169
self.vcpu_count
7270
}
7371

74-
fn fdt_compatibility(&self) -> &str {
72+
pub fn fdt_compatibility(&self) -> &str {
7573
"arm,gic-v3"
7674
}
7775

78-
fn fdt_maint_irq(&self) -> u32 {
76+
pub fn fdt_maint_irq(&self) -> u32 {
7977
GICv3::ARCH_GIC_V3_MAINT_IRQ
8078
}
8179

82-
fn create_device(fd: DeviceFd, vcpu_count: u64) -> Box<dyn GICDevice> {
83-
Box::new(GICv3 {
80+
/// Create the GIC device object
81+
pub fn create_device(fd: DeviceFd, vcpu_count: u64) -> Self {
82+
GICv3 {
8483
fd,
8584
properties: [
8685
GICv3::get_dist_addr(),
@@ -89,18 +88,18 @@ impl GICDevice for GICv3 {
8988
GICv3::get_redists_size(vcpu_count),
9089
],
9190
vcpu_count,
92-
})
91+
}
9392
}
9493

95-
fn save_device(&self, mpidrs: &[u64]) -> Result<GicState> {
94+
pub fn save_device(&self, mpidrs: &[u64]) -> Result<GicState> {
9695
regs::save_state(&self.fd, mpidrs)
9796
}
9897

99-
fn restore_device(&self, mpidrs: &[u64], state: &GicState) -> Result<()> {
98+
pub fn restore_device(&self, mpidrs: &[u64], state: &GicState) -> Result<()> {
10099
regs::restore_state(&self.fd, mpidrs, state)
101100
}
102101

103-
fn init_device_attributes(gic_device: &dyn GICDevice) -> Result<()> {
102+
pub fn init_device_attributes(gic_device: &Self) -> Result<()> {
104103
// Setting up the distributor attribute.
105104
// We are placing the GIC below 1GB so we need to substract the size of the distributor.
106105
Self::set_device_attribute(
@@ -123,6 +122,80 @@ impl GICDevice for GICv3 {
123122

124123
Ok(())
125124
}
125+
126+
/// Initialize a GIC device
127+
pub fn init_device(vm: &VmFd) -> Result<DeviceFd> {
128+
let mut gic_device = kvm_bindings::kvm_create_device {
129+
type_: Self::VERSION,
130+
fd: 0,
131+
flags: 0,
132+
};
133+
134+
vm.create_device(&mut gic_device).map_err(Error::CreateGIC)
135+
}
136+
137+
/// Method to initialize the GIC device
138+
pub fn create(vm: &VmFd, vcpu_count: u64) -> Result<Self> {
139+
let vgic_fd = Self::init_device(vm)?;
140+
141+
let device = Self::create_device(vgic_fd, vcpu_count);
142+
143+
Self::init_device_attributes(&device)?;
144+
145+
Self::finalize_device(&device)?;
146+
147+
Ok(device)
148+
}
149+
150+
/// Finalize the setup of a GIC device
151+
pub fn finalize_device(gic_device: &Self) -> Result<()> {
152+
// On arm there are 3 types of interrupts: SGI (0-15), PPI (16-31), SPI (32-1020).
153+
// SPIs are used to signal interrupts from various peripherals accessible across
154+
// the whole system so these are the ones that we increment when adding a new virtio device.
155+
// KVM_DEV_ARM_VGIC_GRP_NR_IRQS sets the highest SPI number. Consequently, we will have a
156+
// total of `super::layout::IRQ_MAX - 32` usable SPIs in our microVM.
157+
let nr_irqs: u32 = super::layout::IRQ_MAX;
158+
let nr_irqs_ptr = &nr_irqs as *const u32;
159+
Self::set_device_attribute(
160+
gic_device.device_fd(),
161+
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
162+
0,
163+
nr_irqs_ptr as u64,
164+
0,
165+
)?;
166+
167+
// Finalize the GIC.
168+
// See https://code.woboq.org/linux/linux/virt/kvm/arm/vgic/vgic-kvm-device.c.html#211.
169+
Self::set_device_attribute(
170+
gic_device.device_fd(),
171+
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
172+
u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT),
173+
0,
174+
0,
175+
)?;
176+
177+
Ok(())
178+
}
179+
180+
/// Set a GIC device attribute
181+
pub fn set_device_attribute(
182+
fd: &DeviceFd,
183+
group: u32,
184+
attr: u64,
185+
addr: u64,
186+
flags: u32,
187+
) -> Result<()> {
188+
let attr = kvm_bindings::kvm_device_attr {
189+
flags,
190+
group,
191+
attr,
192+
addr,
193+
};
194+
fd.set_device_attr(&attr)
195+
.map_err(|err| Error::DeviceAttribute(err, true, group))?;
196+
197+
Ok(())
198+
}
126199
}
127200

128201
/// Function that flushes

0 commit comments

Comments
 (0)