@@ -3,7 +3,9 @@ use crate::error::{Error, Result};
33use crate :: memory;
44use crate :: percore;
55use crate :: vm;
6+ use alloc:: sync:: Arc ;
67use core:: convert:: TryFrom ;
8+ use core:: sync:: atomic:: AtomicU32 ;
79use num_enum:: TryFromPrimitive ;
810
911#[ derive( Debug ) ]
@@ -41,6 +43,26 @@ enum ApicRegisterSimpleOffset {
4143 TimerDivideConfig = 0x3e0 ,
4244}
4345
46+ /// The portion of guest local APIC state related to logical addressing
47+ ///
48+ /// This portion of state must be 'shared' with other cores, because the
49+ /// state of each local APIC's logical destination registers affects how
50+ /// logically addressed IPIs are transmitted. Therefore, this state is
51+ /// stored in the VirtualMachine instead of in each VCpu.
52+ pub struct LogicalApicState {
53+ pub logical_destination : AtomicU32 ,
54+ pub destination_format : AtomicU32 ,
55+ }
56+
57+ impl core:: default:: Default for LogicalApicState {
58+ fn default ( ) -> Self {
59+ Self {
60+ logical_destination : AtomicU32 :: new ( 0 ) ,
61+ destination_format : AtomicU32 :: new ( 0 ) ,
62+ }
63+ }
64+ }
65+
4466impl TryFrom < u16 > for ApicRegisterOffset {
4567 type Error = Error ;
4668
@@ -102,7 +124,7 @@ impl LocalApic {
102124
103125 // FIXME(alschwalm): The destination is actually a virtual local
104126 // apic id. We should convert that to a global core id for this.
105- let core_id = percore:: CoreId :: from ( dest) ;
127+ let core_id = percore:: CoreId :: from ( dest >> 24 ) ;
106128
107129 debug ! (
108130 "Sending startup message for address = {:?} to core {}" ,
@@ -118,38 +140,77 @@ impl LocalApic {
118140 Ok ( ( ) )
119141 }
120142
121- fn process_interrupt_command ( & mut self , value : u32 ) -> Result < ( ) > {
143+ fn process_interrupt_command (
144+ & mut self ,
145+ vm : Arc < spin:: RwLock < vm:: VirtualMachine > > ,
146+ value : u32 ,
147+ ) -> Result < ( ) > {
122148 let mode = DeliveryMode :: try_from ( ( value >> 8 ) as u8 & 0b111 ) ?;
123149 match mode {
124- DeliveryMode :: StartUp => self . process_sipi_request ( value) ?,
150+ // TODO: for now, just ignore the INIT signal
151+ DeliveryMode :: Init => return Ok ( ( ) ) ,
152+ DeliveryMode :: StartUp => return self . process_sipi_request ( value) ,
125153 _ => ( ) ,
126154 }
127155
128156 let vector = value as u64 & 0xff ;
129157 let dst_mode = DstMode :: try_from ( ( value >> 11 & 0b1 ) as u8 ) ?;
158+ let shorthand = DstShorthand :: try_from ( ( value >> 18 & 0b11 ) as u8 ) ?;
130159
160+ match shorthand {
161+ DstShorthand :: AllIncludingSelf => {
162+ warn ! ( "Unsupported local apic command register shorthand AllIncludingSelf" ) ;
163+ return Ok ( ( ) ) ;
164+ }
165+ DstShorthand :: AllExcludingSelf => {
166+ for core in vm. read ( ) . config . cpus ( ) {
167+ if * core == percore:: read_core_id ( ) {
168+ continue ;
169+ }
170+ vm:: send_vm_msg_core ( vm:: VirtualMachineMsg :: GuestInterrupt {
171+ kind : crate :: vcpu:: InjectedInterruptType :: ExternalInterrupt ,
172+ vector : vector as u8
173+ } , * core, true ) ?
174+ }
175+ return Ok ( ( ) ) ;
176+ }
177+ DstShorthand :: MySelf => {
178+ warn ! ( "Unsupported local apic command register shorthand Self" ) ;
179+ return Ok ( ( ) ) ;
180+ }
181+ DstShorthand :: NoShorthand => ( ) ,
182+ }
183+
184+ // No shorthand was used, so we should have an ICR destination of some sort
131185 if let Some ( dest) = self . icr_destination {
132- // info!("Value = 0x{:x}", value);
133- // info!("Send interrupt vector 0x{:x} to dest = {} [mode={:?}]", vector, dest, dst_mode);
134-
135- // FIXME: hack for time interrupt
136- if vector == 0xec {
137- vm:: send_vm_msg_core ( vm:: VirtualMachineMsg :: GuestInterrupt {
138- kind : crate :: vcpu:: InjectedInterruptType :: ExternalInterrupt ,
139- vector : vector as u8
140- } , percore:: CoreId :: from ( 0x01 ) , true ) ?
186+ match dst_mode {
187+ DstMode :: Logical => {
188+ for core in vm. read ( ) . logical_apic_destination ( dest) ? {
189+ // FIXME(alschwalm): we need to support sending to ourselves (I think)
190+ if * core == percore:: read_core_id ( ) {
191+ continue ;
192+ }
193+ vm:: send_vm_msg_core ( vm:: VirtualMachineMsg :: GuestInterrupt {
194+ kind : crate :: vcpu:: InjectedInterruptType :: ExternalInterrupt ,
195+ vector : vector as u8
196+ } , * core, true ) ?
197+ }
198+ }
199+ DstMode :: Physical => {
200+ warn ! ( "Unsupported Physical address for IPI vector=0x{:x} (dest=0x{:x}/short={:?}/mode={:?})" ,
201+ vector, dest, shorthand, mode) ;
202+ }
141203 }
204+ } else {
205+ warn ! ( "IPI with no icr_destination vector=0x{:x} (dest={:?}/short={:?})" ,
206+ vector, dst_mode, shorthand) ;
142207 }
143208
144209 Ok ( ( ) )
145210 }
146211
147212 pub fn register_read ( & mut self , offset : u16 ) -> Result < u32 > {
148213 let offset = ApicRegisterOffset :: try_from ( offset) ?;
149- // debug!(
150- // "Read from virtual local apic: {:?}",
151- // offset
152- // );
153214 match offset {
154215 ApicRegisterOffset :: Simple ( ApicRegisterSimpleOffset :: ApicId ) => {
155216 // FIXME(alschwalm): we shouldn't really use the core id for this
@@ -159,11 +220,19 @@ impl LocalApic {
159220 }
160221 }
161222
162- pub fn register_write ( & mut self , offset : u16 , value : u32 ) -> Result < ( ) > {
223+ pub fn register_write (
224+ & mut self ,
225+ vm : Arc < spin:: RwLock < vm:: VirtualMachine > > ,
226+ offset : u16 ,
227+ value : u32 ,
228+ ) -> Result < ( ) > {
163229 let offset = ApicRegisterOffset :: try_from ( offset) ?;
164230 match offset {
165231 ApicRegisterOffset :: Simple ( ref simple) => match simple {
166232 ApicRegisterSimpleOffset :: EndOfInterrupt => ( ) ,
233+ ApicRegisterSimpleOffset :: LogicalDestination => {
234+ vm. write ( ) . update_core_logical_destination ( value) ;
235+ }
167236 _ => info ! (
168237 "Write to virtual local apic: {:?}, value=0x{:x}" ,
169238 offset, value
@@ -172,13 +241,13 @@ impl LocalApic {
172241 ApicRegisterOffset :: InterruptCommand ( offset) => {
173242 match offset {
174243 0 => {
175- self . process_interrupt_command ( value) ?;
244+ self . process_interrupt_command ( vm , value) ?;
176245
177246 // TODO(alschwalm): What is the expected behavior here?
178247 self . icr_destination = None ;
179248 }
180249 1 => {
181- self . icr_destination = Some ( value >> 24 ) ;
250+ self . icr_destination = Some ( value) ;
182251 }
183252 _ => unreachable ! ( ) ,
184253 }
0 commit comments