Skip to content

Commit

Permalink
Add rust wrappers required by external dependencies
Browse files Browse the repository at this point in the history
The libcrt implements the libc interface required to build SVSM external
dependencies, but part of it is backed by SVSM core functions
implemented in Rust.

This patch adds wrappers for malloc(), calloc(), realloc(), free(),
abort() and serial_out(). The latter is not part of the libc standard, but
the libcrt uses it as a backend for printf.

The "-Wl,-u,malloc" is used in the Makefile to prevent the linker from
removing the wrapper.rs symbols.

Co-developed-by: Vikram Narayanan <vikram186@gmail.com>
Signed-off-by: Vikram Narayanan <vikram186@gmail.com>
Signed-off-by: Claudio Carvalho <cclaudio@linux.ibm.com>
  • Loading branch information
cclaudio committed Mar 29, 2023
1 parent 15c042f commit da5be60
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 4 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ memoffset = "0.6"
paste = "1.0"
memchr = { version = "2", default-features = false }
uuid = { version = "1", default-features = false }
cty = "0.2.2"

[dependencies.lazy_static]
version = "1.0"
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ doc: .prereq
svsm.bin: svsm.bin.elf
objcopy -g -O binary $< $@

# "-Wl,-u,malloc" prevents the linker from removing the wrapper.rs symbols
svsm.bin.elf: $(OBJS) src/start/svsm.lds
$(GCC) $(LD_FLAGS) -o $@ $(OBJS)
$(GCC) $(LD_FLAGS) -o $@ $(OBJS) -Wl,-u,malloc

%.a: src/*.rs src/cpu/*.rs src/mem/*.rs src/protocols/*.rs src/util/*.rs
@xargo build --features $(FEATURES)
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub mod svsm_request;
pub mod util;
/// Handle the list of VMSA pages
pub mod vmsa_list;
/// Wrappers for external dependencies
pub mod wrapper;

extern crate alloc;

Expand Down
73 changes: 72 additions & 1 deletion src/mem/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ use crate::globals::*;
use crate::mem::{pgtable_pa_to_va, pgtable_va_to_pa};
use crate::pgtable::*;
use crate::util::locking::SpinLock;
use crate::util::util::memset;
use crate::vc_terminate_svsm_enomem;
use crate::STATIC_ASSERT;

use core::alloc::{GlobalAlloc, Layout};
use core::mem::size_of;
use core::ptr;
use core::{cmp, ptr};
use x86_64::addr::{align_up, PhysAddr, VirtAddr};
use x86_64::structures::paging::frame::PhysFrame;

Expand Down Expand Up @@ -114,6 +116,10 @@ impl AllocatedInfo {
.unwrap();
AllocatedInfo { order: order }
}

pub fn get_order(&self) -> usize {
self.order
}
}

struct SlabPageInfo {
Expand Down Expand Up @@ -618,6 +624,49 @@ pub fn mem_allocate(size: usize) -> Result<VirtAddr, ()> {
unsafe { ALLOCATOR.slab_alloc(size) }
}

/// Allocate 'size' bytes and sets the memory to zero
pub fn mem_callocate(size: usize) -> Result<VirtAddr, ()> {
let result: Result<VirtAddr, ()> = mem_allocate(size);

if let Ok(va) = result {
memset(va.as_mut_ptr::<u8>(), 0, size);
return Ok(va);
}

Err(())
}

/// Change the size of memory pointed by va to size. If success it always
/// free the old va, however it returns Ok(new_va) if size > 0 or
/// Ok(VirtAddr::zero) if size == 0.
pub fn mem_reallocate(va: VirtAddr, size: usize) -> Result<VirtAddr, ()> {
if va.is_null() {
return mem_allocate(size);
}
if size == 0 {
mem_free(va);
return Ok(VirtAddr::zero());
}

let bytes: usize = sizeof_alloc(va)?;
let result: Result<VirtAddr, ()> = mem_allocate(size);
if let Ok(new_va) = result {
// Copy from start the minimum of the old and new sizes. If the
// new size is larger than the old size, the added memory will
// *not* be initialized.
unsafe {
ptr::copy_nonoverlapping(
va.as_ptr::<u8>(),
new_va.as_mut_ptr::<u8>(),
cmp::min(bytes, size),
)
};
mem_free(va);
}

result
}

pub fn mem_free_frames(frame: PhysFrame, _count: u64) {
let vaddr: VirtAddr = pgtable_pa_to_va(frame.start_address());
free_page(vaddr);
Expand Down Expand Up @@ -712,6 +761,10 @@ impl SlabPage {
self.free
}

pub fn get_item_size(&self) -> u16 {
self.item_size
}

pub fn get_next_page(&self) -> VirtAddr {
self.next_page
}
Expand Down Expand Up @@ -1134,6 +1187,24 @@ fn root_mem_init(pstart: PhysAddr, vstart: VirtAddr, page_count: usize) {
}
}

/// Get the memory size allocated to a VirtAddr
fn sizeof_alloc(va: VirtAddr) -> Result<usize, ()> {
let info: SvsmPageInfo = ROOT_MEM.lock().get_page_info(va)?;

let alloc_size: usize = match info {
SvsmPageInfo::Allocated(ai) => (ai.get_order() as u64 * PAGE_SIZE) as usize,
SvsmPageInfo::SlabPage(si) => {
let slab: *mut Slab = si.slab.as_u64() as *mut Slab;
unsafe { (*slab).page.get_item_size() as usize }
}
_ => {
return Err(());
}
};

Ok(alloc_size)
}

unsafe fn __mem_init() {
let pstart: PhysAddr = pgtable_va_to_pa(get_dyn_mem_begin());
let pend: PhysAddr = pgtable_va_to_pa(get_dyn_mem_end());
Expand Down
4 changes: 2 additions & 2 deletions src/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ pub mod map_guard;
pub mod pgtable;

pub use crate::mem::alloc::{
mem_allocate, mem_allocate_frame, mem_allocate_frames, mem_create_stack, mem_free,
mem_free_frame, mem_free_frames, mem_init,
mem_allocate, mem_allocate_frame, mem_allocate_frames, mem_callocate, mem_create_stack,
mem_free, mem_free_frame, mem_free_frames, mem_init, mem_reallocate,
};

pub use crate::mem::pgtable::{
Expand Down
66 changes: 66 additions & 0 deletions src/wrapper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright (C) 2023 IBM
*
* Authors:
* Claudio Carvalho <cclaudio@ibm.com>
* Vikram Narayanan <vikram186@gmail.com>
*/

