1mod protocol;
7
8use async_trait::async_trait;
9use guestmem::AccessError;
10use guid::Guid;
11use mesh::payload::Protobuf;
12use std::io::IoSlice;
13use task_control::StopTask;
14use thiserror::Error;
15use video_core::DirtyRect;
16use video_core::FramebufferControl;
17use video_core::FramebufferFormat;
18use vmbus_async::async_dgram::AsyncRecv;
19use vmbus_async::async_dgram::AsyncRecvExt;
20use vmbus_async::async_dgram::AsyncSend;
21use vmbus_async::async_dgram::AsyncSendExt;
22use vmbus_async::pipe::MessagePipe;
23use vmbus_channel::RawAsyncChannel;
24use vmbus_channel::bus::ChannelType;
25use vmbus_channel::bus::OfferParams;
26use vmbus_channel::channel::ChannelOpenError;
27use vmbus_channel::gpadl_ring::GpadlRingMem;
28use vmbus_channel::simple::SaveRestoreSimpleVmbusDevice;
29use vmbus_channel::simple::SimpleVmbusDevice;
30use vmcore::save_restore::SavedStateRoot;
31use zerocopy::FromBytes;
32use zerocopy::Immutable;
33use zerocopy::IntoBytes;
34use zerocopy::KnownLayout;
35use zerocopy::Ref;
36
37#[derive(Debug, Error)]
38enum Error {
39 #[error("out of order packet")]
40 UnexpectedPacketOrder,
41 #[error("memory access error")]
42 Access(#[from] AccessError),
43 #[error("unknown message type: {0:#x}")]
44 UnknownMessageType(u32),
45 #[error("invalid packet")]
46 InvalidPacket,
47 #[error("channel i/o error")]
48 Io(#[source] std::io::Error),
49 #[error("failed to accept vmbus channel")]
50 Accept(#[from] vmbus_channel::offer::Error),
51}
52
53#[derive(Debug)]
54enum Request {
55 Version(protocol::Version),
56 VramLocation {
57 user_context: u64,
58 address: Option<u64>,
59 },
60 SituationUpdate {
61 user_context: u64,
62 situation: protocol::VideoOutputSituation,
63 },
64 PointerPosition {
65 is_visible: bool,
66 x: i32,
67 y: i32,
68 },
69 PointerShape,
70 Dirt(Vec<protocol::Rectangle>),
71 BiosInfo,
72 SupportedResolutions {
73 maximum_count: u8,
74 },
75 Capability,
76}
77
78fn parse_packet(buf: &[u8]) -> Result<Request, Error> {
79 let (header, buf) =
80 Ref::<_, protocol::MessageHeader>::from_prefix(buf).map_err(|_| Error::InvalidPacket)?; let request = match header.typ.to_ne() {
82 protocol::MESSAGE_VERSION_REQUEST => {
83 let message = protocol::VersionRequestMessage::ref_from_prefix(buf)
84 .map_err(|_| Error::InvalidPacket)?
85 .0; Request::Version(message.version)
87 }
88 protocol::MESSAGE_VRAM_LOCATION => {
89 let message = protocol::VramLocationMessage::ref_from_prefix(buf)
90 .map_err(|_| Error::InvalidPacket)?
91 .0; let address = if message.is_vram_gpa_address_specified != 0 {
93 Some(message.vram_gpa_address.into())
94 } else {
95 None
96 };
97 Request::VramLocation {
98 user_context: message.user_context.into(),
99 address,
100 }
101 }
102 protocol::MESSAGE_SITUATION_UPDATE => {
103 let message = protocol::SituationUpdateMessage::ref_from_prefix(buf)
104 .map_err(|_| Error::InvalidPacket)?
105 .0; Request::SituationUpdate {
107 user_context: message.user_context.into(),
108 situation: message.video_output,
109 }
110 }
111 protocol::MESSAGE_POINTER_POSITION => {
112 let message = protocol::PointerPositionMessage::ref_from_prefix(buf)
113 .map_err(|_| Error::InvalidPacket)?
114 .0; Request::PointerPosition {
116 is_visible: message.is_visible != 0,
117 x: message.image_x.into(),
118 y: message.image_y.into(),
119 }
120 }
121 protocol::MESSAGE_POINTER_SHAPE => {
122 Request::PointerShape
124 }
125 protocol::MESSAGE_DIRT => {
126 let (message, buf) = Ref::<_, protocol::DirtMessage>::from_prefix(buf)
127 .map_err(|_| Error::InvalidPacket)?; Request::Dirt(
129 <[protocol::Rectangle]>::ref_from_prefix_with_elems(
130 buf,
131 message.dirt_count as usize,
132 )
133 .map_err(|_| Error::InvalidPacket)? .0
135 .into(),
136 )
137 }
138 protocol::MESSAGE_BIOS_INFO_REQUEST => Request::BiosInfo,
139 protocol::MESSAGE_SUPPORTED_RESOLUTIONS_REQUEST => {
140 let message = protocol::SupportedResolutionsRequestMessage::ref_from_prefix(buf)
141 .map_err(|_| Error::InvalidPacket)?
142 .0; Request::SupportedResolutions {
144 maximum_count: message.maximum_resolution_count,
145 }
146 }
147 protocol::MESSAGE_CAPABILITY_REQUEST => Request::Capability,
148 typ => return Err(Error::UnknownMessageType(typ)),
149 };
150 Ok(request)
151}
152
153pub struct Video {
155 control: Box<dyn FramebufferControl>,
156 dirt_send: Option<mesh::Sender<Vec<DirtyRect>>>,
158}
159
160impl Video {
161 pub fn new(
163 control: Box<dyn FramebufferControl>,
164 dirt_send: Option<mesh::Sender<Vec<DirtyRect>>>,
165 ) -> anyhow::Result<Self> {
166 Ok(Self { control, dirt_send })
167 }
168}
169
170#[derive(Protobuf, SavedStateRoot)]
172#[mesh(package = "ui.synthvid")]
173pub struct SavedState(ChannelState);
174
175pub struct VideoChannel {
177 channel: MessagePipe<GpadlRingMem>,
178 state: ChannelState,
179 packet_buf: PacketBuffer,
180}
181
182#[derive(Debug, Copy, Clone, Protobuf)]
183#[mesh(package = "ui.synthvid")]
184struct Version {
185 #[mesh(1)]
186 major: u16,
187 #[mesh(2)]
188 minor: u16,
189}
190
191impl From<protocol::Version> for Version {
192 fn from(version: protocol::Version) -> Self {
193 Self {
194 major: version.major(),
195 minor: version.minor(),
196 }
197 }
198}
199
200impl From<Version> for protocol::Version {
201 fn from(version: Version) -> Self {
202 Self::new(version.major, version.minor)
203 }
204}
205
206#[derive(Debug, Clone, Protobuf, Default)]
207#[mesh(package = "ui.synthvid")]
208enum ChannelState {
209 #[mesh(1)]
210 #[default]
211 ReadVersion,
212 #[mesh(2)]
213 WriteVersion {
214 #[mesh(1)]
215 version: Version,
216 },
217 #[mesh(3)]
218 Active {
219 #[mesh(1)]
220 version: Version,
221 #[mesh(2)]
222 substate: ActiveState,
223 },
224}
225
226#[derive(Debug, Clone, Protobuf)]
227#[mesh(package = "ui.synthvid")]
228enum ActiveState {
229 #[mesh(1)]
230 ReadRequest,
231 #[mesh(2)]
232 SendVramAck {
233 #[mesh(1)]
234 user_context: u64,
235 },
236 #[mesh(3)]
237 SendSituationUpdateAck {
238 #[mesh(1)]
239 user_context: u64,
240 },
241 #[mesh(4)]
242 SendBiosInfo,
243 #[mesh(5)]
244 SendSupportedResolutions {
245 #[mesh(1)]
246 maximum_count: u8,
247 },
248 #[mesh(6)]
249 SendCapability,
250}
251
252struct PacketBuffer {
253 buf: Vec<u8>,
254}
255
256impl PacketBuffer {
257 fn new() -> Self {
258 Self {
259 buf: vec![0; protocol::MAX_VMBUS_PACKET_SIZE],
260 }
261 }
262
263 async fn recv_packet(
264 &mut self,
265 reader: &mut (impl AsyncRecv + Unpin),
266 ) -> Result<Request, Error> {
267 let n = match reader.recv(&mut self.buf).await {
268 Ok(n) => n,
269 Err(e) => return Err(Error::Io(e)),
270 };
271 let buf = &self.buf[..n];
272 parse_packet(buf)
273 }
274}
275
276#[async_trait]
277impl SimpleVmbusDevice for Video {
278 type Runner = VideoChannel;
279 type SavedState = SavedState;
280
281 fn offer(&self) -> OfferParams {
282 OfferParams {
283 interface_name: "video".to_owned(),
284 interface_id: Guid {
285 data1: 0xda0a7802,
286 data2: 0xe377,
287 data3: 0x4aac,
288 data4: [0x8e, 0x77, 0x5, 0x58, 0xeb, 0x10, 0x73, 0xf8],
289 },
290 instance_id: Guid {
291 data1: 0x5620e0c7,
292 data2: 0x8062,
293 data3: 0x4dce,
294 data4: [0xae, 0xb7, 0x52, 0xc, 0x7e, 0xf7, 0x61, 0x71],
295 },
296 mmio_megabytes: 8,
297 channel_type: ChannelType::Device { pipe_packets: true },
298 ..Default::default()
299 }
300 }
301
302 fn inspect(&mut self, req: inspect::Request<'_>, task: Option<&mut VideoChannel>) {
303 let mut resp = req.respond();
304 if let Some(this) = task {
305 let (version, state) = match &this.state {
306 ChannelState::ReadVersion => (None, "read_version"),
307 ChannelState::WriteVersion { version } => (Some(*version), "write_version"),
308 ChannelState::Active { version, substate } => (
309 Some(*version),
310 match substate {
311 ActiveState::ReadRequest => "read_request",
312 ActiveState::SendVramAck { .. } => "send_vram_ack",
313 ActiveState::SendSituationUpdateAck { .. } => "send_situation_update_ack",
314 ActiveState::SendBiosInfo => "send_bios_info",
315 ActiveState::SendSupportedResolutions { .. } => {
316 "send_supported_resolutions"
317 }
318 ActiveState::SendCapability => "send_capability",
319 },
320 ),
321 };
322 resp.field("state", state)
323 .field(
324 "version",
325 version.map(|v| format!("{}.{}", v.major, v.minor)),
326 )
327 .field_mut("channel", &mut this.channel);
328 }
329 }
330
331 fn open(
332 &mut self,
333 channel: RawAsyncChannel<GpadlRingMem>,
334 _guest_memory: guestmem::GuestMemory,
335 ) -> Result<Self::Runner, ChannelOpenError> {
336 let pipe = MessagePipe::new(channel)?;
337 Ok(VideoChannel::new(pipe, ChannelState::default()))
338 }
339
340 async fn run(
341 &mut self,
342 stop: &mut StopTask<'_>,
343 channel: &mut VideoChannel,
344 ) -> Result<(), task_control::Cancelled> {
345 stop.until_stopped(async {
346 match channel.process(&mut self.control, &self.dirt_send).await {
347 Ok(()) => {}
348 Err(err) => tracing::error!(error = &err as &dyn std::error::Error, "video error"),
349 }
350 })
351 .await
352 }
353
354 fn supports_save_restore(
355 &mut self,
356 ) -> Option<
357 &mut dyn SaveRestoreSimpleVmbusDevice<SavedState = Self::SavedState, Runner = Self::Runner>,
358 > {
359 Some(self)
360 }
361}
362
363impl SaveRestoreSimpleVmbusDevice for Video {
364 fn save_open(&mut self, runner: &Self::Runner) -> Self::SavedState {
365 SavedState(runner.state.clone())
366 }
367
368 fn restore_open(
369 &mut self,
370 state: Self::SavedState,
371 channel: RawAsyncChannel<GpadlRingMem>,
372 ) -> Result<Self::Runner, ChannelOpenError> {
373 let pipe = MessagePipe::new(channel)?;
374 Ok(VideoChannel::new(pipe, state.0))
375 }
376}
377
378impl VideoChannel {
379 fn new(channel: MessagePipe<GpadlRingMem>, state: ChannelState) -> Self {
380 Self {
381 channel,
382 state,
383 packet_buf: PacketBuffer::new(),
384 }
385 }
386
387 async fn send_packet<T: IntoBytes + ?Sized + Immutable + KnownLayout>(
388 writer: &mut (impl AsyncSend + Unpin),
389 typ: u32,
390 packet: &T,
391 ) -> Result<(), Error> {
392 let header = protocol::MessageHeader {
393 typ: typ.into(),
394 size: (size_of_val(packet) as u32).into(),
395 };
396 writer
397 .send_vectored(&[
398 IoSlice::new(header.as_bytes()),
399 IoSlice::new(packet.as_bytes()),
400 ])
401 .await
402 .map_err(Error::Io)?;
403
404 Ok(())
405 }
406
407 async fn process(
408 &mut self,
409 framebuffer: &mut Box<dyn FramebufferControl>,
410 dirt_send: &Option<mesh::Sender<Vec<DirtyRect>>>,
411 ) -> Result<(), Error> {
412 process_channel(
413 &mut self.channel,
414 &mut self.state,
415 &mut self.packet_buf,
416 framebuffer,
417 dirt_send,
418 )
419 .await
420 }
421}
422
423async fn process_channel(
424 channel: &mut (impl AsyncRecv + AsyncSend + Unpin),
425 state: &mut ChannelState,
426 packet_buf: &mut PacketBuffer,
427 framebuffer: &mut Box<dyn FramebufferControl>,
428 dirt_send: &Option<mesh::Sender<Vec<DirtyRect>>>,
429) -> Result<(), Error> {
430 loop {
431 match state {
432 ChannelState::ReadVersion => {
433 let version =
434 if let Request::Version(version) = packet_buf.recv_packet(channel).await? {
435 version.into()
436 } else {
437 return Err(Error::UnexpectedPacketOrder);
438 };
439 *state = ChannelState::WriteVersion { version };
440 }
441 ChannelState::WriteVersion { version } => {
442 let server_version = Version {
443 major: protocol::VERSION_MAJOR,
444 minor: protocol::VERSION_MINOR_BLUE,
445 };
446 let is_accepted = if version.major == server_version.major {
447 protocol::ACCEPTED_WITH_VERSION_EXCHANGE
448 } else {
449 0
450 };
451 VideoChannel::send_packet(
452 channel,
453 protocol::MESSAGE_VERSION_RESPONSE,
454 &protocol::VersionResponseMessage {
455 version: (*version).into(),
456 is_accepted,
457 max_video_outputs: 1,
458 },
459 )
460 .await?;
461 if is_accepted != 0 {
462 tracelimit::info_ratelimited!(?version, "video negotiation succeeded");
463 *state = ChannelState::Active {
464 version: *version,
465 substate: ActiveState::ReadRequest,
466 };
467 } else {
468 tracelimit::warn_ratelimited!(?version, "video negotiation failed");
469 *state = ChannelState::ReadVersion;
470 }
471 }
472 ChannelState::Active {
473 version: _,
474 substate,
475 } => match *substate {
476 ActiveState::ReadRequest => {
477 let packet = packet_buf.recv_packet(channel).await?;
478 match packet {
479 Request::VramLocation {
480 user_context,
481 address,
482 } => {
483 framebuffer.unmap().await;
484 if let Some(address) = address {
485 framebuffer.map(address).await;
486 }
487 *substate = ActiveState::SendVramAck { user_context };
488 }
489 Request::SituationUpdate {
490 user_context,
491 situation,
492 } => {
493 framebuffer
494 .set_format(FramebufferFormat {
495 width: u32::from(situation.width_pixels) as usize,
496 height: u32::from(situation.height_pixels) as usize,
497 bytes_per_line: u32::from(situation.pitch_bytes) as usize,
498 offset: u32::from(situation.primary_surface_vram_offset)
499 as usize,
500 })
501 .await;
502 *substate = ActiveState::SendSituationUpdateAck { user_context };
503 }
504 Request::PointerPosition { is_visible, x, y } => {
505 let _ = (is_visible, x, y);
506 }
507 Request::PointerShape => {}
508 Request::Dirt(rects) => {
509 if let Some(send) = dirt_send {
510 let dirty: Vec<DirtyRect> = rects
511 .iter()
512 .map(|r| DirtyRect {
513 left: r.left.into(),
514 top: r.top.into(),
515 right: r.right.into(),
516 bottom: r.bottom.into(),
517 })
518 .collect();
519 send.send(dirty);
520 }
521 }
522 Request::BiosInfo => {
523 *substate = ActiveState::SendBiosInfo;
524 }
525 Request::SupportedResolutions { maximum_count } => {
526 *substate = ActiveState::SendSupportedResolutions { maximum_count };
527 }
528 Request::Capability => {
529 *substate = ActiveState::SendCapability;
530 }
531 Request::Version(_) => return Err(Error::UnexpectedPacketOrder),
532 }
533 }
534 ActiveState::SendVramAck { user_context } => {
535 VideoChannel::send_packet(
536 channel,
537 protocol::MESSAGE_VRAM_LOCATION_ACK,
538 &protocol::VramLocationAckMessage {
539 user_context: user_context.into(),
540 },
541 )
542 .await?;
543 *substate = ActiveState::ReadRequest;
544 }
545 ActiveState::SendSituationUpdateAck { user_context } => {
546 VideoChannel::send_packet(
547 channel,
548 protocol::MESSAGE_SITUATION_UPDATE_ACK,
549 &protocol::SituationUpdateAckMessage {
550 user_context: user_context.into(),
551 },
552 )
553 .await?;
554 *substate = ActiveState::ReadRequest;
555 }
556 ActiveState::SendBiosInfo => {
557 VideoChannel::send_packet(
558 channel,
559 protocol::MESSAGE_BIOS_INFO_RESPONSE,
560 &protocol::BiosInfoResponseMessage {
561 stop_device_supported: 1.into(),
562 reserved: [0; 12],
563 },
564 )
565 .await?;
566 *substate = ActiveState::ReadRequest;
567 }
568 ActiveState::SendSupportedResolutions { maximum_count } => {
569 if maximum_count < protocol::MAXIMUM_RESOLUTIONS_COUNT {
570 VideoChannel::send_packet(
571 channel,
572 protocol::MESSAGE_SUPPORTED_RESOLUTIONS_RESPONSE,
573 &protocol::SupportedResolutionsResponseMessage {
574 edid_block: protocol::EDID_BLOCK,
575 resolution_count: 0,
576 default_resolution_index: 0,
577 is_standard: 0,
578 },
579 )
580 .await?;
581 } else {
582 const RESOLUTIONS: &[(u16, u16)] = &[(1024, 768), (1280, 1024)];
583
584 let mut packet = Vec::new();
585 packet.extend_from_slice(
586 protocol::SupportedResolutionsResponseMessage {
587 edid_block: protocol::EDID_BLOCK,
588 resolution_count: RESOLUTIONS.len().try_into().unwrap(),
589 default_resolution_index: 0,
590 is_standard: 0,
591 }
592 .as_bytes(),
593 );
594 for r in RESOLUTIONS {
595 packet.extend_from_slice(
596 protocol::ScreenInfo {
597 width: r.0.into(),
598 height: r.1.into(),
599 }
600 .as_bytes(),
601 );
602 }
603 VideoChannel::send_packet(
604 channel,
605 protocol::MESSAGE_SUPPORTED_RESOLUTIONS_RESPONSE,
606 packet.as_slice(),
607 )
608 .await?;
609 }
610 *substate = ActiveState::ReadRequest;
611 }
612 ActiveState::SendCapability => {
613 VideoChannel::send_packet(
614 channel,
615 protocol::MESSAGE_CAPABILITY_RESPONSE,
616 &protocol::CapabilityResponseMessage {
617 lock_on_disconnect: 0.into(),
618 reserved: [0.into(); 15],
619 },
620 )
621 .await?;
622 *substate = ActiveState::ReadRequest;
623 }
624 },
625 }
626 }
627}
628
629#[cfg(test)]
630mod tests {
631 use super::*;
632 use framebuffer::FRAMEBUFFER_SIZE;
633 use guestmem::MappableGuestMemory;
634 use guestmem::MappedMemoryRegion;
635 use guestmem::MemoryMapper;
636 use pal_async::DefaultDriver;
637 use pal_async::async_test;
638 use pal_async::task::Spawn;
639 use pal_async::task::Task;
640 use sparse_mmap::AsMappableRef;
641 use sparse_mmap::SparseMapping;
642 use sparse_mmap::alloc_shared_memory;
643 use std::io::ErrorKind;
644 use std::sync::Arc;
645 use vmbus_async::pipe::connected_message_pipes;
646 use vmbus_ring::RingMem;
647
648 struct TestGuestMemory;
649
650 impl MappableGuestMemory for TestGuestMemory {
651 fn map_to_guest(&mut self, _gpa: u64, _writable: bool) -> std::io::Result<()> {
652 Ok(())
653 }
654
655 fn unmap_from_guest(&mut self) {}
656 }
657
658 struct TestMappedRegion(SparseMapping);
659
660 impl MappedMemoryRegion for TestMappedRegion {
661 fn map(
662 &self,
663 offset: usize,
664 section: &dyn AsMappableRef,
665 file_offset: u64,
666 len: usize,
667 writable: bool,
668 ) -> std::io::Result<()> {
669 self.0.map_file(offset, len, section, file_offset, writable)
670 }
671
672 fn unmap(&self, offset: usize, len: usize) -> std::io::Result<()> {
673 self.0.unmap(offset, len)
674 }
675 }
676
677 struct TestMemoryMapper;
678
679 impl MemoryMapper for TestMemoryMapper {
680 fn new_region(
681 &self,
682 len: usize,
683 _debug_name: String,
684 ) -> std::io::Result<(Box<dyn MappableGuestMemory>, Arc<dyn MappedMemoryRegion>)> {
685 Ok((
686 Box::new(TestGuestMemory),
687 Arc::new(TestMappedRegion(SparseMapping::new(len)?)),
688 ))
689 }
690 }
691
692 fn framebuffer_fixture() -> (
693 framebuffer::FramebufferDevice,
694 Box<dyn FramebufferControl>,
695 framebuffer::View,
696 ) {
697 let vram = alloc_shared_memory(FRAMEBUFFER_SIZE, "video-test").unwrap();
698 let (fb, access) = framebuffer::framebuffer(vram, FRAMEBUFFER_SIZE, 0).unwrap();
699 let device =
700 framebuffer::FramebufferDevice::new(Box::new(TestMemoryMapper), fb, None).unwrap();
701 let control: Box<dyn FramebufferControl> = Box::new(device.control());
702 let view = access.view().unwrap();
703 (device, control, view)
704 }
705
706 async fn send_packet<T: IntoBytes + Immutable + KnownLayout>(
707 writer: &mut (impl AsyncSend + Unpin),
708 typ: u32,
709 packet: &T,
710 ) {
711 let header = protocol::MessageHeader {
712 typ: typ.into(),
713 size: (size_of_val(packet) as u32).into(),
714 };
715 writer
716 .send_vectored(&[
717 IoSlice::new(header.as_bytes()),
718 IoSlice::new(packet.as_bytes()),
719 ])
720 .await
721 .unwrap();
722 }
723
724 async fn send_dirt_packet(
725 writer: &mut (impl AsyncSend + Unpin),
726 rects: &[protocol::Rectangle],
727 ) {
728 let header = protocol::MessageHeader {
729 typ: protocol::MESSAGE_DIRT.into(),
730 size: ((size_of::<protocol::DirtMessage>() + size_of_val(rects)) as u32).into(),
731 };
732 let dirt = protocol::DirtMessage {
733 video_output: 0,
734 dirt_count: rects.len().try_into().unwrap(),
735 };
736 writer
737 .send_vectored(&[
738 IoSlice::new(header.as_bytes()),
739 IoSlice::new(dirt.as_bytes()),
740 IoSlice::new(rects.as_bytes()),
741 ])
742 .await
743 .unwrap();
744 }
745
746 async fn recv_bytes(reader: &mut (impl AsyncRecv + Unpin + Send)) -> Vec<u8> {
747 let mut packet = vec![0; protocol::MAX_VSP_TO_VSC_MESSAGE_SIZE.max(512)];
748 let n = reader.recv(&mut packet).await.unwrap();
749 packet.truncate(n);
750 packet
751 }
752
753 fn parse_header(packet: &[u8]) -> (protocol::MessageHeader, &[u8]) {
754 let (header, rest) = Ref::<_, protocol::MessageHeader>::from_prefix(packet).unwrap();
755 (*header, rest)
756 }
757
758 fn start_worker<T: RingMem + 'static + Unpin + Send + Sync>(
759 driver: &DefaultDriver,
760 mut control: Box<dyn FramebufferControl>,
761 dirt_send: Option<mesh::Sender<Vec<DirtyRect>>>,
762 mut channel: MessagePipe<T>,
763 ) -> Task<Result<(), Error>> {
764 driver.spawn("video worker", async move {
765 let mut state = ChannelState::ReadVersion;
766 let mut packet_buf = PacketBuffer::new();
767 process_channel(
768 &mut channel,
769 &mut state,
770 &mut packet_buf,
771 &mut control,
772 &dirt_send,
773 )
774 .await
775 .or_else(|e| match e {
776 Error::Io(err) if err.kind() == ErrorKind::ConnectionReset => Ok(()),
777 _ => Err(e),
778 })
779 })
780 }
781
782 #[async_test]
783 async fn test_channel_updates_framebuffer_and_forwards_dirt(driver: DefaultDriver) {
784 let (host, mut guest) = connected_message_pipes(16384);
785 let (_device, control, mut view) = framebuffer_fixture();
786 let (dirt_send, mut dirt_recv) = mesh::channel();
787 let worker = start_worker(&driver, control, Some(dirt_send), host);
788
789 let version = protocol::Version::new(protocol::VERSION_MAJOR, protocol::VERSION_MINOR_BLUE);
790 send_packet(
791 &mut guest,
792 protocol::MESSAGE_VERSION_REQUEST,
793 &protocol::VersionRequestMessage { version },
794 )
795 .await;
796
797 let packet = recv_bytes(&mut guest).await;
798 let (header, rest) = parse_header(&packet);
799 assert_eq!(header.typ.to_ne(), protocol::MESSAGE_VERSION_RESPONSE);
800 let response = protocol::VersionResponseMessage::ref_from_prefix(rest)
801 .unwrap()
802 .0;
803 assert_eq!(response.version.major(), protocol::VERSION_MAJOR);
804 assert_eq!(response.version.minor(), protocol::VERSION_MINOR_BLUE);
805 assert_eq!(
806 response.is_accepted,
807 protocol::ACCEPTED_WITH_VERSION_EXCHANGE
808 );
809 assert_eq!(response.max_video_outputs, 1);
810
811 send_packet(
812 &mut guest,
813 protocol::MESSAGE_VRAM_LOCATION,
814 &protocol::VramLocationMessage {
815 user_context: 0x1234u64.into(),
816 is_vram_gpa_address_specified: 1,
817 vram_gpa_address: 0x4000u64.into(),
818 },
819 )
820 .await;
821
822 let packet = recv_bytes(&mut guest).await;
823 let (header, rest) = parse_header(&packet);
824 assert_eq!(header.typ.to_ne(), protocol::MESSAGE_VRAM_LOCATION_ACK);
825 let ack = protocol::VramLocationAckMessage::ref_from_prefix(rest)
826 .unwrap()
827 .0;
828 assert_eq!(ack.user_context.to_ne(), 0x1234);
829
830 send_packet(
831 &mut guest,
832 protocol::MESSAGE_SITUATION_UPDATE,
833 &protocol::SituationUpdateMessage {
834 user_context: 0x5678u64.into(),
835 video_output_count: 1,
836 video_output: protocol::VideoOutputSituation {
837 active: 1,
838 primary_surface_vram_offset: 0.into(),
839 depth_bits: 32,
840 width_pixels: 800u32.into(),
841 height_pixels: 600u32.into(),
842 pitch_bytes: (800u32 * 4).into(),
843 },
844 },
845 )
846 .await;
847
848 let packet = recv_bytes(&mut guest).await;
849 let (header, rest) = parse_header(&packet);
850 assert_eq!(header.typ.to_ne(), protocol::MESSAGE_SITUATION_UPDATE_ACK);
851 let ack = protocol::SituationUpdateAckMessage::ref_from_prefix(rest)
852 .unwrap()
853 .0;
854 assert_eq!(ack.user_context.to_ne(), 0x5678);
855 assert_eq!(view.resolution(), (800, 600));
856
857 let rects = [
858 protocol::Rectangle {
859 left: 1.into(),
860 top: 2.into(),
861 right: 30.into(),
862 bottom: 40.into(),
863 },
864 protocol::Rectangle {
865 left: 100.into(),
866 top: 120.into(),
867 right: 140.into(),
868 bottom: 180.into(),
869 },
870 ];
871 send_dirt_packet(&mut guest, &rects).await;
872
873 let dirt = dirt_recv.recv().await.unwrap();
874 assert_eq!(dirt.len(), 2);
875 assert_eq!(dirt[0].left, 1);
876 assert_eq!(dirt[0].top, 2);
877 assert_eq!(dirt[0].right, 30);
878 assert_eq!(dirt[0].bottom, 40);
879 assert_eq!(dirt[1].left, 100);
880 assert_eq!(dirt[1].top, 120);
881 assert_eq!(dirt[1].right, 140);
882 assert_eq!(dirt[1].bottom, 180);
883
884 drop(guest);
885 worker.await.unwrap();
886 }
887
888 #[async_test]
889 async fn test_channel_reports_bios_resolutions_and_capability(driver: DefaultDriver) {
890 let (host, mut guest) = connected_message_pipes(16384);
891 let (_device, control, _view) = framebuffer_fixture();
892 let worker = start_worker(&driver, control, None, host);
893
894 send_packet(
895 &mut guest,
896 protocol::MESSAGE_VERSION_REQUEST,
897 &protocol::VersionRequestMessage {
898 version: protocol::Version::new(
899 protocol::VERSION_MAJOR,
900 protocol::VERSION_MINOR_BLUE,
901 ),
902 },
903 )
904 .await;
905 let _ = recv_bytes(&mut guest).await;
906
907 send_packet(
908 &mut guest,
909 protocol::MESSAGE_BIOS_INFO_REQUEST,
910 &protocol::BiosInfoRequestMessage {},
911 )
912 .await;
913 let packet = recv_bytes(&mut guest).await;
914 let (header, rest) = parse_header(&packet);
915 assert_eq!(header.typ.to_ne(), protocol::MESSAGE_BIOS_INFO_RESPONSE);
916 let bios = protocol::BiosInfoResponseMessage::ref_from_prefix(rest)
917 .unwrap()
918 .0;
919 assert_eq!(bios.stop_device_supported.to_ne(), 1);
920
921 send_packet(
922 &mut guest,
923 protocol::MESSAGE_SUPPORTED_RESOLUTIONS_REQUEST,
924 &protocol::SupportedResolutionsRequestMessage {
925 maximum_resolution_count: protocol::MAXIMUM_RESOLUTIONS_COUNT,
926 },
927 )
928 .await;
929 let packet = recv_bytes(&mut guest).await;
930 let (header, rest) = parse_header(&packet);
931 assert_eq!(
932 header.typ.to_ne(),
933 protocol::MESSAGE_SUPPORTED_RESOLUTIONS_RESPONSE
934 );
935 let (response, rest) =
936 Ref::<_, protocol::SupportedResolutionsResponseMessage>::from_prefix(rest).unwrap();
937 assert_eq!(response.resolution_count as usize, 2);
938 let (screens, tail) = <[protocol::ScreenInfo]>::ref_from_prefix_with_elems(
939 rest,
940 response.resolution_count as usize,
941 )
942 .unwrap();
943 assert!(tail.is_empty());
944 assert_eq!(screens[0].width.to_ne(), 1024);
945 assert_eq!(screens[0].height.to_ne(), 768);
946 assert_eq!(screens[1].width.to_ne(), 1280);
947 assert_eq!(screens[1].height.to_ne(), 1024);
948
949 send_packet(
950 &mut guest,
951 protocol::MESSAGE_CAPABILITY_REQUEST,
952 &protocol::CapabilityRequestMessage {},
953 )
954 .await;
955 let packet = recv_bytes(&mut guest).await;
956 let (header, rest) = parse_header(&packet);
957 assert_eq!(header.typ.to_ne(), protocol::MESSAGE_CAPABILITY_RESPONSE);
958 let capability = protocol::CapabilityResponseMessage::ref_from_prefix(rest)
959 .unwrap()
960 .0;
961 assert_eq!(capability.lock_on_disconnect.to_ne(), 0);
962
963 drop(guest);
964 worker.await.unwrap();
965 }
966
967 #[async_test]
968 async fn test_channel_rejects_out_of_order_request(driver: DefaultDriver) {
969 let (host, mut guest) = connected_message_pipes(16384);
970 let (_device, control, _view) = framebuffer_fixture();
971 let worker = start_worker(&driver, control, None, host);
972
973 send_packet(
974 &mut guest,
975 protocol::MESSAGE_BIOS_INFO_REQUEST,
976 &protocol::BiosInfoRequestMessage {},
977 )
978 .await;
979
980 let err = worker.await.unwrap_err();
981 assert!(matches!(err, Error::UnexpectedPacketOrder));
982 }
983}