1use crate::{
8 guest, ok, sys, AsHandleRef, GPAddr, Handle, HandleBased, HandleRef, MonotonicInstant, Signals,
9 Status, VcpuContents,
10};
11use bitflags::bitflags;
12use std::mem;
13
14#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
19#[repr(transparent)]
20pub struct Port(Handle);
21impl_handle_based!(Port);
22
23bitflags! {
24 pub struct PortOptions: u32 {
26 const BIND_TO_INTERRUPT = sys::ZX_PORT_BIND_TO_INTERRUPT;
27 }
28}
29
30#[derive(Debug, Copy, Clone, Eq, PartialEq)]
32pub enum PacketContents {
33 User(UserPacket),
35 SignalOne(SignalPacket),
37 GuestBell(GuestBellPacket),
39 GuestMem(GuestMemPacket),
41 GuestIo(GuestIoPacket),
43 GuestVcpu(GuestVcpuPacket),
45 Pager(PagerPacket),
47 Interrupt(InterruptPacket),
49 PowerTransition(PowerTransitionPacket),
52
53 #[doc(hidden)]
54 __Nonexhaustive,
55}
56
57#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
60pub struct UserPacket(sys::zx_packet_user_t);
61
62#[derive(Copy, Clone, Debug, Eq, PartialEq)]
65pub struct SignalPacket(sys::zx_packet_signal_t);
66
67#[derive(Copy, Clone, Debug, Eq, PartialEq)]
70pub struct GuestBellPacket(sys::zx_packet_guest_bell_t);
71
72#[derive(Copy, Clone, Debug, Eq, PartialEq)]
75pub struct GuestMemPacket(sys::zx_packet_guest_mem_t);
76
77#[derive(Copy, Clone, Debug, Eq, PartialEq)]
80pub struct GuestIoPacket(sys::zx_packet_guest_io_t);
81
82#[derive(Copy, Clone, Debug, Eq, PartialEq)]
85pub struct GuestVcpuPacket(sys::zx_packet_guest_vcpu_t);
86
87#[derive(Copy, Clone, Debug, Eq, PartialEq)]
90pub struct PagerPacket(sys::zx_packet_page_request_t);
91
92#[derive(Copy, Clone, Debug, Eq, PartialEq)]
95pub struct InterruptPacket(sys::zx_packet_interrupt_t);
96
97#[derive(Copy, Clone, Debug, Eq, PartialEq)]
100pub struct PowerTransitionPacket(sys::zx_packet_processor_power_level_transition_request_t);
101
102#[derive(PartialEq, Eq, Debug)]
105pub struct Packet(pub(crate) sys::zx_port_packet_t);
106
107impl Packet {
108 pub fn from_user_packet(key: u64, status: i32, user: UserPacket) -> Packet {
110 Packet(sys::zx_port_packet_t {
111 key: key,
112 packet_type: sys::zx_packet_type_t::ZX_PKT_TYPE_USER,
113 status: status,
114 union: user.0,
115 })
116 }
117
118 pub fn from_guest_mem_packet(key: u64, status: i32, mem: GuestMemPacket) -> Packet {
120 let mut raw = sys::zx_port_packet_t {
121 key,
122 packet_type: sys::zx_packet_type_t::ZX_PKT_TYPE_GUEST_MEM,
123 status,
124 union: Default::default(),
125 };
126 let bytes: &[u8; std::mem::size_of::<sys::zx_packet_guest_mem_t>()] =
134 unsafe { mem::transmute(&mem.0) };
135 raw.union[0..std::mem::size_of::<sys::zx_packet_guest_mem_t>()].copy_from_slice(bytes);
136 Packet(raw)
137 }
138
139 pub fn from_guest_io_packet(key: u64, status: i32, io: GuestIoPacket) -> Packet {
141 let mut raw = sys::zx_port_packet_t {
142 key,
143 packet_type: sys::zx_packet_type_t::ZX_PKT_TYPE_GUEST_IO,
144 status,
145 union: Default::default(),
146 };
147 let bytes: &[u8; std::mem::size_of::<sys::zx_packet_guest_io_t>()] =
150 unsafe { mem::transmute(&io.0) };
151 raw.union[0..std::mem::size_of::<sys::zx_packet_guest_io_t>()].copy_from_slice(bytes);
152 Packet(raw)
153 }
154
155 pub fn from_guest_vcpu_packet(key: u64, status: i32, vcpu: GuestVcpuPacket) -> Packet {
157 Packet(sys::zx_port_packet_t {
158 key,
159 packet_type: sys::zx_packet_type_t::ZX_PKT_TYPE_GUEST_VCPU,
160 status,
161 union: unsafe { mem::transmute_copy(&vcpu.0) },
162 })
163 }
164
165 pub fn from_power_transition_packet(
167 key: u64,
168 status: i32,
169 power_transition_packet: PowerTransitionPacket,
170 ) -> Packet {
171 Packet(sys::zx_port_packet_t {
172 key: key,
173 packet_type:
174 sys::zx_packet_type_t::ZX_PKT_TYPE_PROCESSOR_POWER_LEVEL_TRANSITION_REQUEST,
175 status: status,
176 union: unsafe { mem::transmute_copy(&power_transition_packet.0) },
177 })
178 }
179
180 pub fn key(&self) -> u64 {
182 self.0.key
183 }
184
185 pub fn status(&self) -> i32 {
188 self.0.status
189 }
190
191 pub fn contents(&self) -> PacketContents {
193 match self.0.packet_type {
194 sys::zx_packet_type_t::ZX_PKT_TYPE_USER => {
195 PacketContents::User(UserPacket(self.0.union))
196 }
197
198 sys::zx_packet_type_t::ZX_PKT_TYPE_SIGNAL_ONE => {
199 PacketContents::SignalOne(SignalPacket(unsafe {
200 mem::transmute_copy(&self.0.union)
201 }))
202 }
203
204 sys::zx_packet_type_t::ZX_PKT_TYPE_GUEST_BELL => {
205 PacketContents::GuestBell(GuestBellPacket(unsafe {
206 mem::transmute_copy(&self.0.union)
207 }))
208 }
209
210 sys::zx_packet_type_t::ZX_PKT_TYPE_GUEST_MEM => {
211 PacketContents::GuestMem(GuestMemPacket(unsafe {
212 mem::transmute_copy(&self.0.union)
213 }))
214 }
215
216 sys::zx_packet_type_t::ZX_PKT_TYPE_GUEST_IO => {
217 PacketContents::GuestIo(GuestIoPacket(unsafe {
218 mem::transmute_copy(&self.0.union)
219 }))
220 }
221
222 sys::zx_packet_type_t::ZX_PKT_TYPE_GUEST_VCPU => {
223 PacketContents::GuestVcpu(GuestVcpuPacket(unsafe {
224 mem::transmute_copy(&self.0.union)
225 }))
226 }
227
228 sys::zx_packet_type_t::ZX_PKT_TYPE_PAGE_REQUEST => {
229 PacketContents::Pager(PagerPacket(unsafe { mem::transmute_copy(&self.0.union) }))
230 }
231
232 sys::zx_packet_type_t::ZX_PKT_TYPE_INTERRUPT => {
233 PacketContents::Interrupt(InterruptPacket(unsafe {
234 mem::transmute_copy(&self.0.union)
235 }))
236 }
237
238 sys::zx_packet_type_t::ZX_PKT_TYPE_PROCESSOR_POWER_LEVEL_TRANSITION_REQUEST => {
239 PacketContents::PowerTransition(PowerTransitionPacket(unsafe {
240 mem::transmute_copy(&self.0.union)
241 }))
242 }
243
244 _ => panic!("unexpected packet type"),
245 }
246 }
247}
248
249impl UserPacket {
250 pub fn from_u8_array(val: [u8; 32]) -> UserPacket {
251 UserPacket(val)
252 }
253
254 pub fn as_u8_array(&self) -> &[u8; 32] {
255 &self.0
256 }
257
258 pub fn as_mut_u8_array(&mut self) -> &mut [u8; 32] {
259 &mut self.0
260 }
261}
262
263impl SignalPacket {
264 pub fn trigger(&self) -> Signals {
266 Signals::from_bits_truncate(self.0.trigger)
267 }
268
269 pub fn observed(&self) -> Signals {
271 Signals::from_bits_truncate(self.0.observed)
272 }
273
274 pub fn count(&self) -> u64 {
276 self.0.count
277 }
278
279 pub fn timestamp(&self) -> sys::zx_time_t {
281 self.0.timestamp
282 }
283
284 pub fn raw_packet(&self) -> &sys::zx_packet_signal_t {
286 &self.0
287 }
288}
289
290impl GuestBellPacket {
291 pub fn addr(&self) -> GPAddr {
293 GPAddr(self.0.addr)
294 }
295}
296
297impl GuestMemPacket {
298 pub fn from_raw(mem: sys::zx_packet_guest_mem_t) -> GuestMemPacket {
299 GuestMemPacket(mem)
300 }
301
302 pub fn addr(&self) -> GPAddr {
304 GPAddr(self.0.addr)
305 }
306}
307
308#[cfg(target_arch = "aarch64")]
309impl GuestMemPacket {
310 pub fn access_size(&self) -> Option<guest::MemAccessSize> {
314 match self.0.access_size {
315 1 => Some(guest::MemAccessSize::Bits8),
316 2 => Some(guest::MemAccessSize::Bits16),
317 4 => Some(guest::MemAccessSize::Bits32),
318 8 => Some(guest::MemAccessSize::Bits64),
319 _ => None,
320 }
321 }
322
323 pub fn sign_extend(&self) -> bool {
325 self.0.sign_extend
326 }
327
328 pub fn reg(&self) -> u8 {
330 self.0.xt
331 }
332
333 pub fn data(&self) -> Option<guest::MemData> {
335 if let guest::AccessType::Write = self.access_type() {
336 self.access_size().map(|size| match size {
337 guest::MemAccessSize::Bits8 => guest::MemData::Data8(self.0.data as u8),
338 guest::MemAccessSize::Bits16 => guest::MemData::Data16(self.0.data as u16),
339 guest::MemAccessSize::Bits32 => guest::MemData::Data32(self.0.data as u32),
340 guest::MemAccessSize::Bits64 => guest::MemData::Data64(self.0.data),
341 })
342 } else {
343 None
344 }
345 }
346
347 pub fn access_type(&self) -> guest::AccessType {
349 match self.0.read {
350 true => guest::AccessType::Read,
351 false => guest::AccessType::Write,
352 }
353 }
354}
355
356#[cfg(target_arch = "x86_64")]
357impl GuestMemPacket {
358 pub fn default_operand_size(&self) -> Option<guest::CSDefaultOperandSize> {
362 match self.0.default_operand_size {
364 2 => Some(guest::CSDefaultOperandSize::Bits16),
365 4 => Some(guest::CSDefaultOperandSize::Bits32),
366 _ => None,
367 }
368 }
369}
370
371impl GuestIoPacket {
372 pub fn from_raw(io: sys::zx_packet_guest_io_t) -> GuestIoPacket {
373 GuestIoPacket(io)
374 }
375
376 pub fn port(&self) -> u16 {
378 self.0.port
379 }
380
381 pub fn access_size(&self) -> Option<guest::PortAccessSize> {
385 match self.0.access_size {
386 1 => Some(guest::PortAccessSize::Bits8),
387 2 => Some(guest::PortAccessSize::Bits16),
388 4 => Some(guest::PortAccessSize::Bits32),
389 _ => None,
390 }
391 }
392
393 pub fn access_type(&self) -> guest::AccessType {
395 match self.0.input {
396 true => guest::AccessType::Read,
397 false => guest::AccessType::Write,
398 }
399 }
400
401 pub fn data(&self) -> Option<guest::PortData> {
403 #[repr(C)]
404 union DataUnion {
405 bit8: [u8; 4],
406 bit16: [u16; 2],
407 bit32: [u32; 1],
408 }
409 if let guest::AccessType::Write = self.access_type() {
410 unsafe {
411 let data = &DataUnion { bit8: self.0.data };
412 self.access_size().map(|size| match size {
413 guest::PortAccessSize::Bits8 => guest::PortData::Data8(data.bit8[0]),
414 guest::PortAccessSize::Bits16 => guest::PortData::Data16(data.bit16[0]),
415 guest::PortAccessSize::Bits32 => guest::PortData::Data32(data.bit32[0]),
416 })
417 }
418 } else {
419 None
420 }
421 }
422}
423
424impl GuestVcpuPacket {
425 pub fn from_raw(vcpu: sys::zx_packet_guest_vcpu_t) -> GuestVcpuPacket {
426 GuestVcpuPacket(vcpu)
427 }
428
429 pub fn contents(&self) -> VcpuContents {
430 match self.0.r#type {
431 sys::zx_packet_guest_vcpu_type_t::ZX_PKT_GUEST_VCPU_INTERRUPT => unsafe {
432 VcpuContents::Interrupt {
433 mask: self.0.union.interrupt.mask,
434 vector: self.0.union.interrupt.vector,
435 }
436 },
437 sys::zx_packet_guest_vcpu_type_t::ZX_PKT_GUEST_VCPU_STARTUP => unsafe {
438 VcpuContents::Startup {
439 id: self.0.union.startup.id,
440 entry: self.0.union.startup.entry,
441 }
442 },
443 sys::zx_packet_guest_vcpu_type_t::ZX_PKT_GUEST_VCPU_EXIT => unsafe {
444 VcpuContents::Exit { retcode: self.0.union.exit.retcode }
445 },
446 _ => panic!("unexpected VCPU packet type"),
447 }
448 }
449}
450
451impl PagerPacket {
452 pub fn command(&self) -> sys::zx_page_request_command_t {
454 self.0.command
455 }
456
457 pub fn range(&self) -> std::ops::Range<u64> {
459 self.0.offset..self.0.offset + self.0.length
460 }
461}
462
463impl InterruptPacket {
464 pub fn timestamp(&self) -> sys::zx_time_t {
465 self.0.timestamp
466 }
467}
468
469impl PowerTransitionPacket {
470 pub fn from_raw(
471 packet: sys::zx_packet_processor_power_level_transition_request_t,
472 ) -> PowerTransitionPacket {
473 PowerTransitionPacket(packet)
474 }
475
476 pub fn domain_id(&self) -> u32 {
477 self.0.domain_id
478 }
479
480 pub fn options(&self) -> u32 {
481 self.0.options
482 }
483
484 pub fn control_interface(&self) -> u64 {
485 self.0.control_interface
486 }
487
488 pub fn control_argument(&self) -> u64 {
489 self.0.control_argument
490 }
491}
492
493impl Port {
494 pub fn create() -> Self {
505 Self::create_with_opts(PortOptions::from_bits_truncate(0))
506 }
507
508 pub fn create_with_opts(opts: PortOptions) -> Self {
509 unsafe {
510 let mut handle = 0;
511 let status = sys::zx_port_create(opts.bits(), &mut handle);
512 ok(status).expect(
513 "port creation always succeeds except with OOM or when job policy denies it",
514 );
515 Handle::from_raw(handle).into()
516 }
517 }
518
519 pub fn queue(&self, packet: &Packet) -> Result<(), Status> {
525 let status =
526 unsafe { sys::zx_port_queue(self.raw_handle(), std::ptr::from_ref(&packet.0)) };
527 ok(status)
528 }
529
530 pub fn wait(&self, deadline: MonotonicInstant) -> Result<Packet, Status> {
536 let mut packet = Default::default();
537 ok(unsafe { sys::zx_port_wait(self.raw_handle(), deadline.into_nanos(), &mut packet) })?;
538 Ok(Packet(packet))
539 }
540
541 pub fn cancel<H>(&self, source: &H, key: u64) -> Result<(), Status>
547 where
548 H: AsHandleRef,
549 {
550 let status = unsafe { sys::zx_port_cancel(self.raw_handle(), source.raw_handle(), key) };
551 ok(status)
552 }
553}
554
555bitflags! {
556 #[repr(transparent)]
558 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
559 pub struct WaitAsyncOpts: u32 {
560 const TIMESTAMP = sys::ZX_WAIT_ASYNC_TIMESTAMP;
562
563 const BOOT_TIMESTAMP = sys::ZX_WAIT_ASYNC_BOOT_TIMESTAMP;
565
566 const EDGE_TRIGGERED = sys::ZX_WAIT_ASYNC_EDGE;
569 }
570}
571
572#[cfg(test)]
573mod tests {
574 use super::*;
575 use crate::{Duration, Event};
576 use assert_matches::assert_matches;
577
578 #[test]
579 fn port_basic() {
580 let ten_ms = Duration::from_millis(10);
581
582 let port = Port::create();
583
584 assert_eq!(port.wait(MonotonicInstant::after(ten_ms)), Err(Status::TIMED_OUT));
586
587 let packet = Packet::from_user_packet(42, 123, UserPacket::from_u8_array([13; 32]));
589 assert!(port.queue(&packet).is_ok());
590
591 let read_packet = port.wait(MonotonicInstant::after(ten_ms)).unwrap();
593 assert_eq!(read_packet, packet);
594 }
595
596 #[test]
597 fn create_with_opts() {
598 let _port = Port::create_with_opts(PortOptions::BIND_TO_INTERRUPT);
599 }
600
601 #[test]
602 fn wait_async_once() {
603 let ten_ms = Duration::from_millis(10);
604 let key = 42;
605
606 let port = Port::create();
607 let event = Event::create();
608 let no_opts = WaitAsyncOpts::empty();
609
610 assert!(event
611 .wait_async_handle(&port, key, Signals::USER_0 | Signals::USER_1, no_opts)
612 .is_ok());
613
614 assert_eq!(port.wait(MonotonicInstant::after(ten_ms)), Err(Status::TIMED_OUT));
616
617 assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok());
619 let read_packet = port.wait(MonotonicInstant::after(ten_ms)).unwrap();
620 assert_eq!(read_packet.key(), key);
621 assert_eq!(read_packet.status(), 0);
622 match read_packet.contents() {
623 PacketContents::SignalOne(sig) => {
624 assert_eq!(sig.trigger(), Signals::USER_0 | Signals::USER_1);
625 assert_eq!(sig.observed(), Signals::USER_0);
626 assert_eq!(sig.count(), 1);
627 }
628 _ => panic!("wrong packet type"),
629 }
630
631 assert_eq!(port.wait(MonotonicInstant::after(ten_ms)), Err(Status::TIMED_OUT));
633
634 assert!(event.wait_async_handle(&port, key, Signals::USER_0, no_opts).is_ok());
636 let read_packet = port.wait(MonotonicInstant::after(ten_ms)).unwrap();
637 assert_eq!(read_packet.key(), key);
638 assert_eq!(read_packet.status(), 0);
639 match read_packet.contents() {
640 PacketContents::SignalOne(sig) => {
641 assert_eq!(sig.trigger(), Signals::USER_0);
642 assert_eq!(sig.observed(), Signals::USER_0);
643 assert_eq!(sig.count(), 1);
644 }
645 _ => panic!("wrong packet type"),
646 }
647
648 assert!(event.wait_async_handle(&port, key, Signals::USER_0, no_opts).is_ok());
651 assert!(port.cancel(&event, key).is_ok());
652 assert_eq!(port.wait(MonotonicInstant::after(ten_ms)), Err(Status::TIMED_OUT));
653
654 assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok()); assert!(event.wait_async_handle(&port, key, Signals::USER_0, no_opts).is_ok());
657 assert!(port.cancel(&event, key).is_ok());
658 assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok());
659 assert_eq!(port.wait(MonotonicInstant::after(ten_ms)), Err(Status::TIMED_OUT));
660 }
661
662 #[test]
663 fn guest_mem_packet() {
664 #[cfg(target_arch = "x86_64")]
665 let guest_mem_packet = sys::zx_packet_guest_mem_t {
666 addr: 0xaaaabbbbccccdddd,
667 cr3: 0x0123456789abcdef,
668 rip: 0xffffffff00000000,
669 instruction_size: 8,
670 default_operand_size: 2,
671 };
672 #[cfg(target_arch = "aarch64")]
673 let guest_mem_packet = sys::zx_packet_guest_mem_t {
674 addr: 0x8877665544332211,
675 access_size: 8,
676 sign_extend: true,
677 xt: 0xf3,
678 read: false,
679 data: 0x1122334455667788,
680 };
681 #[cfg(target_arch = "riscv64")]
682 let guest_mem_packet = {
683 let mut ret = sys::zx_packet_guest_mem_t::default();
684 ret.addr = 0x8877665544332211;
685 ret
686 };
687 const KEY: u64 = 0x5555555555555555;
688 const STATUS: i32 = sys::ZX_ERR_INTERNAL;
689
690 let packet =
691 Packet::from_guest_mem_packet(KEY, STATUS, GuestMemPacket::from_raw(guest_mem_packet));
692
693 assert_matches!(packet.contents(), PacketContents::GuestMem(GuestMemPacket(packet)) if packet == guest_mem_packet);
694 assert_eq!(packet.key(), KEY);
695 assert_eq!(packet.status(), STATUS);
696 }
697
698 #[test]
699 fn guest_io_packet() {
700 const GUEST_IO_PACKET: sys::zx_packet_guest_io_t = sys::zx_packet_guest_io_t {
701 port: 0xabcd,
702 access_size: 4,
703 input: true,
704 data: [0xaa, 0xbb, 0xcc, 0xdd],
705 };
706 const KEY: u64 = 0x0123456789abcdef;
707 const STATUS: i32 = sys::ZX_ERR_NO_RESOURCES;
708
709 let packet =
710 Packet::from_guest_io_packet(KEY, STATUS, GuestIoPacket::from_raw(GUEST_IO_PACKET));
711
712 assert_matches!(packet.contents(), PacketContents::GuestIo(GuestIoPacket(packet)) if packet == GUEST_IO_PACKET);
713 assert_eq!(packet.key(), KEY);
714 assert_eq!(packet.status(), STATUS);
715 }
716
717 #[test]
718 fn guest_vcpu_interrupt_packet() {
719 let mut guest_vcpu_packet = sys::zx_packet_guest_vcpu_t::default();
721 guest_vcpu_packet.r#type = sys::zx_packet_guest_vcpu_type_t::ZX_PKT_GUEST_VCPU_INTERRUPT;
722 guest_vcpu_packet.union = sys::zx_packet_guest_vcpu_union_t {
723 interrupt: {
724 let mut interrupt = sys::zx_packet_guest_vcpu_interrupt_t::default();
725 interrupt.mask = 0xaaaaaaaaaaaaaaaa;
726 interrupt.vector = 0x12;
727 interrupt
728 },
729 };
730 const KEY: u64 = 0x0123456789abcdef;
731 const STATUS: i32 = sys::ZX_ERR_NO_RESOURCES;
732
733 let packet = Packet::from_guest_vcpu_packet(
734 KEY,
735 STATUS,
736 GuestVcpuPacket::from_raw(guest_vcpu_packet),
737 );
738
739 assert_matches!(packet.contents(), PacketContents::GuestVcpu(GuestVcpuPacket(packet)) if packet == guest_vcpu_packet);
740 assert_eq!(packet.key(), KEY);
741 assert_eq!(packet.status(), STATUS);
742 }
743
744 #[test]
745 fn guest_vcpu_startup_packet() {
746 let mut guest_vcpu_packet = sys::zx_packet_guest_vcpu_t::default();
747 guest_vcpu_packet.r#type = sys::zx_packet_guest_vcpu_type_t::ZX_PKT_GUEST_VCPU_STARTUP;
748 guest_vcpu_packet.union = sys::zx_packet_guest_vcpu_union_t {
749 startup: sys::zx_packet_guest_vcpu_startup_t { id: 16, entry: 0xffffffff11111111 },
750 };
751 const KEY: u64 = 0x0123456789abcdef;
752 const STATUS: i32 = sys::ZX_ERR_NO_RESOURCES;
753
754 let packet = Packet::from_guest_vcpu_packet(
755 KEY,
756 STATUS,
757 GuestVcpuPacket::from_raw(guest_vcpu_packet),
758 );
759
760 assert_matches!(packet.contents(), PacketContents::GuestVcpu(GuestVcpuPacket(packet)) if packet == guest_vcpu_packet);
761 assert_eq!(packet.key(), KEY);
762 assert_eq!(packet.status(), STATUS);
763 }
764
765 #[test]
766 fn guest_vcpu_exit_packet() {
767 let mut guest_vcpu_packet = sys::zx_packet_guest_vcpu_t::default();
768 guest_vcpu_packet.r#type = sys::zx_packet_guest_vcpu_type_t::ZX_PKT_GUEST_VCPU_EXIT;
769 let mut exit = sys::zx_packet_guest_vcpu_exit_t::default();
770 exit.retcode = 12345678;
771 guest_vcpu_packet.union = sys::zx_packet_guest_vcpu_union_t { exit };
772 const KEY: u64 = 0x0123456789abcdef;
773 const STATUS: i32 = sys::ZX_ERR_NO_RESOURCES;
774
775 let packet = Packet::from_guest_vcpu_packet(
776 KEY,
777 STATUS,
778 GuestVcpuPacket::from_raw(guest_vcpu_packet),
779 );
780
781 assert_matches!(packet.contents(), PacketContents::GuestVcpu(GuestVcpuPacket(packet)) if packet == guest_vcpu_packet);
782 assert_eq!(packet.key(), KEY);
783 assert_eq!(packet.status(), STATUS);
784 }
785
786 #[test]
787 fn power_transition_packet() {
788 let power_transition_packet =
789 sys::zx_packet_processor_power_level_transition_request_t::default();
790 const KEY: u64 = 0x0123456789abcdef;
791 const STATUS: i32 = sys::ZX_ERR_NO_RESOURCES;
792
793 let packet = Packet::from_power_transition_packet(
794 KEY,
795 STATUS,
796 PowerTransitionPacket::from_raw(power_transition_packet),
797 );
798
799 assert_matches!(
800 packet.contents(),
801 PacketContents::PowerTransition(PowerTransitionPacket(packet)) if packet == power_transition_packet
802 );
803 assert_eq!(packet.key(), KEY);
804 assert_eq!(packet.status(), STATUS);
805 }
806}