From 387cc8bfeaf734144ea13926634e7922cf38cf33 Mon Sep 17 00:00:00 2001 From: Jiaqi Gao Date: Fri, 17 May 2024 04:35:20 -0400 Subject: [PATCH] td-shim: remove the use of `Vec` in `e820` 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 --- td-shim/src/bin/td-shim/e820.rs | 84 ++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 28 deletions(-) diff --git a/td-shim/src/bin/td-shim/e820.rs b/td-shim/src/bin/td-shim/e820.rs index 2c1b3792..09eb8286 100644 --- a/td-shim/src/bin/td-shim/e820.rs +++ b/td-shim/src/bin/td-shim/e820.rs @@ -3,8 +3,6 @@ // 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... @@ -12,7 +10,8 @@ const MAX_E820_ENTRY: usize = 128; #[derive(Debug)] pub struct E820Table { - entries: Vec, + entries: [E820Entry; MAX_E820_ENTRY], + num_entries: usize, } #[derive(Debug)] @@ -20,12 +19,14 @@ 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, } } } @@ -39,7 +40,7 @@ impl E820Table { unsafe { &*slice_from_raw_parts( self.entries.as_ptr() as *const u8, - core::mem::size_of::() * self.entries.len(), + core::mem::size_of::() * self.num_entries, ) } } @@ -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); } @@ -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(()) } @@ -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; @@ -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(()); @@ -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) { @@ -158,10 +154,9 @@ 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; @@ -169,16 +164,48 @@ impl E820Table { && 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] } } @@ -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);