2
2
// SPDX-License-Identifier: Apache-2.0
3
3
4
4
use crossbeam_channel:: Sender ;
5
- use std:: collections:: btree_map:: Entry ;
6
- use std:: collections:: { BTreeMap , VecDeque } ;
5
+ use std:: collections:: VecDeque ;
7
6
use std:: convert:: TryInto ;
7
+ use std:: sync:: { Arc , Mutex } ;
8
8
9
9
use arch:: aarch64:: gicv2:: GICv2 ;
10
10
use arch:: aarch64:: layout:: GTIMER_VIRT ;
@@ -23,32 +23,101 @@ enum VcpuStatus {
23
23
struct VcpuInfo {
24
24
status : VcpuStatus ,
25
25
pending_irqs : VecDeque < u32 > ,
26
- wfe_sender : Sender < u32 > ,
26
+ wfe_sender : Option < Sender < u32 > > ,
27
+ }
28
+
29
+ pub struct VcpuList {
30
+ vcpus : Vec < Mutex < VcpuInfo > > ,
31
+ vtimer_irq : u32 ,
32
+ }
33
+
34
+ impl VcpuList {
35
+ pub fn new ( ) -> Self {
36
+ let mut vcpus = Vec :: with_capacity ( MAX_CPUS as usize ) ;
37
+ for _ in 0 ..MAX_CPUS {
38
+ vcpus. push ( Mutex :: new ( VcpuInfo {
39
+ status : VcpuStatus :: Running ,
40
+ pending_irqs : VecDeque :: new ( ) ,
41
+ wfe_sender : None ,
42
+ } ) ) ;
43
+ }
44
+
45
+ Self {
46
+ vcpus,
47
+ vtimer_irq : GTIMER_VIRT + 16 ,
48
+ }
49
+ }
50
+
51
+ fn set_irq_common ( & self , vcpuid : u8 , irq_line : u32 ) {
52
+ let vcpu = & mut self . vcpus [ vcpuid as usize ] . lock ( ) . unwrap ( ) ;
53
+ vcpu. pending_irqs . push_back ( irq_line) ;
54
+
55
+ match vcpu. status {
56
+ VcpuStatus :: Waiting => {
57
+ vcpu. wfe_sender
58
+ . as_mut ( )
59
+ . unwrap ( )
60
+ . send ( vcpuid as u32 )
61
+ . unwrap ( ) ;
62
+ vcpu. status = VcpuStatus :: Running ;
63
+ }
64
+ VcpuStatus :: Running => {
65
+ vcpu_request_exit ( vcpuid as u64 ) . unwrap ( ) ;
66
+ }
67
+ }
68
+ }
69
+
70
+ pub fn set_vtimer_irq ( & self , vcpuid : u64 ) {
71
+ assert ! ( vcpuid < MAX_CPUS ) ;
72
+ self . set_irq_common ( vcpuid as u8 , self . vtimer_irq ) ;
73
+ }
74
+
75
+ pub fn register ( & self , vcpuid : u64 , wfe_sender : Sender < u32 > ) {
76
+ assert ! ( vcpuid < MAX_CPUS ) ;
77
+ let vcpu = & mut self . vcpus [ vcpuid as usize ] . lock ( ) . unwrap ( ) ;
78
+ vcpu. wfe_sender = Some ( wfe_sender) ;
79
+ }
80
+
81
+ pub fn should_wait ( & self , vcpuid : u64 ) -> bool {
82
+ assert ! ( vcpuid < MAX_CPUS ) ;
83
+ let vcpu = & mut self . vcpus [ vcpuid as usize ] . lock ( ) . unwrap ( ) ;
84
+ if vcpu. pending_irqs . is_empty ( ) {
85
+ vcpu. status = VcpuStatus :: Waiting ;
86
+ true
87
+ } else {
88
+ false
89
+ }
90
+ }
91
+
92
+ pub fn has_pending_irq ( & self , vcpuid : u64 ) -> bool {
93
+ assert ! ( vcpuid < MAX_CPUS ) ;
94
+ let vcpu = & mut self . vcpus [ vcpuid as usize ] . lock ( ) . unwrap ( ) ;
95
+ !vcpu. pending_irqs . is_empty ( )
96
+ }
97
+
98
+ pub fn get_pending_irq ( & self , vcpuid : u8 ) -> u32 {
99
+ let vcpu = & mut self . vcpus [ vcpuid as usize ] . lock ( ) . unwrap ( ) ;
100
+ vcpu. pending_irqs . pop_front ( ) . unwrap_or ( 1023 )
101
+ }
27
102
}
28
103
29
104
pub struct Gic {
30
105
cpu_size : u64 ,
31
106
ctlr : u32 ,
32
107
irq_cfg : [ u8 ; IRQ_NUM as usize ] ,
33
- vcpus : BTreeMap < u8 , VcpuInfo > ,
108
+ vcpu_list : Arc < VcpuList > ,
34
109
vcpu_count : u8 ,
35
110
irq_target : [ u8 ; IRQ_NUM as usize ] ,
36
111
vtimer_irq : u32 ,
37
112
}
38
113
39
- impl Default for Gic {
40
- fn default ( ) -> Self {
41
- Self :: new ( )
42
- }
43
- }
44
-
45
114
impl Gic {
46
- pub fn new ( ) -> Self {
115
+ pub fn new ( vcpu_list : Arc < VcpuList > ) -> Self {
47
116
Self {
48
117
cpu_size : GICv2 :: get_cpu_size ( ) ,
49
118
ctlr : 0 ,
50
119
irq_cfg : [ 0 ; IRQ_NUM as usize ] ,
51
- vcpus : BTreeMap :: new ( ) ,
120
+ vcpu_list ,
52
121
vcpu_count : 0 ,
53
122
irq_target : [ 0 ; IRQ_NUM as usize ] ,
54
123
vtimer_irq : GTIMER_VIRT + 16 ,
@@ -66,105 +135,23 @@ impl Gic {
66
135
GICv2 :: get_dist_size ( ) + GICv2 :: get_cpu_size ( )
67
136
}
68
137
69
- fn set_irq_common ( & mut self , vcpuid : u8 , irq_line : u32 ) {
70
- match self . vcpus . entry ( vcpuid) {
71
- Entry :: Vacant ( _) => {
72
- panic ! ( "Unknown vCPU id: {}" , vcpuid) ;
73
- }
74
- Entry :: Occupied ( mut vcpu_entry) => {
75
- let vcpu = vcpu_entry. get_mut ( ) ;
76
-
77
- vcpu. pending_irqs . push_back ( irq_line) ;
78
-
79
- match vcpu. status {
80
- VcpuStatus :: Waiting => {
81
- vcpu. wfe_sender . send ( vcpuid as u32 ) . unwrap ( ) ;
82
- vcpu. status = VcpuStatus :: Running ;
83
- }
84
- VcpuStatus :: Running => {
85
- vcpu_request_exit ( vcpuid as u64 ) . unwrap ( ) ;
86
- }
87
- }
88
- }
89
- }
138
+ pub fn add_vcpu ( & mut self ) {
139
+ self . vcpu_count += 1 ;
90
140
}
91
141
92
- pub fn set_sgi_irq ( & mut self , vcpuid : u8 , irq_line : u32 ) {
142
+ fn set_sgi_irq ( & self , vcpuid : u8 , irq_line : u32 ) {
93
143
assert ! ( irq_line < 16 ) ;
94
- self . set_irq_common ( vcpuid, irq_line) ;
144
+ self . vcpu_list . set_irq_common ( vcpuid, irq_line) ;
95
145
}
96
146
97
- pub fn set_vtimer_irq ( & mut self , vcpuid : u64 ) {
98
- assert ! ( vcpuid < MAX_CPUS ) ;
99
- self . set_irq_common ( vcpuid as u8 , self . vtimer_irq ) ;
100
- }
101
-
102
- pub fn set_irq ( & mut self , irq_line : u32 ) {
147
+ pub fn set_irq ( & self , irq_line : u32 ) {
103
148
for vcpuid in 0 ..self . vcpu_count {
104
149
if ( self . irq_target [ irq_line as usize ] & ( 1 << vcpuid) ) == 0 {
105
150
continue ;
106
151
}
107
152
108
153
debug ! ( "signaling irq={} to vcpuid={}" , irq_line, vcpuid) ;
109
-
110
- self . set_irq_common ( vcpuid, irq_line) ;
111
- }
112
- }
113
-
114
- pub fn register_vcpu ( & mut self , vcpuid : u64 , wfe_sender : Sender < u32 > ) {
115
- assert ! ( vcpuid < MAX_CPUS ) ;
116
- self . vcpus . insert (
117
- vcpuid as u8 ,
118
- VcpuInfo {
119
- status : VcpuStatus :: Running ,
120
- wfe_sender,
121
- pending_irqs : VecDeque :: new ( ) ,
122
- } ,
123
- ) ;
124
- assert ! ( self . vcpus. len( ) <= MAX_CPUS as usize ) ;
125
- self . vcpu_count = self . vcpus . len ( ) as u8 ;
126
- }
127
-
128
- pub fn vcpu_should_wait ( & mut self , vcpuid : u64 ) -> bool {
129
- assert ! ( vcpuid < MAX_CPUS ) ;
130
- match self . vcpus . entry ( vcpuid as u8 ) {
131
- Entry :: Vacant ( _) => {
132
- panic ! ( "Unknown vCPU id: {}" , vcpuid) ;
133
- }
134
- Entry :: Occupied ( mut vcpu_entry) => {
135
- let vcpu = vcpu_entry. get_mut ( ) ;
136
- if vcpu. pending_irqs . is_empty ( ) {
137
- vcpu. status = VcpuStatus :: Waiting ;
138
- true
139
- } else {
140
- false
141
- }
142
- }
143
- }
144
- }
145
-
146
- pub fn vcpu_has_pending_irq ( & mut self , vcpuid : u64 ) -> bool {
147
- assert ! ( vcpuid < MAX_CPUS ) ;
148
- match self . vcpus . entry ( vcpuid as u8 ) {
149
- Entry :: Vacant ( _) => {
150
- panic ! ( "Unknown vCPU id: {}" , vcpuid) ;
151
- }
152
- Entry :: Occupied ( mut vcpu_entry) => {
153
- let vcpu = vcpu_entry. get_mut ( ) ;
154
- !vcpu. pending_irqs . is_empty ( )
155
- }
156
- }
157
- }
158
-
159
- fn get_pending_irq ( & mut self , vcpuid : u8 ) -> u32 {
160
- match self . vcpus . entry ( vcpuid) {
161
- Entry :: Vacant ( _) => {
162
- panic ! ( "Unknown vCPU id: {}" , vcpuid) ;
163
- }
164
- Entry :: Occupied ( mut vcpu_entry) => {
165
- let vcpu = vcpu_entry. get_mut ( ) ;
166
- vcpu. pending_irqs . pop_front ( ) . unwrap_or ( 1023 )
167
- }
154
+ self . vcpu_list . set_irq_common ( vcpuid, irq_line) ;
168
155
}
169
156
}
170
157
@@ -280,7 +267,7 @@ impl Gic {
280
267
281
268
let mut val = 0 ;
282
269
if offset == 0xc {
283
- val = self . get_pending_irq ( vcpuid as u8 ) ;
270
+ val = self . vcpu_list . get_pending_irq ( vcpuid as u8 ) ;
284
271
}
285
272
for ( i, b) in val. to_le_bytes ( ) . iter ( ) . enumerate ( ) {
286
273
data[ i] = * b;
0 commit comments