Skip to content

Commit

Permalink
td-shim: remove the use of Vec in e820
Browse files Browse the repository at this point in the history
Reducing the use of heap can improve the functional safety. For e820
implementation, use an fixed `MAX_E820_ENTRY` size array to replace the
vector.

Signed-off-by: Jiaqi Gao <jiaqi.gao@intel.com>
  • Loading branch information
gaojiaqi7 authored and jyao1 committed May 27, 2024
1 parent 2c5c43c commit 65cc7b0
Showing 1 changed file with 56 additions and 28 deletions.
84 changes: 56 additions & 28 deletions td-shim/src/bin/td-shim/e820.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,30 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent

use core::ptr::slice_from_raw_parts;

use alloc::vec::Vec;
use td_shim::e820::{E820Entry, E820Type};

// Linux BootParam supports 128 e820 entries, so...
const MAX_E820_ENTRY: usize = 128;

#[derive(Debug)]
pub struct E820Table {
entries: Vec<E820Entry>,
entries: [E820Entry; MAX_E820_ENTRY],
num_entries: usize,
}

#[derive(Debug)]
pub enum E820Error {
RangeAlreadyExists,
RangeNotExists,
TooManyEntries,
InvalidIndex,
}

impl Default for E820Table {
fn default() -> Self {
Self {
entries: Vec::new(),
entries: [E820Entry::default(); MAX_E820_ENTRY],
num_entries: 0,
}
}
}
Expand All @@ -39,7 +40,7 @@ impl E820Table {
unsafe {
&*slice_from_raw_parts(
self.entries.as_ptr() as *const u8,
core::mem::size_of::<E820Entry>() * self.entries.len(),
core::mem::size_of::<E820Entry>() * self.num_entries,
)
}
}
Expand All @@ -51,8 +52,8 @@ impl E820Table {
start: u64,
length: u64,
) -> Result<(), E820Error> {
let mut pos = self.entries.len();
for (i, e) in self.entries.iter().enumerate() {
let mut pos = self.num_entries;
for (i, e) in self.entries[..self.num_entries].iter().enumerate() {
if start >= e.addr && start < e.addr + e.size {
return Err(E820Error::RangeAlreadyExists);
}
Expand All @@ -61,11 +62,10 @@ impl E820Table {
break;
}
}
if self.entries.len() == MAX_E820_ENTRY && !self.able_to_merge(pos, r#type, start, length) {
if self.num_entries == MAX_E820_ENTRY && !self.able_to_merge(pos, r#type, start, length) {
return Err(E820Error::TooManyEntries);
}
self.entries
.insert(pos, E820Entry::new(start, length, r#type));
self.insert_entry(pos, E820Entry::new(start, length, r#type));
self.merge();
Ok(())
}
Expand All @@ -77,10 +77,9 @@ impl E820Table {
start: u64,
length: u64,
) -> Result<(), E820Error> {
let entry_num = self.entries.len();
let mut idx = 0;
loop {
if idx == entry_num {
if idx == self.num_entries {
break;
}
let entry_end = self.entries[idx].addr + self.entries[idx].size;
Expand All @@ -101,37 +100,34 @@ impl E820Table {
// if the entry num of e820 table has reached the maximum, and
// the new entry cannot be merged with an exits one, then return
// an error.
if entry_num == MAX_E820_ENTRY
if self.num_entries == MAX_E820_ENTRY
&& !self.able_to_merge(idx, r#type, start, length)
{
return Err(E820Error::TooManyEntries);
}
self.entries[idx].size -= length;
self.entries[idx].addr = start + length;
self.entries
.insert(idx, E820Entry::new(start, length, r#type))
self.insert_entry(idx, E820Entry::new(start, length, r#type))?;
} else if self.entries[idx].addr + self.entries[idx].size == start + length {
// check if the new entry can be merged with the right one
if entry_num == MAX_E820_ENTRY
if self.num_entries == MAX_E820_ENTRY
&& !self.able_to_merge(idx, r#type, start, length)
{
return Err(E820Error::TooManyEntries);
}
self.entries[idx].size -= length;
self.entries
.insert(idx + 1, E820Entry::new(start, length, r#type))
self.insert_entry(idx + 1, E820Entry::new(start, length, r#type))?;
} else {
self.entries[idx].size = start - self.entries[idx].addr;
self.entries
.insert(idx + 1, E820Entry::new(start, length, r#type));
self.entries.insert(
self.insert_entry(idx + 1, E820Entry::new(start, length, r#type))?;
self.insert_entry(
idx + 2,
E820Entry::new(
start + length,
entry_end - (start + length),
self.entries[idx].r#type.into(),
),
);
)?;
}
self.merge();
return Ok(());
Expand All @@ -147,7 +143,7 @@ impl E820Table {
if (pos > 0
&& self.entries[pos - 1].r#type == r#type as u32
&& self.entries[pos - 1].addr + self.entries[pos - 1].size == start)
|| (pos + 1 < self.entries.len()
|| (pos + 1 < self.num_entries
&& self.entries[pos + 1].r#type == r#type as u32
&& self.entries[pos + 1].addr == start + length)
{
Expand All @@ -158,27 +154,58 @@ impl E820Table {
}

fn merge(&mut self) {
let mut entry_num = self.entries.len();
let mut idx = 0;
loop {
if idx == entry_num - 1 {
if idx == self.num_entries - 1 {
break;
}
let entry_end = self.entries[idx].addr + self.entries[idx].size;
if entry_end == self.entries[idx + 1].addr
&& self.entries[idx].r#type == self.entries[idx + 1].r#type
{
self.entries[idx].size += self.entries[idx + 1].size;
self.entries.remove(idx + 1);
entry_num -= 1;
self.remove_entry(idx + 1);
continue;
}
idx += 1;
}
}

fn insert_entry(&mut self, index: usize, entry: E820Entry) -> Result<(), E820Error> {
if self.num_entries >= MAX_E820_ENTRY {
return Err(E820Error::TooManyEntries);
}
if index > self.num_entries {
return Err(E820Error::InvalidIndex);
}

// Move all entries after the index back one position
for idx in (index..self.num_entries).rev() {
self.entries[idx + 1] = self.entries[idx];
}

self.entries[index] = entry;
self.num_entries += 1;
Ok(())
}

fn remove_entry(&mut self, index: usize) -> Result<(), E820Error> {
if index >= self.num_entries {
return Err(E820Error::InvalidIndex);
}

// Move all entries after the index forward one position
for idx in index..self.num_entries - 1 {
self.entries[idx] = self.entries[idx + 1];
}

self.entries[self.num_entries - 1] = E820Entry::default();
self.num_entries -= 1;
Ok(())
}

pub fn as_slice(&self) -> &[E820Entry] {
&self.entries
&self.entries[..self.num_entries]
}
}

Expand All @@ -191,6 +218,7 @@ mod tests {
let mut table = E820Table::new();
table.add_range(E820Type::Memory, 0x0, 0x1000).unwrap();
table.add_range(E820Type::Memory, 0x2000, 0x1000).unwrap();
std::println!("table: {:x?}", table);
assert_eq!(table.as_slice().len(), 2);
table.add_range(E820Type::Memory, 0x1000, 0x1000).unwrap();
assert_eq!(table.as_slice().len(), 1);
Expand Down

0 comments on commit 65cc7b0

Please sign in to comment.