Skip to main content

virt/x86/
vp.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Per-VP state.
5
6use super::SegmentRegister;
7use super::TableRegister;
8use super::X86PartitionCapabilities;
9use crate::state::HvRegisterState;
10use crate::state::StateElement;
11use crate::state::state_trait;
12use hvdef::HV_MESSAGE_SIZE;
13use hvdef::HvInternalActivityRegister;
14use hvdef::HvMessage;
15use hvdef::HvRegisterValue;
16use hvdef::HvX64InterruptStateRegister;
17use hvdef::HvX64PendingEventReg0;
18use hvdef::HvX64PendingExceptionEvent;
19use hvdef::HvX64PendingExtIntEvent;
20use hvdef::HvX64PendingInterruptionRegister;
21use hvdef::HvX64PendingInterruptionType;
22use hvdef::HvX64RegisterName;
23use hvdef::HvX64SegmentRegister;
24use hvdef::HvX64TableRegister;
25use inspect::Inspect;
26use mesh_protobuf::Protobuf;
27use std::fmt::Debug;
28use vm_topology::processor::x86::X86VpInfo;
29use x86defs::RFlags;
30use x86defs::X64_CR0_CD;
31use x86defs::X64_CR0_ET;
32use x86defs::X64_CR0_NW;
33use x86defs::X64_EFER_NXE;
34use x86defs::X86X_MSR_DEFAULT_PAT;
35use x86defs::apic::APIC_BASE_PAGE;
36use x86defs::apic::ApicBase;
37use x86defs::apic::ApicVersion;
38use x86defs::xsave::DEFAULT_MXCSR;
39use x86defs::xsave::Fxsave;
40use x86defs::xsave::INIT_FCW;
41use x86defs::xsave::XCOMP_COMPRESSED;
42use x86defs::xsave::XFEATURE_SSE;
43use x86defs::xsave::XFEATURE_X87;
44use x86defs::xsave::XFEATURE_YMM;
45use x86defs::xsave::XSAVE_LEGACY_LEN;
46use x86defs::xsave::XSAVE_VARIABLE_OFFSET;
47use x86defs::xsave::XsaveHeader;
48use zerocopy::FromBytes;
49use zerocopy::FromZeros;
50use zerocopy::Immutable;
51use zerocopy::IntoBytes;
52use zerocopy::KnownLayout;
53use zerocopy::Ref;
54
55#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Protobuf, Inspect)]
56#[mesh(package = "virt.x86")]
57pub struct Registers {
58    #[inspect(hex)]
59    #[mesh(1)]
60    pub rax: u64,
61    #[inspect(hex)]
62    #[mesh(2)]
63    pub rcx: u64,
64    #[inspect(hex)]
65    #[mesh(3)]
66    pub rdx: u64,
67    #[inspect(hex)]
68    #[mesh(4)]
69    pub rbx: u64,
70    #[inspect(hex)]
71    #[mesh(5)]
72    pub rsp: u64,
73    #[inspect(hex)]
74    #[mesh(6)]
75    pub rbp: u64,
76    #[inspect(hex)]
77    #[mesh(7)]
78    pub rsi: u64,
79    #[inspect(hex)]
80    #[mesh(8)]
81    pub rdi: u64,
82    #[inspect(hex)]
83    #[mesh(9)]
84    pub r8: u64,
85    #[inspect(hex)]
86    #[mesh(10)]
87    pub r9: u64,
88    #[inspect(hex)]
89    #[mesh(11)]
90    pub r10: u64,
91    #[inspect(hex)]
92    #[mesh(12)]
93    pub r11: u64,
94    #[inspect(hex)]
95    #[mesh(13)]
96    pub r12: u64,
97    #[inspect(hex)]
98    #[mesh(14)]
99    pub r13: u64,
100    #[inspect(hex)]
101    #[mesh(15)]
102    pub r14: u64,
103    #[inspect(hex)]
104    #[mesh(16)]
105    pub r15: u64,
106    #[inspect(hex)]
107    #[mesh(17)]
108    pub rip: u64,
109    #[inspect(hex)]
110    #[mesh(18)]
111    pub rflags: u64,
112    #[mesh(19)]
113    pub cs: SegmentRegister,
114    #[mesh(20)]
115    pub ds: SegmentRegister,
116    #[mesh(21)]
117    pub es: SegmentRegister,
118    #[mesh(22)]
119    pub fs: SegmentRegister,
120    #[mesh(23)]
121    pub gs: SegmentRegister,
122    #[mesh(24)]
123    pub ss: SegmentRegister,
124    #[mesh(25)]
125    pub tr: SegmentRegister,
126    #[mesh(26)]
127    pub ldtr: SegmentRegister,
128    #[mesh(27)]
129    pub gdtr: TableRegister,
130    #[mesh(28)]
131    pub idtr: TableRegister,
132    #[inspect(hex)]
133    #[mesh(29)]
134    pub cr0: u64,
135    #[inspect(hex)]
136    #[mesh(30)]
137    pub cr2: u64,
138    #[inspect(hex)]
139    #[mesh(31)]
140    pub cr3: u64,
141    #[inspect(hex)]
142    #[mesh(32)]
143    pub cr4: u64,
144    #[inspect(hex)]
145    #[mesh(33)]
146    pub cr8: u64,
147    #[inspect(hex)]
148    #[mesh(34)]
149    pub efer: u64,
150}
151
152impl HvRegisterState<HvX64RegisterName, 34> for Registers {
153    fn names(&self) -> &'static [HvX64RegisterName; 34] {
154        &[
155            HvX64RegisterName::Rax,
156            HvX64RegisterName::Rcx,
157            HvX64RegisterName::Rdx,
158            HvX64RegisterName::Rbx,
159            HvX64RegisterName::Rsp,
160            HvX64RegisterName::Rbp,
161            HvX64RegisterName::Rsi,
162            HvX64RegisterName::Rdi,
163            HvX64RegisterName::R8,
164            HvX64RegisterName::R9,
165            HvX64RegisterName::R10,
166            HvX64RegisterName::R11,
167            HvX64RegisterName::R12,
168            HvX64RegisterName::R13,
169            HvX64RegisterName::R14,
170            HvX64RegisterName::R15,
171            HvX64RegisterName::Rip,
172            HvX64RegisterName::Rflags,
173            HvX64RegisterName::Cr0,
174            HvX64RegisterName::Cr2,
175            HvX64RegisterName::Cr3,
176            HvX64RegisterName::Cr4,
177            HvX64RegisterName::Cr8,
178            HvX64RegisterName::Efer,
179            HvX64RegisterName::Cs,
180            HvX64RegisterName::Ds,
181            HvX64RegisterName::Es,
182            HvX64RegisterName::Fs,
183            HvX64RegisterName::Gs,
184            HvX64RegisterName::Ss,
185            HvX64RegisterName::Tr,
186            HvX64RegisterName::Ldtr,
187            HvX64RegisterName::Gdtr,
188            HvX64RegisterName::Idtr,
189        ]
190    }
191
192    fn get_values<'a>(&self, it: impl Iterator<Item = &'a mut HvRegisterValue>) {
193        for (dest, src) in it.zip([
194            self.rax.into(),
195            self.rcx.into(),
196            self.rdx.into(),
197            self.rbx.into(),
198            self.rsp.into(),
199            self.rbp.into(),
200            self.rsi.into(),
201            self.rdi.into(),
202            self.r8.into(),
203            self.r9.into(),
204            self.r10.into(),
205            self.r11.into(),
206            self.r12.into(),
207            self.r13.into(),
208            self.r14.into(),
209            self.r15.into(),
210            self.rip.into(),
211            self.rflags.into(),
212            self.cr0.into(),
213            self.cr2.into(),
214            self.cr3.into(),
215            self.cr4.into(),
216            self.cr8.into(),
217            self.efer.into(),
218            HvX64SegmentRegister::from(self.cs).into(),
219            HvX64SegmentRegister::from(self.ds).into(),
220            HvX64SegmentRegister::from(self.es).into(),
221            HvX64SegmentRegister::from(self.fs).into(),
222            HvX64SegmentRegister::from(self.gs).into(),
223            HvX64SegmentRegister::from(self.ss).into(),
224            HvX64SegmentRegister::from(self.tr).into(),
225            HvX64SegmentRegister::from(self.ldtr).into(),
226            HvX64TableRegister::from(self.gdtr).into(),
227            HvX64TableRegister::from(self.idtr).into(),
228        ]) {
229            *dest = src;
230        }
231    }
232
233    fn set_values(&mut self, mut it: impl Iterator<Item = HvRegisterValue>) {
234        for (dest, src) in [
235            &mut self.rax,
236            &mut self.rcx,
237            &mut self.rdx,
238            &mut self.rbx,
239            &mut self.rsp,
240            &mut self.rbp,
241            &mut self.rsi,
242            &mut self.rdi,
243            &mut self.r8,
244            &mut self.r9,
245            &mut self.r10,
246            &mut self.r11,
247            &mut self.r12,
248            &mut self.r13,
249            &mut self.r14,
250            &mut self.r15,
251            &mut self.rip,
252            &mut self.rflags,
253            &mut self.cr0,
254            &mut self.cr2,
255            &mut self.cr3,
256            &mut self.cr4,
257            &mut self.cr8,
258            &mut self.efer,
259        ]
260        .into_iter()
261        .zip(&mut it)
262        {
263            *dest = src.as_u64();
264        }
265
266        for (dest, src) in [
267            &mut self.cs,
268            &mut self.ds,
269            &mut self.es,
270            &mut self.fs,
271            &mut self.gs,
272            &mut self.ss,
273            &mut self.tr,
274            &mut self.ldtr,
275        ]
276        .into_iter()
277        .zip(&mut it)
278        {
279            *dest = src.as_segment().into();
280        }
281
282        for (dest, src) in [&mut self.gdtr, &mut self.idtr].into_iter().zip(it) {
283            *dest = src.as_table().into();
284        }
285    }
286}
287
288impl StateElement<X86PartitionCapabilities, X86VpInfo> for Registers {
289    fn is_present(_caps: &X86PartitionCapabilities) -> bool {
290        true
291    }
292
293    fn at_reset(caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
294        let cs = SegmentRegister {
295            base: 0xffff0000,
296            limit: 0xffff,
297            selector: 0xf000,
298            attributes: 0x9b,
299        };
300        let ds = SegmentRegister {
301            base: 0,
302            limit: 0xffff,
303            selector: 0,
304            attributes: 0x93,
305        };
306        let tr = SegmentRegister {
307            base: 0,
308            limit: 0xffff,
309            selector: 0,
310            attributes: 0x8b,
311        };
312        let ldtr = SegmentRegister {
313            base: 0,
314            limit: 0xffff,
315            selector: 0,
316            attributes: 0x82,
317        };
318        let gdtr = TableRegister {
319            base: 0,
320            limit: 0xffff,
321        };
322        let efer = if caps.nxe_forced_on { X64_EFER_NXE } else { 0 };
323        Self {
324            rax: 0,
325            rcx: 0,
326            rdx: caps.reset_rdx,
327            rbx: 0,
328            rbp: 0,
329            rsp: 0,
330            rsi: 0,
331            rdi: 0,
332            r8: 0,
333            r9: 0,
334            r10: 0,
335            r11: 0,
336            r12: 0,
337            r13: 0,
338            r14: 0,
339            r15: 0,
340            rip: 0xfff0,
341            rflags: RFlags::at_reset().into(),
342            cs,
343            ds,
344            es: ds,
345            fs: ds,
346            gs: ds,
347            ss: ds,
348            tr,
349            ldtr,
350            gdtr,
351            idtr: gdtr,
352            cr0: X64_CR0_ET | X64_CR0_CD | X64_CR0_NW,
353            cr2: 0,
354            cr3: 0,
355            cr4: 0,
356            cr8: 0,
357            efer,
358        }
359    }
360}
361
362#[derive(Default, Debug, PartialEq, Eq, Protobuf, Inspect)]
363#[mesh(package = "virt.x86")]
364pub struct Activity {
365    #[mesh(1)]
366    pub mp_state: MpState,
367    #[mesh(2)]
368    pub nmi_pending: bool,
369    #[mesh(3)]
370    pub nmi_masked: bool,
371    #[mesh(4)]
372    pub interrupt_shadow: bool,
373    #[mesh(5)]
374    pub pending_event: Option<PendingEvent>,
375    #[mesh(6)]
376    pub pending_interruption: Option<PendingInterruption>,
377}
378
379#[derive(Copy, Clone, Debug, PartialEq, Eq, Protobuf, Inspect, Default)]
380#[mesh(package = "virt.x86")]
381pub enum MpState {
382    #[mesh(1)]
383    #[default]
384    Running,
385    #[mesh(2)]
386    WaitForSipi,
387    #[mesh(3)]
388    Halted,
389    #[mesh(4)]
390    Idle,
391}
392
393// N.B. This does not include the NMI pending bit, which must be get/set via the
394//      APIC page.
395impl HvRegisterState<HvX64RegisterName, 4> for Activity {
396    fn names(&self) -> &'static [HvX64RegisterName; 4] {
397        &[
398            HvX64RegisterName::InternalActivityState,
399            HvX64RegisterName::PendingInterruption,
400            HvX64RegisterName::InterruptState,
401            HvX64RegisterName::PendingEvent0,
402        ]
403    }
404
405    fn get_values<'a>(&self, it: impl Iterator<Item = &'a mut HvRegisterValue>) {
406        let mut activity = HvInternalActivityRegister::from(0);
407        match self.mp_state {
408            MpState::Running => {}
409            MpState::WaitForSipi => {
410                activity.set_startup_suspend(true);
411            }
412            MpState::Halted => {
413                activity.set_halt_suspend(true);
414            }
415            MpState::Idle => {
416                activity.set_idle_suspend(true);
417            }
418        };
419
420        let pending_event = if let Some(event) = self.pending_event {
421            match event {
422                PendingEvent::Exception {
423                    vector,
424                    error_code,
425                    parameter,
426                } => HvX64PendingExceptionEvent::new()
427                    .with_event_pending(true)
428                    .with_event_type(hvdef::HV_X64_PENDING_EVENT_EXCEPTION)
429                    .with_vector(vector.into())
430                    .with_deliver_error_code(error_code.is_some())
431                    .with_error_code(error_code.unwrap_or(0))
432                    .with_exception_parameter(parameter)
433                    .into(),
434
435                PendingEvent::ExtInt { vector } => HvX64PendingExtIntEvent::new()
436                    .with_event_pending(true)
437                    .with_event_type(hvdef::HV_X64_PENDING_EVENT_EXT_INT)
438                    .with_vector(vector)
439                    .into(),
440            }
441        } else {
442            0
443        };
444
445        let mut pending_interruption = HvX64PendingInterruptionRegister::new();
446        if let Some(interruption) = self.pending_interruption {
447            pending_interruption.set_interruption_pending(true);
448            let ty = match interruption {
449                PendingInterruption::Exception { vector, error_code } => {
450                    pending_interruption.set_interruption_vector(vector.into());
451                    pending_interruption.set_deliver_error_code(error_code.is_some());
452                    pending_interruption.set_error_code(error_code.unwrap_or(0));
453                    HvX64PendingInterruptionType::HV_X64_PENDING_EXCEPTION
454                }
455                PendingInterruption::Interrupt { vector } => {
456                    pending_interruption.set_interruption_vector(vector.into());
457                    HvX64PendingInterruptionType::HV_X64_PENDING_INTERRUPT
458                }
459                PendingInterruption::Nmi => HvX64PendingInterruptionType::HV_X64_PENDING_NMI,
460            };
461            pending_interruption.set_interruption_type(ty.0);
462        }
463
464        let interrupt_state = HvX64InterruptStateRegister::new()
465            .with_nmi_masked(self.nmi_masked)
466            .with_interrupt_shadow(self.interrupt_shadow);
467
468        for (dest, src) in it.zip([
469            HvRegisterValue::from(u64::from(activity)),
470            u64::from(pending_interruption).into(),
471            u64::from(interrupt_state).into(),
472            pending_event.into(),
473        ]) {
474            *dest = src;
475        }
476    }
477
478    fn set_values(&mut self, mut it: impl Iterator<Item = HvRegisterValue>) {
479        let activity = HvInternalActivityRegister::from(it.next().unwrap().as_u64());
480        let interruption = HvX64PendingInterruptionRegister::from(it.next().unwrap().as_u64());
481        let interrupt_state = HvX64InterruptStateRegister::from(it.next().unwrap().as_u64());
482        let event = HvX64PendingEventReg0::from(it.next().unwrap().as_u128());
483
484        let mp_state = if activity.startup_suspend() {
485            MpState::WaitForSipi
486        } else if activity.halt_suspend() {
487            MpState::Halted
488        } else if activity.idle_suspend() {
489            MpState::Idle
490        } else {
491            MpState::Running
492        };
493
494        let pending_event = event.event_pending().then(|| match event.event_type() {
495            hvdef::HV_X64_PENDING_EVENT_EXCEPTION => {
496                let event = HvX64PendingExceptionEvent::from(u128::from(event));
497                PendingEvent::Exception {
498                    vector: event.vector().try_into().expect("exception code is 8 bits"),
499                    error_code: event.deliver_error_code().then(|| event.error_code()),
500                    parameter: event.exception_parameter(),
501                }
502            }
503            hvdef::HV_X64_PENDING_EVENT_EXT_INT => {
504                let event = HvX64PendingExtIntEvent::from(u128::from(event));
505                PendingEvent::ExtInt {
506                    vector: event.vector(),
507                }
508            }
509            ty => panic!("unhandled event type: {}", ty),
510        });
511
512        let pending_interruption = interruption.interruption_pending().then(|| {
513            match HvX64PendingInterruptionType(interruption.interruption_type()) {
514                HvX64PendingInterruptionType::HV_X64_PENDING_INTERRUPT => {
515                    PendingInterruption::Interrupt {
516                        vector: interruption
517                            .interruption_vector()
518                            .try_into()
519                            .expect("x86 vector is 8 bits"),
520                    }
521                }
522                HvX64PendingInterruptionType::HV_X64_PENDING_NMI => PendingInterruption::Nmi,
523                HvX64PendingInterruptionType::HV_X64_PENDING_EXCEPTION => {
524                    PendingInterruption::Exception {
525                        vector: interruption
526                            .interruption_vector()
527                            .try_into()
528                            .expect("exception code is 8 bits"),
529                        error_code: interruption
530                            .deliver_error_code()
531                            .then(|| interruption.error_code()),
532                    }
533                }
534                ty => panic!("unhandled interruption type: {ty:?}"),
535            }
536        });
537
538        *self = Self {
539            mp_state,
540            nmi_pending: false,
541            nmi_masked: interrupt_state.nmi_masked(),
542            interrupt_shadow: interrupt_state.interrupt_shadow(),
543            pending_event,
544            pending_interruption,
545        };
546    }
547}
548
549impl StateElement<X86PartitionCapabilities, X86VpInfo> for Activity {
550    fn is_present(_caps: &X86PartitionCapabilities) -> bool {
551        true
552    }
553
554    fn at_reset(_caps: &X86PartitionCapabilities, vp_info: &X86VpInfo) -> Self {
555        let mp_state = if vp_info.base.is_bsp() {
556            MpState::Running
557        } else {
558            // FUTURE: we should really emulate INIT and SIPI to have
559            // finer-grained control over the states.
560            MpState::WaitForSipi
561        };
562        Self {
563            mp_state,
564            nmi_pending: false,
565            nmi_masked: false,
566            interrupt_shadow: false,
567            pending_event: None,
568            pending_interruption: None,
569        }
570    }
571}
572
573#[derive(Debug, PartialEq, Eq, Copy, Clone, Protobuf, Inspect)]
574#[mesh(package = "virt.x86")]
575#[inspect(external_tag)]
576pub enum PendingEvent {
577    #[mesh(1)]
578    Exception {
579        #[mesh(1)]
580        vector: u8,
581        #[mesh(2)]
582        error_code: Option<u32>,
583        #[mesh(3)]
584        parameter: u64,
585    },
586    #[mesh(2)]
587    ExtInt {
588        #[mesh(1)]
589        vector: u8,
590    },
591}
592
593#[derive(Debug, PartialEq, Eq, Copy, Clone, Protobuf, Inspect)]
594#[mesh(package = "virt.x86")]
595#[inspect(external_tag)]
596pub enum PendingInterruption {
597    #[mesh(1)]
598    Exception {
599        #[mesh(1)]
600        vector: u8,
601        #[mesh(2)]
602        error_code: Option<u32>,
603    },
604    #[mesh(2)]
605    Interrupt {
606        #[mesh(1)]
607        vector: u8,
608    },
609    #[mesh(3)]
610    Nmi,
611}
612
613#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, Protobuf, Inspect)]
614#[mesh(package = "virt.x86")]
615pub struct DebugRegisters {
616    #[mesh(1)]
617    #[inspect(hex)]
618    pub dr0: u64,
619    #[mesh(2)]
620    #[inspect(hex)]
621    pub dr1: u64,
622    #[mesh(3)]
623    #[inspect(hex)]
624    pub dr2: u64,
625    #[mesh(4)]
626    #[inspect(hex)]
627    pub dr3: u64,
628    #[mesh(5)]
629    #[inspect(hex)]
630    pub dr6: u64,
631    #[mesh(6)]
632    #[inspect(hex)]
633    pub dr7: u64,
634}
635
636impl HvRegisterState<HvX64RegisterName, 6> for DebugRegisters {
637    fn names(&self) -> &'static [HvX64RegisterName; 6] {
638        &[
639            HvX64RegisterName::Dr0,
640            HvX64RegisterName::Dr1,
641            HvX64RegisterName::Dr2,
642            HvX64RegisterName::Dr3,
643            HvX64RegisterName::Dr6,
644            HvX64RegisterName::Dr7,
645        ]
646    }
647
648    fn get_values<'a>(&self, it: impl Iterator<Item = &'a mut HvRegisterValue>) {
649        for (dest, src) in it.zip([
650            self.dr0.into(),
651            self.dr1.into(),
652            self.dr2.into(),
653            self.dr3.into(),
654            self.dr6.into(),
655            self.dr7.into(),
656        ]) {
657            *dest = src;
658        }
659    }
660
661    fn set_values(&mut self, it: impl Iterator<Item = HvRegisterValue>) {
662        for (src, dest) in it.zip([
663            &mut self.dr0,
664            &mut self.dr1,
665            &mut self.dr2,
666            &mut self.dr3,
667            &mut self.dr6,
668            &mut self.dr7,
669        ]) {
670            *dest = src.as_u64();
671        }
672    }
673}
674
675impl StateElement<X86PartitionCapabilities, X86VpInfo> for DebugRegisters {
676    fn is_present(_caps: &X86PartitionCapabilities) -> bool {
677        true
678    }
679
680    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
681        Self {
682            dr0: 0,
683            dr1: 0,
684            dr2: 0,
685            dr3: 0,
686            dr6: 0xffff0ff0,
687            dr7: 0x400,
688        }
689    }
690
691    fn can_compare(caps: &X86PartitionCapabilities) -> bool {
692        // Some machines support clearing bit 16 for some TSX debugging feature,
693        // but the hypervisor does not support restoring DR6 into this state.
694        // Ignore comparison failures in this case.
695        !caps.dr6_tsx_broken
696    }
697}
698
699#[derive(PartialEq, Eq, Protobuf)]
700#[mesh(package = "virt.x86")]
701pub struct Xsave {
702    #[mesh(1)]
703    pub data: Vec<u64>,
704}
705
706impl Xsave {
707    fn normalize(&mut self) {
708        let (mut fxsave, data) = Ref::<_, Fxsave>::from_prefix(self.data.as_mut_bytes()).unwrap();
709        let header = XsaveHeader::mut_from_prefix(data).unwrap().0; // TODO: zerocopy: ref-from-prefix: use-rest-of-range (https://github.com/microsoft/openvmm/issues/759)
710
711        // Clear the mxcsr mask since it's ignored in the restore process and
712        // will only cause xsave comparisons to fail.
713        fxsave.mxcsr_mask = 0;
714
715        // Clear SSE state if it's not actually set to anything interesting.
716        // This normalizes behavior between mshv (which always sets SSE in
717        // xstate_bv) and KVM (which does not).
718        if header.xstate_bv & XFEATURE_SSE != 0 {
719            if fxsave.xmm.iter().eq(std::iter::repeat_n(&[0; 16], 16))
720                && fxsave.mxcsr == DEFAULT_MXCSR
721            {
722                header.xstate_bv &= !XFEATURE_SSE;
723            }
724        } else {
725            fxsave.xmm.fill(Default::default());
726        }
727
728        if header.xstate_bv & (XFEATURE_SSE | XFEATURE_YMM) == 0 {
729            fxsave.mxcsr = 0;
730        }
731
732        // Clear init FPU state as well.
733        if header.xstate_bv & XFEATURE_X87 != 0 {
734            if fxsave.fcw == INIT_FCW
735                && fxsave.fsw == 0
736                && fxsave.ftw == 0
737                && fxsave.fop == 0
738                && fxsave.fip == 0
739                && fxsave.fdp == 0
740                && fxsave.st == [[0; 16]; 8]
741            {
742                fxsave.fcw = 0;
743                header.xstate_bv &= !XFEATURE_X87;
744            }
745        } else {
746            fxsave.fcw = 0;
747            fxsave.fsw = 0;
748            fxsave.ftw = 0;
749            fxsave.fop = 0;
750            fxsave.fip = 0;
751            fxsave.fdp = 0;
752            fxsave.st.fill(Default::default());
753        }
754
755        // Clear the portion of the xsave legacy region that's specified to not
756        // to be used by the processor. Never versions of KVM put garbage values
757        // in here for some (possibly incorrect) reason.
758        fxsave.unused.fill(0);
759    }
760
761    /// Construct from the xsave compact format.
762    pub fn from_compact(data: &[u8], caps: &X86PartitionCapabilities) -> Self {
763        assert_eq!(data.len() % 8, 0);
764        let mut aligned = vec![0; data.len() / 8];
765        aligned.as_mut_bytes().copy_from_slice(data);
766        let mut this = Self { data: aligned };
767
768        this.normalize();
769
770        // Some versions of the MS hypervisor fail to set xstate_bv for
771        // supervisor states. In this case, force-enable them--this is always
772        // safe (since their init state == zero) and does not have a performance
773        // penalty.
774        if caps.xsaves_state_bv_broken {
775            let header =
776                XsaveHeader::mut_from_prefix(&mut this.data.as_mut_bytes()[XSAVE_LEGACY_LEN..])
777                    .unwrap()
778                    .0; // TODO: zerocopy: ref-from-prefix: use-rest-of-range (https://github.com/microsoft/openvmm/issues/759)
779
780            // Just enable supervisor states that were possible when the
781            // hypervisor had the bug. Future ones will only be supported by
782            // fixed hypervisors.
783            header.xstate_bv |= header.xcomp_bv & 0x1c00;
784        }
785
786        this
787    }
788
789    /// Construct from standard (non-compact) xsave format.
790    pub fn from_standard(src: &[u8], caps: &X86PartitionCapabilities) -> Self {
791        let mut this = Self {
792            data: vec![0; caps.xsave.compact_len as usize / 8],
793        };
794        this.data.as_mut_bytes()[..XSAVE_VARIABLE_OFFSET]
795            .copy_from_slice(&src[..XSAVE_VARIABLE_OFFSET]);
796
797        let (mut header, data) =
798            Ref::<_, XsaveHeader>::from_prefix(&mut this.data.as_mut_bytes()[XSAVE_LEGACY_LEN..])
799                .unwrap();
800
801        header.xcomp_bv = caps.xsave.features | caps.xsave.supervisor_features | XCOMP_COMPRESSED;
802        let mut cur = 0;
803        for i in 2..63 {
804            if header.xcomp_bv & (1 << i) != 0 {
805                let feature = &caps.xsave.feature_info[i];
806                let offset = feature.offset as usize;
807                let len = feature.len as usize;
808                if feature.align {
809                    cur = (cur + 63) & !63;
810                }
811                if header.xstate_bv & (1 << i) != 0 {
812                    data[cur..cur + len].copy_from_slice(&src[offset..offset + len]);
813                }
814                cur += len;
815            }
816        }
817        this.normalize();
818        this
819    }
820
821    /// Write out to standard (non-compact) xsave format.
822    pub fn write_standard(&self, data: &mut [u8], caps: &X86PartitionCapabilities) {
823        // Copy the legacy region including default values for disabled features.
824        data[..XSAVE_LEGACY_LEN].copy_from_slice(self.fxsave().as_bytes());
825
826        // Copy the xsave header but clear xcomp_bv.
827        let header = self.xsave_header();
828        data[XSAVE_LEGACY_LEN..XSAVE_VARIABLE_OFFSET].copy_from_slice(
829            XsaveHeader {
830                xcomp_bv: 0,
831                ..*header
832            }
833            .as_bytes(),
834        );
835
836        // Copy the features.
837        let mut cur = XSAVE_VARIABLE_OFFSET;
838        for i in 2..63 {
839            if header.xcomp_bv & (1 << i) != 0 {
840                let feature = &caps.xsave.feature_info[i];
841                let offset = feature.offset as usize;
842                let len = feature.len as usize;
843                if feature.align {
844                    cur = (cur + 63) & !63;
845                }
846                if header.xstate_bv & (1 << i) != 0 {
847                    data[offset..offset + len]
848                        .copy_from_slice(&self.data.as_bytes()[cur..cur + len]);
849                }
850                cur += len;
851            }
852        }
853    }
854
855    /// Returns the compact form.
856    pub fn compact(&self) -> &[u8] {
857        self.data.as_bytes()
858    }
859
860    /// Returns the legacy fxsave state only.
861    ///
862    /// Since this does not include `xstate_bv`, fields for disabled features
863    /// will be set to their default values.
864    pub fn fxsave(&self) -> Fxsave {
865        let mut fxsave = Fxsave::read_from_prefix(self.data.as_bytes()).unwrap().0; // TODO: zerocopy: use-rest-of-range (https://github.com/microsoft/openvmm/issues/759)
866        let header = self.xsave_header();
867        if header.xstate_bv & XFEATURE_X87 == 0 {
868            fxsave.fcw = INIT_FCW;
869        }
870        if header.xstate_bv & (XFEATURE_SSE | XFEATURE_YMM) == 0 {
871            fxsave.mxcsr = DEFAULT_MXCSR;
872        }
873        fxsave
874    }
875
876    fn xsave_header(&self) -> &XsaveHeader {
877        XsaveHeader::ref_from_prefix(&self.data.as_bytes()[XSAVE_LEGACY_LEN..])
878            .unwrap()
879            .0 // TODO: zerocopy: ref-from-prefix: use-rest-of-range (https://github.com/microsoft/openvmm/issues/759)
880    }
881}
882
883impl Debug for Xsave {
884    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
885        f.debug_struct("Xsave")
886            .field("legacy", &format_args!("{:x?}", self.fxsave()))
887            .field("header", &format_args!("{:x?}", self.xsave_header()))
888            .field("data", &&self.data[XSAVE_VARIABLE_OFFSET / 8..])
889            .finish()
890    }
891}
892
893impl Inspect for Xsave {
894    fn inspect(&self, req: inspect::Request<'_>) {
895        let Fxsave {
896            fcw,
897            fsw,
898            ftw,
899            reserved: _,
900            fop,
901            fip,
902            fdp,
903            mxcsr,
904            mxcsr_mask,
905            st,
906            xmm,
907            reserved2: _,
908            unused: _,
909        } = self.fxsave();
910
911        let &XsaveHeader {
912            xstate_bv,
913            xcomp_bv,
914            reserved: _,
915        } = self.xsave_header();
916
917        let mut resp = req.respond();
918        resp.hex("fcw", fcw)
919            .hex("fsw", fsw)
920            .hex("ftw", ftw)
921            .hex("fop", fop)
922            .hex("fip", fip)
923            .hex("fdp", fdp)
924            .hex("mxcsr", mxcsr)
925            .hex("mxcsr_mask", mxcsr_mask)
926            .hex("xstate_bv", xstate_bv)
927            .hex("xcomp_bv", xcomp_bv);
928
929        for (st, name) in st
930            .iter()
931            .zip(["st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7"])
932        {
933            resp.field(name, st);
934        }
935
936        for (xmm, name) in xmm.iter().zip([
937            "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9",
938            "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
939        ]) {
940            resp.field(name, xmm);
941        }
942    }
943}
944
945impl StateElement<X86PartitionCapabilities, X86VpInfo> for Xsave {
946    fn is_present(_caps: &X86PartitionCapabilities) -> bool {
947        true
948    }
949
950    fn at_reset(caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
951        let mut data = vec![0; caps.xsave.compact_len as usize];
952        *XsaveHeader::mut_from_prefix(&mut data[XSAVE_LEGACY_LEN..])
953            .unwrap()
954            .0 = XsaveHeader {
955            // TODO: zerocopy: ref-from-prefix: use-rest-of-range (https://github.com/microsoft/openvmm/issues/759)
956            xstate_bv: 0,
957            xcomp_bv: XCOMP_COMPRESSED | caps.xsave.features | caps.xsave.supervisor_features,
958            reserved: [0; 6],
959        };
960        Self::from_compact(&data, caps)
961    }
962}
963
964#[derive(PartialEq, Eq, Clone, Protobuf, Inspect)]
965#[mesh(package = "virt.x86")]
966#[inspect(hex)]
967pub struct Apic {
968    #[mesh(1)]
969    pub apic_base: u64,
970    #[inspect(with = "ApicRegisters::from_array_ref")]
971    #[mesh(2)]
972    pub registers: [u32; 64],
973    #[inspect(iter_by_index)]
974    #[mesh(3)]
975    pub auto_eoi: [u32; 8],
976}
977
978impl Debug for Apic {
979    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
980        let Self {
981            apic_base,
982            registers,
983            auto_eoi,
984        } = self;
985        f.debug_struct("Apic")
986            .field("apic_base", &format_args!("{:#x}", apic_base))
987            .field("registers", &format_args!("{:#x?}", registers))
988            .field("registers", &format_args!("{:#x?}", auto_eoi))
989            .finish()
990    }
991}
992
993impl Apic {
994    pub fn new(apic_base: ApicBase, registers: ApicRegisters, auto_eoi: [u32; 8]) -> Self {
995        Self {
996            apic_base: apic_base.into(),
997            registers: *registers.as_array(),
998            auto_eoi,
999        }
1000    }
1001
1002    pub fn registers(&self) -> &ApicRegisters {
1003        ApicRegisters::from_array_ref(&self.registers)
1004    }
1005}
1006
1007#[repr(C)]
1008#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1009#[inspect(hex)]
1010pub struct ApicRegisters {
1011    #[inspect(skip)]
1012    pub reserved_0: [u32; 2],
1013    pub id: u32,
1014    pub version: u32,
1015    #[inspect(skip)]
1016    pub reserved_4: [u32; 4],
1017    pub tpr: u32, // Task Priority Register
1018    pub apr: u32, // Arbitration Priority Register
1019    pub ppr: u32, // Processor Priority Register
1020    pub eoi: u32, //
1021    pub rrd: u32, // Remote Read Register
1022    pub ldr: u32, // Logical Destination Register
1023    pub dfr: u32, // Destination Format Register
1024    pub svr: u32, // Spurious Interrupt Vector
1025    #[inspect(iter_by_index)]
1026    pub isr: [u32; 8], // In-Service Register
1027    #[inspect(iter_by_index)]
1028    pub tmr: [u32; 8], // Trigger Mode Register
1029    #[inspect(iter_by_index)]
1030    pub irr: [u32; 8], // Interrupt Request Register
1031    pub esr: u32, // Error Status Register
1032    #[inspect(skip)]
1033    pub reserved_29: [u32; 6],
1034    pub lvt_cmci: u32,
1035    #[inspect(iter_by_index)]
1036    pub icr: [u32; 2], // Interrupt Command Register
1037    pub lvt_timer: u32,
1038    pub lvt_thermal: u32,
1039    pub lvt_pmc: u32,
1040    pub lvt_lint0: u32,
1041    pub lvt_lint1: u32,
1042    pub lvt_error: u32,
1043    pub timer_icr: u32, // Initial Count Register
1044    pub timer_ccr: u32, // Current Count Register
1045    #[inspect(skip)]
1046    pub reserved_3a: [u32; 4],
1047    pub timer_dcr: u32, // Divide Configuration Register
1048    #[inspect(skip)]
1049    pub reserved_3f: u32,
1050}
1051
1052const _: () = assert!(size_of::<ApicRegisters>() == 0x100);
1053
1054impl From<ApicRegisters> for hvdef::HvX64InterruptControllerState {
1055    fn from(value: ApicRegisters) -> Self {
1056        Self {
1057            apic_id: value.id,
1058            apic_version: value.version,
1059            apic_ldr: value.ldr,
1060            apic_dfr: value.dfr,
1061            apic_spurious: value.svr,
1062            apic_isr: value.isr,
1063            apic_tmr: value.tmr,
1064            apic_irr: value.irr,
1065            apic_esr: value.esr,
1066            apic_icr_high: value.icr[1],
1067            apic_icr_low: value.icr[0],
1068            apic_lvt_timer: value.lvt_timer,
1069            apic_lvt_thermal: value.lvt_thermal,
1070            apic_lvt_perfmon: value.lvt_pmc,
1071            apic_lvt_lint0: value.lvt_lint0,
1072            apic_lvt_lint1: value.lvt_lint1,
1073            apic_lvt_error: value.lvt_error,
1074            apic_lvt_cmci: value.lvt_cmci,
1075            apic_error_status: value.esr,
1076            apic_initial_count: value.timer_icr,
1077            apic_counter_value: value.timer_ccr,
1078            apic_divide_configuration: value.timer_dcr,
1079            apic_remote_read: value.rrd,
1080        }
1081    }
1082}
1083
1084impl From<hvdef::HvX64InterruptControllerState> for ApicRegisters {
1085    fn from(value: hvdef::HvX64InterruptControllerState) -> Self {
1086        let hvdef::HvX64InterruptControllerState {
1087            apic_id,
1088            apic_version,
1089            apic_ldr,
1090            apic_dfr,
1091            apic_spurious,
1092            apic_isr,
1093            apic_tmr,
1094            apic_irr,
1095            apic_esr,
1096            apic_icr_high,
1097            apic_icr_low,
1098            apic_lvt_timer,
1099            apic_lvt_thermal,
1100            apic_lvt_perfmon,
1101            apic_lvt_lint0,
1102            apic_lvt_lint1,
1103            apic_lvt_error,
1104            apic_lvt_cmci,
1105            // The unlatched error status is not preserved across save/restore.
1106            apic_error_status: _,
1107            apic_initial_count,
1108            apic_counter_value,
1109            apic_divide_configuration,
1110            apic_remote_read,
1111        } = value;
1112        Self {
1113            reserved_0: [0; 2],
1114            id: apic_id,
1115            version: apic_version,
1116            reserved_4: [0; 4],
1117            tpr: 0,
1118            apr: 0,
1119            ppr: 0,
1120            eoi: 0,
1121            rrd: apic_remote_read,
1122            ldr: apic_ldr,
1123            dfr: apic_dfr,
1124            svr: apic_spurious,
1125            isr: apic_isr,
1126            tmr: apic_tmr,
1127            irr: apic_irr,
1128            esr: apic_esr,
1129            reserved_29: [0; 6],
1130            lvt_cmci: apic_lvt_cmci,
1131            icr: [apic_icr_low, apic_icr_high],
1132            lvt_timer: apic_lvt_timer,
1133            lvt_thermal: apic_lvt_thermal,
1134            lvt_pmc: apic_lvt_perfmon,
1135            lvt_lint0: apic_lvt_lint0,
1136            lvt_lint1: apic_lvt_lint1,
1137            lvt_error: apic_lvt_error,
1138            timer_icr: apic_initial_count,
1139            timer_ccr: apic_counter_value,
1140            reserved_3a: [0; 4],
1141            timer_dcr: apic_divide_configuration,
1142            reserved_3f: 0,
1143        }
1144    }
1145}
1146
1147#[repr(C)]
1148#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1149struct ApicRegister {
1150    value: u32,
1151    zero: [u32; 3],
1152}
1153
1154impl ApicRegisters {
1155    pub fn as_array(&self) -> &[u32; 64] {
1156        zerocopy::transmute_ref!(self)
1157    }
1158
1159    pub fn from_array(array: [u32; 64]) -> Self {
1160        zerocopy::transmute!(array)
1161    }
1162
1163    pub fn from_array_ref(array: &[u32; 64]) -> &Self {
1164        zerocopy::transmute_ref!(array)
1165    }
1166
1167    pub fn as_page(&self) -> [u8; 1024] {
1168        let mut bytes = [0; 1024];
1169        self.as_array()
1170            .map(|value| ApicRegister {
1171                value,
1172                zero: [0; 3],
1173            })
1174            .write_to(bytes.as_mut_slice())
1175            .unwrap();
1176        bytes
1177    }
1178
1179    /// Convert from an APIC page.
1180    pub fn from_page(page: &[u8; 1024]) -> Self {
1181        let registers = <[ApicRegister; 64]>::read_from_bytes(page.as_slice()).unwrap();
1182        Self::from_array(registers.map(|reg| reg.value))
1183    }
1184}
1185
1186impl StateElement<X86PartitionCapabilities, X86VpInfo> for Apic {
1187    fn is_present(_caps: &X86PartitionCapabilities) -> bool {
1188        true
1189    }
1190
1191    fn at_reset(caps: &X86PartitionCapabilities, vp_info: &X86VpInfo) -> Self {
1192        let x2apic = caps.x2apic_enabled;
1193
1194        let mut regs = ApicRegisters::new_zeroed();
1195        regs.id = if x2apic {
1196            vp_info.apic_id
1197        } else {
1198            vp_info.apic_id << 24
1199        };
1200        regs.version = ApicVersion::new()
1201            .with_version(0x14)
1202            .with_max_lvt_entry(5)
1203            .into();
1204        if x2apic {
1205            regs.ldr = ((vp_info.apic_id << 12) & 0xffff0000) | (1 << (vp_info.apic_id & 0xf));
1206        } else {
1207            regs.dfr = !0;
1208        }
1209        regs.svr = 0xff;
1210        regs.lvt_timer = 0x10000;
1211        regs.lvt_thermal = 0x10000;
1212        regs.lvt_pmc = 0x10000;
1213        regs.lvt_lint0 = 0x10000;
1214        regs.lvt_lint1 = 0x10000;
1215        regs.lvt_error = 0x10000;
1216
1217        let apic_base = ApicBase::new()
1218            .with_base_page(APIC_BASE_PAGE)
1219            .with_bsp(vp_info.base.is_bsp())
1220            .with_x2apic(x2apic)
1221            .with_enable(true);
1222
1223        Apic::new(apic_base, regs, [0; 8])
1224    }
1225
1226    fn can_compare(caps: &X86PartitionCapabilities) -> bool {
1227        // If a partition (ie KVM) cannot freeze time, one of the APIC timer values will continue counting up after restore.
1228        // For now, disallow comparing the whole Apic structure if so.
1229        caps.can_freeze_time
1230    }
1231}
1232
1233// The IRR bit number corresponding to NMI pending in the Hyper-V exo APIC saved
1234// state.
1235const NMI_VECTOR: u32 = 2;
1236
1237impl ApicRegisters {
1238    /// Sets the non-architectural Hyper-V NMI pending bit in the APIC page.
1239    pub fn set_hv_apic_nmi_pending(&mut self, pending: bool) {
1240        self.irr[0] &= !(1 << NMI_VECTOR);
1241        self.irr[0] |= (pending as u32) << NMI_VECTOR;
1242    }
1243
1244    /// Gets the non-architectural Hyper-V NMI pending bit from the APIC page.
1245    pub fn hv_apic_nmi_pending(&self) -> bool {
1246        self.irr[0] & (1 << NMI_VECTOR) != 0
1247    }
1248}
1249
1250#[derive(Debug, Default, PartialEq, Eq, Protobuf, Inspect)]
1251#[mesh(package = "virt.x86")]
1252pub struct Xcr0 {
1253    #[mesh(1)]
1254    #[inspect(hex)]
1255    pub value: u64,
1256}
1257
1258impl HvRegisterState<HvX64RegisterName, 1> for Xcr0 {
1259    fn names(&self) -> &'static [HvX64RegisterName; 1] {
1260        &[HvX64RegisterName::Xfem]
1261    }
1262
1263    fn get_values<'a>(&self, it: impl Iterator<Item = &'a mut HvRegisterValue>) {
1264        for (dest, src) in it.zip([self.value]) {
1265            *dest = src.into();
1266        }
1267    }
1268
1269    fn set_values(&mut self, it: impl Iterator<Item = HvRegisterValue>) {
1270        for (src, dest) in it.zip([&mut self.value]) {
1271            *dest = src.as_u64();
1272        }
1273    }
1274}
1275
1276impl StateElement<X86PartitionCapabilities, X86VpInfo> for Xcr0 {
1277    fn is_present(caps: &X86PartitionCapabilities) -> bool {
1278        caps.xsave.features != 0
1279    }
1280
1281    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1282        Self { value: 1 }
1283    }
1284}
1285
1286#[derive(Debug, Default, PartialEq, Eq, Protobuf, Inspect)]
1287#[mesh(package = "virt.x86")]
1288pub struct Xss {
1289    #[mesh(1)]
1290    #[inspect(hex)]
1291    pub value: u64,
1292}
1293
1294impl HvRegisterState<HvX64RegisterName, 1> for Xss {
1295    fn names(&self) -> &'static [HvX64RegisterName; 1] {
1296        &[HvX64RegisterName::Xss]
1297    }
1298
1299    fn get_values<'a>(&self, it: impl Iterator<Item = &'a mut HvRegisterValue>) {
1300        for (dest, src) in it.zip([self.value]) {
1301            *dest = src.into();
1302        }
1303    }
1304
1305    fn set_values(&mut self, it: impl Iterator<Item = HvRegisterValue>) {
1306        for (src, dest) in it.zip([&mut self.value]) {
1307            *dest = src.as_u64();
1308        }
1309    }
1310}
1311
1312impl StateElement<X86PartitionCapabilities, X86VpInfo> for Xss {
1313    fn is_present(caps: &X86PartitionCapabilities) -> bool {
1314        caps.xsave.supervisor_features != 0
1315    }
1316
1317    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1318        Self { value: 0 }
1319    }
1320}
1321
1322#[repr(C)]
1323#[derive(Default, Debug, PartialEq, Eq, Protobuf, Inspect)]
1324#[mesh(package = "virt.x86")]
1325pub struct Pat {
1326    #[mesh(1)]
1327    #[inspect(hex)]
1328    pub value: u64,
1329}
1330
1331impl HvRegisterState<HvX64RegisterName, 1> for Pat {
1332    fn names(&self) -> &'static [HvX64RegisterName; 1] {
1333        &[HvX64RegisterName::Pat]
1334    }
1335
1336    fn get_values<'a>(&self, it: impl Iterator<Item = &'a mut HvRegisterValue>) {
1337        for (dest, src) in it.zip([self.value]) {
1338            *dest = src.into();
1339        }
1340    }
1341
1342    fn set_values(&mut self, it: impl Iterator<Item = HvRegisterValue>) {
1343        for (src, dest) in it.zip([&mut self.value]) {
1344            *dest = src.as_u64();
1345        }
1346    }
1347}
1348
1349impl StateElement<X86PartitionCapabilities, X86VpInfo> for Pat {
1350    fn is_present(_caps: &X86PartitionCapabilities) -> bool {
1351        true
1352    }
1353
1354    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1355        Self {
1356            value: X86X_MSR_DEFAULT_PAT,
1357        }
1358    }
1359}
1360
1361#[repr(C)]
1362#[derive(Default, Debug, PartialEq, Eq, Protobuf, Inspect)]
1363#[mesh(package = "virt.x86")]
1364#[inspect(hex)]
1365pub struct Mtrrs {
1366    #[mesh(1)]
1367    #[inspect(hex)]
1368    pub msr_mtrr_def_type: u64,
1369    #[mesh(2)]
1370    #[inspect(iter_by_index)]
1371    pub fixed: [u64; 11],
1372    #[mesh(3)]
1373    #[inspect(iter_by_index)]
1374    pub variable: [u64; 16],
1375}
1376
1377impl HvRegisterState<HvX64RegisterName, 28> for Mtrrs {
1378    fn names(&self) -> &'static [HvX64RegisterName; 28] {
1379        &[
1380            HvX64RegisterName::MsrMtrrDefType,
1381            HvX64RegisterName::MsrMtrrFix64k00000,
1382            HvX64RegisterName::MsrMtrrFix16k80000,
1383            HvX64RegisterName::MsrMtrrFix16kA0000,
1384            HvX64RegisterName::MsrMtrrFix4kC0000,
1385            HvX64RegisterName::MsrMtrrFix4kC8000,
1386            HvX64RegisterName::MsrMtrrFix4kD0000,
1387            HvX64RegisterName::MsrMtrrFix4kD8000,
1388            HvX64RegisterName::MsrMtrrFix4kE0000,
1389            HvX64RegisterName::MsrMtrrFix4kE8000,
1390            HvX64RegisterName::MsrMtrrFix4kF0000,
1391            HvX64RegisterName::MsrMtrrFix4kF8000,
1392            HvX64RegisterName::MsrMtrrPhysBase0,
1393            HvX64RegisterName::MsrMtrrPhysMask0,
1394            HvX64RegisterName::MsrMtrrPhysBase1,
1395            HvX64RegisterName::MsrMtrrPhysMask1,
1396            HvX64RegisterName::MsrMtrrPhysBase2,
1397            HvX64RegisterName::MsrMtrrPhysMask2,
1398            HvX64RegisterName::MsrMtrrPhysBase3,
1399            HvX64RegisterName::MsrMtrrPhysMask3,
1400            HvX64RegisterName::MsrMtrrPhysBase4,
1401            HvX64RegisterName::MsrMtrrPhysMask4,
1402            HvX64RegisterName::MsrMtrrPhysBase5,
1403            HvX64RegisterName::MsrMtrrPhysMask5,
1404            HvX64RegisterName::MsrMtrrPhysBase6,
1405            HvX64RegisterName::MsrMtrrPhysMask6,
1406            HvX64RegisterName::MsrMtrrPhysBase7,
1407            HvX64RegisterName::MsrMtrrPhysMask7,
1408        ]
1409    }
1410
1411    fn get_values<'a>(&self, it: impl Iterator<Item = &'a mut HvRegisterValue>) {
1412        for (dest, src) in it.zip(
1413            [self.msr_mtrr_def_type]
1414                .into_iter()
1415                .chain(self.fixed)
1416                .chain(self.variable),
1417        ) {
1418            *dest = src.into();
1419        }
1420    }
1421
1422    fn set_values(&mut self, it: impl Iterator<Item = HvRegisterValue>) {
1423        for (src, dest) in it.zip(
1424            [&mut self.msr_mtrr_def_type]
1425                .into_iter()
1426                .chain(&mut self.fixed)
1427                .chain(&mut self.variable),
1428        ) {
1429            *dest = src.as_u64();
1430        }
1431    }
1432}
1433
1434impl StateElement<X86PartitionCapabilities, X86VpInfo> for Mtrrs {
1435    fn is_present(_caps: &X86PartitionCapabilities) -> bool {
1436        true
1437    }
1438
1439    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1440        Self {
1441            msr_mtrr_def_type: 0,
1442            fixed: [0; 11],
1443            variable: [0; 16],
1444        }
1445    }
1446}
1447
1448#[repr(C)]
1449#[derive(Default, Debug, PartialEq, Eq, Protobuf, Inspect)]
1450#[mesh(package = "virt.x86")]
1451#[inspect(hex)]
1452pub struct VirtualMsrs {
1453    #[mesh(1)]
1454    pub kernel_gs_base: u64,
1455    #[mesh(2)]
1456    pub sysenter_cs: u64,
1457    #[mesh(3)]
1458    pub sysenter_eip: u64,
1459    #[mesh(4)]
1460    pub sysenter_esp: u64,
1461    #[mesh(5)]
1462    pub star: u64,
1463    #[mesh(6)]
1464    pub lstar: u64,
1465    #[mesh(7)]
1466    pub cstar: u64,
1467    #[mesh(8)]
1468    pub sfmask: u64,
1469}
1470
1471impl HvRegisterState<HvX64RegisterName, 8> for VirtualMsrs {
1472    fn names(&self) -> &'static [HvX64RegisterName; 8] {
1473        &[
1474            HvX64RegisterName::KernelGsBase,
1475            HvX64RegisterName::SysenterCs,
1476            HvX64RegisterName::SysenterEsp,
1477            HvX64RegisterName::SysenterEip,
1478            HvX64RegisterName::Star,
1479            HvX64RegisterName::Lstar,
1480            HvX64RegisterName::Cstar,
1481            HvX64RegisterName::Sfmask,
1482        ]
1483    }
1484
1485    fn get_values<'a>(&self, it: impl Iterator<Item = &'a mut HvRegisterValue>) {
1486        for (dest, src) in it.zip([
1487            self.kernel_gs_base,
1488            self.sysenter_cs,
1489            self.sysenter_eip,
1490            self.sysenter_esp,
1491            self.star,
1492            self.lstar,
1493            self.cstar,
1494            self.sfmask,
1495        ]) {
1496            *dest = src.into();
1497        }
1498    }
1499
1500    fn set_values(&mut self, it: impl Iterator<Item = HvRegisterValue>) {
1501        for (src, dest) in it.zip([
1502            &mut self.kernel_gs_base,
1503            &mut self.sysenter_cs,
1504            &mut self.sysenter_eip,
1505            &mut self.sysenter_esp,
1506            &mut self.star,
1507            &mut self.lstar,
1508            &mut self.cstar,
1509            &mut self.sfmask,
1510        ]) {
1511            *dest = src.as_u64();
1512        }
1513    }
1514}
1515
1516impl StateElement<X86PartitionCapabilities, X86VpInfo> for VirtualMsrs {
1517    fn is_present(_caps: &X86PartitionCapabilities) -> bool {
1518        true
1519    }
1520
1521    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1522        Self {
1523            kernel_gs_base: 0,
1524            sysenter_cs: 0,
1525            sysenter_eip: 0,
1526            sysenter_esp: 0,
1527            star: 0,
1528            lstar: 0,
1529            cstar: 0,
1530            sfmask: 0,
1531        }
1532    }
1533}
1534
1535#[repr(C)]
1536#[derive(Default, Debug, PartialEq, Eq, Protobuf, Inspect)]
1537#[mesh(package = "virt.x86")]
1538pub struct TscAux {
1539    #[mesh(1)]
1540    #[inspect(hex)]
1541    pub value: u64,
1542}
1543
1544impl HvRegisterState<HvX64RegisterName, 1> for TscAux {
1545    fn names(&self) -> &'static [HvX64RegisterName; 1] {
1546        &[HvX64RegisterName::TscAux]
1547    }
1548
1549    fn get_values<'a>(&self, it: impl Iterator<Item = &'a mut HvRegisterValue>) {
1550        for (dest, src) in it.zip([self.value]) {
1551            *dest = src.into();
1552        }
1553    }
1554
1555    fn set_values(&mut self, it: impl Iterator<Item = HvRegisterValue>) {
1556        for (src, dest) in it.zip([&mut self.value]) {
1557            *dest = src.as_u64();
1558        }
1559    }
1560}
1561
1562impl StateElement<X86PartitionCapabilities, X86VpInfo> for TscAux {
1563    fn is_present(caps: &X86PartitionCapabilities) -> bool {
1564        caps.tsc_aux
1565    }
1566
1567    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1568        Default::default()
1569    }
1570}
1571
1572#[repr(C)]
1573#[derive(Default, Debug, PartialEq, Eq, Protobuf, Inspect)]
1574#[mesh(package = "virt.x86")]
1575pub struct Tsc {
1576    #[mesh(1)]
1577    #[inspect(hex)]
1578    pub value: u64,
1579}
1580
1581impl HvRegisterState<HvX64RegisterName, 1> for Tsc {
1582    fn names(&self) -> &'static [HvX64RegisterName; 1] {
1583        &[HvX64RegisterName::Tsc]
1584    }
1585
1586    fn get_values<'a>(&self, it: impl Iterator<Item = &'a mut HvRegisterValue>) {
1587        for (dest, src) in it.zip([self.value]) {
1588            *dest = src.into();
1589        }
1590    }
1591
1592    fn set_values(&mut self, it: impl Iterator<Item = HvRegisterValue>) {
1593        for (src, dest) in it.zip([&mut self.value]) {
1594            *dest = src.as_u64();
1595        }
1596    }
1597}
1598
1599impl StateElement<X86PartitionCapabilities, X86VpInfo> for Tsc {
1600    fn is_present(_caps: &X86PartitionCapabilities) -> bool {
1601        true
1602    }
1603
1604    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1605        Self { value: 0 }
1606    }
1607
1608    fn can_compare(caps: &X86PartitionCapabilities) -> bool {
1609        caps.can_freeze_time
1610    }
1611}
1612
1613#[repr(C)]
1614#[derive(Default, Debug, PartialEq, Eq, Protobuf, Inspect)]
1615#[mesh(package = "virt.x86")]
1616pub struct Cet {
1617    #[mesh(1)]
1618    #[inspect(hex)]
1619    pub scet: u64,
1620    // Ucet is part of xsave state.
1621}
1622
1623impl HvRegisterState<HvX64RegisterName, 1> for Cet {
1624    fn names(&self) -> &'static [HvX64RegisterName; 1] {
1625        &[HvX64RegisterName::SCet]
1626    }
1627
1628    fn get_values<'a>(&self, it: impl Iterator<Item = &'a mut HvRegisterValue>) {
1629        for (dest, src) in it.zip([self.scet]) {
1630            *dest = src.into();
1631        }
1632    }
1633
1634    fn set_values(&mut self, it: impl Iterator<Item = HvRegisterValue>) {
1635        for (src, dest) in it.zip([&mut self.scet]) {
1636            *dest = src.as_u64();
1637        }
1638    }
1639}
1640
1641impl StateElement<X86PartitionCapabilities, X86VpInfo> for Cet {
1642    fn is_present(caps: &X86PartitionCapabilities) -> bool {
1643        caps.cet
1644    }
1645
1646    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1647        Self { scet: 0 }
1648    }
1649}
1650
1651#[repr(C)]
1652#[derive(Default, Debug, PartialEq, Eq, Protobuf, Inspect)]
1653#[mesh(package = "virt.x86")]
1654#[inspect(hex)]
1655pub struct CetSs {
1656    #[mesh(1)]
1657    pub ssp: u64,
1658    #[mesh(2)]
1659    pub interrupt_ssp_table_addr: u64,
1660    // Plx_ssp are part of xsave state.
1661}
1662
1663impl HvRegisterState<HvX64RegisterName, 2> for CetSs {
1664    fn names(&self) -> &'static [HvX64RegisterName; 2] {
1665        &[
1666            HvX64RegisterName::Ssp,
1667            HvX64RegisterName::InterruptSspTableAddr,
1668        ]
1669    }
1670
1671    fn get_values<'a>(&self, it: impl Iterator<Item = &'a mut HvRegisterValue>) {
1672        for (dest, src) in it.zip([self.ssp, self.interrupt_ssp_table_addr]) {
1673            *dest = src.into();
1674        }
1675    }
1676
1677    fn set_values(&mut self, it: impl Iterator<Item = HvRegisterValue>) {
1678        for (src, dest) in it.zip([&mut self.ssp, &mut self.interrupt_ssp_table_addr]) {
1679            *dest = src.as_u64();
1680        }
1681    }
1682}
1683
1684impl StateElement<X86PartitionCapabilities, X86VpInfo> for CetSs {
1685    fn is_present(caps: &X86PartitionCapabilities) -> bool {
1686        caps.cet_ss
1687    }
1688
1689    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1690        Default::default()
1691    }
1692}
1693
1694#[repr(C)]
1695#[derive(Debug, Default, PartialEq, Eq, Protobuf, Inspect)]
1696#[mesh(package = "virt.x86")]
1697#[inspect(hex)]
1698pub struct SyntheticMsrs {
1699    #[mesh(1)]
1700    pub vp_assist_page: u64,
1701    #[mesh(2)]
1702    pub scontrol: u64,
1703    #[mesh(3)]
1704    pub siefp: u64,
1705    #[mesh(4)]
1706    pub simp: u64,
1707    #[mesh(5)]
1708    #[inspect(iter_by_index)]
1709    pub sint: [u64; 16],
1710}
1711
1712impl HvRegisterState<HvX64RegisterName, 20> for SyntheticMsrs {
1713    fn names(&self) -> &'static [HvX64RegisterName; 20] {
1714        &[
1715            HvX64RegisterName::VpAssistPage,
1716            HvX64RegisterName::Scontrol,
1717            HvX64RegisterName::Sifp,
1718            HvX64RegisterName::Sipp,
1719            HvX64RegisterName::Sint0,
1720            HvX64RegisterName::Sint1,
1721            HvX64RegisterName::Sint2,
1722            HvX64RegisterName::Sint3,
1723            HvX64RegisterName::Sint4,
1724            HvX64RegisterName::Sint5,
1725            HvX64RegisterName::Sint6,
1726            HvX64RegisterName::Sint7,
1727            HvX64RegisterName::Sint8,
1728            HvX64RegisterName::Sint9,
1729            HvX64RegisterName::Sint10,
1730            HvX64RegisterName::Sint11,
1731            HvX64RegisterName::Sint12,
1732            HvX64RegisterName::Sint13,
1733            HvX64RegisterName::Sint14,
1734            HvX64RegisterName::Sint15,
1735        ]
1736    }
1737    fn get_values<'a>(&self, it: impl Iterator<Item = &'a mut HvRegisterValue>) {
1738        for (dest, src) in it.zip(
1739            [self.vp_assist_page, self.scontrol, self.siefp, self.simp]
1740                .into_iter()
1741                .chain(self.sint),
1742        ) {
1743            *dest = src.into();
1744        }
1745    }
1746
1747    fn set_values(&mut self, it: impl Iterator<Item = HvRegisterValue>) {
1748        for (src, dest) in it.zip(
1749            [
1750                &mut self.vp_assist_page,
1751                &mut self.scontrol,
1752                &mut self.siefp,
1753                &mut self.simp,
1754            ]
1755            .into_iter()
1756            .chain(&mut self.sint),
1757        ) {
1758            *dest = src.as_u64();
1759        }
1760    }
1761}
1762
1763impl StateElement<X86PartitionCapabilities, X86VpInfo> for SyntheticMsrs {
1764    fn is_present(caps: &X86PartitionCapabilities) -> bool {
1765        caps.hv1
1766    }
1767
1768    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1769        Self {
1770            vp_assist_page: 0,
1771            scontrol: 1,
1772            siefp: 0,
1773            simp: 0,
1774            sint: [0x10000; 16],
1775        }
1776    }
1777}
1778
1779#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Protobuf, Inspect)]
1780#[mesh(package = "virt.x86")]
1781#[inspect(hex)]
1782pub struct SynicTimer {
1783    #[mesh(1)]
1784    pub config: u64,
1785    #[mesh(2)]
1786    pub count: u64,
1787    #[mesh(3)]
1788    pub adjustment: u64,
1789    #[mesh(4)]
1790    pub undelivered_message_expiration_time: Option<u64>,
1791}
1792
1793#[derive(Debug, Copy, Clone, Eq, PartialEq, Protobuf, Inspect)]
1794#[mesh(package = "virt.x86")]
1795pub struct SynicTimers {
1796    #[mesh(1)]
1797    #[inspect(iter_by_index)]
1798    pub timers: [SynicTimer; 4],
1799}
1800
1801impl SynicTimers {
1802    pub fn as_hv(&self) -> hvdef::HvSyntheticTimersState {
1803        let timers = self.timers.map(|timer| hvdef::HvStimerState {
1804            undelivered_message_pending: timer.undelivered_message_expiration_time.is_some().into(),
1805            reserved: 0,
1806            config: timer.config,
1807            count: timer.count,
1808            adjustment: timer.adjustment,
1809            undelivered_expiration_time: timer.undelivered_message_expiration_time.unwrap_or(0),
1810        });
1811
1812        hvdef::HvSyntheticTimersState {
1813            timers,
1814            reserved: [0; 5],
1815        }
1816    }
1817
1818    pub fn from_hv(state: hvdef::HvSyntheticTimersState) -> Self {
1819        let timers = state.timers.map(|timer| SynicTimer {
1820            config: timer.config,
1821            count: timer.count,
1822            adjustment: timer.adjustment,
1823            undelivered_message_expiration_time: (timer.undelivered_message_pending & 1 != 0)
1824                .then_some(timer.undelivered_expiration_time),
1825        });
1826        Self { timers }
1827    }
1828}
1829
1830impl StateElement<X86PartitionCapabilities, X86VpInfo> for SynicTimers {
1831    fn is_present(caps: &X86PartitionCapabilities) -> bool {
1832        caps.hv1
1833    }
1834
1835    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1836        Self {
1837            timers: [SynicTimer::default(); 4],
1838        }
1839    }
1840
1841    fn can_compare(_caps: &X86PartitionCapabilities) -> bool {
1842        // These can't be compared, since the hypervisor may choose to
1843        // immediately deliver the undelivered message.
1844        false
1845    }
1846}
1847
1848#[derive(Debug, Default, PartialEq, Eq, Protobuf, Inspect)]
1849#[mesh(package = "virt.x86")]
1850pub struct SynicMessageQueues {
1851    #[mesh(1)]
1852    #[inspect(with = "|x| inspect::iter_by_index(x.iter().map(Vec::len))")]
1853    pub queues: [Vec<[u8; HV_MESSAGE_SIZE]>; 16],
1854}
1855
1856impl StateElement<X86PartitionCapabilities, X86VpInfo> for SynicMessageQueues {
1857    fn is_present(caps: &X86PartitionCapabilities) -> bool {
1858        caps.hv1
1859    }
1860
1861    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1862        Default::default()
1863    }
1864}
1865
1866#[derive(Debug, Copy, Clone, PartialEq, Eq, Protobuf)]
1867#[mesh(package = "virt.x86")]
1868pub struct SynicMessagePage {
1869    #[mesh(1)]
1870    pub data: [u8; 4096],
1871}
1872
1873impl Inspect for SynicMessagePage {
1874    fn inspect(&self, req: inspect::Request<'_>) {
1875        let mut resp = req.respond();
1876        let mut occupied = 0u16;
1877        for (sint, slot) in self
1878            .data
1879            .as_chunks::<HV_MESSAGE_SIZE>()
1880            .0
1881            .iter()
1882            .enumerate()
1883        {
1884            let msg: HvMessage = zerocopy::transmute!(*slot);
1885            if msg.header.typ != hvdef::HvMessageType::HvMessageTypeNone {
1886                occupied |= 1 << sint;
1887            }
1888        }
1889        resp.binary("occupied_bitmap", occupied);
1890    }
1891}
1892
1893impl StateElement<X86PartitionCapabilities, X86VpInfo> for SynicMessagePage {
1894    fn is_present(caps: &X86PartitionCapabilities) -> bool {
1895        caps.hv1
1896    }
1897
1898    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1899        Self { data: [0; 4096] }
1900    }
1901}
1902
1903#[derive(Debug, Copy, Clone, PartialEq, Eq, Protobuf, Inspect)]
1904#[mesh(package = "virt.x86")]
1905#[inspect(skip)]
1906pub struct SynicEventFlagsPage {
1907    #[mesh(1)]
1908    pub data: [u8; 4096],
1909}
1910
1911impl StateElement<X86PartitionCapabilities, X86VpInfo> for SynicEventFlagsPage {
1912    fn is_present(caps: &X86PartitionCapabilities) -> bool {
1913        caps.hv1
1914    }
1915
1916    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1917        Self { data: [0; 4096] }
1918    }
1919}
1920
1921/// Opaque nested-virtualization state blob for save/restore.
1922#[derive(Debug, Clone, Default, PartialEq, Eq, Protobuf, Inspect)]
1923#[mesh(package = "virt.x86")]
1924#[inspect(skip)]
1925pub struct NestedState {
1926    #[mesh(1)]
1927    pub data: Vec<u8>,
1928}
1929
1930impl StateElement<X86PartitionCapabilities, X86VpInfo> for NestedState {
1931    fn is_present(caps: &X86PartitionCapabilities) -> bool {
1932        caps.nested_virt
1933    }
1934
1935    fn at_reset(_caps: &X86PartitionCapabilities, _vp_info: &X86VpInfo) -> Self {
1936        Self::default()
1937    }
1938
1939    fn can_compare(_caps: &X86PartitionCapabilities) -> bool {
1940        false
1941    }
1942}
1943
1944state_trait! {
1945    "Per-VP state",
1946    AccessVpState,
1947    X86PartitionCapabilities,
1948    X86VpInfo,
1949    VpSavedState,
1950    "virt.x86",
1951    (1, "registers", registers, set_registers, Registers),
1952    (2, "activity", activity, set_activity, Activity),
1953    (3, "xsave", xsave, set_xsave, Xsave),
1954    (4, "apic", apic, set_apic, Apic),
1955    (5, "xcr", xcr, set_xcr, Xcr0),
1956    (6, "xss", xss, set_xss, Xss),
1957    (7, "mtrrs", mtrrs, set_mtrrs, Mtrrs),
1958    (8, "pat", pat, set_pat, Pat),
1959    (9, "msrs", virtual_msrs, set_virtual_msrs, VirtualMsrs),
1960    (10, "drs", debug_regs, set_debug_regs, DebugRegisters),
1961    (11, "tsc", tsc, set_tsc, Tsc),
1962    (12, "cet", cet, set_cet, Cet),
1963    (13, "cet_ss", cet_ss, set_cet_ss, CetSs),
1964    (14, "tsc_aux", tsc_aux, set_tsc_aux, TscAux),
1965
1966    // Synic state
1967    (100, "synic", synic_msrs, set_synic_msrs, SyntheticMsrs),
1968    // The simp page contents must come after synic MSRs so that the SIMP page
1969    // register is set, but before the message queues and timers in case the
1970    // hypervisor decides to flush a pending message to the message page during
1971    // restore.
1972    (
1973        101,
1974        "simp",
1975        synic_message_page,
1976        set_synic_message_page,
1977        SynicMessagePage
1978    ),
1979    (
1980        102,
1981        "siefp",
1982        synic_event_flags_page,
1983        set_synic_event_flags_page,
1984        SynicEventFlagsPage
1985    ),
1986    (
1987        103,
1988        "synic_message_queues",
1989        synic_message_queues,
1990        set_synic_message_queues,
1991        SynicMessageQueues
1992    ),
1993    (104, "synic_timers", synic_timers, set_synic_timers, SynicTimers),
1994
1995    (200, "nested_state", nested_state, set_nested_state, NestedState),
1996}
1997
1998/// Resets register state for an x86 INIT via the APIC.
1999pub fn x86_init<T: AccessVpState>(access: &mut T, vp_info: &X86VpInfo) -> Result<(), T::Error> {
2000    // Reset core register and debug register state, but preserve a few bits of cr0.
2001    let cr0 = access.registers()?.cr0;
2002    let mut regs = Registers::at_reset(access.caps(), vp_info);
2003    let cr0_mask = X64_CR0_NW | X64_CR0_CD;
2004    regs.cr0 = (cr0 & cr0_mask) | (regs.cr0 & !cr0_mask);
2005    access.set_registers(&regs)?;
2006    access.set_debug_regs(&StateElement::at_reset(access.caps(), vp_info))?;
2007
2008    // Reset the APIC state, leaving the APIC base address and APIC ID intact.
2009    //
2010    // Note that there may be still be pending interrupt requests in the APIC
2011    // (e.g. an incoming SIPI), which this should not affect.
2012    let current_apic = access.apic()?;
2013    let mut apic = Apic::at_reset(access.caps(), vp_info);
2014    apic.registers[x86defs::apic::ApicRegister::ID.0 as usize] =
2015        current_apic.registers[x86defs::apic::ApicRegister::ID.0 as usize];
2016    apic.apic_base = current_apic.apic_base;
2017    access.set_apic(&apic)?;
2018
2019    // Enable the wait-for-SIPI state.
2020    if !vp_info.base.is_bsp() {
2021        let mut activity = access.activity()?;
2022        activity.mp_state = MpState::WaitForSipi;
2023        access.set_activity(&activity)?;
2024    }
2025
2026    Ok(())
2027}