1use crate::interface_args::SuccessArgs;
7use thiserror::Error;
8use zerocopy::transmute;
9
10#[derive(Debug, Error, PartialEq, Eq, Clone, Copy)]
13pub enum Error {
14 #[error("Invalid Flag for Notification Set")]
15 InvalidNotificationSetFlag(u32),
16 #[error("Invalid notification count")]
17 InvalidNotificationCount,
18}
19
20#[derive(Debug, Eq, PartialEq, Clone, Copy)]
22pub struct NotificationBindFlags {
23 pub per_vcpu_notification: bool,
24}
25
26impl NotificationBindFlags {
27 const PER_VCPU_NOTIFICATION: u32 = 1;
28}
29
30impl From<NotificationBindFlags> for u32 {
31 fn from(flags: NotificationBindFlags) -> Self {
32 let mut bits: u32 = 0;
33 if flags.per_vcpu_notification {
34 bits |= NotificationBindFlags::PER_VCPU_NOTIFICATION;
35 }
36 bits
37 }
38}
39
40impl From<u32> for NotificationBindFlags {
41 fn from(flags: u32) -> Self {
42 Self {
43 per_vcpu_notification: flags & Self::PER_VCPU_NOTIFICATION != 0,
44 }
45 }
46}
47
48#[derive(Debug, Eq, PartialEq, Clone, Copy)]
50pub struct NotificationSetFlags {
51 pub delay_schedule_receiver: bool,
52 pub vcpu_id: Option<u16>,
53}
54
55impl NotificationSetFlags {
56 const PER_VCP_NOTIFICATION: u32 = 1 << 0;
57 const DELAY_SCHEDULE_RECEIVER: u32 = 1 << 1;
58 const VCPU_ID_SHIFT: u32 = 16;
59
60 const MBZ_BITS: u32 = 0xfffc;
61}
62
63impl From<NotificationSetFlags> for u32 {
64 fn from(flags: NotificationSetFlags) -> Self {
65 let mut bits: u32 = 0;
66
67 if flags.delay_schedule_receiver {
68 bits |= NotificationSetFlags::DELAY_SCHEDULE_RECEIVER;
69 }
70 if let Some(vcpu_id) = flags.vcpu_id {
71 bits |= NotificationSetFlags::PER_VCP_NOTIFICATION;
72 bits |= u32::from(vcpu_id) << NotificationSetFlags::VCPU_ID_SHIFT;
73 }
74
75 bits
76 }
77}
78
79impl TryFrom<u32> for NotificationSetFlags {
80 type Error = Error;
81
82 fn try_from(flags: u32) -> Result<Self, Self::Error> {
83 if (flags & Self::MBZ_BITS) != 0 {
84 return Err(Error::InvalidNotificationSetFlag(flags));
85 }
86
87 let tentative_vcpu_id = (flags >> Self::VCPU_ID_SHIFT) as u16;
88
89 let vcpu_id = if (flags & Self::PER_VCP_NOTIFICATION) != 0 {
90 Some(tentative_vcpu_id)
91 } else {
92 if tentative_vcpu_id != 0 {
93 return Err(Error::InvalidNotificationSetFlag(flags));
94 }
95 None
96 };
97
98 Ok(Self {
99 delay_schedule_receiver: (flags & Self::DELAY_SCHEDULE_RECEIVER) != 0,
100 vcpu_id,
101 })
102 }
103}
104
105#[derive(Debug, Eq, PartialEq, Clone, Copy)]
107pub struct NotificationGetFlags {
108 pub sp_bitmap_id: bool,
109 pub vm_bitmap_id: bool,
110 pub spm_bitmap_id: bool,
111 pub hyp_bitmap_id: bool,
112}
113
114impl NotificationGetFlags {
115 const SP_BITMAP_ID: u32 = 1;
116 const VM_BITMAP_ID: u32 = 1 << 1;
117 const SPM_BITMAP_ID: u32 = 1 << 2;
118 const HYP_BITMAP_ID: u32 = 1 << 3;
119}
120
121impl From<NotificationGetFlags> for u32 {
122 fn from(flags: NotificationGetFlags) -> Self {
123 let mut bits: u32 = 0;
124 if flags.sp_bitmap_id {
125 bits |= NotificationGetFlags::SP_BITMAP_ID;
126 }
127 if flags.vm_bitmap_id {
128 bits |= NotificationGetFlags::VM_BITMAP_ID;
129 }
130 if flags.spm_bitmap_id {
131 bits |= NotificationGetFlags::SPM_BITMAP_ID;
132 }
133 if flags.hyp_bitmap_id {
134 bits |= NotificationGetFlags::HYP_BITMAP_ID;
135 }
136 bits
137 }
138}
139
140impl From<u32> for NotificationGetFlags {
141 fn from(flags: u32) -> Self {
143 Self {
144 sp_bitmap_id: (flags & Self::SP_BITMAP_ID) != 0,
145 vm_bitmap_id: (flags & Self::VM_BITMAP_ID) != 0,
146 spm_bitmap_id: (flags & Self::SPM_BITMAP_ID) != 0,
147 hyp_bitmap_id: (flags & Self::HYP_BITMAP_ID) != 0,
148 }
149 }
150}
151
152#[derive(Debug, Eq, PartialEq, Clone, Copy)]
154pub struct SuccessArgsNotificationGet {
155 pub sp_notifications: Option<u64>,
156 pub vm_notifications: Option<u64>,
157 pub spm_notifications: Option<u32>,
158 pub hypervisor_notifications: Option<u32>,
159}
160
161impl From<SuccessArgsNotificationGet> for SuccessArgs {
162 fn from(value: SuccessArgsNotificationGet) -> Self {
163 let mut args = [0; 6];
164
165 if let Some(bitmap) = value.sp_notifications {
166 args[0] = bitmap as u32;
167 args[1] = (bitmap >> 32) as u32;
168 }
169
170 if let Some(bitmap) = value.vm_notifications {
171 args[2] = bitmap as u32;
172 args[3] = (bitmap >> 32) as u32;
173 }
174
175 if let Some(bitmap) = value.spm_notifications {
176 args[4] = bitmap;
177 }
178
179 if let Some(bitmap) = value.hypervisor_notifications {
180 args[5] = bitmap;
181 }
182
183 Self::Args32(args)
184 }
185}
186
187impl TryFrom<(NotificationGetFlags, SuccessArgs)> for SuccessArgsNotificationGet {
188 type Error = crate::Error;
189
190 fn try_from(value: (NotificationGetFlags, SuccessArgs)) -> Result<Self, Self::Error> {
191 let (flags, value) = value;
192 let args = value.try_get_args32()?;
193
194 let sp_notifications = if flags.sp_bitmap_id {
195 Some(u64::from(args[0]) | (u64::from(args[1]) << 32))
196 } else {
197 None
198 };
199
200 let vm_notifications = if flags.vm_bitmap_id {
201 Some(u64::from(args[2]) | (u64::from(args[3]) << 32))
202 } else {
203 None
204 };
205
206 let spm_notifications = if flags.spm_bitmap_id {
207 Some(args[4])
208 } else {
209 None
210 };
211
212 let hypervisor_notifications = if flags.hyp_bitmap_id {
213 Some(args[5])
214 } else {
215 None
216 };
217
218 Ok(Self {
219 sp_notifications,
220 vm_notifications,
221 spm_notifications,
222 hypervisor_notifications,
223 })
224 }
225}
226
227#[derive(Debug, Eq, PartialEq, Clone, Copy)]
230pub struct SuccessArgsNotificationInfoGet<const MAX_COUNT: usize> {
231 pub more_pending_notifications: bool,
232 pub(crate) list_count: usize,
233 pub(crate) id_counts: [u8; MAX_COUNT],
234 pub(crate) ids: [u16; MAX_COUNT],
235}
236
237impl<const MAX_COUNT: usize> Default for SuccessArgsNotificationInfoGet<MAX_COUNT> {
238 fn default() -> Self {
239 Self {
240 more_pending_notifications: false,
241 list_count: 0,
242 id_counts: [0; MAX_COUNT],
243 ids: [0; MAX_COUNT],
244 }
245 }
246}
247
248impl<const MAX_COUNT: usize> SuccessArgsNotificationInfoGet<MAX_COUNT> {
249 const MORE_PENDING_NOTIFICATIONS_FLAG: u64 = 1 << 0;
250 const LIST_COUNT_SHIFT: usize = 7;
251 const LIST_COUNT_MASK: u64 = 0x1f;
252 const ID_COUNT_SHIFT: usize = 12;
253 const ID_COUNT_MASK: u64 = 0x03;
254 const ID_COUNT_BITS: usize = 2;
255
256 pub fn add_list(&mut self, endpoint: u16, vcpu_ids: &[u16]) -> Result<(), Error> {
257 if self.list_count >= MAX_COUNT || vcpu_ids.len() > Self::ID_COUNT_MASK as usize {
258 return Err(Error::InvalidNotificationCount);
259 }
260
261 let mut current_id_index = self.list_count + self.id_counts.iter().sum::<u8>() as usize;
264 if current_id_index + 1 + vcpu_ids.len() > MAX_COUNT {
265 return Err(Error::InvalidNotificationCount);
267 }
268
269 self.id_counts[self.list_count] = vcpu_ids.len() as u8;
270 self.list_count += 1;
271
272 self.ids[current_id_index] = endpoint;
274 current_id_index += 1;
275
276 self.ids[current_id_index..current_id_index + vcpu_ids.len()].copy_from_slice(vcpu_ids);
278
279 Ok(())
280 }
281
282 pub fn iter(&self) -> NotificationInfoGetIterator<'_> {
283 NotificationInfoGetIterator {
284 list_index: 0,
285 id_index: 0,
286 id_count: &self.id_counts[0..self.list_count],
287 ids: &self.ids,
288 }
289 }
290
291 fn pack(self) -> (u64, [u16; MAX_COUNT]) {
293 let mut flags = if self.more_pending_notifications {
294 Self::MORE_PENDING_NOTIFICATIONS_FLAG
295 } else {
296 0
297 };
298
299 flags |= (self.list_count as u64) << Self::LIST_COUNT_SHIFT;
300 for (count, shift) in self.id_counts.iter().take(self.list_count).zip(
301 (Self::ID_COUNT_SHIFT..Self::ID_COUNT_SHIFT + Self::ID_COUNT_BITS * MAX_COUNT)
302 .step_by(Self::ID_COUNT_BITS),
303 ) {
304 flags |= u64::from(*count) << shift;
305 }
306
307 (flags, self.ids)
308 }
309
310 fn unpack(flags: u64, ids: [u16; MAX_COUNT]) -> Result<Self, Error> {
312 let count_of_lists = ((flags >> Self::LIST_COUNT_SHIFT) & Self::LIST_COUNT_MASK) as usize;
313
314 if count_of_lists > MAX_COUNT {
315 return Err(Error::InvalidNotificationCount);
316 }
317
318 let mut count_of_ids = [0; MAX_COUNT];
319 let mut count_of_ids_bits = flags >> Self::ID_COUNT_SHIFT;
320
321 for id in count_of_ids.iter_mut().take(count_of_lists) {
322 *id = (count_of_ids_bits & Self::ID_COUNT_MASK) as u8;
323 count_of_ids_bits >>= Self::ID_COUNT_BITS;
324 }
325
326 let id_field_count = count_of_lists + count_of_ids.iter().sum::<u8>() as usize;
327 if id_field_count > MAX_COUNT {
328 return Err(Error::InvalidNotificationCount);
329 }
330
331 Ok(Self {
332 more_pending_notifications: (flags & Self::MORE_PENDING_NOTIFICATIONS_FLAG) != 0,
333 list_count: count_of_lists,
334 id_counts: count_of_ids,
335 ids,
336 })
337 }
338}
339
340pub type SuccessArgsNotificationInfoGet32 = SuccessArgsNotificationInfoGet<10>;
342
343impl From<SuccessArgsNotificationInfoGet32> for SuccessArgs {
344 fn from(value: SuccessArgsNotificationInfoGet32) -> Self {
345 let (flags, ids) = value.pack();
346 let id_regs: [u32; 5] = transmute!(ids);
347
348 let mut args = [0; 6];
349 args[0] = flags as u32;
350 args[1..6].copy_from_slice(&id_regs);
351
352 SuccessArgs::Args32(args)
353 }
354}
355
356impl TryFrom<SuccessArgs> for SuccessArgsNotificationInfoGet32 {
357 type Error = crate::Error;
358
359 fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
360 let args = value.try_get_args32()?;
361 let flags = args[0].into();
362 let id_regs: [u32; 5] = args[1..6].try_into().unwrap();
363 Self::unpack(flags, transmute!(id_regs)).map_err(|e| e.into())
364 }
365}
366
367pub type SuccessArgsNotificationInfoGet64 = SuccessArgsNotificationInfoGet<20>;
369
370impl From<SuccessArgsNotificationInfoGet64> for SuccessArgs {
371 fn from(value: SuccessArgsNotificationInfoGet64) -> Self {
372 let (flags, ids) = value.pack();
373 let id_regs: [u64; 5] = transmute!(ids);
374
375 let mut args = [0; 16];
376 args[0] = flags;
377 args[1..6].copy_from_slice(&id_regs);
378
379 SuccessArgs::Args64(args)
380 }
381}
382
383impl TryFrom<SuccessArgs> for SuccessArgsNotificationInfoGet64 {
384 type Error = crate::Error;
385
386 fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
387 let args = value.try_get_args64()?;
388 let flags = args[0];
389 let id_regs: [u64; 5] = args[1..6].try_into().unwrap();
390 Self::unpack(flags, transmute!(id_regs)).map_err(|e| e.into())
391 }
392}
393
394pub struct NotificationInfoGetIterator<'a> {
397 list_index: usize,
398 id_index: usize,
399 id_count: &'a [u8],
400 ids: &'a [u16],
401}
402
403impl<'a> Iterator for NotificationInfoGetIterator<'a> {
404 type Item = (u16, &'a [u16]);
405
406 fn next(&mut self) -> Option<Self::Item> {
407 if self.list_index < self.id_count.len() {
408 let partition_id = self.ids[self.id_index];
409 let id_range =
410 (self.id_index + 1)..=(self.id_index + self.id_count[self.list_index] as usize);
411
412 self.id_index += 1 + self.id_count[self.list_index] as usize;
413 self.list_index += 1;
414
415 Some((partition_id, &self.ids[id_range]))
416 } else {
417 None
418 }
419 }
420}
421
422#[cfg(test)]
423mod tests {
424 use super::*;
425
426 #[test]
427 fn success_args_notification_info_get32() {
428 let mut notifications = SuccessArgsNotificationInfoGet32::default();
429
430 notifications.add_list(0x0000, &[0, 2, 3]).unwrap();
432 notifications.add_list(0x0000, &[4, 6]).unwrap();
433 notifications.add_list(0x0002, &[]).unwrap();
434 notifications.add_list(0x0003, &[1]).unwrap();
435
436 let args: SuccessArgs = notifications.into();
437 assert_eq!(
438 SuccessArgs::Args32([
439 0x0004_b200,
440 0x0000_0000,
441 0x0003_0002,
442 0x0004_0000,
443 0x0002_0006,
444 0x0001_0003
445 ]),
446 args
447 );
448
449 let notifications = SuccessArgsNotificationInfoGet32::try_from(args).unwrap();
450 let mut iter = notifications.iter();
451 assert_eq!(Some((0x0000, &[0, 2, 3][..])), iter.next());
452 assert_eq!(Some((0x0000, &[4, 6][..])), iter.next());
453 assert_eq!(Some((0x0002, &[][..])), iter.next());
454 assert_eq!(Some((0x0003, &[1][..])), iter.next());
455 }
456
457 #[test]
458 fn success_args_notification_info_get64() {
459 let mut notifications = SuccessArgsNotificationInfoGet64::default();
460
461 notifications.add_list(0x0000, &[0, 2, 3]).unwrap();
463 notifications.add_list(0x0000, &[4, 6]).unwrap();
464 notifications.add_list(0x0002, &[]).unwrap();
465 notifications.add_list(0x0003, &[1]).unwrap();
466
467 let args: SuccessArgs = notifications.into();
468 assert_eq!(
469 SuccessArgs::Args64([
470 0x0004_b200,
471 0x0003_0002_0000_0000,
472 0x0002_0006_0004_0000,
473 0x0000_0000_0001_0003,
474 0x0000_0000_0000_0000,
475 0x0000_0000_0000_0000,
476 0,
477 0,
478 0,
479 0,
480 0,
481 0,
482 0,
483 0,
484 0,
485 0
486 ]),
487 args
488 );
489
490 let notifications = SuccessArgsNotificationInfoGet64::try_from(args).unwrap();
491 let mut iter = notifications.iter();
492 assert_eq!(Some((0x0000, &[0, 2, 3][..])), iter.next());
493 assert_eq!(Some((0x0000, &[4, 6][..])), iter.next());
494 assert_eq!(Some((0x0002, &[][..])), iter.next());
495 assert_eq!(Some((0x0003, &[1][..])), iter.next());
496 }
497}