22// SPDX-License-Identifier: Apache-2.0
33
44use crossbeam_channel:: Sender ;
5- use std:: collections:: btree_map:: Entry ;
6- use std:: collections:: { BTreeMap , VecDeque } ;
5+ use std:: collections:: VecDeque ;
76use std:: convert:: TryInto ;
7+ use std:: sync:: { Arc , Mutex } ;
88
99use arch:: aarch64:: gicv2:: GICv2 ;
1010use arch:: aarch64:: layout:: GTIMER_VIRT ;
@@ -23,32 +23,101 @@ enum VcpuStatus {
2323struct VcpuInfo {
2424 status : VcpuStatus ,
2525 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+ }
27102}
28103
29104pub struct Gic {
30105 cpu_size : u64 ,
31106 ctlr : u32 ,
32107 irq_cfg : [ u8 ; IRQ_NUM as usize ] ,
33- vcpus : BTreeMap < u8 , VcpuInfo > ,
108+ vcpu_list : Arc < VcpuList > ,
34109 vcpu_count : u8 ,
35110 irq_target : [ u8 ; IRQ_NUM as usize ] ,
36111 vtimer_irq : u32 ,
37112}
38113
39- impl Default for Gic {
40- fn default ( ) -> Self {
41- Self :: new ( )
42- }
43- }
44-
45114impl Gic {
46- pub fn new ( ) -> Self {
115+ pub fn new ( vcpu_list : Arc < VcpuList > ) -> Self {
47116 Self {
48117 cpu_size : GICv2 :: get_cpu_size ( ) ,
49118 ctlr : 0 ,
50119 irq_cfg : [ 0 ; IRQ_NUM as usize ] ,
51- vcpus : BTreeMap :: new ( ) ,
120+ vcpu_list ,
52121 vcpu_count : 0 ,
53122 irq_target : [ 0 ; IRQ_NUM as usize ] ,
54123 vtimer_irq : GTIMER_VIRT + 16 ,
@@ -66,105 +135,23 @@ impl Gic {
66135 GICv2 :: get_dist_size ( ) + GICv2 :: get_cpu_size ( )
67136 }
68137
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 ;
90140 }
91141
92- pub fn set_sgi_irq ( & mut self , vcpuid : u8 , irq_line : u32 ) {
142+ fn set_sgi_irq ( & self , vcpuid : u8 , irq_line : u32 ) {
93143 assert ! ( irq_line < 16 ) ;
94- self . set_irq_common ( vcpuid, irq_line) ;
144+ self . vcpu_list . set_irq_common ( vcpuid, irq_line) ;
95145 }
96146
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 ) {
103148 for vcpuid in 0 ..self . vcpu_count {
104149 if ( self . irq_target [ irq_line as usize ] & ( 1 << vcpuid) ) == 0 {
105150 continue ;
106151 }
107152
108153 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) ;
168155 }
169156 }
170157
@@ -280,7 +267,7 @@ impl Gic {
280267
281268 let mut val = 0 ;
282269 if offset == 0xc {
283- val = self . get_pending_irq ( vcpuid as u8 ) ;
270+ val = self . vcpu_list . get_pending_irq ( vcpuid as u8 ) ;
284271 }
285272 for ( i, b) in val. to_le_bytes ( ) . iter ( ) . enumerate ( ) {
286273 data[ i] = * b;
0 commit comments