1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//! The word a guest passes out when it wants a component's attention, and the
//! two macros that name the values inside it.
//!
//! Code inside the guest puts a 48-bit body in RAX and executes a vmcall; a
//! component subscribed to `#[core(vmcall)]` is handed it as a [`VMCall`],
//! already decoded. That splits into the 32-bit call type and the 16-bit
//! destination component id, which is what the call is routed on.
/// Define a `#[repr(u32)]` enum whose discriminants are `fnv1a_32` of the
/// variant names, plus a `from_raw` that turns a wire value back into one.
///
/// Use it for the call-type half of a vmcall body. A variant's number follows
/// from its name, so adding one in the middle of the list renumbers nothing and
/// renaming one changes the wire value.
///
/// The hash covers the variant name alone, so `Ready` is the same number in
/// every `vmcall_enum!`. Where two enums must not collide, reach for
/// [`tag_enum!`](crate::tag_enum) instead, which hashes the enum name in as well.
///
/// `from_raw` answers `None` for a word that matches no variant — a guest that
/// is newer than the component, or a body that was never a call at all.
///
/// # Examples
///
/// ```ignore
/// vmcall_enum! {
/// pub enum AgentCalls {
/// Ready,
/// Poll,
/// Result,
/// }
/// }
///
/// assert_eq!(AgentCalls::Ready as u32, 0x0bca_3294);
/// assert_eq!(AgentCalls::from_raw(0x0bca_3294), Some(AgentCalls::Ready));
/// assert_eq!(AgentCalls::from_raw(0), None);
///
/// #[core(vmcall)]
/// fn on_vmcall(&mut self, _t: &mut Control, call: VMCall) {
/// match AgentCalls::from_raw(call.ty_raw()) {
/// Some(AgentCalls::Ready) => self.armed = true,
/// Some(_) | None => {},
/// }
/// }
/// ```
/// Define a `#[repr(u64)]` enum whose discriminants are
/// `fnv1a_64("EnumName::VariantName")`, plus a `from_raw` that turns a wire
/// value back into one.
///
/// The enum name is part of the hash, so a `Read` in one of these and a `Read`
/// in another are different numbers. Reach for it over
/// [`vmcall_enum!`](crate::vmcall_enum) for a tag riding in a shared buffer,
/// where a value from the wrong protocol must not decode as a plausible member
/// of yours.
///
/// `from_raw` answers `None` for anything that matches no variant.
///
/// # Examples
///
/// ```ignore
/// tag_enum! {
/// pub enum CmdTag {
/// WriteFile,
/// ReadFile,
/// }
/// }
///
/// assert_eq!(CmdTag::WriteFile as u64, 0x0e3a_03f3_7c93_bb56);
/// assert_eq!(CmdTag::from_raw(0x0e3a_03f3_7c93_bb56), Some(CmdTag::WriteFile));
/// assert_eq!(CmdTag::from_raw(1), None);
/// ```
/// The 48 bits of RAX that carry a body; the top 16 are not part of it.
pub const VMC_BODY_MASK: u64 = 0x0000_FFFF_FFFF_FFFF;
/// Bits `[47:16]`, the call type.
pub const VMC_TYPE_MASK: u64 = 0x0000_FFFF_FFFF_0000;
/// Bits `[15:0]`, the destination component id.
pub const VMC_DST_MASK: u64 = 0x0000_0000_0000_FFFF;
/// The destination that reaches every loaded component instead of one.
pub const VMC_DST_BROADCAST: u16 = 0;
/// One vmcall body: a 32-bit call type and a 16-bit destination, packed into 48
/// bits.
///
/// A `#[core(vmcall)]` handler is passed one of these directly. Read
/// [`dst`](VMCall::dst) to see whether the call was aimed at you, and
/// [`ty_raw`](VMCall::ty_raw) to see which call it was.
/// [`from_body`](VMCall::from_body) is for decoding a raw register value
/// yourself.
///
/// # Examples
///
/// ```ignore
/// vmcall_enum! { pub enum AgentCalls { Ready, Poll } }
///
/// // What the guest agent puts in RAX, aimed at every component.
/// let call = VMCall::new(AgentCalls::Ready as u32, VMC_DST_BROADCAST);
/// assert_eq!(call.body(), 0x0bca_3294_0000);
///
/// // What the handler does with it.
/// let got = VMCall::from_body(call.body());
/// assert_eq!(got.dst(), VMC_DST_BROADCAST);
/// assert_eq!(AgentCalls::from_raw(got.ty_raw()), Some(AgentCalls::Ready));
/// ```
;