1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/openeuler-stratovirt

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
ramfb.rs 9.7 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
liuxiangdong Отправлено год назад a3e4890
// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved.
//
// StratoVirt is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan
// PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
use std::mem::size_of;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, Weak};
use std::time::Duration;
use anyhow::{Context, Result};
use drm_fourcc::DrmFourcc;
use log::error;
use super::fwcfg::{FwCfgOps, FwCfgWriteCallback};
use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType};
use crate::{Device, DeviceBase};
use acpi::AmlBuilder;
use address_space::{AddressSpace, GuestAddress};
use machine_manager::event_loop::EventLoop;
use ui::console::{
console_init, display_graphic_update, display_replace_surface, ConsoleType, DisplayConsole,
DisplaySurface, HardWareOperations,
};
use ui::input::{key_event, KEYCODE_RET};
use util::pixman::{pixman_format_bpp, pixman_format_code_t, pixman_image_create_bits};
const BYTES_PER_PIXELS: u32 = 8;
const WIDTH_MAX: u32 = 16_000;
const HEIGHT_MAX: u32 = 12_000;
const INSTALL_CHECK_INTERVEL_MS: u64 = 500;
const INSTALL_RELEASE_INTERVEL_MS: u64 = 200;
const INSTALL_PRESS_INTERVEL_MS: u64 = 100;
#[repr(packed)]
struct RamfbCfg {
_addr: u64,
_fourcc: u32,
_flags: u32,
_width: u32,
_height: u32,
_stride: u32,
}
#[derive(Clone)]
pub struct RamfbState {
pub surface: Option<DisplaySurface>,
pub con: Option<Weak<Mutex<DisplayConsole>>>,
sys_mem: Arc<AddressSpace>,
install: Arc<AtomicBool>,
}
// SAFETY: The type of image, the field of the struct DisplaySurface
// is the raw pointer. create_display_surface() method will create
// image object. The memory that the image pointer refers to is
// modified by guest OS and accessed by vnc. So implement Sync and
// Send is safe.
unsafe impl Sync for RamfbState {}
// SAFETY: The reason is same as above.
unsafe impl Send for RamfbState {}
impl RamfbState {
pub fn new(sys_mem: Arc<AddressSpace>, install: bool) -> Self {
let ramfb_opts = Arc::new(RamfbInterface {});
let con = console_init("ramfb".to_string(), ConsoleType::Graphic, ramfb_opts);
Self {
surface: None,
con,
sys_mem,
install: Arc::new(AtomicBool::new(install)),
}
}
pub fn setup(&mut self, fw_cfg: &Arc<Mutex<dyn FwCfgOps>>) -> Result<()> {
let mut locked_fw_cfg = fw_cfg.lock().unwrap();
let ramfb_state_cb = self.clone();
let cfg: Vec<u8> = [0; size_of::<RamfbCfg>()].to_vec();
locked_fw_cfg
.add_file_callback_entry(
"etc/ramfb",
cfg,
None,
Some(Arc::new(Mutex::new(ramfb_state_cb))),
true,
)
.with_context(|| "Failed to set fwcfg")?;
Ok(())
}
fn create_display_surface(
&mut self,
width: u32,
height: u32,
format: pixman_format_code_t,
mut stride: u32,
addr: u64,
) {
if width < 16 || height < 16 || width > WIDTH_MAX || height > HEIGHT_MAX {
error!("The resolution: {}x{} is unsupported.", width, height);
}
if stride == 0 {
let linesize = width * pixman_format_bpp(format as u32) as u32 / BYTES_PER_PIXELS;
stride = linesize;
}
let fb_addr = match self.sys_mem.addr_cache_init(GuestAddress(addr)) {
Some((hva, len)) => {
if len < stride as u64 {
error!("Insufficient contiguous memory length");
return;
}
hva
}
None => {
error!("Failed to get the host address of the framebuffer");
return;
}
};
let mut ds = DisplaySurface {
format,
..Default::default()
};
// SAFETY: pixman_image_create_bits() is C function. All
// parameters passed of the function have been checked.
// It returns a raw pointer.
unsafe {
ds.image = pixman_image_create_bits(
format,
width as i32,
height as i32,
fb_addr as *mut u32,
stride as i32,
);
}
if ds.image.is_null() {
error!("Failed to create the surface of Ramfb!");
return;
}
self.surface = Some(ds);
set_press_event(self.install.clone(), fb_addr as *const u8);
}
fn reset_ramfb_state(&mut self) {
self.surface = None;
}
}
impl FwCfgWriteCallback for RamfbState {
fn write_callback(&mut self, data: Vec<u8>, _start: u64, _len: usize) {
if data.len() < 28 {
error!("RamfbCfg data format is incorrect");
return;
}
let addr = u64::from_be_bytes(
data.as_slice()
.split_at(size_of::<u64>())
.0
.try_into()
.unwrap(),
);
let fourcc = u32::from_be_bytes(
data.as_slice()[8..]
.split_at(size_of::<u32>())
.0
.try_into()
.unwrap(),
);
let width = u32::from_be_bytes(
data.as_slice()[16..]
.split_at(size_of::<u32>())
.0
.try_into()
.unwrap(),
);
let height = u32::from_be_bytes(
data.as_slice()[20..]
.split_at(size_of::<u32>())
.0
.try_into()
.unwrap(),
);
let stride = u32::from_be_bytes(
data.as_slice()[24..]
.split_at(size_of::<u32>())
.0
.try_into()
.unwrap(),
);
let format: pixman_format_code_t = if fourcc == DrmFourcc::Xrgb8888 as u32 {
pixman_format_code_t::PIXMAN_x8r8g8b8
} else {
error!("Unsupported drm format: {}", fourcc);
return;
};
self.create_display_surface(width, height, format, stride, addr);
display_replace_surface(&self.con, self.surface)
.unwrap_or_else(|e| error!("Error occurs during surface switching: {:?}", e));
}
}
pub struct RamfbInterface {}
impl HardWareOperations for RamfbInterface {
fn hw_update(&self, con: Arc<Mutex<DisplayConsole>>) {
let locked_con = con.lock().unwrap();
let width = locked_con.width;
let height = locked_con.height;
drop(locked_con);
display_graphic_update(&Some(Arc::downgrade(&con)), 0, 0, width, height)
.unwrap_or_else(|e| error!("Error occurs during graphic updating: {:?}", e));
}
}
pub struct Ramfb {
base: SysBusDevBase,
pub ramfb_state: RamfbState,
}
impl Ramfb {
pub fn new(sys_mem: Arc<AddressSpace>, install: bool) -> Self {
Ramfb {
base: SysBusDevBase::new(SysBusDevType::Ramfb),
ramfb_state: RamfbState::new(sys_mem, install),
}
}
pub fn realize(self, sysbus: &mut SysBus) -> Result<()> {
let dev = Arc::new(Mutex::new(self));
sysbus.attach_dynamic_device(&dev)?;
Ok(())
}
}
impl Device for Ramfb {
fn device_base(&self) -> &DeviceBase {
&self.base.base
}
fn device_base_mut(&mut self) -> &mut DeviceBase {
&mut self.base.base
}
}
impl SysBusDevOps for Ramfb {
fn sysbusdev_base(&self) -> &SysBusDevBase {
&self.base
}
fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase {
&mut self.base
}
fn read(&mut self, _data: &mut [u8], _base: GuestAddress, _offset: u64) -> bool {
error!("Ramfb can not be read!");
false
}
fn write(&mut self, _data: &[u8], _base: GuestAddress, _offset: u64) -> bool {
error!("Ramfb can not be written!");
false
}
fn reset(&mut self) -> Result<()> {
self.ramfb_state.reset_ramfb_state();
Ok(())
}
}
impl AmlBuilder for Ramfb {
fn aml_bytes(&self) -> Vec<u8> {
Vec::new()
}
}
fn set_press_event(install: Arc<AtomicBool>, data: *const u8) {
let black_screen =
// SAFETY: data is the raw pointer of framebuffer. EDKII has malloc the memory of
// the framebuffer. So dereference the data is safe.
unsafe { !data.is_null() && *data == 0 && *data.offset(1) == 0 && *data.offset(2) == 0 };
if install.load(Ordering::Acquire) && black_screen {
let set_press_func = Box::new(move || {
set_press_event(install.clone(), data);
});
let press_func = Box::new(move || {
key_event(KEYCODE_RET, true)
.unwrap_or_else(|e| error!("Ramfb couldn't press return key: {:?}", e));
});
let release_func = Box::new(move || {
key_event(KEYCODE_RET, false)
.unwrap_or_else(|e| error!("Ramfb couldn't release return key: {:?}.", e));
});
let ctx = EventLoop::get_ctx(None).unwrap();
ctx.timer_add(
set_press_func,
Duration::from_millis(INSTALL_CHECK_INTERVEL_MS),
);
ctx.timer_add(press_func, Duration::from_millis(INSTALL_PRESS_INTERVEL_MS));
ctx.timer_add(
release_func,
Duration::from_millis(INSTALL_RELEASE_INTERVEL_MS),
);
} else {
install.store(false, Ordering::Release);
}
}

Комментарий ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/openeuler-stratovirt.git
git@gitlife.ru:oschina-mirror/openeuler-stratovirt.git
oschina-mirror
openeuler-stratovirt
openeuler-stratovirt
v2.4.0