#![warn(missing_docs)]
use anyhow::Context;
use chipset_device::ChipsetDevice;
use guestmem::GuestMemory;
use guestmem::MappableGuestMemory;
use guestmem::MemoryMapper;
use inspect::Inspect;
use inspect::InspectMut;
use memory_range::MemoryRange;
use mesh::payload::Protobuf;
use mesh::MeshPayload;
use parking_lot::Mutex;
use sparse_mmap::Mappable;
use sparse_mmap::SparseMapping;
use std::convert::Infallible;
use std::io;
use std::sync::Arc;
use video_core::FramebufferControl;
use video_core::FramebufferFormat;
use video_core::ResolvedFramebuffer;
use video_core::SharedFramebufferHandle;
use vm_resource::kind::FramebufferHandleKind;
use vm_resource::ResolveResource;
use vmcore::device_state::ChangeDeviceState;
use vmcore::save_restore::RestoreError;
use vmcore::save_restore::SaveError;
use vmcore::save_restore::SaveRestore;
use vmcore::save_restore::SavedStateRoot;
fn default_framebuffer_format() -> FramebufferFormat {
FramebufferFormat {
width: 1024,
height: 768,
bytes_per_line: 1024 * 4,
offset: 0,
}
}
pub const FRAMEBUFFER_SIZE: usize = 8 * 1024 * 1024; pub fn framebuffer(
vram: Mappable,
len: usize,
offset: u64,
) -> io::Result<(Framebuffer, FramebufferAccess)> {
assert_eq!(
len, FRAMEBUFFER_SIZE,
"no framebuffer size flexibility for now"
);
let (send, recv) = mesh::channel();
let fb = Framebuffer {
vram: vram.try_clone()?,
len,
format_send: send,
};
let access = FramebufferAccess {
vram,
len,
format_recv: recv,
offset,
};
Ok((fb, access))
}
#[derive(Debug, MeshPayload)]
pub struct Framebuffer {
vram: Mappable,
len: usize,
format_send: mesh::Sender<FramebufferFormat>,
}
impl Framebuffer {
pub fn len(&self) -> usize {
self.len
}
pub fn format_send(self) -> mesh::Sender<FramebufferFormat> {
self.format_send
}
}
#[derive(Debug, MeshPayload)]
pub struct FramebufferAccess {
vram: Mappable,
len: usize,
format_recv: mesh::Receiver<FramebufferFormat>,
offset: u64,
}
impl FramebufferAccess {
pub fn view(self) -> io::Result<View> {
let mapping = SparseMapping::new(self.len)?;
mapping.map_file(0, self.len, &self.vram, self.offset, false)?;
Ok(View {
mapping,
format_recv: self.format_recv,
format: None,
vram: self.vram,
len: self.len,
offset: self.offset,
})
}
}
#[derive(Debug)]
pub struct View {
mapping: SparseMapping,
format_recv: mesh::Receiver<FramebufferFormat>,
format: Option<FramebufferFormat>,
vram: Mappable,
len: usize,
offset: u64,
}
impl View {
pub fn read_line(&mut self, line: u16, data: &mut [u8]) {
if let Some(format) = &self.format {
if let Some(offset) = (line as usize)
.checked_mul(format.bytes_per_line)
.and_then(|x| x.checked_add(format.offset))
{
let len = std::cmp::min(data.len(), format.width * 4);
let _ = self.mapping.read_at(offset, &mut data[..len]);
return;
}
}
data.fill(0);
}
pub fn resolution(&mut self) -> (u16, u16) {
while let Ok(format) = self.format_recv.try_recv() {
self.format = Some(format);
}
if let Some(format) = &self.format {
(format.width as u16, format.height as u16)
} else {
(1, 1)
}
}
pub fn access(self) -> FramebufferAccess {
let (send, recv) = mesh::channel();
if let Some(format) = self.format {
send.send(format);
}
send.bridge(self.format_recv);
FramebufferAccess {
vram: self.vram,
len: self.len,
format_recv: recv,
offset: self.offset,
}
}
}
#[derive(InspectMut)]
pub struct FramebufferDevice {
#[inspect(flatten)]
inner: Arc<Mutex<FramebufferInner>>,
#[inspect(hex)]
len: usize,
}
#[derive(Clone)]
pub struct FramebufferLocalControl {
inner: Arc<Mutex<FramebufferInner>>,
len: usize,
}
#[derive(Inspect)]
struct FramebufferInner {
#[inspect(skip)]
_mem_fixed: Option<Box<dyn MappableGuestMemory>>,
#[inspect(skip)]
framebuffer: Option<Framebuffer>,
mapping_state: Option<MappingState>,
format: FramebufferFormat,
#[inspect(skip)]
mapper: Box<dyn MemoryMapper>,
}
#[derive(Inspect)]
struct MappingState {
gpa: u64,
subrange: MemoryRange,
#[inspect(skip)]
mem: Box<dyn MappableGuestMemory>,
}
#[derive(Debug, Clone, Protobuf, SavedStateRoot)]
#[mesh(package = "framebuffer")]
pub struct SavedState {
#[mesh(1)]
mapping: Option<SavedMappingState>,
#[mesh(2)]
format: FramebufferFormat,
}
#[derive(Debug, Clone, Protobuf)]
#[mesh(package = "framebuffer")]
struct SavedMappingState {
#[mesh(1)]
gpa: u64,
#[mesh(2)]
subrange: MemoryRange,
}
impl FramebufferDevice {
pub fn new(
mapper: Box<dyn MemoryMapper>,
framebuffer: Framebuffer,
framebuffer_gpa_base_fixed: Option<u64>,
) -> anyhow::Result<Self> {
let len = framebuffer.len;
let mem_fixed = if let Some(gpa) = framebuffer_gpa_base_fixed {
let (mut mem, region) = mapper
.new_region(len, "framebuffer-vtl2".to_owned())
.context("failed to create vtl2 framebuffer memory region")?;
region
.map(0, &framebuffer.vram, 0, len, true)
.context("failed to map vtl2 framebuffer memory region")?;
mem.map_to_guest(gpa, true)?;
Some(mem)
} else {
None
};
let format = default_framebuffer_format();
framebuffer.format_send.send(format);
Ok(Self {
inner: Arc::new(Mutex::new(FramebufferInner {
_mem_fixed: mem_fixed,
mapping_state: None,
format,
framebuffer: Some(framebuffer),
mapper,
})),
len,
})
}
pub fn into_framebuffer(self) -> Framebuffer {
self.inner.lock().framebuffer.take().unwrap()
}
pub fn control(&self) -> FramebufferLocalControl {
FramebufferLocalControl {
inner: self.inner.clone(),
len: self.len,
}
}
}
impl ChangeDeviceState for FramebufferDevice {
fn start(&mut self) {}
async fn stop(&mut self) {}
async fn reset(&mut self) {
let mut inner = self.inner.lock();
inner.mapping_state = Default::default();
if let Some(mut state) = inner.mapping_state.take() {
state.mem.unmap_from_guest();
}
}
}
impl ChipsetDevice for FramebufferDevice {}
impl SaveRestore for FramebufferDevice {
type SavedState = SavedState;
fn save(&mut self) -> Result<Self::SavedState, SaveError> {
let inner = self.inner.lock();
let mapping = inner.mapping_state.as_ref().map(
|MappingState {
gpa,
subrange,
mem: _,
}| SavedMappingState {
gpa: *gpa,
subrange: *subrange,
},
);
Ok(SavedState {
format: inner.format,
mapping,
})
}
fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
let SavedState { mapping, format } = state;
let mut inner = self.inner.lock();
let inner = &mut *inner;
inner.format = format;
if let Some(mapping) = mapping {
inner
.map(mapping.gpa, Some(mapping.subrange))
.context("failed to map VRAM to guest")
.map_err(RestoreError::Other)?;
}
inner
.framebuffer
.as_mut()
.unwrap()
.format_send
.send(inner.format);
Ok(())
}
}
impl FramebufferInner {
fn map(&mut self, gpa: u64, framebuffer_range: Option<MemoryRange>) -> anyhow::Result<()> {
if let Some(mut state) = self.mapping_state.take() {
state.mem.unmap_from_guest();
}
let Some(framebuffer) = &self.framebuffer else {
return Ok(());
};
let framebuffer_range =
framebuffer_range.unwrap_or_else(|| MemoryRange::new(0..framebuffer.len as u64));
let (mut mem, region) = self
.mapper
.new_region(framebuffer_range.len() as usize, "framebuffer".to_owned())
.context("failed to create framebuffer region")?;
region
.map(
0,
&framebuffer.vram,
framebuffer_range.start(),
framebuffer_range.len() as usize,
true,
)
.context("failed to map framebuffer memory")?;
mem.map_to_guest(gpa, true)
.context("failed to map VRAM to guest")?;
self.mapping_state = Some(MappingState {
gpa,
subrange: framebuffer_range,
mem,
});
tracing::debug!("Mapped VRAM to guest at address {:#x}", gpa);
Ok(())
}
}
impl FramebufferLocalControl {
pub fn map(&mut self, gpa: u64, framebuffer_range: Option<MemoryRange>) {
if let Err(err) = self.inner.lock().map(gpa, framebuffer_range) {
tracing::error!(
gpa,
error = err.as_ref() as &dyn std::error::Error,
"failed to map framebuffer to guest"
);
}
}
pub fn unmap(&mut self) {
let mut inner = self.inner.lock();
if let Some(mut state) = inner.mapping_state.take() {
state.mem.unmap_from_guest();
}
}
pub fn len(&self) -> usize {
self.len
}
pub fn set_format(&mut self, format: FramebufferFormat) {
let mut inner = self.inner.lock();
let inner = &mut *inner;
if inner.format != format {
inner.format = format;
if let Some(framebuffer) = &mut inner.framebuffer {
framebuffer.format_send.send(inner.format);
}
}
}
pub fn memory(&self) -> io::Result<GuestMemory> {
let inner = self.inner.lock();
let framebuffer = inner
.framebuffer
.as_ref()
.expect("framebuffer is still active");
let mapping = SparseMapping::new(framebuffer.len())?;
mapping.map_file(0, framebuffer.len(), &framebuffer.vram, 0, true)?;
Ok(GuestMemory::new("framebuffer", mapping))
}
}
#[async_trait::async_trait]
impl FramebufferControl for FramebufferLocalControl {
async fn map(&mut self, gpa: u64) {
self.map(gpa, None);
}
async fn unmap(&mut self) {
self.unmap();
}
async fn set_format(&mut self, format: FramebufferFormat) {
self.set_format(format);
}
}
impl ResolveResource<FramebufferHandleKind, SharedFramebufferHandle> for FramebufferLocalControl {
type Output = ResolvedFramebuffer;
type Error = Infallible;
fn resolve(
&self,
_resource: SharedFramebufferHandle,
_input: (),
) -> Result<Self::Output, Self::Error> {
Ok(self.clone().into())
}
}