3
3
4
4
mod regs;
5
5
6
- use std:: boxed:: Box ;
7
6
use std:: result;
8
7
9
- use kvm_ioctls:: DeviceFd ;
8
+ use kvm_ioctls:: { DeviceFd , VmFd } ;
10
9
11
- use crate :: arch:: aarch64:: gic:: { Error , GICDevice , GicState } ;
10
+ use crate :: arch:: aarch64:: gic:: { Error , GicState } ;
12
11
13
12
type Result < T > = result:: Result < T , Error > ;
14
13
15
14
/// Represent a GIC v2 device
16
- pub struct GICv2 {
17
- /// The file descriptor for the KVM device
18
- fd : DeviceFd ,
15
+ #[ derive( Debug ) ]
16
+ pub struct GICv2 ( super :: GIC ) ;
19
17
20
- /// GIC device properties, to be used for setting up the fdt entry
21
- properties : [ u64 ; 4 ] ,
18
+ impl std :: ops :: Deref for GICv2 {
19
+ type Target = super :: GIC ;
22
20
23
- /// Number of CPUs handled by the device
24
- vcpu_count : u64 ,
21
+ fn deref ( & self ) -> & Self :: Target {
22
+ & self . 0
23
+ }
25
24
}
26
25
27
26
impl GICv2 {
@@ -52,35 +51,20 @@ impl GICv2 {
52
51
const fn get_cpu_size ( ) -> u64 {
53
52
GICv2 :: KVM_VGIC_V2_CPU_SIZE
54
53
}
55
- }
56
-
57
- impl GICDevice for GICv2 {
58
- fn version ( ) -> u32 {
59
- kvm_bindings:: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2
60
- }
61
-
62
- fn device_fd ( & self ) -> & DeviceFd {
63
- & self . fd
64
- }
65
54
66
- fn device_properties ( & self ) -> & [ u64 ] {
67
- & self . properties
68
- }
55
+ pub const VERSION : u32 = kvm_bindings:: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2;
69
56
70
- fn vcpu_count ( & self ) -> u64 {
71
- self . vcpu_count
72
- }
73
-
74
- fn fdt_compatibility ( & self ) -> & str {
57
+ pub fn fdt_compatibility ( & self ) -> & str {
75
58
"arm,gic-400"
76
59
}
77
60
78
- fn fdt_maint_irq ( & self ) -> u32 {
61
+ pub fn fdt_maint_irq ( & self ) -> u32 {
79
62
GICv2 :: ARCH_GIC_V2_MAINT_IRQ
80
63
}
81
64
82
- fn create_device ( fd : DeviceFd , vcpu_count : u64 ) -> Box < dyn GICDevice > {
83
- Box :: new ( GICv2 {
65
+ /// Create the GIC device object
66
+ pub fn create_device ( fd : DeviceFd , vcpu_count : u64 ) -> Self {
67
+ GICv2 ( super :: GIC {
84
68
fd,
85
69
properties : [
86
70
GICv2 :: get_dist_addr ( ) ,
@@ -92,15 +76,15 @@ impl GICDevice for GICv2 {
92
76
} )
93
77
}
94
78
95
- fn save_device ( & self , mpidrs : & [ u64 ] ) -> Result < GicState > {
79
+ pub fn save_device ( & self , mpidrs : & [ u64 ] ) -> Result < GicState > {
96
80
regs:: save_state ( & self . fd , mpidrs)
97
81
}
98
82
99
- fn restore_device ( & self , mpidrs : & [ u64 ] , state : & GicState ) -> Result < ( ) > {
83
+ pub fn restore_device ( & self , mpidrs : & [ u64 ] , state : & GicState ) -> Result < ( ) > {
100
84
regs:: restore_state ( & self . fd , mpidrs, state)
101
85
}
102
86
103
- fn init_device_attributes ( gic_device : & dyn GICDevice ) -> Result < ( ) > {
87
+ pub fn init_device_attributes ( gic_device : & Self ) -> Result < ( ) > {
104
88
// Setting up the distributor attribute.
105
89
// We are placing the GIC below 1GB so we need to substract the size of the distributor.
106
90
Self :: set_device_attribute (
@@ -122,4 +106,78 @@ impl GICDevice for GICv2 {
122
106
123
107
Ok ( ( ) )
124
108
}
109
+
110
+ /// Initialize a GIC device
111
+ pub fn init_device ( vm : & VmFd ) -> Result < DeviceFd > {
112
+ let mut gic_device = kvm_bindings:: kvm_create_device {
113
+ type_ : Self :: VERSION ,
114
+ fd : 0 ,
115
+ flags : 0 ,
116
+ } ;
117
+
118
+ vm. create_device ( & mut gic_device) . map_err ( Error :: CreateGIC )
119
+ }
120
+
121
+ /// Method to initialize the GIC device
122
+ pub fn create ( vm : & VmFd , vcpu_count : u64 ) -> Result < Self > {
123
+ let vgic_fd = Self :: init_device ( vm) ?;
124
+
125
+ let device = Self :: create_device ( vgic_fd, vcpu_count) ;
126
+
127
+ Self :: init_device_attributes ( & device) ?;
128
+
129
+ Self :: finalize_device ( & device) ?;
130
+
131
+ Ok ( device)
132
+ }
133
+
134
+ /// Finalize the setup of a GIC device
135
+ pub fn finalize_device ( gic_device : & Self ) -> Result < ( ) > {
136
+ // On arm there are 3 types of interrupts: SGI (0-15), PPI (16-31), SPI (32-1020).
137
+ // SPIs are used to signal interrupts from various peripherals accessible across
138
+ // the whole system so these are the ones that we increment when adding a new virtio device.
139
+ // KVM_DEV_ARM_VGIC_GRP_NR_IRQS sets the highest SPI number. Consequently, we will have a
140
+ // total of `super::layout::IRQ_MAX - 32` usable SPIs in our microVM.
141
+ let nr_irqs: u32 = super :: layout:: IRQ_MAX ;
142
+ let nr_irqs_ptr = & nr_irqs as * const u32 ;
143
+ Self :: set_device_attribute (
144
+ gic_device. device_fd ( ) ,
145
+ kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_NR_IRQS ,
146
+ 0 ,
147
+ nr_irqs_ptr as u64 ,
148
+ 0 ,
149
+ ) ?;
150
+
151
+ // Finalize the GIC.
152
+ // See https://code.woboq.org/linux/linux/virt/kvm/arm/vgic/vgic-kvm-device.c.html#211.
153
+ Self :: set_device_attribute (
154
+ gic_device. device_fd ( ) ,
155
+ kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL ,
156
+ u64:: from ( kvm_bindings:: KVM_DEV_ARM_VGIC_CTRL_INIT ) ,
157
+ 0 ,
158
+ 0 ,
159
+ ) ?;
160
+
161
+ Ok ( ( ) )
162
+ }
163
+
164
+ /// Set a GIC device attribute
165
+ pub fn set_device_attribute (
166
+ fd : & DeviceFd ,
167
+ group : u32 ,
168
+ attr : u64 ,
169
+ addr : u64 ,
170
+ flags : u32 ,
171
+ ) -> Result < ( ) > {
172
+ let attr = kvm_bindings:: kvm_device_attr {
173
+ flags,
174
+ group,
175
+ attr,
176
+ addr,
177
+ } ;
178
+ fd. set_device_attr ( & attr)
179
+ . map_err ( |err| Error :: DeviceAttribute ( err, true , group) ) ?;
180
+
181
+ Ok ( ( ) )
182
+ }
125
183
}
0 commit comments