microsoft/openvmm

Public

mirrored from https://github.com/microsoft/openvmmAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
release/2411-fork

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

openhcl/hcl/src/ioctl/deferred.rs

111lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Support routines for deferred actions.
5
6use super::Hcl;
7use crate::protocol;
8use crate::protocol::hcl_run;
9use std::ptr::addr_of_mut;
10use std::ptr::NonNull;
11use zerocopy::AsBytes;
12
13#[derive(Debug, Default)]
14pub struct DeferredActions {
15 actions: Vec<DeferredAction>,
16}
17
18const MAX_ACTIONS: usize = 8;
19
20impl DeferredActions {
21 /// Pushes the actions.
22 pub fn push(&mut self, hcl: &Hcl, action: DeferredAction) {
23 if self.actions.len() < MAX_ACTIONS {
24 self.actions.push(action);
25 } else {
26 action.run(hcl);
27 }
28 }
29
30 /// Copies the queued actions to the slots in the run page. Issues any
31 /// immediately that won't fit in the run page.
32 pub fn copy_to_slots(&mut self, slots: &mut DeferredActionSlots, hcl: &Hcl) {
33 for action in self.actions.drain(..) {
34 if !action.post(slots) {
35 action.run(hcl);
36 }
37 }
38 }
39
40 /// Runs actions immediately without deferring them to VTL return.
41 pub fn run_actions(&mut self, hcl: &Hcl) {
42 for action in self.actions.drain(..) {
43 action.run(hcl);
44 }
45 }
46}
47
48/// A deferred action that can be handled by the hypervisor as part of switching
49/// VTLs.
50#[derive(Debug, Copy, Clone)]
51pub enum DeferredAction {
52 SignalEvent { vp: u32, sint: u8, flag: u16 },
53}
54
55impl DeferredAction {
56 /// Run the action via a hypercall.
57 fn run(&self, hcl: &Hcl) {
58 match *self {
59 DeferredAction::SignalEvent { vp, sint, flag } => {
60 let _ = hcl.hvcall_signal_event_direct(vp, sint, flag);
61 }
62 }
63 }
64
65 /// Post the action to the HCL.
66 fn post(&self, slots: &mut DeferredActionSlots) -> bool {
67 match *self {
68 DeferredAction::SignalEvent { vp, sint, flag } => slots.push(
69 protocol::hv_vp_assist_page_signal_event {
70 action_type: protocol::HV_VP_ASSIST_PAGE_ACTION_TYPE_SIGNAL_EVENT,
71 vp,
72 vtl: 0,
73 sint,
74 flag,
75 }
76 .as_bytes(),
77 ),
78 }
79 }
80}
81
82/// A reference to the HCL run data structure's deferred action slots.
83pub struct DeferredActionSlots(NonNull<hcl_run>);
84
85impl DeferredActionSlots {
86 /// # Safety
87 /// The caller must ensure that the return action fields in `run` remain
88 /// valid and unaliased for the lifetime of this object.
89 pub unsafe fn new(run: NonNull<hcl_run>) -> Self {
90 Self(run)
91 }
92
93 fn push(&mut self, action: &[u8]) -> bool {
94 let (used, buffer);
95 // SAFETY: this thread is the only one concurrently accessing the
96 // action-related portions of the run structure.
97 unsafe {
98 used = &mut *addr_of_mut!((*self.0.as_ptr()).vtl_ret_action_size);
99 buffer = &mut *addr_of_mut!((*self.0.as_ptr()).vtl_ret_actions);
100 }
101 let offset = *used as usize;
102 if let Some(buffer) = buffer.get_mut(offset..offset + action.len()) {
103 buffer.copy_from_slice(action);
104 *used += action.len() as u32;
105 true
106 } else {
107 // The action buffer is full.
108 false
109 }
110 }
111}
112