Skip to content

Commit

Permalink
SVSM/fs/init: Populate RamFS from archive file
Browse files Browse the repository at this point in the history
Add code to parse the archive file and populate the RamFS. The archive
file format is still very simple and subject to change.

Signed-off-by: Joerg Roedel <jroedel@suse.de>
  • Loading branch information
joergroedel committed May 11, 2023
1 parent 1e187b9 commit 35a470c
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 1 deletion.
163 changes: 163 additions & 0 deletions src/fs/init.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2023 SUSE LLC
//
// Author: Joerg Roedel <jroedel@suse.de>

use crate::address::{Address, PhysAddr};
use crate::error::SvsmError;
use crate::mm::ptguards::PerCPUPageMappingGuard;

use super::*;

extern crate alloc;
use alloc::slice;
use alloc::string::String;
use alloc::vec::Vec;

const PACKIT_MAGIC: [u8; 4] = [0x50, 0x4b, 0x49, 0x54];

struct PackItHeader {
/// Header Magic (PKIT)
magic: [u8; 4],
/// Header Size
header_size: u32,
}

impl PackItHeader {
const fn new() -> Self {
PackItHeader {
magic: [0; 4],
header_size: 8,
}
}

fn load(buf: &[u8]) -> Result<Self, SvsmError> {
assert!(buf.len() >= 8);

let mut hdr = PackItHeader::new();
hdr.magic.copy_from_slice(&buf[0..4]);

// array indexes are static so the try_into() never fails
hdr.header_size = u32::from_le_bytes(buf[4..8].try_into().unwrap());

if hdr.magic != PACKIT_MAGIC {
log::error!("Unexpected header in FS archive");
return Err(SvsmError::FileSystem(FsError::inval()));
}

Ok(hdr)
}

fn len(&self) -> usize {
self.header_size as usize
}
}

struct FileHeader {
name_len: u16,
file_size: u64,
name: String,
}

impl FileHeader {
fn load(buf: &[u8]) -> Result<Self, SvsmError> {
assert!(buf.len() >= 12);

// array indexes are static so the try_into() never fails
let hdr_type = u16::from_le_bytes(buf[0..2].try_into().unwrap());
let name_len = u16::from_le_bytes(buf[2..4].try_into().unwrap());
let file_size = u64::from_le_bytes(buf[4..12].try_into().unwrap());

let header_len: usize = name_len as usize + 12;

if buf.len() < header_len {
log::error!("Unexpected end of archive");
return Err(SvsmError::FileSystem(FsError::inval()));
}

let Ok(name) = String::from_utf8(Vec::from(&buf[12..header_len])) else {
log::error!("Invalid filename in archive");
return Err(SvsmError::FileSystem(FsError::inval()));
};

if hdr_type != 1 || name_len == 0 {
log::error!("Invalid file header in archive");
return Err(SvsmError::FileSystem(FsError::inval()));
}

Ok(FileHeader {
name_len,
file_size,
name: name,
})
}

fn file_name(&self) -> &str {
self.name.as_str()
}

fn file_size(&self) -> usize {
let size: usize = self.file_size.try_into().unwrap();
size
}

fn header_size(&self) -> usize {
let len: usize = self.name_len.into();
12usize + len
}

fn total_size(&self) -> usize {
self.file_size() + self.header_size()
}
}

pub fn populate_ram_fs(kernel_fs_start: u64, kernel_fs_end: u64) -> Result<(), SvsmError> {
assert!(kernel_fs_end >= kernel_fs_start);

let pstart = PhysAddr::from(kernel_fs_start);
let pend = PhysAddr::from(kernel_fs_end);
let size = pend - pstart;

if size == 0 {
return Ok(());
}

log::info!("Unpacking FS archive...");

let guard = PerCPUPageMappingGuard::create(pstart.page_align(), pend.page_align_up(), 0)?;
let vstart = guard.virt_addr().offset(pstart.page_offset());

let data: &[u8] = unsafe { slice::from_raw_parts(vstart.as_ptr(), size) };
let hdr = PackItHeader::load(data)?;

let mut current = hdr.len();
while current < size {
let fh = FileHeader::load(&data[current..])?;

let start = current
.checked_add(fh.header_size())
.ok_or(SvsmError::FileSystem(FsError::inval()))?;
let end = start
.checked_add(fh.file_size())
.ok_or(SvsmError::FileSystem(FsError::inval()))?;

let file = create_all(fh.file_name())?;
let file_data = data
.get(start..end)
.ok_or(SvsmError::FileSystem(FsError::inval()))?;
file.truncate(0)?;
let written = file.write(&file_data)?;
if written != fh.file_size() {
log::error!("Incomplete data write to {}", fh.file_name());
return Err(SvsmError::FileSystem(FsError::inval()));
}

log::info!(" Unpacked {}", fh.file_name());
current += fh.total_size();
}

log::info!("Unpacking done");

Ok(())
}
2 changes: 2 additions & 0 deletions src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

mod api;
mod fs;
mod init;
mod ramfs;

pub use api::*;
pub use fs::*;
pub use init::populate_ram_fs;
5 changes: 4 additions & 1 deletion src/svsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use svsm::cpu::smp::start_secondary_cpus;
use svsm::debug::stacktrace::print_stack;
use svsm::elf;
use svsm::error::SvsmError;
use svsm::fs::initialize_fs;
use svsm::fs::{initialize_fs, populate_ram_fs};
use svsm::fw_cfg::FwCfg;
use svsm::kernel_launch::KernelLaunchInfo;
use svsm::mm::alloc::{memory_info, print_memory_info, root_mem_init};
Expand Down Expand Up @@ -414,6 +414,9 @@ pub extern "C" fn svsm_main() {

initialize_fs();

populate_ram_fs(LAUNCH_INFO.kernel_fs_start, LAUNCH_INFO.kernel_fs_end)
.expect("Failed to unpack FS archive");

let cpus = load_acpi_cpu_info(&fw_cfg).expect("Failed to load ACPI tables");
let mut nr_cpus = 0;

Expand Down

0 comments on commit 35a470c

Please sign in to comment.