Skip to content

Commit

Permalink
Merge branch 'utils/memory_region'
Browse files Browse the repository at this point in the history
  • Loading branch information
joergroedel committed Nov 20, 2023
2 parents 5fdabd7 + b6d1f2c commit d6b56b3
Show file tree
Hide file tree
Showing 14 changed files with 351 additions and 190 deletions.
8 changes: 6 additions & 2 deletions src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,18 @@ pub trait Address:
self.is_aligned(PAGE_SIZE)
}

fn checked_offset(&self, off: InnerAddr) -> Option<Self> {
fn checked_add(&self, off: InnerAddr) -> Option<Self> {
self.bits().checked_add(off).map(|addr| addr.into())
}

fn checked_sub(&self, off: InnerAddr) -> Option<Self> {
self.bits().checked_sub(off).map(|addr| addr.into())
}

fn saturating_add(&self, off: InnerAddr) -> Self {
Self::from(self.bits().saturating_add(off))
}

fn page_offset(&self) -> usize {
self.bits() & (PAGE_SIZE - 1)
}
Expand Down Expand Up @@ -258,7 +262,7 @@ impl ops::Add<InnerAddr> for VirtAddr {
}

impl Address for VirtAddr {
fn checked_offset(&self, off: InnerAddr) -> Option<Self> {
fn checked_add(&self, off: InnerAddr) -> Option<Self> {
self.bits()
.checked_add(off)
.map(|addr| sign_extend(addr).into())
Expand Down
2 changes: 1 addition & 1 deletion src/debug/stacktrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct StackBounds {
#[cfg(feature = "enable-stacktrace")]
impl StackBounds {
fn range_is_on_stack(&self, begin: VirtAddr, len: usize) -> bool {
match begin.checked_offset(len) {
match begin.checked_add(len) {
Some(end) => begin >= self.bottom && end <= self.top,
None => false,
}
Expand Down
60 changes: 25 additions & 35 deletions src/fw_cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

extern crate alloc;

use crate::address::{Address, PhysAddr};
use crate::error::SvsmError;
use crate::mm::pagetable::max_phys_addr;
use crate::utils::MemoryRegion;

use super::io::IOPort;
use super::string::FixedString;
Expand Down Expand Up @@ -67,20 +69,6 @@ impl FwCfgFile {
}
}

#[derive(Clone, Copy, Debug)]
pub struct MemoryRegion {
pub start: u64,
pub end: u64,
}

impl MemoryRegion {
/// Returns `true` if the region overlaps with another region with given
/// start and end.
pub fn overlaps(&self, start: u64, end: u64) -> bool {
self.start < end && start < self.end
}
}

impl<'a> FwCfg<'a> {
pub fn new(driver: &'a dyn IOPort) -> Self {
FwCfg { driver }
Expand Down Expand Up @@ -150,7 +138,7 @@ impl<'a> FwCfg<'a> {
Err(SvsmError::FwCfg(FwCfgError::FileNotFound))
}

fn find_svsm_region(&self) -> Result<MemoryRegion, SvsmError> {
fn find_svsm_region(&self) -> Result<MemoryRegion<PhysAddr>, SvsmError> {
let file = self.file_selector("etc/sev/svsm")?;

if file.size != 16 {
Expand All @@ -161,19 +149,19 @@ impl<'a> FwCfg<'a> {
Ok(self.read_memory_region())
}

fn read_memory_region(&self) -> MemoryRegion {
let start: u64 = self.read_le();
let size: u64 = self.read_le();
let end = start.saturating_add(size);
fn read_memory_region(&self) -> MemoryRegion<PhysAddr> {
let start = PhysAddr::from(self.read_le::<u64>());
let size = self.read_le::<u64>();
let end = start.saturating_add(size as usize);

assert!(start <= max_phys_addr(), "{start:#018x} is out of range");
assert!(end <= max_phys_addr(), "{end:#018x} is out of range");

MemoryRegion { start, end }
MemoryRegion::from_addresses(start, end)
}

pub fn get_memory_regions(&self) -> Result<Vec<MemoryRegion>, SvsmError> {
let mut regions: Vec<MemoryRegion> = Vec::new();
pub fn get_memory_regions(&self) -> Result<Vec<MemoryRegion<PhysAddr>>, SvsmError> {
let mut regions = Vec::new();
let file = self.file_selector("etc/e820")?;
let entries = file.size / 20;

Expand All @@ -191,33 +179,35 @@ impl<'a> FwCfg<'a> {
Ok(regions)
}

fn find_kernel_region_e820(&self) -> Result<MemoryRegion, SvsmError> {
fn find_kernel_region_e820(&self) -> Result<MemoryRegion<PhysAddr>, SvsmError> {
let regions = self.get_memory_regions()?;
let mut kernel_region = regions
let kernel_region = regions
.iter()
.max_by_key(|region| region.start)
.copied()
.max_by_key(|region| region.start())
.ok_or(SvsmError::FwCfg(FwCfgError::KernelRegion))?;

let start =
(kernel_region.end.saturating_sub(KERNEL_REGION_SIZE)) & KERNEL_REGION_SIZE_MASK;
let start = PhysAddr::from(
kernel_region
.end()
.bits()
.saturating_sub(KERNEL_REGION_SIZE as usize)
& KERNEL_REGION_SIZE_MASK as usize,
);

if start < kernel_region.start {
if start < kernel_region.start() {
return Err(SvsmError::FwCfg(FwCfgError::KernelRegion));
}

kernel_region.start = start;

Ok(kernel_region)
Ok(MemoryRegion::new(start, kernel_region.len()))
}

pub fn find_kernel_region(&self) -> Result<MemoryRegion, SvsmError> {
pub fn find_kernel_region(&self) -> Result<MemoryRegion<PhysAddr>, SvsmError> {
let kernel_region = self
.find_svsm_region()
.or_else(|_| self.find_kernel_region_e820())?;

// Make sure that the kernel region doesn't overlap with the loader.
if kernel_region.start < 640 * 1024 {
if kernel_region.start() < PhysAddr::from(640 * 1024u64) {
return Err(SvsmError::FwCfg(FwCfgError::KernelRegion));
}

Expand All @@ -227,7 +217,7 @@ impl<'a> FwCfg<'a> {
// This needs to be &mut self to prevent iterator invalidation, where the caller
// could do fw_cfg.select() while iterating. Having a mutable reference prevents
// other references.
pub fn iter_flash_regions(&mut self) -> impl Iterator<Item = MemoryRegion> + '_ {
pub fn iter_flash_regions(&mut self) -> impl Iterator<Item = MemoryRegion<PhysAddr>> + '_ {
let num = match self.file_selector("etc/flash") {
Ok(file) => {
self.select(file.selector);
Expand Down
80 changes: 28 additions & 52 deletions src/fw_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,59 +6,28 @@

extern crate alloc;

use crate::address::{Address, PhysAddr};
use crate::address::PhysAddr;
use crate::cpu::percpu::this_cpu_mut;
use crate::error::SvsmError;
use crate::kernel_launch::KernelLaunchInfo;
use crate::mm::PerCPUPageMappingGuard;
use crate::sev::ghcb::PageStateChangeOp;
use crate::sev::{pvalidate, rmp_adjust, PvalidateOp, RMPFlags};
use crate::types::{PageSize, PAGE_SIZE};
use crate::utils::{overlap, zero_mem_region};
use crate::utils::{zero_mem_region, MemoryRegion};
use alloc::vec::Vec;

use core::cmp;
use core::fmt;
use core::mem::{align_of, size_of, size_of_val};
use core::str::FromStr;

#[derive(Copy, Clone, Debug)]
pub struct SevPreValidMem {
base: PhysAddr,
length: usize,
}

impl SevPreValidMem {
fn new(base: PhysAddr, length: usize) -> Self {
Self { base, length }
}

fn new_4k(base: PhysAddr) -> Self {
Self::new(base, PAGE_SIZE)
}

#[inline]
fn end(&self) -> PhysAddr {
self.base + self.length
}

fn overlap(&self, other: &Self) -> bool {
overlap(self.base, self.end(), other.base, other.end())
}

fn merge(self, other: Self) -> Self {
let base = cmp::min(self.base, other.base);
let length = cmp::max(self.end(), other.end()) - base;
Self::new(base, length)
}
}

#[derive(Clone, Debug)]
pub struct SevFWMetaData {
pub reset_ip: Option<PhysAddr>,
pub cpuid_page: Option<PhysAddr>,
pub secrets_page: Option<PhysAddr>,
pub caa_page: Option<PhysAddr>,
pub valid_mem: Vec<SevPreValidMem>,
pub valid_mem: Vec<MemoryRegion<PhysAddr>>,
}

impl SevFWMetaData {
Expand All @@ -73,7 +42,7 @@ impl SevFWMetaData {
}

pub fn add_valid_mem(&mut self, base: PhysAddr, len: usize) {
self.valid_mem.push(SevPreValidMem::new(base, len));
self.valid_mem.push(MemoryRegion::new(base, len));
}
}

Expand Down Expand Up @@ -392,8 +361,8 @@ fn parse_sev_meta(
Ok(())
}

fn validate_fw_mem_region(region: SevPreValidMem) -> Result<(), SvsmError> {
let pstart = region.base;
fn validate_fw_mem_region(region: MemoryRegion<PhysAddr>) -> Result<(), SvsmError> {
let pstart = region.start();
let pend = region.end();

log::info!("Validating {:#018x}-{:#018x}", pstart, pend);
Expand All @@ -408,10 +377,7 @@ fn validate_fw_mem_region(region: SevPreValidMem) -> Result<(), SvsmError> {
)
.expect("GHCB PSC call failed to validate firmware memory");

for paddr in (pstart.bits()..pend.bits())
.step_by(PAGE_SIZE)
.map(PhysAddr::from)
{
for paddr in region.iter_pages(PageSize::Regular) {
let guard = PerCPUPageMappingGuard::create_4k(paddr)?;
let vaddr = guard.virt_addr();

Expand All @@ -430,17 +396,17 @@ fn validate_fw_mem_region(region: SevPreValidMem) -> Result<(), SvsmError> {
Ok(())
}

fn validate_fw_memory_vec(regions: Vec<SevPreValidMem>) -> Result<(), SvsmError> {
fn validate_fw_memory_vec(regions: Vec<MemoryRegion<PhysAddr>>) -> Result<(), SvsmError> {
if regions.is_empty() {
return Ok(());
}

let mut next_vec: Vec<SevPreValidMem> = Vec::new();
let mut next_vec = Vec::new();
let mut region = regions[0];

for next in regions.into_iter().skip(1) {
if region.overlap(&next) {
region = region.merge(next);
if region.contiguous(&next) {
region = region.merge(&next);
} else {
next_vec.push(next);
}
Expand All @@ -450,27 +416,37 @@ fn validate_fw_memory_vec(regions: Vec<SevPreValidMem>) -> Result<(), SvsmError>
validate_fw_memory_vec(next_vec)
}

pub fn validate_fw_memory(fw_meta: &SevFWMetaData) -> Result<(), SvsmError> {
pub fn validate_fw_memory(
fw_meta: &SevFWMetaData,
launch_info: &KernelLaunchInfo,
) -> Result<(), SvsmError> {
// Initalize vector with regions from the FW
let mut regions = fw_meta.valid_mem.clone();

// Add region for CPUID page if present
if let Some(cpuid_paddr) = fw_meta.cpuid_page {
regions.push(SevPreValidMem::new_4k(cpuid_paddr));
regions.push(MemoryRegion::new(cpuid_paddr, PAGE_SIZE));
}

// Add region for Secrets page if present
if let Some(secrets_paddr) = fw_meta.secrets_page {
regions.push(SevPreValidMem::new_4k(secrets_paddr));
regions.push(MemoryRegion::new(secrets_paddr, PAGE_SIZE));
}

// Add region for CAA page if present
if let Some(caa_paddr) = fw_meta.caa_page {
regions.push(SevPreValidMem::new_4k(caa_paddr));
regions.push(MemoryRegion::new(caa_paddr, PAGE_SIZE));
}

// Sort regions by base address
regions.sort_unstable_by(|a, b| a.base.cmp(&b.base));
regions.sort_unstable_by_key(|a| a.start());

let kernel_region = launch_info.kernel_region();
for region in regions.iter() {
if region.overlap(&kernel_region) {
panic!("FwMeta region ovelaps with kernel");
}
}

validate_fw_memory_vec(regions)
}
Expand Down Expand Up @@ -501,7 +477,7 @@ pub fn print_fw_meta(fw_meta: &SevFWMetaData) {
for region in &fw_meta.valid_mem {
log::info!(
" Pre-Validated Region {:#018x}-{:#018x}",
region.base,
region.start(),
region.end()
);
}
Expand Down
9 changes: 9 additions & 0 deletions src/kernel_launch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
//
// Author: Joerg Roedel <[email protected]>

use crate::address::PhysAddr;
use crate::utils::MemoryRegion;

#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct KernelLaunchInfo {
Expand All @@ -30,4 +33,10 @@ impl KernelLaunchInfo {
pub fn heap_area_virt_end(&self) -> u64 {
self.heap_area_virt_start + self.heap_area_size()
}

pub fn kernel_region(&self) -> MemoryRegion<PhysAddr> {
let start = PhysAddr::from(self.kernel_region_phys_start);
let end = PhysAddr::from(self.kernel_region_phys_end);
MemoryRegion::from_addresses(start, end)
}
}
Loading

0 comments on commit d6b56b3

Please sign in to comment.