Skip to content

Commit aedf1e8

Browse files
authored
Construct and wire up lapics for VTL 1 (#17)
Make the lapics for SNP and Hv backings into an array of 2 instead of just the 1 per-vp, and wire up the VTLs getting passed around. Next up is likely taking the result of polling these two apics and using it to determine which VTL to run in our next run_vp call.
1 parent 214ef24 commit aedf1e8

File tree

6 files changed

+228
-138
lines changed

6 files changed

+228
-138
lines changed

openhcl/virt_mshv_vtl/src/processor/mod.rs

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,10 @@ mod private {
207207
stop: &mut StopVp<'_>,
208208
) -> impl Future<Output = Result<(), VpHaltReason<UhRunVpError>>>;
209209

210-
/// Returns true if the VP is ready to run, false if it is halted.
210+
/// Returns true if the VP is ready to run the given VTL, false if it is halted.
211211
fn poll_apic(
212212
this: &mut UhProcessor<'_, Self>,
213+
vtl: Vtl,
213214
scan_irr: bool,
214215
) -> Result<bool, UhRunVpError>;
215216

@@ -616,7 +617,7 @@ impl<'p, T: Backing> Processor for UhProcessor<'p, T> {
616617
Ordering::Relaxed,
617618
);
618619

619-
let mut scan_irr = true;
620+
let mut first_scan_irr = true;
620621

621622
loop {
622623
// Process VP activity and wait for the VP to be ready.
@@ -639,22 +640,28 @@ impl<'p, T: Backing> Processor for UhProcessor<'p, T> {
639640
}
640641

641642
// Process wakes.
642-
if self.inner.wake_reasons.load(Ordering::Relaxed) != 0 {
643-
scan_irr = self.handle_wake().map_err(VpHaltReason::Hypervisor)?;
643+
let scan_irr = if self.inner.wake_reasons.load(Ordering::Relaxed) != 0 {
644+
self.handle_wake().map_err(VpHaltReason::Hypervisor)?
645+
} else {
646+
[false, false].into()
647+
};
648+
649+
if self.untrusted_synic.is_some() {
650+
self.update_synic(Vtl::Vtl0, true);
644651
}
645652

653+
// TODO CVM GUEST VSM: Split ready into two to track per-vtl
654+
let mut ready = false;
646655
for vtl in [Vtl::Vtl1, Vtl::Vtl0] {
647656
// Process interrupts.
648657
if self.hv(vtl).is_some() {
649658
self.update_synic(vtl, false);
650659
}
651-
}
652-
if self.untrusted_synic.is_some() {
653-
self.update_synic(Vtl::Vtl0, true);
654-
}
655660

656-
let ready = T::poll_apic(self, scan_irr).map_err(VpHaltReason::Hypervisor)?;
657-
scan_irr = false;
661+
ready |= T::poll_apic(self, vtl, scan_irr[vtl] || first_scan_irr)
662+
.map_err(VpHaltReason::Hypervisor)?;
663+
}
664+
first_scan_irr = false;
658665

659666
// Arm the timer.
660667
if let Some(timeout) = self.vmtime.get_timeout() {
@@ -696,8 +703,10 @@ impl<'p, T: Backing> Processor for UhProcessor<'p, T> {
696703
fn flush_async_requests(&mut self) -> Result<(), Self::RunVpError> {
697704
if self.inner.wake_reasons.load(Ordering::Relaxed) != 0 {
698705
let scan_irr = self.handle_wake()?;
699-
if scan_irr {
700-
T::poll_apic(self, true)?;
706+
for vtl in [Vtl::Vtl1, Vtl::Vtl0] {
707+
if scan_irr[vtl] {
708+
T::poll_apic(self, vtl, true)?;
709+
}
701710
}
702711
}
703712
Ok(())
@@ -778,7 +787,7 @@ impl<'a, T: Backing> UhProcessor<'a, T> {
778787
}
779788

780789
/// Returns true if the interrupt controller has work to do.
781-
fn handle_wake(&mut self) -> Result<bool, UhRunVpError> {
790+
fn handle_wake(&mut self) -> Result<VtlArray<bool, 2>, UhRunVpError> {
782791
let wake_reasons_raw = self.inner.wake_reasons.swap(0, Ordering::SeqCst);
783792
let wake_reasons_vtl: [WakeReason; 2] = zerocopy::transmute!(wake_reasons_raw);
784793
for (vtl, wake_reasons) in [
@@ -843,7 +852,6 @@ impl<'a, T: Backing> UhProcessor<'a, T> {
843852
// Should not have already initialized the hv emulator for this vtl
844853
assert!(self.hv(vtl).is_none());
845854

846-
// TODO GUEST_VSM construct VTL 1 lapics
847855
self.hv[vtl] = Some(
848856
self.partition
849857
.hv
@@ -864,7 +872,7 @@ impl<'a, T: Backing> UhProcessor<'a, T> {
864872
}
865873
}
866874

867-
Ok(wake_reasons_vtl[0].intcon())
875+
Ok(wake_reasons_vtl.map(|w| w.intcon()).into())
868876
}
869877

870878
fn request_sint_notifications(&mut self, vtl: Vtl, sints: u16) {

openhcl/virt_mshv_vtl/src/processor/mshv/apic.rs

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,21 @@ use x86defs::RFlags;
3535
#[derive(Inspect)]
3636
pub(super) struct UhApicState {
3737
lapic: LocalApic,
38+
#[inspect(debug)]
39+
vtl: Vtl,
3840
pub(super) halted: bool,
3941
pub(super) startup_suspend: bool,
4042
nmi_pending: bool,
4143
}
4244

4345
impl UhApicState {
44-
pub fn new(lapic: LocalApic, vp_info: &VpInfo) -> Self {
46+
pub fn new(lapic: LocalApic, vtl: Vtl, vp_info: &VpInfo) -> Self {
4547
Self {
4648
lapic,
49+
vtl,
4750
halted: false,
4851
nmi_pending: false,
49-
startup_suspend: !vp_info.is_bsp(),
52+
startup_suspend: vtl == Vtl::Vtl0 && !vp_info.is_bsp(),
5053
}
5154
}
5255

@@ -69,6 +72,7 @@ impl UhApicState {
6972
runner,
7073
dev,
7174
vmtime,
75+
vtl: self.vtl,
7276
})
7377
.mmio_write(address, data);
7478
}
@@ -88,6 +92,7 @@ impl UhApicState {
8892
runner,
8993
dev,
9094
vmtime,
95+
vtl: self.vtl,
9196
})
9297
.mmio_read(address, data);
9398
}
@@ -107,6 +112,7 @@ impl UhApicState {
107112
runner,
108113
dev,
109114
vmtime,
115+
vtl: self.vtl,
110116
})
111117
.msr_write(msr, value)
112118
}
@@ -125,6 +131,7 @@ impl UhApicState {
125131
runner,
126132
dev,
127133
vmtime,
134+
vtl: self.vtl,
128135
})
129136
.msr_read(msr)
130137
}
@@ -254,10 +261,12 @@ impl UhApicState {
254261

255262
impl UhProcessor<'_, HypervisorBackedX86> {
256263
/// Returns true if the VP is ready to run, false if it is halted.
257-
pub(super) fn poll_apic(&mut self, scan_irr: bool) -> Result<bool, UhRunVpError> {
258-
let Some(lapic) = self.backing.lapic.as_mut() else {
264+
pub(super) fn poll_apic(&mut self, vtl: Vtl, scan_irr: bool) -> Result<bool, UhRunVpError> {
265+
let Some(lapics) = self.backing.lapics.as_mut() else {
259266
return Ok(true);
260267
};
268+
269+
let lapic = &mut lapics[vtl];
261270
let ApicWork {
262271
init,
263272
extint,
@@ -286,33 +295,31 @@ impl UhProcessor<'_, HypervisorBackedX86> {
286295
todo!();
287296
}
288297

298+
// TODO WHP GUEST VSM: An INIT/SIPI targeted at a VP with more than one guest VTL enabled is ignored.
289299
if init {
290-
self.handle_init()?;
300+
self.handle_init(vtl)?;
291301
}
292302

293303
if let Some(vector) = sipi {
294-
self.handle_sipi(vector)?;
304+
self.handle_sipi(vtl, vector)?;
295305
}
296306

297-
let lapic = self.backing.lapic.as_ref().unwrap();
307+
let lapic = &self.backing.lapics.as_ref().unwrap()[vtl];
298308
if lapic.halted || lapic.startup_suspend {
299309
return Ok(false);
300310
}
301311

302312
Ok(true)
303313
}
304314

305-
fn handle_init(&mut self) -> Result<(), UhRunVpError> {
315+
fn handle_init(&mut self, vtl: Vtl) -> Result<(), UhRunVpError> {
306316
let vp_info = self.inner.vp_info;
307-
{
308-
let mut access = self.access_state(Vtl::Vtl0);
309-
virt::x86::vp::x86_init(&mut access, &vp_info).map_err(UhRunVpError::State)?;
310-
}
311-
Ok(())
317+
let mut access = self.access_state(vtl);
318+
virt::x86::vp::x86_init(&mut access, &vp_info).map_err(UhRunVpError::State)
312319
}
313320

314-
fn handle_sipi(&mut self, vector: u8) -> Result<(), UhRunVpError> {
315-
let lapic = self.backing.lapic.as_mut().unwrap();
321+
fn handle_sipi(&mut self, vtl: Vtl, vector: u8) -> Result<(), UhRunVpError> {
322+
let lapic = &mut self.backing.lapics.as_mut().unwrap()[vtl];
316323
if lapic.startup_suspend {
317324
let address = (vector as u64) << 12;
318325
let cs: hvdef::HvX64SegmentRegister = hvdef::HvX64SegmentRegister {
@@ -339,6 +346,7 @@ struct UhApicClient<'a, 'b, T> {
339346
runner: &'a mut ProcessorRunner<'b, MshvX64>,
340347
dev: &'a T,
341348
vmtime: &'a VmTimeAccess,
349+
vtl: Vtl,
342350
}
343351

344352
impl<T: CpuIo> ApicClient for UhApicClient<'_, '_, T> {
@@ -365,10 +373,11 @@ impl<T: CpuIo> ApicClient for UhApicClient<'_, '_, T> {
365373
self.partition
366374
.vp(vp_index)
367375
.unwrap()
368-
.wake(Vtl::Vtl0, WakeReason::INTCON);
376+
.wake(self.vtl, WakeReason::INTCON);
369377
}
370378

371379
fn eoi(&mut self, vector: u8) {
380+
debug_assert_eq!(self.vtl, Vtl::Vtl0);
372381
self.dev.handle_eoi(vector.into())
373382
}
374383

openhcl/virt_mshv_vtl/src/processor/mshv/arm64.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,12 @@ impl BackingPrivate for HypervisorBackedArm64 {
194194
Ok(())
195195
}
196196

197-
fn poll_apic(this: &mut UhProcessor<'_, Self>, scan_irr: bool) -> Result<bool, UhRunVpError> {
198-
{
199-
let _ = (this, scan_irr);
200-
Ok(true)
201-
}
197+
fn poll_apic(
198+
_this: &mut UhProcessor<'_, Self>,
199+
_vtl: Vtl,
200+
_scan_irr: bool,
201+
) -> Result<bool, UhRunVpError> {
202+
Ok(true)
202203
}
203204

204205
fn request_extint_readiness(this: &mut UhProcessor<'_, Self>) {

openhcl/virt_mshv_vtl/src/processor/mshv/x64.rs

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ use virt_support_x86emu::emulate::EmuCheckVtlAccessError;
6060
use virt_support_x86emu::emulate::EmuTranslateError;
6161
use virt_support_x86emu::emulate::EmuTranslateResult;
6262
use virt_support_x86emu::emulate::EmulatorSupport;
63+
use vtl_array::VtlArray;
6364
use vtl_array::VtlSet;
6465
use x86defs::xsave::Fxsave;
6566
use x86defs::xsave::XsaveHeader;
@@ -74,7 +75,11 @@ use zerocopy::FromZeroes;
7475
#[derive(InspectMut)]
7576
pub struct HypervisorBackedX86 {
7677
/// Underhill APIC state
77-
pub(super) lapic: Option<apic::UhApicState>,
78+
pub(super) lapics: Option<VtlArray<apic::UhApicState, 2>>,
79+
// TODO WHP GUEST VSM: To be completely correct here, when emulating the APICs
80+
// we would need two sets of deliverability notifications too. However currently
81+
// we don't support VTL 1 on WHP, and on the hypervisor we don't emulate the APIC,
82+
// so this can wait.
7883
#[inspect(with = "|x| inspect::AsHex(u64::from(*x))")]
7984
deliverability_notifications: HvDeliverabilityNotificationsRegister,
8085
/// Next set of deliverability notifications. See register definition for details.
@@ -124,21 +129,27 @@ impl BackingPrivate for HypervisorBackedX86 {
124129
reserved: [0; 384],
125130
};
126131

127-
let lapic = params.partition.lapic.as_ref().map(|arr| {
128-
let lapic_set = &arr[Vtl::Vtl0];
132+
let lapics = params.partition.lapic.as_ref().map(|arr| {
129133
// Initialize APIC base to match the current VM state.
130134
let apic_base = params
131135
.runner
132136
.get_vp_register(HvX64RegisterName::ApicBase)
133137
.unwrap()
134138
.as_u64();
135-
let mut lapic = lapic_set.add_apic(params.vp_info);
136-
lapic.set_apic_base(apic_base).unwrap();
137-
apic::UhApicState::new(lapic, &params.vp_info.base)
139+
let mut lapic0 = arr[Vtl::Vtl0].add_apic(params.vp_info);
140+
lapic0.set_apic_base(apic_base).unwrap();
141+
let mut lapic1 = arr[Vtl::Vtl1].add_apic(params.vp_info);
142+
lapic1.set_apic_base(apic_base).unwrap();
143+
144+
[
145+
apic::UhApicState::new(lapic0, Vtl::Vtl0, &params.vp_info.base),
146+
apic::UhApicState::new(lapic1, Vtl::Vtl1, &params.vp_info.base),
147+
]
148+
.into()
138149
});
139150

140151
Ok(Self {
141-
lapic,
152+
lapics,
142153
deliverability_notifications: Default::default(),
143154
next_deliverability_notifications: Default::default(),
144155
stats: Default::default(),
@@ -275,8 +286,12 @@ impl BackingPrivate for HypervisorBackedX86 {
275286
Ok(())
276287
}
277288

278-
fn poll_apic(this: &mut UhProcessor<'_, Self>, scan_irr: bool) -> Result<bool, UhRunVpError> {
279-
this.poll_apic(scan_irr)
289+
fn poll_apic(
290+
this: &mut UhProcessor<'_, Self>,
291+
vtl: Vtl,
292+
scan_irr: bool,
293+
) -> Result<bool, UhRunVpError> {
294+
this.poll_apic(vtl, scan_irr)
280295
}
281296

282297
fn request_extint_readiness(this: &mut UhProcessor<'_, Self>) {
@@ -591,14 +606,21 @@ impl UhProcessor<'_, HypervisorBackedX86> {
591606
hvdef::HvX64MsrInterceptMessage::ref_from_prefix(self.runner.exit_message().payload())
592607
.unwrap();
593608
let rip = next_rip(&message.header);
609+
let last_vtl = self.last_vtl();
594610

595611
tracing::trace!(msg = %format_args!("{:x?}", message), "msr");
596612

597613
let msr = message.msr_number;
598614
match message.header.intercept_access_type {
599615
HvInterceptAccessType::READ => {
600-
let r = if let Some(lapic) = &mut self.backing.lapic {
601-
lapic.msr_read(self.partition, &mut self.runner, &self.vmtime, dev, msr)
616+
let r = if let Some(lapics) = &mut self.backing.lapics {
617+
lapics[last_vtl].msr_read(
618+
self.partition,
619+
&mut self.runner,
620+
&self.vmtime,
621+
dev,
622+
msr,
623+
)
602624
} else {
603625
Err(MsrError::Unknown)
604626
};
@@ -622,8 +644,8 @@ impl UhProcessor<'_, HypervisorBackedX86> {
622644
}
623645
HvInterceptAccessType::WRITE => {
624646
let value = (message.rax & 0xffff_ffff) | (message.rdx << 32);
625-
let r = if let Some(lapic) = &mut self.backing.lapic {
626-
lapic.msr_write(
647+
let r = if let Some(lapic) = &mut self.backing.lapics {
648+
lapic[last_vtl].msr_write(
627649
self.partition,
628650
&mut self.runner,
629651
&self.vmtime,
@@ -687,7 +709,8 @@ impl UhProcessor<'_, HypervisorBackedX86> {
687709
}
688710

689711
fn handle_halt(&mut self) -> Result<(), VpHaltReason<UhRunVpError>> {
690-
self.backing.lapic.as_mut().unwrap().halt();
712+
let last_vtl = self.last_vtl();
713+
self.backing.lapics.as_mut().unwrap()[last_vtl].halt();
691714
Ok(())
692715
}
693716

@@ -1116,15 +1139,17 @@ impl<T: CpuIo> EmulatorSupport for UhEmulationState<'_, '_, T, HypervisorBackedX
11161139
}
11171140

11181141
fn lapic_base_address(&self) -> Option<u64> {
1142+
let last_vtl = self.vp.last_vtl();
11191143
self.vp
11201144
.backing
1121-
.lapic
1145+
.lapics
11221146
.as_ref()
1123-
.and_then(|lapic| lapic.base_address())
1147+
.and_then(|lapic| lapic[last_vtl].base_address())
11241148
}
11251149

11261150
fn lapic_read(&mut self, address: u64, data: &mut [u8]) {
1127-
self.vp.backing.lapic.as_mut().unwrap().mmio_read(
1151+
let last_vtl = self.vp.last_vtl();
1152+
self.vp.backing.lapics.as_mut().unwrap()[last_vtl].mmio_read(
11281153
self.vp.partition,
11291154
&mut self.vp.runner,
11301155
&self.vp.vmtime,
@@ -1135,7 +1160,8 @@ impl<T: CpuIo> EmulatorSupport for UhEmulationState<'_, '_, T, HypervisorBackedX
11351160
}
11361161

11371162
fn lapic_write(&mut self, address: u64, data: &[u8]) {
1138-
self.vp.backing.lapic.as_mut().unwrap().mmio_write(
1163+
let last_vtl = self.vp.last_vtl();
1164+
self.vp.backing.lapics.as_mut().unwrap()[last_vtl].mmio_write(
11391165
self.vp.partition,
11401166
&mut self.vp.runner,
11411167
&self.vp.vmtime,

0 commit comments

Comments
 (0)