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

OSCHINA-MIRROR/openeuler-stratovirt

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
fwcfg.rs 50 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
Jinhao Gao Отправлено год назад 969efb0
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639
// Copyright (c) 2020 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::sync::{Arc, Mutex};
use anyhow::{anyhow, bail, Context, Result};
#[cfg(target_arch = "x86_64")]
use byteorder::LittleEndian;
use byteorder::{BigEndian, ByteOrder};
use log::{error, warn};
use crate::legacy::error::LegacyError;
use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes};
use crate::{Device, DeviceBase};
use acpi::{
AmlBuilder, AmlDevice, AmlInteger, AmlNameDecl, AmlResTemplate, AmlScopeBuilder, AmlString,
};
#[cfg(target_arch = "x86_64")]
use acpi::{AmlIoDecode, AmlIoResource};
#[cfg(target_arch = "aarch64")]
use acpi::{AmlMemory32Fixed, AmlReadAndWrite};
use address_space::{AddressSpace, GuestAddress};
use util::byte_code::ByteCode;
use util::num_ops::extract_u64;
use util::offset_of;
#[cfg(target_arch = "x86_64")]
const FW_CFG_IO_BASE: u64 = 0x510;
// Size of ioports including control/data registers and DMA.
#[cfg(target_arch = "x86_64")]
const FW_CFG_IO_SIZE: u64 = 0x12;
// FwCfg Signature
const FW_CFG_DMA_SIGNATURE: u128 = 0x51454d5520434647;
/// FwCfg version bits
const FW_CFG_VERSION: u16 = 0x01;
const FW_CFG_VERSION_DMA: u16 = 0x02;
// FwCfg related constants
const FW_CFG_FILE_SLOTS_DFLT: u16 = 0x20;
const FW_CFG_FILE_FIRST: u16 = 0x20;
const FW_CFG_WRITE_CHANNEL: u16 = 0x4000;
const FW_CFG_ARCH_LOCAL: u16 = 0x8000;
const FW_CFG_ENTRY_MASK: u16 = !(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL);
const FW_CFG_INVALID: u16 = 0xffff;
/// FwCfg DMA control bits
const FW_CFG_DMA_CTL_ERROR: u32 = 0x01;
const FW_CFG_DMA_CTL_READ: u32 = 0x02;
const FW_CFG_DMA_CTL_SKIP: u32 = 0x04;
const FW_CFG_DMA_CTL_SELECT: u32 = 0x08;
const FW_CFG_DMA_CTL_WRITE: u32 = 0x10;
/// Define the Firmware Configuration Entry Type
#[repr(u16)]
pub enum FwCfgEntryType {
Signature = 0x00,
Id,
Uuid,
RamSize,
NoGraphic,
NbCpus,
MachineId,
KernelAddr,
KernelSize,
KernelCmdline,
InitrdAddr,
InitrdSize,
BootDevice,
Numa,
BootMenu,
MaxCpus,
KernelEntry,
KernelData,
InitrdData,
CmdlineAddr,
CmdlineSize,
CmdlineData,
SetupAddr,
SetupSize,
SetupData,
FileDir,
#[cfg(target_arch = "x86_64")]
Irq0Override = 0x8002,
#[cfg(target_arch = "x86_64")]
E820Table = 0x8003,
}
/// Get the FwCfg entry name of a given key
fn get_key_name(key: usize) -> &'static str {
static FW_CFG_KEYS: [&str; 26] = [
"signature",
"id",
"uuid",
"ram_size",
"nographic",
"nb_cpus",
"machine_id",
"kernel_addr",
"kernel_size",
"kernel_cmdline",
"initrd_addr",
"initrd_size",
"boot_device",
"numa",
"boot_menu",
"max_cpus",
"kernel_entry",
"kernel_data",
"initrd_data",
"cmdline_addr",
"cmdline_size",
"cmdline_data",
"setup_addr",
"setup_size",
"setup_data",
"file_dir",
];
if key < FW_CFG_FILE_FIRST as usize {
FW_CFG_KEYS[key]
} else {
"unknown"
}
}
/// FwCfg select callback and write callback type definition
type FwCfgCallbackType = Arc<dyn FwCfgCallback + Send + Sync>;
type FwCfgWriteCallbackType = Arc<Mutex<dyn FwCfgWriteCallback + Send + Sync>>;
/// FwCfg select callback
pub trait FwCfgCallback {
fn select_callback(&self);
}
/// FwCfg write callback
pub trait FwCfgWriteCallback {
fn write_callback(&mut self, data: Vec<u8>, start: u64, len: usize);
}
/// The FwCfgEntry type which holds the firmware item
#[derive(Clone, Default)]
struct FwCfgEntry {
data: Vec<u8>,
select_cb: Option<FwCfgCallbackType>,
write_cb: Option<FwCfgWriteCallbackType>,
allow_write: bool,
}
impl FwCfgEntry {
fn new(
data: Vec<u8>,
select_cb: Option<FwCfgCallbackType>,
write_cb: Option<FwCfgWriteCallbackType>,
allow_write: bool,
) -> Self {
FwCfgEntry {
data,
select_cb,
write_cb,
allow_write,
}
}
}
/// The FwCfgFile entry used to retrieve firwmware files by os loader
#[repr(C, packed)]
#[derive(Copy, Clone)]
struct FwCfgFile {
size: u32,
select: u16,
reserved: u16,
name: [u8; 56],
}
impl FwCfgFile {
fn new(size: u32, select: u16, name: &str) -> Self {
let len = std::cmp::min(56, name.len());
let mut bytes = [0; 56];
bytes[..len].copy_from_slice(&name.as_bytes()[..len]);
FwCfgFile {
size,
select,
reserved: 0_u16,
name: bytes,
}
}
/// Convert FwCfgFile item into a big endian format data array
fn as_be_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0; 64_usize];
let mut curr_offset = 0_usize;
let mut next_size = std::mem::size_of::<u32>();
BigEndian::write_u32(
&mut bytes[curr_offset..(curr_offset + next_size)],
self.size,
);
curr_offset += next_size;
next_size = std::mem::size_of::<u16>();
BigEndian::write_u16(
&mut bytes[curr_offset..(curr_offset + next_size)],
self.select,
);
curr_offset += next_size;
next_size = std::mem::size_of::<u16>();
BigEndian::write_u16(
&mut bytes[curr_offset..(curr_offset + next_size)],
self.reserved,
);
curr_offset += next_size;
bytes[curr_offset..].copy_from_slice(&self.name);
bytes
}
}
/// The FwCfgDmaAccess entry used as DMA descriptor in memory for operation
#[repr(C, packed)]
#[derive(Copy, Clone, Default)]
struct FwCfgDmaAccess {
control: u32,
length: u32,
address: u64,
}
impl ByteCode for FwCfgDmaAccess {}
/// write data to DMA memory zone
fn write_dma_memory(
addr_space: &Arc<AddressSpace>,
addr: GuestAddress,
mut buf: &[u8],
len: u64,
) -> Result<()> {
addr_space.write(&mut buf, addr, len).with_context(|| {
format!(
"Failed to write dma memory of fwcfg at gpa=0x{:x} len=0x{:x}",
addr.0, len
)
})?;
Ok(())
}
/// read data form DMA memory zone
fn read_dma_memory(
addr_space: &Arc<AddressSpace>,
addr: GuestAddress,
mut buf: &mut [u8],
len: u64,
) -> Result<()> {
addr_space.read(&mut buf, addr, len).with_context(|| {
format!(
"Failed to read dma memory of fwcfg at gpa=0x{:x} len=0x{:x}",
addr.0, len
)
})?;
Ok(())
}
/// Write DMA result to DMA response zone
fn write_dma_result(addr_space: &Arc<AddressSpace>, addr: GuestAddress, value: u32) -> Result<()> {
let mut dma_buf: [u8; 4] = [0; 4];
BigEndian::write_u32(&mut dma_buf, value);
write_dma_memory(
addr_space,
addr.unchecked_add(offset_of!(FwCfgDmaAccess, control) as u64),
&dma_buf,
dma_buf.len() as u64,
)
.with_context(|| {
format!(
"Failed to write dma result of fwcfg at gpa=0x{:x} value=0x{:x}",
addr.0, value
)
})?;
Ok(())
}
pub struct FwCfgCommon {
// Firmware file slot count
file_slots: u16,
// Arch related firmware entry
arch_entries: Vec<FwCfgEntry>,
// Arch independent firmware entry
entries: Vec<FwCfgEntry>,
// Firmware configuration files
files: Vec<FwCfgFile>,
// The current entry index selected
cur_entry: u16,
// The current entry data offset of the entry selected
cur_offset: u32,
// DMA enable flag
dma_enabled: bool,
// DMA guest address
dma_addr: GuestAddress,
// System memory address space
mem_space: Arc<AddressSpace>,
}
impl FwCfgCommon {
fn new(sys_mem: Arc<AddressSpace>) -> Self {
FwCfgCommon {
file_slots: FW_CFG_FILE_SLOTS_DFLT,
arch_entries: vec![
FwCfgEntry::default();
(FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_DFLT) as usize
],
entries: vec![
FwCfgEntry::default();
(FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_DFLT) as usize
],
files: Vec::new(),
cur_entry: 0,
cur_offset: 0,
dma_enabled: true,
dma_addr: GuestAddress(0),
mem_space: sys_mem,
}
}
/// Check whether the selected entry has a arch_local flag
fn is_arch_local(&self) -> bool {
(self.cur_entry & FW_CFG_ARCH_LOCAL) > 0
}
/// Get the max entry size
fn max_entry(&self) -> u16 {
FW_CFG_FILE_FIRST + self.file_slots
}
/// Get a mutable reference of the current selected entry
fn get_entry_mut(&mut self) -> Result<&mut FwCfgEntry> {
let key = self.cur_entry & FW_CFG_ENTRY_MASK;
if key >= self.max_entry() || self.cur_entry == FW_CFG_INVALID {
return Err(anyhow!(LegacyError::EntryNotFound(
get_key_name(self.cur_entry as usize).to_owned()
)));
};
// unwrap is safe because the count of arch_entries and entries is initialized
// as `FW_CFG_FILE_FIRST + FW_CFG_FILE_SLOTS_DFLT`, which is equal to the return
// value of `max_entry` function.
if self.is_arch_local() {
Ok(self.arch_entries.get_mut(key as usize).unwrap())
} else {
Ok(self.entries.get_mut(key as usize).unwrap())
}
}
/// Select the entry by the key specified
fn select_entry(&mut self, key: u16) {
self.cur_offset = 0;
if (key & FW_CFG_ENTRY_MASK) >= self.max_entry() {
self.cur_entry = FW_CFG_INVALID;
} else {
self.cur_entry = key;
// unwrap() is safe because we have checked the range of `key`.
let selected_entry = self.get_entry_mut().unwrap();
if let Some(ref mut cb) = selected_entry.select_cb {
cb.select_callback();
}
}
}
fn add_entry(
&mut self,
key: FwCfgEntryType,
select_cb: Option<FwCfgCallbackType>,
write_cb: Option<FwCfgWriteCallbackType>,
data: Vec<u8>,
allow_write: bool,
) -> Result<()> {
let key = (key as u16) & FW_CFG_ENTRY_MASK;
if key >= self.max_entry() || data.len() >= std::u32::MAX as usize {
return Err(anyhow!(LegacyError::InvalidFwCfgEntry(key)));
}
let entry = if self.is_arch_local() {
self.arch_entries.get_mut(key as usize)
} else {
self.entries.get_mut(key as usize)
};
if entry.is_none() {
warn!("entry not initialized in construction function");
}
let entry = entry.unwrap();
if !entry.data.is_empty() {
warn!("Entry not empty, will override");
}
entry.data = data;
entry.select_cb = select_cb;
entry.allow_write = allow_write;
entry.write_cb = write_cb;
Ok(())
}
// Update a FwCfgEntry
fn update_entry_data(&mut self, key: u16, mut data: Vec<u8>) -> Result<()> {
if key >= self.max_entry() || data.len() >= std::u32::MAX as usize {
return Err(anyhow!(LegacyError::InvalidFwCfgEntry(key)));
}
let entry = if self.is_arch_local() {
self.arch_entries.get_mut(key as usize)
} else {
self.entries.get_mut(key as usize)
};
if let Some(e) = entry {
e.data.clear();
e.data.append(&mut data);
Ok(())
} else {
Err(anyhow!(LegacyError::EntryNotFound(
get_key_name(key as usize).to_owned()
)))
}
}
fn add_file_callback(
&mut self,
filename: &str,
data: Vec<u8>,
select_cb: Option<FwCfgCallbackType>,
write_cb: Option<FwCfgWriteCallbackType>,
allow_write: bool,
) -> Result<()> {
if self.files.len() >= self.file_slots as usize {
return Err(anyhow!(LegacyError::FileSlotsNotAvailable(
filename.to_owned()
)));
}
let file_name_bytes = filename.to_string().as_bytes().to_vec();
// Check against duplicate file here
if self
.files
.iter()
.any(|f| f.name[0..file_name_bytes.len()].to_vec() == file_name_bytes)
{
return Err(anyhow!(LegacyError::DuplicateFile(filename.to_owned())));
}
let mut index = self.files.len();
for (i, file_entry) in self.files.iter().enumerate() {
if file_name_bytes < file_entry.name.to_vec() {
index = i;
break;
}
}
let file = FwCfgFile::new(
data.len() as u32,
FW_CFG_FILE_FIRST + index as u16,
filename,
);
self.files.insert(index, file);
self.files.iter_mut().skip(index + 1).for_each(|f| {
f.select += 1;
});
let mut bytes = Vec::new();
let file_length_be = BigEndian::read_u32((self.files.len() as u32).as_bytes());
bytes.append(&mut file_length_be.as_bytes().to_vec());
for value in self.files.iter() {
bytes.append(&mut value.as_be_bytes());
}
self.update_entry_data(FwCfgEntryType::FileDir as u16, bytes)?;
self.entries.insert(
FW_CFG_FILE_FIRST as usize + index,
FwCfgEntry::new(data, select_cb, write_cb, allow_write),
);
Ok(())
}
fn modify_file_callback(
&mut self,
filename: &str,
data: Vec<u8>,
select_cb: Option<FwCfgCallbackType>,
write_cb: Option<FwCfgWriteCallbackType>,
allow_write: bool,
) -> Result<()> {
if self.files.len() >= self.file_slots as usize {
return Err(anyhow!(LegacyError::FileSlotsNotAvailable(
filename.to_owned()
)));
}
let file_name_bytes = filename.to_string().as_bytes().to_vec();
// Make sure file entry is existed.
let index = self
.files
.iter()
.position(|f| f.name[0..file_name_bytes.len()].to_vec() == file_name_bytes)
.with_context(|| LegacyError::EntryNotFound(filename.to_owned()))?;
self.files[index].size = data.len() as u32;
// Update FileDir entry
let mut bytes = Vec::new();
let file_length_be = BigEndian::read_u32((self.files.len() as u32).as_bytes());
bytes.append(&mut file_length_be.as_bytes().to_vec());
for value in self.files.iter() {
bytes.append(&mut value.as_be_bytes());
}
self.update_entry_data(FwCfgEntryType::FileDir as u16, bytes)?;
// Update File entry
self.entries[FW_CFG_FILE_FIRST as usize + index] =
FwCfgEntry::new(data, select_cb, write_cb, allow_write);
Ok(())
}
// Fetch FwCfgDma request from guest and handle it
fn handle_dma_request(&mut self) -> Result<()> {
let dma_addr = self.dma_addr;
let mem_space = self.mem_space.clone();
let cur_entry = self.cur_entry;
// Reset dma_addr address before next dma access
self.dma_addr = GuestAddress(0);
// Read DMA request from guest
let mut dma_req = FwCfgDmaAccess::default();
let dma_request = dma_req.as_mut_bytes();
let size = std::mem::size_of::<FwCfgDmaAccess>() as u64;
if let Err(_e) = read_dma_memory(&self.mem_space, dma_addr, dma_request, size) {
write_dma_result(&self.mem_space, dma_addr, FW_CFG_DMA_CTL_ERROR)?;
return Err(anyhow!(LegacyError::ReadDmaRequest(dma_addr.0, size)));
}
// Build `FwCfgDmaAccess` object from dma_request here
let mut dma = FwCfgDmaAccess {
control: BigEndian::read_u32(&dma_request[0..4]),
length: BigEndian::read_u32(&dma_request[4..8]),
address: BigEndian::read_u64(&dma_request[8..]),
};
if dma.control & FW_CFG_DMA_CTL_SELECT > 0 {
self.select_entry((dma.control >> 16) as u16);
}
let mut offset = self.cur_offset;
let mut is_read = false;
let mut is_write = false;
if dma.control & FW_CFG_DMA_CTL_READ != 0 {
is_read = true;
}
if dma.control & FW_CFG_DMA_CTL_WRITE != 0 {
is_write = true;
}
if dma.control & FW_CFG_DMA_CTL_SKIP != 0 {
dma.length = 0;
}
// clear dma.control here
dma.control = 0;
let entry = self.get_entry_mut()?;
let mut len: u32;
while dma.length > 0 && (dma.control & FW_CFG_DMA_CTL_ERROR) == 0 {
if cur_entry == FW_CFG_INVALID
|| entry.data.is_empty()
|| offset >= entry.data.len() as u32
{
len = dma.length;
if is_read {
let data = vec![0_u8; len as usize];
if write_dma_memory(
&mem_space,
GuestAddress(dma.address),
data.as_slice(),
len as u64,
)
.is_err()
{
dma.control |= FW_CFG_DMA_CTL_ERROR;
}
}
if is_write {
dma.control |= FW_CFG_DMA_CTL_ERROR;
}
} else {
if dma.length <= entry.data.len() as u32 - offset {
len = dma.length;
} else {
len = entry.data.len() as u32 - offset;
}
// If it is a DMA read request
if is_read
&& write_dma_memory(
&mem_space,
GuestAddress(dma.address),
&entry.data[offset as usize..],
len as u64,
)
.is_err()
{
dma.control |= FW_CFG_DMA_CTL_ERROR;
}
if is_write {
let mut dma_read_error = false;
let data = &mut entry.data[offset as usize..];
if read_dma_memory(&mem_space, GuestAddress(dma.address), data, len as u64)
.is_err()
{
dma_read_error = true;
}
if dma_read_error || !entry.allow_write || len != dma.length {
dma.control |= FW_CFG_DMA_CTL_ERROR;
} else if true {
if let Some(cb) = &entry.write_cb {
cb.lock().unwrap().write_callback(
data.to_vec(),
offset as u64,
len as usize,
);
}
}
}
offset += len;
}
dma.length -= len;
dma.address += len as u64
}
self.cur_offset = offset;
write_dma_result(&self.mem_space, dma_addr, dma.control)?;
Ok(())
}
/// Write DMA mem register
///
/// # Arguments
///
/// * `addr` - The address to write to
/// * `value` - Value to write
/// * `size` - Length of raw bytes to write
///
/// # Errors
///
/// Return Error if fail to add the file entry.
fn dma_mem_write(&mut self, addr: u64, value: u64, size: u32) -> Result<()> {
if size == 4 {
if addr == 0 {
self.dma_addr = GuestAddress(value << 32);
} else if addr == 4 {
self.dma_addr = GuestAddress(self.dma_addr.raw_value() | value);
self.handle_dma_request()?;
}
} else if size == 8 && addr == 0 {
self.dma_addr = GuestAddress(value);
self.handle_dma_request()?;
} else {
bail!(
"Failed to set DMA address, offset is 0x{:x}, size is 0x{:x}",
addr,
size
);
}
Ok(())
}
/// Read DMA mem register
///
/// # Arguments
///
/// * `addr` - The address to read to
/// * `size` - Length of raw bytes to read
///
/// # Return
///
/// Return the value of the register
fn dma_mem_read(&self, addr: u64, size: u32) -> Result<u64> {
extract_u64(
FW_CFG_DMA_SIGNATURE as u64,
((8 - addr - size as u64) * 8) as u32,
size * 8,
)
.with_context(|| "Failed to extract bits from u64")
}
/// Read data register
///
/// # Arguments
///
/// * `_addr` - The address to read to
/// * `size` - Length of raw bytes to read
///
/// # Return
///
/// Return the value of the register
fn read_data_reg(&mut self, _addr: u64, mut size: u32) -> Result<u64> {
if size == 0 || size > std::mem::size_of::<u64>() as u32 {
bail!(
"Failed to read from FWcfg data register, size {} overflows",
size
);
}
let cur_entry = self.cur_entry;
let mut cur_offset = self.cur_offset;
let entry = self.get_entry_mut()?;
let mut value: u64 = 0;
if cur_entry != FW_CFG_INVALID
&& !entry.data.is_empty()
&& cur_offset < entry.data.len() as u32
{
loop {
value = (value << 8) | entry.data[cur_offset as usize] as u64;
cur_offset += 1;
size -= 1;
if size == 0 || cur_offset >= entry.data.len() as u32 {
break;
}
}
value <<= 8 * size as u64;
}
self.cur_offset = cur_offset;
Ok(value)
}
fn common_realize(&mut self) -> Result<()> {
// Firmware configurations add Signature item
let sig = &[b'Q', b'E', b'M', b'U'];
self.add_entry(FwCfgEntryType::Signature, None, None, sig.to_vec(), false)?;
self.add_entry(
FwCfgEntryType::NoGraphic,
None,
None,
(0_u16).as_bytes().to_vec(),
false,
)?;
self.add_entry(
FwCfgEntryType::BootMenu,
None,
None,
(0_u16).as_bytes().to_vec(),
false,
)?;
// Add FileDir item
self.add_entry(FwCfgEntryType::FileDir, None, None, Vec::new(), false)?;
// Add boot-fail-wait file item, default to 5s
self.add_file_callback(
"etc/boot-fail-wait",
(5_u32).as_bytes().to_vec(),
None,
None,
false,
)?;
// Firmware version
let mut version = FW_CFG_VERSION;
if self.dma_enabled {
version |= FW_CFG_VERSION_DMA;
}
self.add_entry(
FwCfgEntryType::Id,
None,
None,
version.as_bytes().to_vec(),
false,
)?;
Ok(())
}
}
fn get_io_count(data_len: usize) -> usize {
if data_len % 8 == 0 {
8
} else if data_len % 4 == 0 {
4
} else if data_len % 2 == 0 {
2
} else {
1
}
}
fn common_read(
#[cfg(target_arch = "aarch64")] fwcfg_arch: &mut FwCfgMem,
#[cfg(target_arch = "x86_64")] fwcfg_arch: &mut FwCfgIO,
data: &mut [u8],
base: GuestAddress,
offset: u64,
) -> bool {
let data_len = data.len();
let io_count = get_io_count(data_len);
for i in (0..data_len).step_by(io_count) {
if !read_bytes(fwcfg_arch, &mut data[i..i + io_count], base, offset) {
return false;
}
}
true
}
/// FwCfg MMIO Device use for AArch64 platform
#[cfg(target_arch = "aarch64")]
pub struct FwCfgMem {
base: SysBusDevBase,
fwcfg: FwCfgCommon,
}
#[cfg(target_arch = "aarch64")]
impl FwCfgMem {
pub fn new(sys_mem: Arc<AddressSpace>) -> Self {
FwCfgMem {
base: SysBusDevBase::new(SysBusDevType::FwCfg),
fwcfg: FwCfgCommon::new(sys_mem),
}
}
pub fn realize(
mut self,
sysbus: &mut SysBus,
region_base: u64,
region_size: u64,
) -> Result<Arc<Mutex<Self>>> {
self.fwcfg.common_realize()?;
self.set_sys_resource(sysbus, region_base, region_size)
.with_context(|| "Failed to allocate system resource for FwCfg.")?;
let dev = Arc::new(Mutex::new(self));
sysbus
.attach_device(&dev, region_base, region_size, "FwCfgMem")
.with_context(|| "Failed to attach FwCfg device to system bus.")?;
Ok(dev)
}
}
#[cfg(target_arch = "aarch64")]
fn read_bytes(
fwcfg_arch: &mut FwCfgMem,
data: &mut [u8],
_base: GuestAddress,
offset: u64,
) -> bool {
let value = match offset {
0..=7 => match fwcfg_arch.fwcfg.read_data_reg(offset, data.len() as u32) {
Ok(val) => val,
Err(e) => {
error!("Failed to read from FwCfg data register, error is {:?}", e);
return false;
}
},
8..=15 => {
error!("Read from FwCfg control register is not supported.");
0
}
16..=23 => {
if (offset + data.len() as u64) > 0x18 {
error!(
"Illegal parameter: the sum of addr 0x{:x} and size 0x{:x} overflow",
offset - 0x10,
data.len()
);
return false;
}
match fwcfg_arch
.fwcfg
.dma_mem_read(offset - 0x10, data.len() as u32)
{
Ok(val) => val,
Err(e) => {
error!("Failed to handle FwCfg DMA-read, error is {:?}", e);
return false;
}
}
}
_ => {
error!("Failed to read FwCfg, offset 0x{:x} is invalid", offset);
return false;
}
};
match data.len() {
1 => data[0] = value as u8,
2 => BigEndian::write_u16(data, value as u16),
4 => BigEndian::write_u32(data, value as u32),
8 => BigEndian::write_u64(data, value),
_ => {}
}
true
}
#[cfg(target_arch = "aarch64")]
impl FwCfgOps for FwCfgMem {
fn fw_cfg_common(&mut self) -> &mut FwCfgCommon {
&mut self.fwcfg
}
}
#[cfg(target_arch = "aarch64")]
impl Device for FwCfgMem {
fn device_base(&self) -> &DeviceBase {
&self.base.base
}
fn device_base_mut(&mut self) -> &mut DeviceBase {
&mut self.base.base
}
}
#[cfg(target_arch = "aarch64")]
impl SysBusDevOps for FwCfgMem {
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 {
common_read(self, data, base, offset)
}
fn write(&mut self, data: &[u8], _base: GuestAddress, offset: u64) -> bool {
let size = data.len() as u32;
let value = match size {
1 => data[0] as u64,
2 => BigEndian::read_u16(data) as u64,
4 => BigEndian::read_u32(data) as u64,
8 => BigEndian::read_u64(data),
_ => 0,
};
match offset {
0..=7 => {
error!("Write to FwCfg data register is not supported.");
}
8..=15 => {
// Write to FwCfg control register
self.fwcfg.select_entry(value as u16);
}
16..=23 => {
if self
.fwcfg
.dma_mem_write(offset - 0x10, value, size)
.is_err()
{
error!("Failed to write dma at offset=0x{:x}.", offset);
return false;
}
}
_ => {
error!("Failed to write FwCfg, offset 0x{:x} is invalid", offset);
return false;
}
}
true
}
fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> {
Some(&mut self.base.res)
}
fn set_sys_resource(
&mut self,
_sysbus: &mut SysBus,
region_base: u64,
region_size: u64,
) -> Result<()> {
let res = self.get_sys_resource_mut().unwrap();
res.region_base = region_base;
res.region_size = region_size;
Ok(())
}
fn reset(&mut self) -> Result<()> {
self.fwcfg.select_entry(FwCfgEntryType::Signature as u16);
Ok(())
}
}
#[allow(clippy::upper_case_acronyms)]
#[cfg(target_arch = "x86_64")]
pub struct FwCfgIO {
base: SysBusDevBase,
fwcfg: FwCfgCommon,
}
#[cfg(target_arch = "x86_64")]
impl FwCfgIO {
pub fn new(sys_mem: Arc<AddressSpace>) -> Self {
FwCfgIO {
base: SysBusDevBase {
base: DeviceBase::default(),
dev_type: SysBusDevType::FwCfg,
res: SysRes {
region_base: FW_CFG_IO_BASE,
region_size: FW_CFG_IO_SIZE,
irq: -1,
},
..Default::default()
},
fwcfg: FwCfgCommon::new(sys_mem),
}
}
pub fn realize(mut self, sysbus: &mut SysBus) -> Result<Arc<Mutex<Self>>> {
self.fwcfg.common_realize()?;
let region_base = self.base.res.region_base;
let region_size = self.base.res.region_size;
self.set_sys_resource(sysbus, region_base, region_size)
.with_context(|| "Failed to allocate system resource for FwCfg.")?;
let dev = Arc::new(Mutex::new(self));
sysbus
.attach_device(&dev, region_base, region_size, "FwCfgIO")
.with_context(|| "Failed to attach FwCfg device to system bus.")?;
Ok(dev)
}
}
#[cfg(target_arch = "x86_64")]
fn read_bytes(fwcfg_arch: &mut FwCfgIO, data: &mut [u8], base: GuestAddress, offset: u64) -> bool {
let value: u64 = match offset {
0..=1 => match fwcfg_arch.fwcfg.read_data_reg(offset, data.len() as u32) {
Err(e) => {
error!("Failed to read from FwCfg data register, error is {:?}", e);
return false;
}
Ok(val) => val,
},
4..=11 => {
if (offset + data.len() as u64) > 0x14 {
error!(
"Illegal parameter: the sum of addr 0x{:x} and size 0x{:x} overflow",
offset - 0x10,
data.len()
);
return false;
}
match fwcfg_arch.fwcfg.dma_mem_read(offset - 4, data.len() as u32) {
Err(e) => {
error!("Failed to handle FwCfg DMA-read, error is {:?}", e);
return false;
}
Ok(val) => val,
}
}
_ => {
// This should never happen
error!(
"Failed to read FwCfg, ioport 0x{:x} is invalid",
base.0 + offset
);
return false;
}
};
match data.len() {
1 => data[0] = value as u8,
2 => BigEndian::write_u16(data, value as u16),
4 => BigEndian::write_u32(data, value as u32),
8 => BigEndian::write_u64(data, value),
_ => {
warn!(
"Failed to read from FwCfg data register, data length {} is invalid",
data.len()
);
return false;
}
}
true
}
#[cfg(target_arch = "x86_64")]
impl FwCfgOps for FwCfgIO {
fn fw_cfg_common(&mut self) -> &mut FwCfgCommon {
&mut self.fwcfg
}
}
#[cfg(target_arch = "x86_64")]
impl Device for FwCfgIO {
fn device_base(&self) -> &DeviceBase {
&self.base.base
}
fn device_base_mut(&mut self) -> &mut DeviceBase {
&mut self.base.base
}
}
#[cfg(target_arch = "x86_64")]
impl SysBusDevOps for FwCfgIO {
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 {
common_read(self, data, base, offset)
}
fn write(&mut self, data: &[u8], base: GuestAddress, offset: u64) -> bool {
let size = data.len() as u32;
match offset {
0..=1 => {
if size != 2 {
error!(
"Failed to write FwCfg control register, data length {} is invalid",
data.len()
);
return false;
}
self.fwcfg.select_entry(LittleEndian::read_u16(data));
}
4..=11 => {
let value = match size {
1 => data[0] as u64,
2 => BigEndian::read_u16(data) as u64,
4 => BigEndian::read_u32(data) as u64,
8 => BigEndian::read_u64(data),
_ => 0,
};
if let Err(e) = self.fwcfg.dma_mem_write(offset - 4, value, size) {
error!("Failed to handle FwCfg DMA-write, error is {:?}", e);
return false;
}
}
_ => {
// This should never happen
error!(
"Failed to write FwCfg, ioport 0x{:x} is invalid",
base.0 + offset
);
return false;
}
}
true
}
fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> {
Some(&mut self.base.res)
}
fn set_sys_resource(
&mut self,
_sysbus: &mut SysBus,
region_base: u64,
region_size: u64,
) -> Result<()> {
let res = self.get_sys_resource_mut().unwrap();
res.region_base = region_base;
res.region_size = region_size;
Ok(())
}
fn reset(&mut self) -> Result<()> {
self.fwcfg.select_entry(FwCfgEntryType::Signature as u16);
Ok(())
}
}
pub trait FwCfgOps: Send + Sync {
fn fw_cfg_common(&mut self) -> &mut FwCfgCommon;
/// Add an entry to FwCfg device, with Vector content.
///
/// # Arguments
///
/// * `key` - FwCfgEntryType
/// * `data` - Raw data bytes of the entry to be added
fn add_data_entry(&mut self, key: FwCfgEntryType, data: Vec<u8>) -> Result<()> {
self.fw_cfg_common().add_entry(key, None, None, data, false)
}
/// Add an entry to FwCfg device, with String content.
///
/// # Arguments
///
/// * `key` - FwCfgEntryType
/// * `value` - string data entry to be added
fn add_string_entry(&mut self, key: FwCfgEntryType, value: &str) -> Result<()> {
let mut bytes = value.as_bytes().to_vec();
bytes.push(0_u8);
self.fw_cfg_common()
.add_entry(key, None, None, bytes, false)
}
/// Add a file entry to FwCfg device, with select callback function and
/// write callback function.
///
/// # Arguments
///
/// * `filename` - Name of the file
/// * `data` - Raw data bytes of the file to be added
/// * `select_cb` - Select callback
/// * `write_cb` - Write callback
/// * `allow_write` - Does the file allow write
fn add_file_callback_entry(
&mut self,
filename: &str,
data: Vec<u8>,
select_cb: Option<FwCfgCallbackType>,
write_cb: Option<FwCfgWriteCallbackType>,
allow_write: bool,
) -> Result<()> {
self.fw_cfg_common()
.add_file_callback(filename, data, select_cb, write_cb, allow_write)
}
/// Add a file entry to FwCfg device, without callbacks, write-allow.
///
/// # Arguments
///
/// * `filename` - Name of the file
/// * `data` - Raw data bytes of the file to be added
fn add_file_entry(&mut self, filename: &str, data: Vec<u8>) -> Result<()> {
self.fw_cfg_common()
.add_file_callback(filename, data, None, None, true)
}
/// Modify a file entry to FwCfg device, without callbacks, write-allow.
///
/// # Arguments
///
/// * `filename` - Name of the file
/// * `data` - Raw data bytes of the file to be modified
fn modify_file_entry(&mut self, filename: &str, data: Vec<u8>) -> Result<()> {
self.fw_cfg_common()
.modify_file_callback(filename, data, None, None, true)
}
}
#[cfg(target_arch = "aarch64")]
impl AmlBuilder for FwCfgMem {
fn aml_bytes(&self) -> Vec<u8> {
let mut acpi_dev = AmlDevice::new("FWCF");
acpi_dev.append_child(AmlNameDecl::new("_HID", AmlString("QEMU0002".to_string())));
acpi_dev.append_child(AmlNameDecl::new("_STA", AmlInteger(0xB)));
acpi_dev.append_child(AmlNameDecl::new("_CCA", AmlInteger(0x1)));
let mut res = AmlResTemplate::new();
res.append_child(AmlMemory32Fixed::new(
AmlReadAndWrite::ReadWrite,
self.base.res.region_base as u32,
self.base.res.region_size as u32,
));
acpi_dev.append_child(AmlNameDecl::new("_CRS", res));
acpi_dev.aml_bytes()
}
}
#[cfg(target_arch = "x86_64")]
impl AmlBuilder for FwCfgIO {
fn aml_bytes(&self) -> Vec<u8> {
let mut acpi_dev = AmlDevice::new("FWCF");
acpi_dev.append_child(AmlNameDecl::new("_HID", AmlString("QEMU0002".to_string())));
acpi_dev.append_child(AmlNameDecl::new("_STA", AmlInteger(0xB)));
let mut res = AmlResTemplate::new();
res.append_child(AmlIoResource::new(
AmlIoDecode::Decode16,
self.base.res.region_base as u16,
self.base.res.region_base as u16,
0x01,
self.base.res.region_size as u8,
));
acpi_dev.append_child(AmlNameDecl::new("_CRS", res));
acpi_dev.aml_bytes()
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::sysbus::{IRQ_BASE, IRQ_MAX};
use address_space::{AddressSpace, HostMemMapping, Region};
fn sysbus_init() -> SysBus {
let sys_mem = AddressSpace::new(
Region::init_container_region(u64::max_value(), "sys_mem"),
"sys_mem",
None,
)
.unwrap();
#[cfg(target_arch = "x86_64")]
let sys_io = AddressSpace::new(
Region::init_container_region(1 << 16, "sys_io"),
"sys_io",
None,
)
.unwrap();
let free_irqs: (i32, i32) = (IRQ_BASE, IRQ_MAX);
let mmio_region: (u64, u64) = (0x0A00_0000, 0x1000_0000);
SysBus::new(
#[cfg(target_arch = "x86_64")]
&sys_io,
&sys_mem,
free_irqs,
mmio_region,
)
}
fn address_space_init() -> Arc<AddressSpace> {
let root = Region::init_container_region(1 << 36, "root");
let sys_space = AddressSpace::new(root, "sys_space", None).unwrap();
let host_mmap = Arc::new(
HostMemMapping::new(
GuestAddress(0),
None,
0x1000_0000,
None,
false,
false,
false,
)
.unwrap(),
);
sys_space
.root()
.add_subregion(
Region::init_ram_region(host_mmap.clone(), "region_1"),
host_mmap.start_address().raw_value(),
)
.unwrap();
sys_space
}
#[test]
fn test_entry_functions() {
let sys_mem = address_space_init();
let mut fwcfg_common = FwCfgCommon::new(sys_mem);
let ncpus: usize = 1;
fwcfg_common
.add_entry(
FwCfgEntryType::NbCpus,
None,
None,
ncpus.as_bytes().to_vec(),
false,
)
.unwrap();
assert_eq!(
fwcfg_common.entries[FwCfgEntryType::NbCpus as usize].data,
ncpus.as_bytes().to_vec()
);
let cmdline =
"console=ttyAMA0 reboot=t panic=1 tsc=reliable ipv6.disable=1 root=/dev/vda rw"
.to_string();
fwcfg_common
.add_entry(
FwCfgEntryType::CmdlineSize,
None,
None,
(cmdline.len() + 1).as_bytes().to_vec(),
false,
)
.unwrap();
assert_eq!(
fwcfg_common.entries[FwCfgEntryType::CmdlineSize as usize].data,
(cmdline.len() + 1).as_bytes().to_vec()
);
fwcfg_common
.add_entry(
FwCfgEntryType::CmdlineData,
None,
None,
cmdline.as_bytes().to_vec(),
false,
)
.unwrap();
assert_eq!(
fwcfg_common.entries[FwCfgEntryType::CmdlineData as usize].data,
cmdline.as_bytes().to_vec()
);
let boot_order = Vec::<u8>::new();
fwcfg_common
.add_entry(FwCfgEntryType::FileDir, None, None, boot_order, false)
.unwrap();
assert_eq!(
fwcfg_common.entries[FwCfgEntryType::FileDir as usize].data,
Vec::<u8>::new()
);
}
#[test]
fn test_file_entry() {
let sys_mem = address_space_init();
let mut fwcfg_common = FwCfgCommon::new(sys_mem);
assert_eq!(fwcfg_common.common_realize().is_ok(), true);
let file_data = vec![0xcc; 200];
assert_eq!(
fwcfg_common
.add_file_callback("xyz", file_data.clone(), None, None, false)
.is_ok(),
true
);
let id = fwcfg_common.files.last().unwrap().select;
fwcfg_common.select_entry(id);
let entry = fwcfg_common.get_entry_mut().unwrap();
assert_eq!(entry.data, file_data);
let file_data = vec![0x8b; 200];
assert_eq!(
fwcfg_common
.add_file_callback("def", file_data.clone(), None, None, false)
.is_ok(),
true
);
let id = fwcfg_common.files[0].select;
fwcfg_common.select_entry(id);
let entry = fwcfg_common.get_entry_mut().unwrap();
assert_eq!(entry.data, file_data);
let file_data = Vec::new();
assert_eq!(
fwcfg_common
.add_file_callback("bootorder", file_data.clone(), None, None, false)
.is_ok(),
true
);
let id = fwcfg_common.files[0].select;
fwcfg_common.select_entry(id);
let entry = fwcfg_common.get_entry_mut().unwrap();
assert_eq!(entry.data, file_data);
let modify_file_data = "/pci@ffffffffffffffff/pci-bridge@3/scsi@0,1/disk@0,0"
.as_bytes()
.to_vec();
assert_eq!(
fwcfg_common
.modify_file_callback("bootorder", modify_file_data.clone(), None, None, true)
.is_ok(),
true
);
let id = fwcfg_common.files[0].select;
fwcfg_common.select_entry(id);
let entry = fwcfg_common.get_entry_mut().unwrap();
assert_eq!(entry.data, modify_file_data);
assert_eq!(
fwcfg_common
.modify_file_callback("abc", modify_file_data.clone(), None, None, true)
.is_err(),
true
);
let file_data = vec![0x33; 500];
assert_eq!(
fwcfg_common
.add_file_callback("abc", file_data.clone(), None, None, false)
.is_ok(),
true
);
let id = fwcfg_common.files[0].select;
fwcfg_common.select_entry(id);
let entry = fwcfg_common.get_entry_mut().unwrap();
assert_eq!(entry.data, file_data);
}
#[test]
fn test_dma_functions() {
let sys_mem = address_space_init();
let mut fwcfg_common = FwCfgCommon::new(sys_mem);
assert_eq!(fwcfg_common.common_realize().is_ok(), true);
// [1]write dma request.
let mut dma_req = FwCfgDmaAccess::default();
dma_req.length = *u32::from_bytes(&4_u32.to_be_bytes()).unwrap();
dma_req.address = *u64::from_bytes(&0xffff_u64.to_be_bytes()).unwrap();
dma_req.control = *u32::from_bytes(&FW_CFG_DMA_CTL_READ.to_be_bytes()).unwrap();
let dma_request = dma_req.as_mut_bytes();
let addr = GuestAddress(0x0000);
fwcfg_common
.mem_space
.write(&mut dma_request.as_ref(), addr, dma_request.len() as u64)
.unwrap();
// [2]set dma addr.
fwcfg_common.dma_addr = addr;
// [3]handle dma request.
assert_eq!(fwcfg_common.handle_dma_request().is_ok(), true);
// [4]check dma response.
assert_eq!(fwcfg_common.mem_space.read_object::<u32>(addr).unwrap(), 0);
// [5]check dma write result.
let mut read_dma_buf = Vec::new();
let sig_entry_data = [b'Q', b'E', b'M', b'U'];
let len = sig_entry_data.len();
fwcfg_common
.mem_space
.read(&mut read_dma_buf, GuestAddress(0xffff), len as u64)
.unwrap();
assert_eq!(read_dma_buf, sig_entry_data);
// Read uninitialized entry.
let mut dma_req = FwCfgDmaAccess::default();
dma_req.length = *u32::from_bytes(&8_u32.to_be_bytes()).unwrap();
dma_req.address = *u64::from_bytes(&0xffff_u64.to_be_bytes()).unwrap();
dma_req.control = *u32::from_bytes(&FW_CFG_DMA_CTL_READ.to_be_bytes()).unwrap();
let dma_request = dma_req.as_mut_bytes();
let addr = GuestAddress(0x0000);
fwcfg_common
.mem_space
.write(&mut dma_request.as_ref(), addr, dma_request.len() as u64)
.unwrap();
fwcfg_common.dma_addr = addr;
assert_eq!(fwcfg_common.handle_dma_request().is_ok(), true);
// Result should be all zero.
assert_eq!(fwcfg_common.mem_space.read_object::<u32>(addr).unwrap(), 0);
let mut read_dma_buf = Vec::new();
let all_zero = vec![0x0_u8; 4];
let len = all_zero.len();
fwcfg_common
.mem_space
.read(&mut read_dma_buf, GuestAddress(0xffff), len as u64)
.unwrap();
assert_eq!(read_dma_buf, all_zero);
}
#[test]
#[cfg(target_arch = "aarch64")]
fn test_read_write_aarch64() {
let mut sys_bus = sysbus_init();
let sys_mem = address_space_init();
let fwcfg = FwCfgMem::new(sys_mem);
let fwcfg_dev = FwCfgMem::realize(fwcfg, &mut sys_bus, 0x0902_0000, 0x0000_0018).unwrap();
// Read FW_CFG_DMA_SIGNATURE entry.
let base = GuestAddress(0x0000);
let mut read_data = vec![0xff_u8, 0xff, 0xff, 0xff];
let offset = 0x10;
let target_data = vec![0x51_u8, 0x45, 0x4d, 0x55];
fwcfg_dev.lock().unwrap().read(&mut read_data, base, offset);
assert_eq!(read_data, target_data);
// Select entry and read it.
let write_data = vec![0x0_u8];
let offset = 0x8;
let f_back = fwcfg_dev.lock().unwrap().write(&write_data, base, offset);
assert_eq!(f_back, true);
let mut read_data = vec![0xff_u8, 0xff, 0xff, 0xff];
let offset = 0x4;
let sig_entry_data = [b'Q', b'E', b'M', b'U'];
fwcfg_dev.lock().unwrap().read(&mut read_data, base, offset);
assert_eq!(read_data, sig_entry_data);
// Failed to write because of offset overflow.
let write_data = vec![0x0_u8];
let offset = 0x18;
let f_back = fwcfg_dev.lock().unwrap().write(&write_data, base, offset);
assert_eq!(f_back, false);
// Illegal write_data length.
let write_data = vec![0x0_u8];
let offset = 0x10;
let f_back = fwcfg_dev.lock().unwrap().write(&write_data, base, offset);
assert_eq!(f_back, false);
}
#[test]
#[cfg(target_arch = "x86_64")]
fn test_read_write_x86_64() {
let mut sys_bus = sysbus_init();
let sys_mem = address_space_init();
let fwcfg = FwCfgIO::new(sys_mem);
let fwcfg_dev = FwCfgIO::realize(fwcfg, &mut sys_bus).unwrap();
// Read FW_CFG_DMA_SIGNATURE entry.
let base = GuestAddress(0x0000);
let mut read_data = vec![0xff_u8, 0xff, 0xff, 0xff];
let offset = 0x4;
let target_data = vec![0x51_u8, 0x45, 0x4d, 0x55];
fwcfg_dev.lock().unwrap().read(&mut read_data, base, offset);
assert_eq!(read_data, target_data);
// Select entry and read it.
let write_data = vec![0x0_u8, 0x0];
let offset = 0x0;
let f_back = fwcfg_dev.lock().unwrap().write(&write_data, base, offset);
assert_eq!(f_back, true);
let mut read_data = vec![0xff_u8, 0xff, 0xff, 0xff];
let offset = 0x0;
let sig_entry_data = [b'Q', b'E', b'M', b'U'];
fwcfg_dev.lock().unwrap().read(&mut read_data, base, offset);
assert_eq!(read_data, sig_entry_data);
// Failed to write because of offset overflow.
let write_data = vec![0x0_u8];
let offset = 0x0c;
let f_back = fwcfg_dev.lock().unwrap().write(&write_data, base, offset);
assert_eq!(f_back, false);
// Illegal write_data length.
let write_data = vec![0x0_u8];
let offset = 0x0;
let f_back = fwcfg_dev.lock().unwrap().write(&write_data, base, offset);
assert_eq!(f_back, false);
}
}

Опубликовать ( 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