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            self.start_virtual_processor(
263                input.partition_id,
264                input.vp_index,
265                Vtl::try_from(input.target_vtl)?,
266                &input.vp_context,
267            )
268        })
269    }
270}
271
272/// Defines the `HvStartVirtualProcessor` hypercall for arm64.
273pub type HvArm64StartVirtualProcessor = SimpleHypercall<
274    defs::StartVirtualProcessorArm64,
275    (),
276    { HypercallCode::HvCallStartVirtualProcessor.0 },
277>;
278
279impl<T: StartVirtualProcessor<defs::InitialVpContextArm64>>
280    HypercallDispatch<HvArm64StartVirtualProcessor> for T
281{
282    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
283        HvArm64StartVirtualProcessor::run(params, |input| {
284            self.start_virtual_processor(
285                input.partition_id,
286                input.vp_index,
287                Vtl::try_from(input.target_vtl)?,
288                &input.vp_context,
289            )
290        })
291    }
292}
293
294/// Defines the `HvTranslateVirtualAddress` hypercall.
295pub type HvX64TranslateVirtualAddress = SimpleHypercall<
296    defs::TranslateVirtualAddressX64,
297    defs::TranslateVirtualAddressOutput,
298    { HypercallCode::HvCallTranslateVirtualAddress.0 },
299>;
300
301/// Implements the `HvTranslateVirtualAddress` hypercall.
302pub trait TranslateVirtualAddressX64 {
303    /// Translates a GVA to a GPA.
304    fn translate_virtual_address(
305        &mut self,
306        partition_id: u64,
307        vp_index: u32,
308        control_flags: defs::TranslateGvaControlFlagsX64,
309        gva_page: u64,
310    ) -> HvResult<defs::TranslateVirtualAddressOutput>;
311}
312
313impl<T: TranslateVirtualAddressX64> HypercallDispatch<HvX64TranslateVirtualAddress> for T {
314    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
315        HvX64TranslateVirtualAddress::run(params, |input| {
316            self.translate_virtual_address(
317                input.partition_id,
318                input.vp_index,
319                input.control_flags,
320                input.gva_page,
321            )
322        })
323    }
324}
325
326/// Defines the `HvTranslateVirtualAddressEx` hypercall.
327pub type HvX64TranslateVirtualAddressEx = SimpleHypercall<
328    defs::TranslateVirtualAddressX64,
329    defs::TranslateVirtualAddressExOutputX64,
330    { HypercallCode::HvCallTranslateVirtualAddressEx.0 },
331>;
332
333/// Implements the `HvTranslateVirtualAddressEx` hypercall.
334pub trait TranslateVirtualAddressExX64 {
335    /// Translates a GVA to a GPA.
336    fn translate_virtual_address_ex(
337        &mut self,
338        partition_id: u64,
339        vp_index: u32,
340        control_flags: defs::TranslateGvaControlFlagsX64,
341        gva_page: u64,
342    ) -> HvResult<defs::TranslateVirtualAddressExOutputX64>;
343}
344
345impl<T: TranslateVirtualAddressExX64> HypercallDispatch<HvX64TranslateVirtualAddressEx> for T {
346    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
347        HvX64TranslateVirtualAddressEx::run(params, |input| {
348            self.translate_virtual_address_ex(
349                input.partition_id,
350                input.vp_index,
351                input.control_flags,
352                input.gva_page,
353            )
354        })
355    }
356}
357
358/// Defines the `HvTranslateVirtualAddressEx` hypercall.
359pub type HvAarch64TranslateVirtualAddressEx = SimpleHypercall<
360    defs::TranslateVirtualAddressArm64,
361    defs::TranslateVirtualAddressExOutputArm64,
362    { HypercallCode::HvCallTranslateVirtualAddressEx.0 },
363>;
364
365/// Implements the `HvTranslateVirtualAddressEx` hypercall.
366pub trait TranslateVirtualAddressExAarch64 {
367    /// Translates a GVA to a GPA.
368    fn translate_virtual_address_ex(
369        &mut self,
370        partition_id: u64,
371        vp_index: u32,
372        control_flags: defs::TranslateGvaControlFlagsArm64,
373        gva_page: u64,
374    ) -> HvResult<defs::TranslateVirtualAddressExOutputArm64>;
375}
376
377impl<T: TranslateVirtualAddressExAarch64> HypercallDispatch<HvAarch64TranslateVirtualAddressEx>
378    for T
379{
380    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
381        HvAarch64TranslateVirtualAddressEx::run(params, |input| {
382            self.translate_virtual_address_ex(
383                input.partition_id,
384                input.vp_index,
385                input.control_flags,
386                input.gva_page,
387            )
388        })
389    }
390}
391
392/// Defines the `HvGetVpRegisters` hypercall.
393pub type HvGetVpRegisters = RepHypercall<
394    defs::GetSetVpRegisters,
395    HvRegisterName,
396    HvRegisterValue,
397    { HypercallCode::HvCallGetVpRegisters.0 },
398>;
399
400/// Implements the `HvGetVpRegisters` hypercall.
401pub trait GetVpRegisters {
402    /// Gets the requested registers.
403    fn get_vp_registers(
404        &mut self,
405        partition_id: u64,
406        vp_index: u32,
407        vtl: Option<Vtl>,
408        registers: &[HvRegisterName],
409        output: &mut [HvRegisterValue],
410    ) -> HvRepResult;
411}
412
413impl<T: GetVpRegisters> HypercallDispatch<HvGetVpRegisters> for T {
414    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
415        HvGetVpRegisters::run(params, |header, input, output| {
416            self.get_vp_registers(
417                header.partition_id,
418                header.vp_index,
419                header.target_vtl.target_vtl().map_err(|err| (err, 0))?,
420                input,
421                output,
422            )
423        })
424    }
425}
426
427/// Defines the `HvSetVpRegisters` hypercall.
428pub type HvSetVpRegisters = RepHypercall<
429    defs::GetSetVpRegisters,
430    HvRegisterAssoc,
431    (),
432    { HypercallCode::HvCallSetVpRegisters.0 },
433>;
434
435/// Implements the `HvSetVpRegisters` hypercall.
436pub trait SetVpRegisters {
437    /// Sets the requested registers.
438    fn set_vp_registers(
439        &mut self,
440        partition_id: u64,
441        vp_index: u32,
442        vtl: Option<Vtl>,
443        registers: &[HvRegisterAssoc],
444    ) -> HvRepResult;
445}
446
447impl<T: SetVpRegisters> HypercallDispatch<HvSetVpRegisters> for T {
448    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
449        HvSetVpRegisters::run(params, |header, input, _output| {
450            self.set_vp_registers(
451                header.partition_id,
452                header.vp_index,
453                header.target_vtl.target_vtl().map_err(|err| (err, 0))?,
454                input,
455            )
456        })
457    }
458}
459
460/// Implements the `HvInstallIntercept` hypercall.
461pub trait InstallIntercept {
462    /// Post a synic message.
463    fn install_intercept(
464        &mut self,
465        partition_id: u64,
466        access_type_mask: u32,
467        intercept_type: defs::HvInterceptType,
468        intercept_parameters: defs::HvInterceptParameters,
469    ) -> HvResult<()>;
470}
471
472/// Defines the `HvInstallIntercept` hypercall.
473pub type HvInstallIntercept =
474    SimpleHypercall<defs::InstallIntercept, (), { HypercallCode::HvCallInstallIntercept.0 }>;
475
476impl<T: InstallIntercept> HypercallDispatch<HvInstallIntercept> for T {
477    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
478        HvInstallIntercept::run(params, |input| {
479            self.install_intercept(
480                input.partition_id,
481                input.access_type_mask,
482                input.intercept_type,
483                input.intercept_parameters,
484            )
485        })
486    }
487}
488
489/// Operations required to handle VTL switch hypercalls.
490pub trait VtlSwitchOps {
491    /// Advances the instruction pointer for a vtl switch operation whose preconditions have been
492    /// satisfied, in the context of the initiating vtl.
493    fn advance_ip(&mut self);
494    /// Injects an invalid opcode fault for a vtl switch operation whose preconditions have been
495    /// violated, in the context of the initiating vtl.
496    fn inject_invalid_opcode_fault(&mut self);
497}
498
499/// Implements the `HvVtlReturn` hypercall.
500pub trait VtlReturn {
501    /// Checks if a return to a lower vtl is allowed based on current state.
502    fn is_vtl_return_allowed(&self) -> bool;
503
504    /// Return to a lower VTL.
505    fn vtl_return(&mut self, fast: bool);
506}
507
508/// Defines the `HvVtlReturn` hypercall.
509pub type HvVtlReturn = VtlHypercall<{ HypercallCode::HvCallVtlReturn.0 }>;
510
511impl<T: VtlReturn + VtlSwitchOps> HypercallDispatch<HvVtlReturn> for T {
512    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
513        HvVtlReturn::run(params, |input, control| {
514            // Preconditions for a successful vtl return:
515            // 1. Control must be 0 except for the opcode.
516            // 2. Input must be 0 or 1.
517            // 3. VTL state must allow vtl returns.
518            if u64::from(control.with_code(0)) == 0
519                && (input & !1) == 0
520                && self.is_vtl_return_allowed()
521            {
522                // Advance the instruction pointer and issue the vtl return.
523                self.advance_ip();
524                self.vtl_return(input & 1 != 0);
525            } else {
526                // Inject an error.
527                self.inject_invalid_opcode_fault();
528            }
529        })
530    }
531}
532
533/// Implements the `HvVtlCall` hypercall.
534pub trait VtlCall {
535    /// Checks if a call to a higher vtl is allowed based on current state.
536    fn is_vtl_call_allowed(&self) -> bool;
537    /// Calls the higher VTL.
538    fn vtl_call(&mut self);
539}
540
541/// Defines the `HvVtlCall` hypercall.
542pub type HvVtlCall = VtlHypercall<{ HypercallCode::HvCallVtlCall.0 }>;
543
544impl<T: VtlCall + VtlSwitchOps> HypercallDispatch<HvVtlCall> for T {
545    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
546        HvVtlCall::run(params, |input, control| {
547            // Preconditions for a successful vtl call:
548            // 1. Control must be 0 except for the opcode.
549            // 2. Input must be 0.
550            // 3. VTL state must allow a call to higher VTLs.
551            if u64::from(control.with_code(0)) == 0 && input == 0 && self.is_vtl_call_allowed() {
552                // Advance the instruction pointer and issue the vtl call.
553                self.advance_ip();
554                self.vtl_call();
555            } else {
556                self.inject_invalid_opcode_fault();
557            }
558        })
559    }
560}
561
562/// Implements the `HvEnableVpVtl` hypercall.
563pub trait EnableVpVtl<T> {
564    /// Enable the specified VTL.
565    fn enable_vp_vtl(
566        &mut self,
567        partition_id: u64,
568        vp_index: u32,
569        vtl: Vtl,
570        vp_context: &T,
571    ) -> HvResult<()>;
572}
573
574/// Defines the `HvEnableVpVtl` hypercall for x64.
575pub type HvX64EnableVpVtl =
576    SimpleHypercall<defs::EnableVpVtlX64, (), { HypercallCode::HvCallEnableVpVtl.0 }>;
577
578impl<T: EnableVpVtl<hvdef::hypercall::InitialVpContextX64>> HypercallDispatch<HvX64EnableVpVtl>
579    for T
580{
581    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
582        HvX64EnableVpVtl::run(params, |input| {
583            self.enable_vp_vtl(
584                input.partition_id,
585                input.vp_index,
586                Vtl::try_from(input.target_vtl)?,
587                &input.vp_vtl_context,
588            )
589        })
590    }
591}
592
593/// Defines the `HvEnableVpVtl` hypercall for arm64.
594pub type HvArm64EnableVpVtl =
595    SimpleHypercall<defs::EnableVpVtlArm64, (), { HypercallCode::HvCallEnableVpVtl.0 }>;
596
597impl<T: EnableVpVtl<hvdef::hypercall::InitialVpContextArm64>> HypercallDispatch<HvArm64EnableVpVtl>
598    for T
599{
600    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
601        HvArm64EnableVpVtl::run(params, |input| {
602            self.enable_vp_vtl(
603                input.partition_id,
604                input.vp_index,
605                Vtl::try_from(input.target_vtl)?,
606                &input.vp_vtl_context,
607            )
608        })
609    }
610}
611
612/// Implements the `HvModifyVtlProtectionMask` hypercall.
613pub trait ModifyVtlProtectionMask {
614    /// Modify the VTL protection mask for the list of pages specified by `gpa_pages`.
615    /// `map_flags` represents the desired permissions for VTLs lower than `target_vtl`.
616    /// `target_vtl` must be lower or equal to the current VTL. It cannot be VTL0.
617    fn modify_vtl_protection_mask(
618        &mut self,
619        partition_id: u64,
620        map_flags: hvdef::HvMapGpaFlags,
621        target_vtl: Option<Vtl>,
622        gpa_pages: &[u64],
623    ) -> HvRepResult;
624}
625
626/// Defines the `HvModifyVtlProtectionMask` hypercall.
627pub type HvModifyVtlProtectionMask = RepHypercall<
628    defs::ModifyVtlProtectionMask,
629    u64,
630    (),
631    { HypercallCode::HvCallModifyVtlProtectionMask.0 },
632>;
633
634impl<T: ModifyVtlProtectionMask> HypercallDispatch<HvModifyVtlProtectionMask> for T {
635    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
636        HvModifyVtlProtectionMask::run(params, |header, input, _output| {
637            self.modify_vtl_protection_mask(
638                header.partition_id,
639                header.map_flags,
640                header.target_vtl.target_vtl().map_err(|err| (err, 0))?,
641                input,
642            )
643        })
644    }
645}
646
647/// Implements the `HvGetVpIndexFromApicId` hypercall.
648pub trait GetVpIndexFromApicId {
649    /// Gets a list of VP indices from a list of APIC IDs.
650    fn get_vp_index_from_apic_id(
651        &mut self,
652        partition_id: u64,
653        target_vtl: Vtl,
654        apic_ids: &[u32],
655        vp_indices: &mut [u32],
656    ) -> HvRepResult;
657}
658
659/// Defines the `HvGetVpIndexFromApicId` hypercall.
660pub type HvGetVpIndexFromApicId = RepHypercall<
661    defs::GetVpIndexFromApicId,
662    u32,
663    u32,
664    { HypercallCode::HvCallGetVpIndexFromApicId.0 },
665>;
666
667impl<T: GetVpIndexFromApicId> HypercallDispatch<HvGetVpIndexFromApicId> for T {
668    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
669        HvGetVpIndexFromApicId::run(params, |header, input, output| {
670            self.get_vp_index_from_apic_id(
671                header.partition_id,
672                Vtl::try_from(header.target_vtl).map_err(|err| (err, 0))?,
673                input,
674                output,
675            )
676        })
677    }
678}
679
680/// Implements the `HvAcceptGpaPages` hypercall.
681pub trait AcceptGpaPages {
682    /// Accepts the described pages.
683    fn accept_gpa_pages(
684        &mut self,
685        partition_id: u64,
686        page_attributes: AcceptPagesAttributes,
687        vtl_permission_set: VtlPermissionSet,
688        gpa_page_base: u64,
689        page_count: usize,
690    ) -> HvRepResult;
691}
692
693/// Defines the `HvAcceptGpaPages` hypercall.
694pub type HvAcceptGpaPages =
695    RepHypercall<defs::AcceptGpaPages, u64, (), { HypercallCode::HvCallAcceptGpaPages.0 }>;
696
697impl<T: AcceptGpaPages> HypercallDispatch<HvAcceptGpaPages> for T {
698    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
699        HvAcceptGpaPages::run(params, |header, input, _output| {
700            self.accept_gpa_pages(
701                header.partition_id,
702                header.page_attributes,
703                header.vtl_permission_set,
704                header.gpa_page_base,
705                input.len(),
706            )
707        })
708    }
709}
710
711/// Implements the `HvModifySparseGpaPageHostVisibility` hypercall.
712pub trait ModifySparseGpaPageHostVisibility {
713    /// Modifies the host page visibility for the listed pages.
714    fn modify_gpa_visibility(
715        &mut self,
716        partition_id: u64,
717        visibility: HostVisibilityType,
718        gpa_pages: &[u64],
719    ) -> HvRepResult;
720}
721
722/// Defines the `HvModifySparseGpaPageHostVisibility` hypercall.
723pub type HvModifySparseGpaPageHostVisibility = RepHypercall<
724    defs::ModifySparsePageVisibility,
725    u64,
726    (),
727    { HypercallCode::HvCallModifySparseGpaPageHostVisibility.0 },
728>;
729
730impl<T: ModifySparseGpaPageHostVisibility> HypercallDispatch<HvModifySparseGpaPageHostVisibility>
731    for T
732{
733    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
734        HvModifySparseGpaPageHostVisibility::run(params, |header, input, _output| {
735            self.modify_gpa_visibility(
736                header.partition_id,
737                header.host_visibility.host_visibility(),
738                input,
739            )
740        })
741    }
742}
743
744/// Implements the `HvEnablePartitionVtl` hypercall.
745pub trait EnablePartitionVtl {
746    /// Enables the VTL for the partition.
747    fn enable_partition_vtl(
748        &mut self,
749        partition_id: u64,
750        target_vtl: Vtl,
751        flags: defs::EnablePartitionVtlFlags,
752    ) -> HvResult<()>;
753}
754
755/// Defines the `HvEnablePartitionVtl` hypercall.
756pub type HvEnablePartitionVtl =
757    SimpleHypercall<defs::EnablePartitionVtl, (), { HypercallCode::HvCallEnablePartitionVtl.0 }>;
758
759impl<T: EnablePartitionVtl> HypercallDispatch<HvEnablePartitionVtl> for T {
760    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
761        HvEnablePartitionVtl::run(params, |input| {
762            self.enable_partition_vtl(
763                input.partition_id,
764                Vtl::try_from(input.target_vtl).map_err(|_| HvError::AccessDenied)?,
765                input.flags,
766            )
767        })
768    }
769}
770
771/// Implements the `HvFlushVirtualAddressList` hypercall.
772pub trait FlushVirtualAddressList {
773    /// Invalidates portions of the virtual TLB.
774    fn flush_virtual_address_list(
775        &mut self,
776        processor_set: ProcessorSet<'_>,
777        flags: defs::HvFlushFlags,
778        gva_ranges: &[defs::HvGvaRange],
779    ) -> HvRepResult;
780}
781
782/// Defines the `HvFlushVirtualAddressList` hypercall.
783pub type HvFlushVirtualAddressList = RepHypercall<
784    defs::FlushVirtualAddressSpace,
785    defs::HvGvaRange,
786    (),
787    { HypercallCode::HvCallFlushVirtualAddressList.0 },
788>;
789
790impl<T: FlushVirtualAddressList> HypercallDispatch<HvFlushVirtualAddressList> for T {
791    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
792        HvFlushVirtualAddressList::run(params, |header, input, _output| {
793            let masks = &[header.processor_mask];
794            let processors = ProcessorSet::from_processor_masks(1, masks)
795                .ok_or((HvError::InvalidParameter, 0))?;
796            self.flush_virtual_address_list(processors, header.flags, input)
797        })
798    }
799}
800
801/// Implements the `HvFlushVirtualAddressListEx` hypercall.
802pub trait FlushVirtualAddressListEx {
803    /// Invalidates portions of the virtual TLB.
804    fn flush_virtual_address_list_ex(
805        &mut self,
806        processor_set: ProcessorSet<'_>,
807        flags: defs::HvFlushFlags,
808        gva_ranges: &[defs::HvGvaRange],
809    ) -> HvRepResult;
810}
811
812/// Defines the `HvFlushVirtualAddressListEx` hypercall.
813pub type HvFlushVirtualAddressListEx = VariableRepHypercall<
814    defs::FlushVirtualAddressSpaceEx,
815    defs::HvGvaRange,
816    (),
817    { HypercallCode::HvCallFlushVirtualAddressListEx.0 },
818>;
819
820impl<T: FlushVirtualAddressListEx> HypercallDispatch<HvFlushVirtualAddressListEx> for T {
821    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
822        HvFlushVirtualAddressListEx::run(params, |header, variable_input, input, _output| {
823            if header.vp_set_format != hvdef::hypercall::HV_GENERIC_SET_SPARSE_4K {
824                return Err((HvError::InvalidParameter, 0));
825            }
826
827            let processors =
828                ProcessorSet::from_processor_masks(header.vp_set_valid_banks_mask, variable_input)
829                    .ok_or((HvError::InvalidParameter, 0))?;
830            self.flush_virtual_address_list_ex(processors, header.flags, input)
831        })
832    }
833}
834
835/// Implements the `HvFlushVirtualAddressSpace` hypercall.
836pub trait FlushVirtualAddressSpace {
837    /// Invalidates all virtual TLB entries.
838    fn flush_virtual_address_space(
839        &mut self,
840        processor_set: ProcessorSet<'_>,
841        flags: defs::HvFlushFlags,
842    ) -> HvResult<()>;
843}
844
845/// Defines the `HvFlushVirtualAddressSpace` hypercall.
846pub type HvFlushVirtualAddressSpace = SimpleHypercall<
847    defs::FlushVirtualAddressSpace,
848    (),
849    { HypercallCode::HvCallFlushVirtualAddressSpace.0 },
850>;
851
852impl<T: FlushVirtualAddressSpace> HypercallDispatch<HvFlushVirtualAddressSpace> for T {
853    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
854        HvFlushVirtualAddressSpace::run(params, |input| {
855            let masks = &[input.processor_mask];
856            let processors =
857                ProcessorSet::from_processor_masks(1, masks).ok_or(HvError::InvalidParameter)?;
858            self.flush_virtual_address_space(processors, input.flags)
859        })
860    }
861}
862
863/// Implements the `HvFlushVirtualAddressSpaceEx` hypercall.
864pub trait FlushVirtualAddressSpaceEx {
865    /// Invalidates all virtual TLB entries.
866    fn flush_virtual_address_space_ex(
867        &mut self,
868        processor_set: ProcessorSet<'_>,
869        flags: defs::HvFlushFlags,
870    ) -> HvResult<()>;
871}
872
873/// Defines the `HvFlushVirtualAddressSpaceEx` hypercall.
874pub type HvFlushVirtualAddressSpaceEx = VariableHypercall<
875    defs::FlushVirtualAddressSpaceEx,
876    (),
877    { HypercallCode::HvCallFlushVirtualAddressSpaceEx.0 },
878>;
879
880impl<T: FlushVirtualAddressSpaceEx> HypercallDispatch<HvFlushVirtualAddressSpaceEx> for T {
881    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
882        HvFlushVirtualAddressSpaceEx::run(params, |header, input| {
883            if header.vp_set_format != hvdef::hypercall::HV_GENERIC_SET_SPARSE_4K {
884                return Err(HvError::InvalidParameter);
885            }
886
887            let processors =
888                ProcessorSet::from_processor_masks(header.vp_set_valid_banks_mask, input)
889                    .ok_or(HvError::InvalidParameter)?;
890            self.flush_virtual_address_space_ex(processors, header.flags)
891        })
892    }
893}
894
895/// Implements the `HvQuerySparseGpaPageHostVisibility` hypercall.
896pub trait QuerySparseGpaPageHostVisibility {
897    /// Queries the host page visibility for the listed pages.
898    fn query_gpa_visibility(
899        &mut self,
900        partition_id: u64,
901        gpa_pages: &[u64],
902        host_visibility: &mut [HostVisibilityType],
903    ) -> HvRepResult;
904}
905
906/// Defines the `HvQuerySparseGpaPageHostVisibility` hypercall.
907pub type HvQuerySparseGpaPageHostVisibility = RepHypercall<
908    defs::QuerySparsePageVisibility,
909    u64,
910    HostVisibilityType,
911    { HypercallCode::HvCallQuerySparseGpaPageHostVisibility.0 },
912>;
913
914impl<T: QuerySparseGpaPageHostVisibility> HypercallDispatch<HvQuerySparseGpaPageHostVisibility>
915    for T
916{
917    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
918        HvQuerySparseGpaPageHostVisibility::run(params, |header, input, output| {
919            self.query_gpa_visibility(header.partition_id, input, output)
920        })
921    }
922}
923
924/// Implements the `HvExtQueryCapabilities` hypercall.
925pub trait ExtendedQueryCapabilities {
926    /// Queries extended capabilities.
927    fn query_extended_capabilities(&mut self) -> HvResult<u64>;
928}
929
930/// Defines the `HvExtQueryCapabilities` hypercall.
931pub type HvExtQueryCapabilities =
932    SimpleHypercall<(), u64, { HypercallCode::HvExtCallQueryCapabilities.0 }>;
933
934impl<T: ExtendedQueryCapabilities> HypercallDispatch<HvExtQueryCapabilities> for T {
935    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
936        HvExtQueryCapabilities::run(params, |()| self.query_extended_capabilities())
937    }
938}
939
940/// Defines the `HvSendSyntheticClusterIpi` hypercall.
941pub type HvSendSyntheticClusterIpi = SimpleHypercall<
942    defs::SendSyntheticClusterIpi,
943    (),
944    { HypercallCode::HvCallSendSyntheticClusterIpi.0 },
945>;
946
947/// Implements the `HvSendSyntheticClusterIpi` hypercall.
948pub trait SendSyntheticClusterIpi {
949    /// Sends an ipi to a synthetic cluster.
950    fn send_synthetic_cluster_ipi(
951        &mut self,
952        target_vtl: Option<Vtl>,
953        vector: u32,
954        flags: u8,
955        processor_set: ProcessorSet<'_>,
956    ) -> HvResult<()>;
957}
958
959impl<T: SendSyntheticClusterIpi> HypercallDispatch<HvSendSyntheticClusterIpi> for T {
960    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
961        HvSendSyntheticClusterIpi::run(params, |input| {
962            if input.reserved != 0 {
963                return Err(HvError::InvalidParameter);
964            }
965            self.send_synthetic_cluster_ipi(
966                input.target_vtl.target_vtl()?,
967                input.vector,
968                input.flags,
969                ProcessorSet::from_processor_masks(1, &[input.processor_mask])
970                    .ok_or(HvError::InvalidParameter)?,
971            )
972        })
973    }
974}
975
976/// Defines the `HvSendSyntheticClusterIpi` hypercall.
977pub type HvSendSyntheticClusterIpiEx = VariableHypercall<
978    defs::SendSyntheticClusterIpiEx,
979    (),
980    { HypercallCode::HvCallSendSyntheticClusterIpiEx.0 },
981>;
982
983/// Implements the `HvSendSyntheticClusterIpi` hypercall.
984pub trait SendSyntheticClusterIpiEx {
985    /// Sends an ipi to a synthetic cluster.
986    fn send_synthetic_cluster_ipi_ex(
987        &mut self,
988        target_vtl: Option<Vtl>,
989        vector: u32,
990        flags: u8,
991        processor_set: ProcessorSet<'_>,
992    ) -> HvResult<()>;
993}
994
995impl<T: SendSyntheticClusterIpiEx> HypercallDispatch<HvSendSyntheticClusterIpiEx> for T {
996    fn dispatch(&mut self, params: HypercallParameters<'_>) -> HypercallOutput {
997        HvSendSyntheticClusterIpiEx::run(params, |header, input| {
998            if header.reserved != 0 {
999                return Err(HvError::InvalidParameter);
1000            }
1001
1002            if header.vp_set_format != hvdef::hypercall::HV_GENERIC_SET_SPARSE_4K {
1003                return Err(HvError::InvalidParameter);
1004            }
1005
1006            self.send_synthetic_cluster_ipi_ex(
1007                header.target_vtl.target_vtl()?,
1008                header.vector,
1009                header.flags,
1010                ProcessorSet::from_processor_masks(header.vp_set_valid_banks_mask, input)
1011                    .ok_or(HvError::InvalidParameter)?,
1012            )
1013        })
1014    }
1015}