#![allow(non_camel_case_types)]

use crate::cpu::vc_terminate_svsm_general;
use crate::mem::{mem_allocate, mem_callocate, mem_free, mem_reallocate};
use crate::prints;

use core::{ptr, slice, str};
use x86_64::VirtAddr;

#[no_mangle]
pub extern "C" fn malloc(size: cty::c_ulong) -> *mut cty::c_void {
if let Ok(va) = mem_allocate(size as usize) {
return va.as_mut_ptr();
};
ptr::null_mut()
}

#[no_mangle]
pub extern "C" fn calloc(items: cty::c_ulong, size: cty::c_ulong) -> *mut cty::c_void {
if let Some(num_bytes) = items.checked_mul(size as u64) {
if let Ok(va) = mem_callocate(num_bytes as usize) {
return va.as_mut_ptr();
}
}
ptr::null_mut()
}

#[no_mangle]
pub extern "C" fn realloc(p: *mut cty::c_void, size: cty::c_ulong) -> *mut cty::c_void {
if let Ok(va) = mem_reallocate(VirtAddr::new(p as u64), size as usize) {
return va.as_mut_ptr();
}
ptr::null_mut()
}

#[no_mangle]
pub extern "C" fn free(p: *mut cty::c_void) {
if p.is_null() {
return;
}
mem_free(VirtAddr::new(p as u64));
}

#[no_mangle]
pub extern "C" fn serial_out(s: *const cty::c_char, size: cty::c_int) {
let str_slice: &[u8] = unsafe { slice::from_raw_parts(s as *const u8, size as usize) };
if let Ok(rust_str) = str::from_utf8(str_slice) {
prints!("{}", rust_str);
} else {
prints!("ERR: BUG: serial_out arg1 is not a valid utf8 string\n");
}
}

#[no_mangle]
pub extern "C" fn abort() -> ! {
vc_terminate_svsm_general();
}

0 comments on commit da5be60

Please sign in to comment.