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

OSCHINA-MIRROR/openeuler-stratovirt

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Это зеркальный репозиторий, синхронизируется ежедневно с исходного репозитория.
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
table_loader.rs 14 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
ace-yan Отправлено 3 лет назад 76f1d18
// 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 error_chain::bail;
use util::byte_code::ByteCode;
use crate::errors::{ErrorKind, Result, ResultExt};
use crate::AmlBuilder;
const TABLE_LOADER_FILE_NAME_SZ: usize = 56;
const TABLE_LOADER_ENTRY_SZ: usize = 124;
#[repr(u32)]
enum LoaderCmdType {
Allocate = 1_u32,
AddPointer,
AddCksum,
}
#[derive(Copy, Clone)]
#[repr(C, packed)]
struct AllocateEntry {
file: [u8; TABLE_LOADER_FILE_NAME_SZ],
align: u32,
zone: u8,
}
#[derive(Copy, Clone)]
#[repr(C, packed)]
struct AddPointerEntry {
dst_file: [u8; TABLE_LOADER_FILE_NAME_SZ],
src_file: [u8; TABLE_LOADER_FILE_NAME_SZ],
// The location where the pointer stored in dst file.
offset: u32,
// The size of pointer which stored in dst file.
size: u8,
}
#[derive(Copy, Clone)]
#[repr(C, packed)]
struct AddCksumEntry {
file: [u8; TABLE_LOADER_FILE_NAME_SZ],
// Offset that checksum locates in file.
offset: u32,
start: u32,
length: u32,
}
/// The union that stores the content of command.
#[derive(Copy, Clone)]
union EntryContent {
alloc: AllocateEntry,
add_pointer: AddPointerEntry,
add_cksum: AddCksumEntry,
padding: [u8; TABLE_LOADER_ENTRY_SZ],
}
impl Default for EntryContent {
fn default() -> Self {
Self {
padding: [0_u8; TABLE_LOADER_ENTRY_SZ],
}
}
}
impl ByteCode for EntryContent {}
/// Stores the command and corresponding content of entry.
/// - For `AllocateEntry`, Guest will alloc guest memory resource.
/// - For `AddPointerEntry`, Guest will update pointer at specified offset of dst file
/// by adding base address of source file.
/// - For `AddPointerEntry`, Guest will calculate u8-type checksum of a range in file
/// and store it at specified offset of the same file.
#[derive(Copy, Clone, Default)]
struct TableLoaderEntry {
/// The Type of command.
cmd: u32,
/// The content of command.
entry: EntryContent,
}
impl TableLoaderEntry {
fn new_allocate_entry(file: String, align: u32, zone: u8) -> TableLoaderEntry {
let mut file_bytes = [0_u8; TABLE_LOADER_FILE_NAME_SZ];
let name_bytes = file.as_bytes();
file_bytes[0..name_bytes.len()].copy_from_slice(name_bytes);
TableLoaderEntry {
cmd: LoaderCmdType::Allocate as u32,
entry: EntryContent {
alloc: AllocateEntry {
file: file_bytes,
align,
zone,
},
},
}
}
fn new_add_pointer_entry(
dst_file: String,
src_file: String,
offset: u32,
size: u8,
) -> TableLoaderEntry {
let mut dst_file_bytes = [0_u8; TABLE_LOADER_FILE_NAME_SZ];
let dst_name_bytes = dst_file.as_bytes();
dst_file_bytes[0..dst_name_bytes.len()].copy_from_slice(dst_name_bytes);
let mut src_file_bytes = [0_u8; TABLE_LOADER_FILE_NAME_SZ];
let src_name_bytes = src_file.as_bytes();
src_file_bytes[0..src_name_bytes.len()].copy_from_slice(src_name_bytes);
TableLoaderEntry {
cmd: LoaderCmdType::AddPointer as u32,
entry: EntryContent {
add_pointer: AddPointerEntry {
dst_file: dst_file_bytes,
src_file: src_file_bytes,
offset,
size,
},
},
}
}
fn new_add_cksum_entry(
file: String,
cksum_offset: u32,
start: u32,
length: u32,
) -> TableLoaderEntry {
let mut file_bytes = [0_u8; TABLE_LOADER_FILE_NAME_SZ];
let name_bytes = file.as_bytes();
file_bytes[0..name_bytes.len()].copy_from_slice(name_bytes);
TableLoaderEntry {
cmd: LoaderCmdType::AddCksum as u32,
entry: EntryContent {
add_cksum: AddCksumEntry {
file: file_bytes,
offset: cksum_offset,
start,
length,
},
},
}
}
}
impl AmlBuilder for TableLoaderEntry {
fn aml_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.extend(self.cmd.as_bytes());
bytes.extend(self.entry.as_bytes());
bytes
}
}
/// Represents file blob data and corresponding file name.
struct TableLoaderFileEntry {
/// File name.
file_name: String,
/// File blob data.
file_blob: Arc<Mutex<Vec<u8>>>,
}
/// Represents loader-entries that contents file and blob data of file.
#[derive(Default)]
pub struct TableLoader {
/// Command entries.
cmds: Vec<TableLoaderEntry>,
/// File entries.
files: Vec<TableLoaderFileEntry>,
}
impl TableLoader {
/// Construct function.
pub fn new() -> TableLoader {
TableLoader {
cmds: Vec::new(),
files: Vec::new(),
}
}
/// Get byte stream of all loader-entries.
pub fn cmd_entries(&self) -> Vec<u8> {
let mut bytes = Vec::new();
for entry in self.cmds.iter() {
bytes.extend(entry.aml_bytes());
}
bytes
}
/// Find matched file entry according to `file_name` argument.
///
/// # Arguments
///
/// * `file_name` - The name of file to find.
fn find_matched_file(&self, file_name: &str) -> Option<&TableLoaderFileEntry> {
for file_entry in &self.files {
if file_entry.file_name == file_name {
return Some(file_entry);
}
}
None
}
/// Add loader entry of type `Allocate`.
///
/// # Arguments
///
/// * `file` - File name.
/// * `file_blob` - File blob data.
/// * `align` - Required alignment of this blob.
/// * `is_fseg` - Represents range where Guest will allocate for this entry.
/// If true, Guest will allocate in FSEG zone.
pub fn add_alloc_entry(
&mut self,
file: &str,
file_blob: Arc<Mutex<Vec<u8>>>,
align: u32,
is_fseg: bool,
) -> Result<()> {
let file = file.to_string();
if align & (align - 1) != 0 {
return Err(ErrorKind::Alignment(align).into());
}
if self.find_matched_file(&file).is_some() {
return Err(ErrorKind::FileEntryExist(file).into());
}
self.files.push(TableLoaderFileEntry {
file_name: file.clone(),
file_blob,
});
let zone = if is_fseg { 0x2 } else { 0x1 };
self.cmds
.push(TableLoaderEntry::new_allocate_entry(file, align, zone));
Ok(())
}
/// Add loader entry of type `AddChecksum`.
///
/// # Arguments
///
/// * `file` - File name, must already stored in `files` field of `TableLoader`.
/// * `cksum_offset` - Offset that checksum locates in file blob.
/// * `start` - Start address of range.
/// * `length` - Length of range.
pub fn add_cksum_entry(
&mut self,
file: &str,
cksum_offset: u32,
start: u32,
length: u32,
) -> Result<()> {
let file = file.to_string();
let file_entry = self
.find_matched_file(&file)
.chain_err(|| ErrorKind::NoMatchedFile(file.clone()))?;
let file_entry_len = file_entry.file_blob.lock().unwrap().len();
if cksum_offset as usize + 1 > file_entry_len {
return Err(ErrorKind::AddrOverflow(cksum_offset, 1, file_entry_len).into());
}
if start as usize >= file_entry_len || (start + length) as usize > file_entry_len {
return Err(ErrorKind::AddrOverflow(start, length, file_entry_len).into());
}
if cksum_offset < start {
bail!("The offset of checksum should larger offset of start of range in file blob");
}
*file_entry
.file_blob
.lock()
.unwrap()
.get_mut(cksum_offset as usize)
.unwrap() = 0_u8;
self.cmds.push(TableLoaderEntry::new_add_cksum_entry(
file,
cksum_offset,
start,
length,
));
Ok(())
}
/// Add LoaderEntry of type `AddPointer`.
///
/// # Arguments
///
/// * `dst_file` - Dst file name where pointer is stored.
/// * `offset` - Offset where pointer locates in dst file.
/// * `size` - Size of pointer.
/// * `src_file` - Src file name where pointer points to.
/// * `src_offset` - Offset in src file where pointer points to.
pub fn add_pointer_entry(
&mut self,
dst_file: &str,
offset: u32,
size: u8,
src_file: &str,
src_offset: u32,
) -> Result<()> {
let dst_file = dst_file.to_string();
let src_file = src_file.to_string();
let dst_file_entry = self
.find_matched_file(&dst_file)
.chain_err(|| ErrorKind::NoMatchedFile(dst_file.clone()))?;
let src_file_entry = self
.find_matched_file(&src_file)
.chain_err(|| ErrorKind::NoMatchedFile(src_file.clone()))?;
let dst_file_len = dst_file_entry.file_blob.lock().unwrap().len();
let src_file_len = src_file_entry.file_blob.lock().unwrap().len();
if src_offset as usize >= src_file_len
|| (src_offset + u32::from(size)) as usize > src_file_len
{
return Err(ErrorKind::AddrOverflow(src_offset, u32::from(size), src_file_len).into());
}
if offset as usize >= dst_file_len || (offset + u32::from(size)) as usize > dst_file_len {
return Err(ErrorKind::AddrOverflow(offset, u32::from(size), dst_file_len).into());
}
if size != 1 && size != 2 && size != 4 && size != 8 {
return Err(ErrorKind::AddPointerLength(size).into());
}
dst_file_entry.file_blob.lock().unwrap()
[offset as usize..(offset as usize + size as usize)]
.copy_from_slice(&(src_offset as u64).as_bytes()[0..size as usize]);
self.cmds.push(TableLoaderEntry::new_add_pointer_entry(
dst_file, src_file, offset, size,
));
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_alloc_cmd() {
let mut table_loader = TableLoader::new();
let file_name = "etc/table-loader".to_string();
let file_blob = Arc::new(Mutex::new(Vec::new()));
assert!(table_loader
.add_alloc_entry(&file_name, file_blob.clone(), 4_u32, false)
.is_ok());
let file_bytes = file_name.as_bytes();
assert_eq!(
unsafe {
table_loader.cmds.get(0).unwrap().entry.alloc.file[0..file_bytes.len()].to_vec()
},
file_bytes.to_vec()
);
assert_eq!(
unsafe { table_loader.cmds.get(0).unwrap().entry.alloc.align },
4_u32
);
assert_eq!(
unsafe { table_loader.cmds.get(0).unwrap().entry.alloc.zone },
0x1
);
assert!(table_loader
.add_alloc_entry("etc/table-loader", file_blob, 4_u32, false)
.is_err());
}
#[test]
fn test_add_pointer_cmd() {
let mut table_loader = TableLoader::new();
let dst_file = "etc/rdsp".to_string();
let src_file = "etc/table-loader".to_string();
let dst_file_blob = Arc::new(Mutex::new(vec![0_u8; 19]));
let src_file_blob = Arc::new(Mutex::new(vec![0_u8; 5]));
table_loader
.add_alloc_entry(&src_file, src_file_blob, 4_u32, false)
.unwrap();
// Cannot find src file in file list, error occurs.
assert!(table_loader
.add_pointer_entry(&dst_file, 16, 4, &src_file, 0)
.is_err());
table_loader
.add_alloc_entry(&dst_file, dst_file_blob, 4_u32, false)
.unwrap();
// The offset exceeds file_blob's length, error occurs.
assert!(table_loader
.add_pointer_entry(&dst_file, 8, 8, &src_file, 0)
.is_err());
assert!(table_loader
.add_pointer_entry(&dst_file, 16, 2, &src_file, 0)
.is_ok());
// The length of pointer is illegal, expected 1/2/4/8.
assert!(table_loader
.add_pointer_entry(&dst_file, 16, 3, &src_file, 0)
.is_err());
}
#[test]
fn test_add_cksum_pointer() {
let mut table_loader = TableLoader::new();
let file = "etc/table-loader".to_string();
let file_len = 100_u32;
let file_blob = Arc::new(Mutex::new(vec![0_u8; file_len as usize]));
table_loader
.add_alloc_entry(&file, file_blob, 4_u32, false)
.unwrap();
assert!(table_loader.add_cksum_entry(&file, 100, 80, 100).is_err());
assert!(table_loader.add_cksum_entry(&file, 0_u32, 80, 20).is_err());
assert!(table_loader
.add_cksum_entry(&file, 0_u32, 0_u32, file_len + 1)
.is_err());
assert!(table_loader
.add_cksum_entry(&file, (file_len - 1) as u32, 80, 20)
.is_ok());
assert!(table_loader
.add_cksum_entry(&file, file_len - 1, 0, 50)
.is_ok());
}
}

Комментарий ( 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.2.0-rc2