Skip to main content

hv1_hypercall/
imp.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Support for individual hypercalls.
5
6use super::support::HypercallDispatch;
7use super::support::HypercallParameters;
8use super::support::RepHypercall;
9use super::support::SimpleHypercall;
10use super::support::VariableHypercall;
11use super::support::VtlHypercall;
12use crate::support::HvRepResult;
13use crate::support::VariableRepHypercall;
14use hv1_structs::ProcessorSet;
15use hvdef::HvError;
16use hvdef::HvMessage;
17use hvdef::HvRegisterName;
18use hvdef::HvRegisterValue;
19use hvdef::HvResult;
20use hvdef::HypercallCode;
21use hvdef::Vtl;
22use hvdef::hypercall as defs;
23use hvdef::hypercall::AcceptPagesAttributes;
24use hvdef::hypercall::HostVisibilityType;
25use hvdef::hypercall::HvRegisterAssoc;
26use hvdef::hypercall::HypercallOutput;
27use hvdef::hypercall::VtlPermissionSet;
28use zerocopy::IntoBytes;
29
30/// Implements the `HvPostMessage` hypercall.
31pub trait PostMessage {
32    /// Post a synic message.
33    fn post_message(&mut self, connection_id: u32, message: &[u8]) -> HvResult<()>;
34}
35
36/// Defines the `HvPostMessage` hypercall.
37pub type HvPostMessage =
38    SimpleHypercall<defs::PostMessage, (), { HypercallCode::HvCallPostMessage.0 }>;
39
40impl<T: PostMessage> HypercallDispatch<HvPostMessage> for T {
41    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
42        HvPostMessage::run(params, |input| {
43            self.post_message(
44                input.connection_id,
45                input
46                    .payload
47                    .as_bytes()
48                    .get(..input.payload_size as usize)
49                    .ok_or(HvError::InvalidParameter)?,
50            )
51        })
52    }
53}
54
55/// Implements the `HvSignalEvent` hypercall.
56pub trait SignalEvent {
57    /// Signal synic event.
58    fn signal_event(&mut self, connection_id: u32, flag: u16) -> HvResult<()>;
59}
60
61/// Defines the `HvSignalEvent` hypercall.
62pub type HvSignalEvent =
63    SimpleHypercall<defs::SignalEvent, (), { HypercallCode::HvCallSignalEvent.0 }>;
64
65impl<T: SignalEvent> HypercallDispatch<HvSignalEvent> for T {
66    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
67        HvSignalEvent::run(params, |input| {
68            self.signal_event(input.connection_id, input.flag_number)
69        })
70    }
71}
72
73/// Implements the `HvPostMessageDirect` hypercall.
74pub trait PostMessageDirect {
75    /// Posts a message directly, without going through a port/connection.
76    fn post_message_direct(
77        &mut self,
78        partition_id: u64,
79        target_vtl: Vtl,
80        vp: u32,
81        sint: u8,
82        message: &HvMessage,
83    ) -> HvResult<()>;
84}
85
86/// Defines the `HvPostMessageDirect` hypercall.
87pub type HvPostMessageDirect =
88    SimpleHypercall<defs::PostMessageDirect, (), { HypercallCode::HvCallPostMessageDirect.0 }>;
89
90impl<T: PostMessageDirect> HypercallDispatch<HvPostMessageDirect> for T {
91    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
92        HvPostMessageDirect::run(params, |input| {
93            let message = input.message.get();
94            self.post_message_direct(
95                input.partition_id,
96                Vtl::try_from(input.vtl)?,
97                input.vp_index,
98                input.sint,
99                &message,
100            )
101        })
102    }
103}
104
105/// Implements the `HvSignalEventDirect` hypercall.
106pub trait SignalEventDirect {
107    /// Signal synic event directly, without going through a port/connection.
108    fn signal_event_direct(
109        &mut self,
110        partition_id: u64,
111        vtl: Vtl,
112        vp: u32,
113        sint: u8,
114        flag: u16,
115    ) -> HvResult<defs::SignalEventDirectOutput>;
116}
117
118/// Defines the `HvSignalEventDirect` hypercall.
119pub type HvSignalEventDirect = SimpleHypercall<
120    defs::SignalEventDirect,
121    defs::SignalEventDirectOutput,
122    { HypercallCode::HvCallSignalEventDirect.0 },
123>;
124
125impl<T: SignalEventDirect> HypercallDispatch<HvSignalEventDirect> for T {
126    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
127        HvSignalEventDirect::run(params, |input| {
128            self.signal_event_direct(
129                input.target_partition,
130                Vtl::try_from(input.target_vtl)?,
131                input.target_vp,
132                input.target_sint,
133                input.flag_number,
134            )
135        })
136    }
137}
138
139/// Implements the `HvRetargetDeviceInterrupt` hypercall.
140pub trait RetargetDeviceInterrupt {
141    /// Retargets a device interrupt to a new processor set.
142    fn retarget_interrupt(
143        &mut self,
144        device_id: u64,
145        address: u64,
146        data: u32,
147        params: HvInterruptParameters<'_>,
148    ) -> HvResult<()>;
149}
150
151/// Configuration for a hypervisor device interrupt.
152pub struct HvInterruptParameters<'a> {
153    /// The target interrupt vector.
154    pub vector: u32,
155    /// Whether this is a multicast interrupt.
156    pub multicast: bool,
157    /// A target processor list.
158    pub target_processors: ProcessorSet<'a>,
159}
160
161/// Defines the `HvRetargetDeviceInterrupt` hypercall.
162pub type HvRetargetDeviceInterrupt = VariableHypercall<
163    defs::RetargetDeviceInterrupt,
164    (),
165    { HypercallCode::HvCallRetargetDeviceInterrupt.0 },
166>;
167
168impl<T: RetargetDeviceInterrupt> HypercallDispatch<HvRetargetDeviceInterrupt> for T {
169    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
170        HvRetargetDeviceInterrupt::run(params, |input, var_input| {
171            if input.target_header.flags.reserved() != 0 {
172                return Err(HvError::InvalidParameter);
173            }
174
175            let masks = &[input.target_header.mask_or_format];
176            let target_processors = if input.target_header.flags.processor_set() {
177                ProcessorSet::from_generic_set(input.target_header.mask_or_format, var_input)
178            } else {
179                ProcessorSet::from_processor_masks(1, masks)
180            }
181            .ok_or(HvError::InvalidParameter)?;
182
183            if input.entry.source != defs::HvInterruptSource::MSI {
184                return Err(HvError::InvalidParameter);
185            }
186
187            self.retarget_interrupt(
188                input.device_id,
189                input.entry.data[0] as u64,
190                input.entry.data[1],
191                HvInterruptParameters {
192                    vector: input.target_header.vector,
193                    multicast: input.target_header.flags.multicast(),
194                    target_processors,
195                },
196            )
197        })
198    }
199}
200
201/// Defines the `HvAssertVirtualInterrupt` hypercall.
202pub type HvAssertVirtualInterrupt = SimpleHypercall<
203    defs::AssertVirtualInterrupt,
204    (),
205    { HypercallCode::HvCallAssertVirtualInterrupt.0 },
206>;
207
208/// Implements the `HvAssertVirtualInterrupt` hypercall.
209pub trait AssertVirtualInterrupt {
210    /// Asserts a virtual interrupt.
211    fn assert_virtual_interrupt(
212        &mut self,
213        partition_id: u64,
214        interrupt_control: hvdef::HvInterruptControl,
215        destination_address: u64,
216        requested_vector: u32,
217        target_vtl: Vtl,
218    ) -> HvResult<()>;
219}
220
221impl<T: AssertVirtualInterrupt> HypercallDispatch<HvAssertVirtualInterrupt> for T {
222    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
223        HvAssertVirtualInterrupt::run(params, |input| {
224            if input.rsvd0 != 0 || input.rsvd1 != 0 {
225                return Err(HvError::InvalidParameter);
226            }
227            self.assert_virtual_interrupt(
228                input.partition_id,
229                input.interrupt_control,
230                input.destination_address,
231                input.requested_vector,
232                input.target_vtl.try_into()?,
233            )
234        })
235    }
236}
237
238/// Defines the `HvStartVirtualProcessor` hypercall for x64.
239pub type HvX64StartVirtualProcessor = SimpleHypercall<
240    defs::StartVirtualProcessorX64,
241    (),
242    { HypercallCode::HvCallStartVirtualProcessor.0 },
243>;
244
245/// Implements the `HvStartVirtualProcessor` hypercall.
246pub trait StartVirtualProcessor<T> {
247    /// Starts a virtual processor.
248    fn start_virtual_processor(
249        &mut self,
250        partition_id: u64,
251        vp_index: u32,
252        target_vtl: Vtl,
253        vp_context: &T,
254    ) -> HvResult<()>;
255}
256
257impl<T: StartVirtualProcessor<defs::InitialVpContextX64>>
258    HypercallDispatch<HvX64StartVirtualProcessor> for T
259{
260    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
261        HvX64StartVirtualProcessor::run(params, |input| {
262            if input.rsvd0 != 0 || input.rsvd1 != 0 {
263                return Err(HvError::InvalidParameter);
264            }
265            self.start_virtual_processor(
266                input.partition_id,
267                input.vp_index,
268                Vtl::try_from(input.target_vtl)?,
269                &input.vp_context,
270            )
271        })
272    }
273}
274
275/// Defines the `HvStartVirtualProcessor` hypercall for arm64.
276pub type HvArm64StartVirtualProcessor = SimpleHypercall<
277    defs::StartVirtualProcessorArm64,
278    (),
279    { HypercallCode::HvCallStartVirtualProcessor.0 },
280>;
281
282impl<T: StartVirtualProcessor<defs::InitialVpContextArm64>>
283    HypercallDispatch<HvArm64StartVirtualProcessor> for T
284{
285    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
286        HvArm64StartVirtualProcessor::run(params, |input| {
287            self.start_virtual_processor(
288                input.partition_id,
289                input.vp_index,
290                Vtl::try_from(input.target_vtl)?,
291                &input.vp_context,
292            )
293        })
294    }
295}
296
297/// Defines the `HvTranslateVirtualAddress` hypercall.
298pub type HvX64TranslateVirtualAddress = SimpleHypercall<
299    defs::TranslateVirtualAddressX64,
300    defs::TranslateVirtualAddressOutput,
301    { HypercallCode::HvCallTranslateVirtualAddress.0 },
302>;
303
304/// Implements the `HvTranslateVirtualAddress` hypercall.
305pub trait TranslateVirtualAddressX64 {
306    /// Translates a GVA to a GPA.
307    fn translate_virtual_address(
308        &mut self,
309        partition_id: u64,
310        vp_index: u32,
311        control_flags: defs::TranslateGvaControlFlagsX64,
312        gva_page: u64,
313    ) -> HvResult<defs::TranslateVirtualAddressOutput>;
314}
315
316impl<T: TranslateVirtualAddressX64> HypercallDispatch<HvX64TranslateVirtualAddress> for T {
317    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
318        HvX64TranslateVirtualAddress::run(params, |input| {
319            self.translate_virtual_address(
320                input.partition_id,
321                input.vp_index,
322                input.control_flags,
323                input.gva_page,
324            )
325        })
326    }
327}
328
329/// Defines the `HvTranslateVirtualAddressEx` hypercall.
330pub type HvX64TranslateVirtualAddressEx = SimpleHypercall<
331    defs::TranslateVirtualAddressX64,
332    defs::TranslateVirtualAddressExOutputX64,
333    { HypercallCode::HvCallTranslateVirtualAddressEx.0 },
334>;
335
336/// Implements the `HvTranslateVirtualAddressEx` hypercall.
337pub trait TranslateVirtualAddressExX64 {
338    /// Translates a GVA to a GPA.
339    fn translate_virtual_address_ex(
340        &mut self,
341        partition_id: u64,
342        vp_index: u32,
343        control_flags: defs::TranslateGvaControlFlagsX64,
344        gva_page: u64,
345    ) -> HvResult<defs::TranslateVirtualAddressExOutputX64>;
346}
347
348impl<T: TranslateVirtualAddressExX64> HypercallDispatch<HvX64TranslateVirtualAddressEx> for T {
349    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
350        HvX64TranslateVirtualAddressEx::run(params, |input| {
351            self.translate_virtual_address_ex(
352                input.partition_id,
353                input.vp_index,
354                input.control_flags,
355                input.gva_page,
356            )
357        })
358    }
359}
360
361/// Defines the `HvTranslateVirtualAddressEx` hypercall.
362pub type HvAarch64TranslateVirtualAddressEx = SimpleHypercall<
363    defs::TranslateVirtualAddressArm64,
364    defs::TranslateVirtualAddressExOutputArm64,
365    { HypercallCode::HvCallTranslateVirtualAddressEx.0 },
366>;
367
368/// Implements the `HvTranslateVirtualAddressEx` hypercall.
369pub trait TranslateVirtualAddressExAarch64 {
370    /// Translates a GVA to a GPA.
371    fn translate_virtual_address_ex(
372        &mut self,
373        partition_id: u64,
374        vp_index: u32,
375        control_flags: defs::TranslateGvaControlFlagsArm64,
376        gva_page: u64,
377    ) -> HvResult<defs::TranslateVirtualAddressExOutputArm64>;
378}
379
380impl<T: TranslateVirtualAddressExAarch64> HypercallDispatch<HvAarch64TranslateVirtualAddressEx>
381    for T
382{
383    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
384        HvAarch64TranslateVirtualAddressEx::run(params, |input| {
385            self.translate_virtual_address_ex(
386                input.partition_id,
387                input.vp_index,
388                input.control_flags,
389                input.gva_page,
390            )
391        })
392    }
393}
394
395/// Defines the `HvGetVpRegisters` hypercall.
396pub type HvGetVpRegisters = RepHypercall<
397    defs::GetSetVpRegisters,
398    HvRegisterName,
399    HvRegisterValue,
400    { HypercallCode::HvCallGetVpRegisters.0 },
401>;
402
403/// Implements the `HvGetVpRegisters` hypercall.
404pub trait GetVpRegisters {
405    /// Gets the requested registers.
406    fn get_vp_registers(
407        &mut self,
408        partition_id: u64,
409        vp_index: u32,
410        vtl: Option<Vtl>,
411        registers: &[HvRegisterName],
412        output: &mut [HvRegisterValue],
413    ) -> HvRepResult;
414}
415
416impl<T: GetVpRegisters> HypercallDispatch<HvGetVpRegisters> for T {
417    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
418        HvGetVpRegisters::run(params, |header, input, output| {
419            self.get_vp_registers(
420                header.partition_id,
421                header.vp_index,
422                header.target_vtl.target_vtl().map_err(|err| (err, 0))?,
423                input,
424                output,
425            )
426        })
427    }
428}
429
430/// Defines the `HvSetVpRegisters` hypercall.
431pub type HvSetVpRegisters = RepHypercall<
432    defs::GetSetVpRegisters,
433    HvRegisterAssoc,
434    (),
435    { HypercallCode::HvCallSetVpRegisters.0 },
436>;
437
438/// Implements the `HvSetVpRegisters` hypercall.
439pub trait SetVpRegisters {
440    /// Sets the requested registers.
441    fn set_vp_registers(
442        &mut self,
443        partition_id: u64,
444        vp_index: u32,
445        vtl: Option<Vtl>,
446        registers: &[HvRegisterAssoc],
447    ) -> HvRepResult;
448}
449
450impl<T: SetVpRegisters> HypercallDispatch<HvSetVpRegisters> for T {
451    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
452        HvSetVpRegisters::run(params, |header, input, _output| {
453            self.set_vp_registers(
454                header.partition_id,
455                header.vp_index,
456                header.target_vtl.target_vtl().map_err(|err| (err, 0))?,
457                input,
458            )
459        })
460    }
461}
462
463/// Implements the `HvInstallIntercept` hypercall.
464pub trait InstallIntercept {
465    /// Post a synic message.
466    fn install_intercept(
467        &mut self,
468        partition_id: u64,
469        access_type_mask: u32,
470        intercept_type: defs::HvInterceptType,
471        intercept_parameters: defs::HvInterceptParameters,
472    ) -> HvResult<()>;
473}
474
475/// Defines the `HvInstallIntercept` hypercall.
476pub type HvInstallIntercept =
477    SimpleHypercall<defs::InstallIntercept, (), { HypercallCode::HvCallInstallIntercept.0 }>;
478
479impl<T: InstallIntercept> HypercallDispatch<HvInstallIntercept> for T {
480    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
481        HvInstallIntercept::run(params, |input| {
482            self.install_intercept(
483                input.partition_id,
484                input.access_type_mask,
485                input.intercept_type,
486                input.intercept_parameters,
487            )
488        })
489    }
490}
491
492/// Operations required to handle VTL switch hypercalls.
493pub trait VtlSwitchOps {
494    /// Advances the instruction pointer for a vtl switch operation whose preconditions have been
495    /// satisfied, in the context of the initiating vtl.
496    fn advance_ip(&mut self);
497    /// Injects an invalid opcode fault for a vtl switch operation whose preconditions have been
498    /// violated, in the context of the initiating vtl.
499    fn inject_invalid_opcode_fault(&mut self);
500}
501
502/// Implements the `HvVtlReturn` hypercall.
503pub trait VtlReturn {
504    /// Checks if a return to a lower vtl is allowed based on current state.
505    fn is_vtl_return_allowed(&self) -> bool;
506
507    /// Return to a lower VTL.
508    fn vtl_return(&mut self, fast: bool);
509}
510
511/// Defines the `HvVtlReturn` hypercall.
512pub type HvVtlReturn = VtlHypercall<{ HypercallCode::HvCallVtlReturn.0 }>;
513
514impl<T: VtlReturn + VtlSwitchOps> HypercallDispatch<HvVtlReturn> for T {
515    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
516        HvVtlReturn::run(params, |input, control| {
517            // Preconditions for a successful vtl return:
518            // 1. Control must be 0 except for the opcode.
519            // 2. Input must be 0 or 1.
520            // 3. VTL state must allow vtl returns.
521            if u64::from(control.with_code(0)) == 0
522                && (input & !1) == 0
523                && self.is_vtl_return_allowed()
524            {
525                // Advance the instruction pointer and issue the vtl return.
526                self.advance_ip();
527                self.vtl_return(input & 1 != 0);
528            } else {
529                // Inject an error.
530                self.inject_invalid_opcode_fault();
531            }
532        })
533    }
534}
535
536/// Implements the `HvVtlCall` hypercall.
537pub trait VtlCall {
538    /// Checks if a call to a higher vtl is allowed based on current state.
539    fn is_vtl_call_allowed(&self) -> bool;
540    /// Calls the higher VTL.
541    fn vtl_call(&mut self);
542}
543
544/// Defines the `HvVtlCall` hypercall.
545pub type HvVtlCall = VtlHypercall<{ HypercallCode::HvCallVtlCall.0 }>;
546
547impl<T: VtlCall + VtlSwitchOps> HypercallDispatch<HvVtlCall> for T {
548    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
549        HvVtlCall::run(params, |input, control| {
550            // Preconditions for a successful vtl call:
551            // 1. Control must be 0 except for the opcode.
552            // 2. Input must be 0.
553            // 3. VTL state must allow a call to higher VTLs.
554            if u64::from(control.with_code(0)) == 0 && input == 0 && self.is_vtl_call_allowed() {
555                // Advance the instruction pointer and issue the vtl call.
556                self.advance_ip();
557                self.vtl_call();
558            } else {
559                self.inject_invalid_opcode_fault();
560            }
561        })
562    }
563}
564
565/// Implements the `HvEnableVpVtl` hypercall.
566pub trait EnableVpVtl<T> {
567    /// Enable the specified VTL.
568    fn enable_vp_vtl(
569        &mut self,
570        partition_id: u64,
571        vp_index: u32,
572        vtl: Vtl,
573        vp_context: &T,
574    ) -> HvResult<()>;
575}
576
577/// Defines the `HvEnableVpVtl` hypercall for x64.
578pub type HvX64EnableVpVtl =
579    SimpleHypercall<defs::EnableVpVtlX64, (), { HypercallCode::HvCallEnableVpVtl.0 }>;
580
581impl<T: EnableVpVtl<hvdef::hypercall::InitialVpContextX64>> HypercallDispatch<HvX64EnableVpVtl>
582    for T
583{
584    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
585        HvX64EnableVpVtl::run(params, |input| {
586            self.enable_vp_vtl(
587                input.partition_id,
588                input.vp_index,
589                Vtl::try_from(input.target_vtl)?,
590                &input.vp_vtl_context,
591            )
592        })
593    }
594}
595
596/// Defines the `HvEnableVpVtl` hypercall for arm64.
597pub type HvArm64EnableVpVtl =
598    SimpleHypercall<defs::EnableVpVtlArm64, (), { HypercallCode::HvCallEnableVpVtl.0 }>;
599
600impl<T: EnableVpVtl<hvdef::hypercall::InitialVpContextArm64>> HypercallDispatch<HvArm64EnableVpVtl>
601    for T
602{
603    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
604        HvArm64EnableVpVtl::run(params, |input| {
605            self.enable_vp_vtl(
606                input.partition_id,
607                input.vp_index,
608                Vtl::try_from(input.target_vtl)?,
609                &input.vp_vtl_context,
610            )
611        })
612    }
613}
614
615/// Implements the `HvModifyVtlProtectionMask` hypercall.
616pub trait ModifyVtlProtectionMask {
617    /// Modify the VTL protection mask for the list of pages specified by `gpa_pages`.
618    /// `map_flags` represents the desired permissions for VTLs lower than `target_vtl`.
619    /// `target_vtl` must be lower or equal to the current VTL. It cannot be VTL0.
620    fn modify_vtl_protection_mask(
621        &mut self,
622        partition_id: u64,
623        map_flags: hvdef::HvMapGpaFlags,
624        target_vtl: Option<Vtl>,
625        gpa_pages: &[u64],
626    ) -> HvRepResult;
627}
628
629/// Defines the `HvModifyVtlProtectionMask` hypercall.
630pub type HvModifyVtlProtectionMask = RepHypercall<
631    defs::ModifyVtlProtectionMask,
632    u64,
633    (),
634    { HypercallCode::HvCallModifyVtlProtectionMask.0 },
635>;
636
637impl<T: ModifyVtlProtectionMask> HypercallDispatch<HvModifyVtlProtectionMask> for T {
638    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
639        HvModifyVtlProtectionMask::run(params, |header, input, _output| {
640            self.modify_vtl_protection_mask(
641                header.partition_id,
642                header.map_flags,
643                header.target_vtl.target_vtl().map_err(|err| (err, 0))?,
644                input,
645            )
646        })
647    }
648}
649
650/// Implements the `HvGetVpIndexFromApicId` hypercall.
651pub trait GetVpIndexFromApicId {
652    /// Gets a list of VP indices from a list of APIC IDs.
653    fn get_vp_index_from_apic_id(
654        &mut self,
655        partition_id: u64,
656        target_vtl: Vtl,
657        apic_ids: &[u32],
658        vp_indices: &mut [u32],
659    ) -> HvRepResult;
660}
661
662/// Defines the `HvGetVpIndexFromApicId` hypercall.
663pub type HvGetVpIndexFromApicId = RepHypercall<
664    defs::GetVpIndexFromApicId,
665    u32,
666    u32,
667    { HypercallCode::HvCallGetVpIndexFromApicId.0 },
668>;
669
670impl<T: GetVpIndexFromApicId> HypercallDispatch<HvGetVpIndexFromApicId> for T {
671    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
672        HvGetVpIndexFromApicId::run(params, |header, input, output| {
673            self.get_vp_index_from_apic_id(
674                header.partition_id,
675                Vtl::try_from(header.target_vtl).map_err(|err| (err, 0))?,
676                input,
677                output,
678            )
679        })
680    }
681}
682
683/// Implements the `HvAcceptGpaPages` hypercall.
684pub trait AcceptGpaPages {
685    /// Accepts the described pages.
686    fn accept_gpa_pages(
687        &mut self,
688        partition_id: u64,
689        page_attributes: AcceptPagesAttributes,
690        vtl_permission_set: VtlPermissionSet,
691        gpa_page_base: u64,
692        page_count: usize,
693    ) -> HvRepResult;
694}
695
696/// Defines the `HvAcceptGpaPages` hypercall.
697pub type HvAcceptGpaPages =
698    RepHypercall<defs::AcceptGpaPages, u64, (), { HypercallCode::HvCallAcceptGpaPages.0 }>;
699
700impl<T: AcceptGpaPages> HypercallDispatch<HvAcceptGpaPages> for T {
701    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
702        HvAcceptGpaPages::run(params, |header, input, _output| {
703            self.accept_gpa_pages(
704                header.partition_id,
705                header.page_attributes,
706                header.vtl_permission_set,
707                header.gpa_page_base,
708                input.len(),
709            )
710        })
711    }
712}
713
714/// Implements the `HvModifySparseGpaPageHostVisibility` hypercall.
715pub trait ModifySparseGpaPageHostVisibility {
716    /// Modifies the host page visibility for the listed pages.
717    fn modify_gpa_visibility(
718        &mut self,
719        partition_id: u64,
720        visibility: HostVisibilityType,
721        gpa_pages: &[u64],
722    ) -> HvRepResult;
723}
724
725/// Defines the `HvModifySparseGpaPageHostVisibility` hypercall.
726pub type HvModifySparseGpaPageHostVisibility = RepHypercall<
727    defs::ModifySparsePageVisibility,
728    u64,
729    (),
730    { HypercallCode::HvCallModifySparseGpaPageHostVisibility.0 },
731>;
732
733impl<T: ModifySparseGpaPageHostVisibility> HypercallDispatch<HvModifySparseGpaPageHostVisibility>
734    for T
735{
736    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
737        HvModifySparseGpaPageHostVisibility::run(params, |header, input, _output| {
738            self.modify_gpa_visibility(
739                header.partition_id,
740                header.host_visibility.host_visibility(),
741                input,
742            )
743        })
744    }
745}
746
747/// Implements the `HvEnablePartitionVtl` hypercall.
748pub trait EnablePartitionVtl {
749    /// Enables the VTL for the partition.
750    fn enable_partition_vtl(
751        &mut self,
752        partition_id: u64,
753        target_vtl: Vtl,
754        flags: defs::EnablePartitionVtlFlags,
755    ) -> HvResult<()>;
756}
757
758/// Defines the `HvEnablePartitionVtl` hypercall.
759pub type HvEnablePartitionVtl =
760    SimpleHypercall<defs::EnablePartitionVtl, (), { HypercallCode::HvCallEnablePartitionVtl.0 }>;
761
762impl<T: EnablePartitionVtl> HypercallDispatch<HvEnablePartitionVtl> for T {
763    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
764        HvEnablePartitionVtl::run(params, |input| {
765            self.enable_partition_vtl(
766                input.partition_id,
767                Vtl::try_from(input.target_vtl).map_err(|_| HvError::AccessDenied)?,
768                input.flags,
769            )
770        })
771    }
772}
773
774/// Implements the `HvFlushVirtualAddressList` hypercall.
775pub trait FlushVirtualAddressList {
776    /// Invalidates portions of the virtual TLB.
777    fn flush_virtual_address_list(
778        &mut self,
779        processor_set: ProcessorSet<'_>,
780        flags: defs::HvFlushFlags,
781        gva_ranges: &[defs::HvGvaRange],
782    ) -> HvRepResult;
783}
784
785/// Defines the `HvFlushVirtualAddressList` hypercall.
786pub type HvFlushVirtualAddressList = RepHypercall<
787    defs::FlushVirtualAddressSpace,
788    defs::HvGvaRange,
789    (),
790    { HypercallCode::HvCallFlushVirtualAddressList.0 },
791>;
792
793impl<T: FlushVirtualAddressList> HypercallDispatch<HvFlushVirtualAddressList> for T {
794    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
795        HvFlushVirtualAddressList::run(params, |header, input, _output| {
796            let masks = &[header.processor_mask];
797            let processors = ProcessorSet::from_processor_masks(1, masks)
798                .ok_or((HvError::InvalidParameter, 0))?;
799            self.flush_virtual_address_list(processors, header.flags, input)
800        })
801    }
802}
803
804/// Implements the `HvFlushVirtualAddressListEx` hypercall.
805pub trait FlushVirtualAddressListEx {
806    /// Invalidates portions of the virtual TLB.
807    fn flush_virtual_address_list_ex(
808        &mut self,
809        processor_set: ProcessorSet<'_>,
810        flags: defs::HvFlushFlags,
811        gva_ranges: &[defs::HvGvaRange],
812    ) -> HvRepResult;
813}
814
815/// Defines the `HvFlushVirtualAddressListEx` hypercall.
816pub type HvFlushVirtualAddressListEx = VariableRepHypercall<
817    defs::FlushVirtualAddressSpaceEx,
818    defs::HvGvaRange,
819    (),
820    { HypercallCode::HvCallFlushVirtualAddressListEx.0 },
821>;
822
823impl<T: FlushVirtualAddressListEx> HypercallDispatch<HvFlushVirtualAddressListEx> for T {
824    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
825        HvFlushVirtualAddressListEx::run(params, |header, variable_input, input, _output| {
826            if header.vp_set_format != hvdef::hypercall::HV_GENERIC_SET_SPARSE_4K {
827                return Err((HvError::InvalidParameter, 0));
828            }
829
830            let processors =
831                ProcessorSet::from_processor_masks(header.vp_set_valid_banks_mask, variable_input)
832                    .ok_or((HvError::InvalidParameter, 0))?;
833            self.flush_virtual_address_list_ex(processors, header.flags, input)
834        })
835    }
836}
837
838/// Implements the `HvFlushVirtualAddressSpace` hypercall.
839pub trait FlushVirtualAddressSpace {
840    /// Invalidates all virtual TLB entries.
841    fn flush_virtual_address_space(
842        &mut self,
843        processor_set: ProcessorSet<'_>,
844        flags: defs::HvFlushFlags,
845    ) -> HvResult<()>;
846}
847
848/// Defines the `HvFlushVirtualAddressSpace` hypercall.
849pub type HvFlushVirtualAddressSpace = SimpleHypercall<
850    defs::FlushVirtualAddressSpace,
851    (),
852    { HypercallCode::HvCallFlushVirtualAddressSpace.0 },
853>;
854
855impl<T: FlushVirtualAddressSpace> HypercallDispatch<HvFlushVirtualAddressSpace> for T {
856    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
857        HvFlushVirtualAddressSpace::run(params, |input| {
858            let masks = &[input.processor_mask];
859            let processors =
860                ProcessorSet::from_processor_masks(1, masks).ok_or(HvError::InvalidParameter)?;
861            self.flush_virtual_address_space(processors, input.flags)
862        })
863    }
864}
865
866/// Implements the `HvFlushVirtualAddressSpaceEx` hypercall.
867pub trait FlushVirtualAddressSpaceEx {
868    /// Invalidates all virtual TLB entries.
869    fn flush_virtual_address_space_ex(
870        &mut self,
871        processor_set: ProcessorSet<'_>,
872        flags: defs::HvFlushFlags,
873    ) -> HvResult<()>;
874}
875
876/// Defines the `HvFlushVirtualAddressSpaceEx` hypercall.
877pub type HvFlushVirtualAddressSpaceEx = VariableHypercall<
878    defs::FlushVirtualAddressSpaceEx,
879    (),
880    { HypercallCode::HvCallFlushVirtualAddressSpaceEx.0 },
881>;
882
883impl<T: FlushVirtualAddressSpaceEx> HypercallDispatch<HvFlushVirtualAddressSpaceEx> for T {
884    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
885        HvFlushVirtualAddressSpaceEx::run(params, |header, input| {
886            if header.vp_set_format != hvdef::hypercall::HV_GENERIC_SET_SPARSE_4K {
887                return Err(HvError::InvalidParameter);
888            }
889
890            let processors =
891                ProcessorSet::from_processor_masks(header.vp_set_valid_banks_mask, input)
892                    .ok_or(HvError::InvalidParameter)?;
893            self.flush_virtual_address_space_ex(processors, header.flags)
894        })
895    }
896}
897
898/// Implements the `HvQuerySparseGpaPageHostVisibility` hypercall.
899pub trait QuerySparseGpaPageHostVisibility {
900    /// Queries the host page visibility for the listed pages.
901    fn query_gpa_visibility(
902        &mut self,
903        partition_id: u64,
904        gpa_pages: &[u64],
905        host_visibility: &mut [HostVisibilityType],
906    ) -> HvRepResult;
907}
908
909/// Defines the `HvQuerySparseGpaPageHostVisibility` hypercall.
910pub type HvQuerySparseGpaPageHostVisibility = RepHypercall<
911    defs::QuerySparsePageVisibility,
912    u64,
913    HostVisibilityType,
914    { HypercallCode::HvCallQuerySparseGpaPageHostVisibility.0 },
915>;
916
917impl<T: QuerySparseGpaPageHostVisibility> HypercallDispatch<HvQuerySparseGpaPageHostVisibility>
918    for T
919{
920    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
921        HvQuerySparseGpaPageHostVisibility::run(params, |header, input, output| {
922            self.query_gpa_visibility(header.partition_id, input, output)
923        })
924    }
925}
926
927/// Implements the `HvExtQueryCapabilities` hypercall.
928pub trait ExtendedQueryCapabilities {
929    /// Queries extended capabilities.
930    fn query_extended_capabilities(&mut self) -> HvResult<u64>;
931}
932
933/// Defines the `HvExtQueryCapabilities` hypercall.
934pub type HvExtQueryCapabilities =
935    SimpleHypercall<(), u64, { HypercallCode::HvExtCallQueryCapabilities.0 }>;
936
937impl<T: ExtendedQueryCapabilities> HypercallDispatch<HvExtQueryCapabilities> for T {
938    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
939        HvExtQueryCapabilities::run(params, |()| self.query_extended_capabilities())
940    }
941}
942
943/// Defines the `HvSendSyntheticClusterIpi` hypercall.
944pub type HvSendSyntheticClusterIpi = SimpleHypercall<
945    defs::SendSyntheticClusterIpi,
946    (),
947    { HypercallCode::HvCallSendSyntheticClusterIpi.0 },
948>;
949
950/// Implements the `HvSendSyntheticClusterIpi` hypercall.
951pub trait SendSyntheticClusterIpi {
952    /// Sends an ipi to a synthetic cluster.
953    fn send_synthetic_cluster_ipi(
954        &mut self,
955        target_vtl: Option<Vtl>,
956        vector: u32,
957        flags: u8,
958        processor_set: ProcessorSet<'_>,
959    ) -> HvResult<()>;
960}
961
962impl<T: SendSyntheticClusterIpi> HypercallDispatch<HvSendSyntheticClusterIpi> for T {
963    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
964        HvSendSyntheticClusterIpi::run(params, |input| {
965            if input.reserved != 0 {
966                return Err(HvError::InvalidParameter);
967            }
968            self.send_synthetic_cluster_ipi(
969                input.target_vtl.target_vtl()?,
970                input.vector,
971                input.flags,
972                ProcessorSet::from_processor_masks(1, &[input.processor_mask])
973                    .ok_or(HvError::InvalidParameter)?,
974            )
975        })
976    }
977}
978
979/// Defines the `HvSendSyntheticClusterIpi` hypercall.
980pub type HvSendSyntheticClusterIpiEx = VariableHypercall<
981    defs::SendSyntheticClusterIpiEx,
982    (),
983    { HypercallCode::HvCallSendSyntheticClusterIpiEx.0 },
984>;
985
986/// Implements the `HvSendSyntheticClusterIpi` hypercall.
987pub trait SendSyntheticClusterIpiEx {
988    /// Sends an ipi to a synthetic cluster.
989    fn send_synthetic_cluster_ipi_ex(
990        &mut self,
991        target_vtl: Option<Vtl>,
992        vector: u32,
993        flags: u8,
994        processor_set: ProcessorSet<'_>,
995    ) -> HvResult<()>;
996}
997
998impl<T: SendSyntheticClusterIpiEx> HypercallDispatch<HvSendSyntheticClusterIpiEx> for T {
999    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
1000        HvSendSyntheticClusterIpiEx::run(params, |header, input| {
1001            if header.reserved != 0 {
1002                return Err(HvError::InvalidParameter);
1003            }
1004
1005            if header.vp_set_format != hvdef::hypercall::HV_GENERIC_SET_SPARSE_4K {
1006                return Err(HvError::InvalidParameter);
1007            }
1008
1009            self.send_synthetic_cluster_ipi_ex(
1010                header.target_vtl.target_vtl()?,
1011                header.vector,
1012                header.flags,
1013                ProcessorSet::from_processor_masks(header.vp_set_valid_banks_mask, input)
1014                    .ok_or(HvError::InvalidParameter)?,
1015            )
1016        })
1017    }
1018}
1019
1020/// Defines the `HvVbsVmCallReport` hypercall.
1021pub type HvVbsVmCallReport = SimpleHypercall<
1022    defs::VbsVmCallReport,
1023    defs::VbsVmCallReportOutput,
1024    { HypercallCode::HvCallVbsVmCallReport.0 },
1025>;
1026
1027/// Implements the `HvVbsVmCallReport` hypercall.
1028pub trait VbsVmCallReport {
1029    /// Generates a VBS VM call report.
1030    fn vbs_vm_call_report(&self, report_data: &[u8]) -> HvResult<defs::VbsVmCallReportOutput>;
1031}
1032
1033impl<T: VbsVmCallReport> HypercallDispatch<HvVbsVmCallReport> for T {
1034    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
1035        HvVbsVmCallReport::run(params, |header| {
1036            self.vbs_vm_call_report(&header.report_data)
1037        })
1038    }
1039}
1040
1041/// Defines the `HvRestorePartitionTime` hypercall.
1042pub type HvRestorePartitionTime = SimpleHypercall<
1043    defs::RestorePartitionTime,
1044    (),
1045    { HypercallCode::HvCallRestorePartitionTime.0 },
1046>;
1047
1048/// Implements the `HvRestorePartitionTime` hypercall.
1049pub trait RestorePartitionTime {
1050    /// Restores the partition time.
1051    fn restore_partition_time(
1052        &mut self,
1053        partition_id: u64,
1054        tsc_sequence: u32,
1055        reference_time_in_100_ns: u64,
1056        tsc: u64,
1057    ) -> HvResult<()>;
1058}
1059
1060impl<T: RestorePartitionTime> HypercallDispatch<HvRestorePartitionTime> for T {
1061    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
1062        HvRestorePartitionTime::run(params, |input| {
1063            if input.reserved != 0 {
1064                return Err(HvError::InvalidParameter);
1065            }
1066
1067            self.restore_partition_time(
1068                input.partition_id,
1069                input.tsc_sequence,
1070                input.reference_time_in_100_ns,
1071                input.tsc,
1072            )
1073        })
1074    }
1075}