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::FramebufferControl;
16use video_core::FramebufferFormat;
17use vmbus_async::async_dgram::AsyncRecv;
18use vmbus_async::async_dgram::AsyncRecvExt;
19use vmbus_async::async_dgram::AsyncSend;
20use vmbus_async::async_dgram::AsyncSendExt;
21use vmbus_async::pipe::MessagePipe;
22use vmbus_channel::RawAsyncChannel;
23use vmbus_channel::bus::ChannelType;
24use vmbus_channel::bus::OfferParams;
25use vmbus_channel::channel::ChannelOpenError;
26use vmbus_channel::gpadl_ring::GpadlRingMem;
27use vmbus_channel::simple::SaveRestoreSimpleVmbusDevice;
28use vmbus_channel::simple::SimpleVmbusDevice;
29use vmcore::save_restore::SavedStateRoot;
30use zerocopy::FromBytes;
31use zerocopy::Immutable;
32use zerocopy::IntoBytes;
33use zerocopy::KnownLayout;
34use zerocopy::Ref;
35
36#[derive(Debug, Error)]
37enum Error {
38 #[error("out of order packet")]
39 UnexpectedPacketOrder,
40 #[error("memory access error")]
41 Access(#[from] AccessError),
42 #[error("unknown message type: {0:#x}")]
43 UnknownMessageType(u32),
44 #[error("invalid packet")]
45 InvalidPacket,
46 #[error("channel i/o error")]
47 Io(#[source] std::io::Error),
48 #[error("failed to accept vmbus channel")]
49 Accept(#[from] vmbus_channel::offer::Error),
50}
51
52#[derive(Debug)]
53enum Request {
54 Version(protocol::Version),
55 VramLocation {
56 user_context: u64,
57 address: Option<u64>,
58 },
59 SituationUpdate {
60 user_context: u64,
61 situation: protocol::VideoOutputSituation,
62 },
63 PointerPosition {
64 is_visible: bool,
65 x: i32,
66 y: i32,
67 },
68 PointerShape,
69 Dirt(Vec<protocol::Rectangle>),
70 BiosInfo,
71 SupportedResolutions {
72 maximum_count: u8,
73 },
74 Capability,
75}
76
77fn parse_packet(buf: &[u8]) -> Result<Request, Error> {
78 let (header, buf) =
79 Ref::<_, protocol::MessageHeader>::from_prefix(buf).map_err(|_| Error::InvalidPacket)?; let request = match header.typ.to_ne() {
81 protocol::MESSAGE_VERSION_REQUEST => {
82 let message = protocol::VersionRequestMessage::ref_from_prefix(buf)
83 .map_err(|_| Error::InvalidPacket)?
84 .0; Request::Version(message.version)
86 }
87 protocol::MESSAGE_VRAM_LOCATION => {
88 let message = protocol::VramLocationMessage::ref_from_prefix(buf)
89 .map_err(|_| Error::InvalidPacket)?
90 .0; let address = if message.is_vram_gpa_address_specified != 0 {
92 Some(message.vram_gpa_address.into())
93 } else {
94 None
95 };
96 Request::VramLocation {
97 user_context: message.user_context.into(),
98 address,
99 }
100 }
101 protocol::MESSAGE_SITUATION_UPDATE => {
102 let message = protocol::SituationUpdateMessage::ref_from_prefix(buf)
103 .map_err(|_| Error::InvalidPacket)?
104 .0; Request::SituationUpdate {
106 user_context: message.user_context.into(),
107 situation: message.video_output,
108 }
109 }
110 protocol::MESSAGE_POINTER_POSITION => {
111 let message = protocol::PointerPositionMessage::ref_from_prefix(buf)
112 .map_err(|_| Error::InvalidPacket)?
113 .0; Request::PointerPosition {
115 is_visible: message.is_visible != 0,
116 x: message.image_x.into(),
117 y: message.image_y.into(),
118 }
119 }
120 protocol::MESSAGE_POINTER_SHAPE => {
121 Request::PointerShape
123 }
124 protocol::MESSAGE_DIRT => {
125 let (message, buf) = Ref::<_, protocol::DirtMessage>::from_prefix(buf)
126 .map_err(|_| Error::InvalidPacket)?; Request::Dirt(
128 <[protocol::Rectangle]>::ref_from_prefix_with_elems(
129 buf,
130 message.dirt_count as usize,
131 )
132 .map_err(|_| Error::InvalidPacket)? .0
134 .into(),
135 )
136 }
137 protocol::MESSAGE_BIOS_INFO_REQUEST => Request::BiosInfo,
138 protocol::MESSAGE_SUPPORTED_RESOLUTIONS_REQUEST => {
139 let message = protocol::SupportedResolutionsRequestMessage::ref_from_prefix(buf)
140 .map_err(|_| Error::InvalidPacket)?
141 .0; Request::SupportedResolutions {
143 maximum_count: message.maximum_resolution_count,
144 }
145 }
146 protocol::MESSAGE_CAPABILITY_REQUEST => Request::Capability,
147 typ => return Err(Error::UnknownMessageType(typ)),
148 };
149 Ok(request)
150}
151
152pub struct Video {
154 control: Box<dyn FramebufferControl>,
155}
156
157impl Video {
158 pub fn new(control: Box<dyn FramebufferControl>) -> anyhow::Result<Self> {
160 Ok(Self { control })
161 }
162}
163
164#[derive(Protobuf, SavedStateRoot)]
166#[mesh(package = "ui.synthvid")]
167pub struct SavedState(ChannelState);
168
169pub struct VideoChannel {
171 channel: MessagePipe<GpadlRingMem>,
172 state: ChannelState,
173 packet_buf: PacketBuffer,
174}
175
176#[derive(Debug, Copy, Clone, Protobuf)]
177#[mesh(package = "ui.synthvid")]
178struct Version {
179 #[mesh(1)]
180 major: u16,
181 #[mesh(2)]
182 minor: u16,
183}
184
185impl From<protocol::Version> for Version {
186 fn from(version: protocol::Version) -> Self {
187 Self {
188 major: version.major(),
189 minor: version.minor(),
190 }
191 }
192}
193
194impl From<Version> for protocol::Version {
195 fn from(version: Version) -> Self {
196 Self::new(version.major, version.minor)
197 }
198}
199
200#[derive(Debug, Clone, Protobuf)]
201#[mesh(package = "ui.synthvid")]
202enum ChannelState {
203 #[mesh(1)]
204 ReadVersion,
205 #[mesh(2)]
206 WriteVersion {
207 #[mesh(1)]
208 version: Version,
209 },
210 #[mesh(3)]
211 Active {
212 #[mesh(1)]
213 version: Version,
214 #[mesh(2)]
215 substate: ActiveState,
216 },
217}
218
219impl Default for ChannelState {
220 fn default() -> Self {
221 Self::ReadVersion
222 }
223}
224
225#[derive(Debug, Clone, Protobuf)]
226#[mesh(package = "ui.synthvid")]
227enum ActiveState {
228 #[mesh(1)]
229 ReadRequest,
230 #[mesh(2)]
231 SendVramAck {
232 #[mesh(1)]
233 user_context: u64,
234 },
235 #[mesh(3)]
236 SendSituationUpdateAck {
237 #[mesh(1)]
238 user_context: u64,
239 },
240 #[mesh(4)]
241 SendBiosInfo,
242 #[mesh(5)]
243 SendSupportedResolutions {
244 #[mesh(1)]
245 maximum_count: u8,
246 },
247 #[mesh(6)]
248 SendCapability,
249}
250
251struct PacketBuffer {
252 buf: Vec<u8>,
253}
254
255impl PacketBuffer {
256 fn new() -> Self {
257 Self {
258 buf: vec![0; protocol::MAX_VMBUS_PACKET_SIZE],
259 }
260 }
261
262 async fn recv_packet(
263 &mut self,
264 reader: &mut (impl AsyncRecv + Unpin),
265 ) -> Result<Request, Error> {
266 let n = match reader.recv(&mut self.buf).await {
267 Ok(n) => n,
268 Err(e) => return Err(Error::Io(e)),
269 };
270 let buf = &self.buf[..n];
271 parse_packet(buf)
272 }
273}
274
275#[async_trait]
276impl SimpleVmbusDevice for Video {
277 type Runner = VideoChannel;
278 type SavedState = SavedState;
279
280 fn offer(&self) -> OfferParams {
281 OfferParams {
282 interface_name: "video".to_owned(),
283 interface_id: Guid {
284 data1: 0xda0a7802,
285 data2: 0xe377,
286 data3: 0x4aac,
287 data4: [0x8e, 0x77, 0x5, 0x58, 0xeb, 0x10, 0x73, 0xf8],
288 },
289 instance_id: Guid {
290 data1: 0x5620e0c7,
291 data2: 0x8062,
292 data3: 0x4dce,
293 data4: [0xae, 0xb7, 0x52, 0xc, 0x7e, 0xf7, 0x61, 0x71],
294 },
295 mmio_megabytes: 8,
296 channel_type: ChannelType::Device { pipe_packets: true },
297 ..Default::default()
298 }
299 }
300
301 fn inspect(&mut self, req: inspect::Request<'_>, task: Option<&mut VideoChannel>) {
302 let mut resp = req.respond();
303 if let Some(this) = task {
304 let (version, state) = match &this.state {
305 ChannelState::ReadVersion => (None, "read_version"),
306 ChannelState::WriteVersion { version } => (Some(*version), "write_version"),
307 ChannelState::Active { version, substate } => (
308 Some(*version),
309 match substate {
310 ActiveState::ReadRequest => "read_request",
311 ActiveState::SendVramAck { .. } => "send_vram_ack",
312 ActiveState::SendSituationUpdateAck { .. } => "send_situation_update_ack",
313 ActiveState::SendBiosInfo => "send_bios_info",
314 ActiveState::SendSupportedResolutions { .. } => {
315 "send_supported_resolutions"
316 }
317 ActiveState::SendCapability => "send_capability",
318 },
319 ),
320 };
321 resp.field("state", state)
322 .field(
323 "version",
324 version.map(|v| format!("{}.{}", v.major, v.minor)),
325 )
326 .field_mut("channel", &mut this.channel);
327 }
328 }
329
330 fn open(
331 &mut self,
332 channel: RawAsyncChannel<GpadlRingMem>,
333 _guest_memory: guestmem::GuestMemory,
334 ) -> Result<Self::Runner, ChannelOpenError> {
335 let pipe = MessagePipe::new(channel)?;
336 Ok(VideoChannel::new(pipe, ChannelState::default()))
337 }
338
339 async fn run(
340 &mut self,
341 stop: &mut StopTask<'_>,
342 channel: &mut VideoChannel,
343 ) -> Result<(), task_control::Cancelled> {
344 stop.until_stopped(async {
345 match channel.process(&mut self.control).await {
346 Ok(()) => {}
347 Err(err) => tracing::error!(error = &err as &dyn std::error::Error, "video error"),
348 }
349 })
350 .await
351 }
352
353 fn supports_save_restore(
354 &mut self,
355 ) -> Option<
356 &mut dyn SaveRestoreSimpleVmbusDevice<SavedState = Self::SavedState, Runner = Self::Runner>,
357 > {
358 Some(self)
359 }
360}
361
362impl SaveRestoreSimpleVmbusDevice for Video {
363 fn save_open(&mut self, runner: &Self::Runner) -> Self::SavedState {
364 SavedState(runner.state.clone())
365 }
366
367 fn restore_open(
368 &mut self,
369 state: Self::SavedState,
370 channel: RawAsyncChannel<GpadlRingMem>,
371 ) -> Result<Self::Runner, ChannelOpenError> {
372 let pipe = MessagePipe::new(channel)?;
373 Ok(VideoChannel::new(pipe, state.0))
374 }
375}
376
377impl VideoChannel {
378 fn new(channel: MessagePipe<GpadlRingMem>, state: ChannelState) -> Self {
379 Self {
380 channel,
381 state,
382 packet_buf: PacketBuffer::new(),
383 }
384 }
385
386 async fn send_packet<T: IntoBytes + ?Sized + Immutable + KnownLayout>(
387 writer: &mut (impl AsyncSend + Unpin),
388 typ: u32,
389 packet: &T,
390 ) -> Result<(), Error> {
391 let header = protocol::MessageHeader {
392 typ: typ.into(),
393 size: (size_of_val(packet) as u32).into(),
394 };
395 writer
396 .send_vectored(&[
397 IoSlice::new(header.as_bytes()),
398 IoSlice::new(packet.as_bytes()),
399 ])
400 .await
401 .map_err(Error::Io)?;
402
403 Ok(())
404 }
405
406 async fn process(
407 &mut self,
408 framebuffer: &mut Box<dyn FramebufferControl>,
409 ) -> Result<(), Error> {
410 let mut channel = &mut self.channel;
411 loop {
412 match &mut self.state {
413 ChannelState::ReadVersion => {
414 let version = if let Request::Version(version) =
415 self.packet_buf.recv_packet(&mut channel).await?
416 {
417 version.into()
418 } else {
419 return Err(Error::UnexpectedPacketOrder);
420 };
421 self.state = ChannelState::WriteVersion { version };
422 }
423 ChannelState::WriteVersion { version } => {
424 let server_version = Version {
425 major: protocol::VERSION_MAJOR,
426 minor: protocol::VERSION_MINOR_BLUE,
427 };
428 let is_accepted = if version.major == server_version.major {
429 protocol::ACCEPTED_WITH_VERSION_EXCHANGE
430 } else {
431 0
432 };
433 Self::send_packet(
434 &mut channel,
435 protocol::MESSAGE_VERSION_RESPONSE,
436 &protocol::VersionResponseMessage {
437 version: (*version).into(),
438 is_accepted,
439 max_video_outputs: 1,
440 },
441 )
442 .await?;
443 if is_accepted != 0 {
444 tracelimit::info_ratelimited!(?version, "video negotiation succeeded");
445 self.state = ChannelState::Active {
446 version: *version,
447 substate: ActiveState::ReadRequest,
448 };
449 } else {
450 tracelimit::warn_ratelimited!(?version, "video negotiation failed");
451 self.state = ChannelState::ReadVersion;
452 }
453 }
454 ChannelState::Active {
455 version: _,
456 substate,
457 } => {
458 match *substate {
459 ActiveState::ReadRequest => {
460 let packet = self.packet_buf.recv_packet(&mut channel).await?;
461 match packet {
462 Request::VramLocation {
463 user_context,
464 address,
465 } => {
466 framebuffer.unmap().await;
467 if let Some(address) = address {
468 framebuffer.map(address).await;
473 }
474 *substate = ActiveState::SendVramAck { user_context };
475 }
476 Request::SituationUpdate {
477 user_context,
478 situation,
479 } => {
480 framebuffer
481 .set_format(FramebufferFormat {
482 width: u32::from(situation.width_pixels) as usize,
483 height: u32::from(situation.height_pixels) as usize,
484 bytes_per_line: u32::from(situation.pitch_bytes)
485 as usize,
486 offset: u32::from(situation.primary_surface_vram_offset)
487 as usize,
488 })
489 .await;
490 *substate =
491 ActiveState::SendSituationUpdateAck { user_context };
492 }
493 Request::PointerPosition { is_visible, x, y } => {
494 let _ = (is_visible, x, y);
495 }
496 Request::PointerShape => {}
497 Request::Dirt(_rects) => {
498 }
500 Request::BiosInfo => {
501 *substate = ActiveState::SendBiosInfo;
502 }
503 Request::SupportedResolutions { maximum_count } => {
504 *substate =
505 ActiveState::SendSupportedResolutions { maximum_count };
506 }
507 Request::Capability => {
508 *substate = ActiveState::SendCapability;
509 }
510 Request::Version(_) => return Err(Error::UnexpectedPacketOrder),
511 }
512 }
513 ActiveState::SendVramAck { user_context } => {
514 Self::send_packet(
515 &mut channel,
516 protocol::MESSAGE_VRAM_LOCATION_ACK,
517 &protocol::VramLocationAckMessage {
518 user_context: user_context.into(),
519 },
520 )
521 .await?;
522 *substate = ActiveState::ReadRequest;
523 }
524 ActiveState::SendSituationUpdateAck { user_context } => {
525 Self::send_packet(
526 &mut channel,
527 protocol::MESSAGE_SITUATION_UPDATE_ACK,
528 &protocol::SituationUpdateAckMessage {
529 user_context: user_context.into(),
530 },
531 )
532 .await?;
533 *substate = ActiveState::ReadRequest;
534 }
535 ActiveState::SendBiosInfo => {
536 Self::send_packet(
537 &mut channel,
538 protocol::MESSAGE_BIOS_INFO_RESPONSE,
539 &protocol::BiosInfoResponseMessage {
540 stop_device_supported: 1.into(),
541 reserved: [0; 12],
542 },
543 )
544 .await?;
545 *substate = ActiveState::ReadRequest;
546 }
547 ActiveState::SendSupportedResolutions { maximum_count } => {
548 if maximum_count < protocol::MAXIMUM_RESOLUTIONS_COUNT {
549 Self::send_packet(
550 &mut channel,
551 protocol::MESSAGE_SUPPORTED_RESOLUTIONS_RESPONSE,
552 &protocol::SupportedResolutionsResponseMessage {
553 edid_block: protocol::EDID_BLOCK,
554 resolution_count: 0,
555 default_resolution_index: 0,
556 is_standard: 0,
557 },
558 )
559 .await?;
560 } else {
561 const RESOLUTIONS: &[(u16, u16)] = &[(1024, 768), (1280, 1024)];
562
563 let mut packet = Vec::new();
564 packet.extend_from_slice(
565 protocol::SupportedResolutionsResponseMessage {
566 edid_block: protocol::EDID_BLOCK,
567 resolution_count: RESOLUTIONS.len().try_into().unwrap(),
568 default_resolution_index: 0,
569 is_standard: 0,
570 }
571 .as_bytes(),
572 );
573 for r in RESOLUTIONS {
574 packet.extend_from_slice(
575 protocol::ScreenInfo {
576 width: r.0.into(),
577 height: r.1.into(),
578 }
579 .as_bytes(),
580 );
581 }
582 Self::send_packet(
583 &mut channel,
584 protocol::MESSAGE_SUPPORTED_RESOLUTIONS_RESPONSE,
585 packet.as_slice(),
586 )
587 .await?;
588 }
589 *substate = ActiveState::ReadRequest;
590 }
591 ActiveState::SendCapability => {
592 Self::send_packet(
593 &mut channel,
594 protocol::MESSAGE_CAPABILITY_RESPONSE,
595 &protocol::CapabilityResponseMessage {
596 lock_on_disconnect: 0.into(),
597 reserved: [0.into(); 15],
598 },
599 )
600 .await?;
601 *substate = ActiveState::ReadRequest;
602 }
603 }
604 }
605 }
606 }
607 }
608}