forked from coconut-svsm/svsm
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request coconut-svsm#505 from vijaydhanraj/userptr_wrapper
Introduce UserPtr wrapper around GuestPtr
- Loading branch information
Showing
5 changed files
with
228 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,11 +4,20 @@ | |
// | ||
// Author: Joerg Roedel <[email protected]> | ||
|
||
extern crate alloc; | ||
|
||
use crate::address::{Address, VirtAddr}; | ||
use crate::cpu::x86::smap::{clac, stac}; | ||
use crate::error::SvsmError; | ||
use crate::insn_decode::{InsnError, InsnMachineMem}; | ||
use crate::mm::{USER_MEM_END, USER_MEM_START}; | ||
use alloc::string::String; | ||
use alloc::vec::Vec; | ||
use core::arch::asm; | ||
use core::ffi::c_char; | ||
use core::mem::{size_of, MaybeUninit}; | ||
use syscall::PATH_MAX; | ||
use zerocopy::FromBytes; | ||
|
||
#[inline] | ||
pub fn read_u8(v: VirtAddr) -> Result<u8, SvsmError> { | ||
|
@@ -269,6 +278,100 @@ impl<T: Copy> InsnMachineMem for GuestPtr<T> { | |
} | ||
} | ||
|
||
struct UserAccessGuard; | ||
|
||
impl UserAccessGuard { | ||
pub fn new() -> Self { | ||
stac(); | ||
Self | ||
} | ||
} | ||
|
||
impl Drop for UserAccessGuard { | ||
fn drop(&mut self) { | ||
clac(); | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct UserPtr<T: Copy> { | ||
guest_ptr: GuestPtr<T>, | ||
} | ||
|
||
impl<T: Copy> UserPtr<T> { | ||
#[inline] | ||
pub fn new(v: VirtAddr) -> Self { | ||
Self { | ||
guest_ptr: GuestPtr::new(v), | ||
} | ||
} | ||
|
||
fn check_bounds(&self) -> bool { | ||
let v = VirtAddr::from(self.guest_ptr.ptr); | ||
|
||
(USER_MEM_START..USER_MEM_END).contains(&v) | ||
&& (USER_MEM_START..USER_MEM_END).contains(&(v + size_of::<T>())) | ||
} | ||
|
||
#[inline] | ||
pub fn read(&self) -> Result<T, SvsmError> | ||
where | ||
T: FromBytes, | ||
{ | ||
if !self.check_bounds() { | ||
return Err(SvsmError::InvalidAddress); | ||
} | ||
let _guard = UserAccessGuard::new(); | ||
unsafe { self.guest_ptr.read() } | ||
} | ||
|
||
#[inline] | ||
pub fn write(&self, buf: T) -> Result<(), SvsmError> { | ||
self.write_ref(&buf) | ||
} | ||
|
||
#[inline] | ||
pub fn write_ref(&self, buf: &T) -> Result<(), SvsmError> { | ||
if !self.check_bounds() { | ||
return Err(SvsmError::InvalidAddress); | ||
} | ||
let _guard = UserAccessGuard::new(); | ||
unsafe { self.guest_ptr.write_ref(buf) } | ||
} | ||
|
||
#[inline] | ||
pub const fn cast<N: Copy>(&self) -> UserPtr<N> { | ||
UserPtr { | ||
guest_ptr: self.guest_ptr.cast(), | ||
} | ||
} | ||
|
||
#[inline] | ||
pub fn offset(&self, count: isize) -> UserPtr<T> { | ||
UserPtr { | ||
guest_ptr: self.guest_ptr.offset(count), | ||
} | ||
} | ||
} | ||
|
||
impl UserPtr<c_char> { | ||
/// Reads a null-terminated C string from the user space. | ||
/// Allocates memory for the string and returns a `String`. | ||
pub fn read_c_string(&self) -> Result<String, SvsmError> { | ||
let mut buffer = Vec::new(); | ||
|
||
for offset in 0..PATH_MAX { | ||
let current_ptr = self.offset(offset as isize); | ||
let char_result = current_ptr.read()?; | ||
match char_result { | ||
0 => return String::from_utf8(buffer).map_err(|_| SvsmError::InvalidUtf8), | ||
c => buffer.push(c as u8), | ||
} | ||
} | ||
Err(SvsmError::InvalidBytes) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
// | ||
// Copyright (c) 2024 Intel Corporation. | ||
// | ||
// Author: Chuanxiao Dong <[email protected]> | ||
|
||
use core::arch::asm; | ||
|
||
/// Macro to generate system call functions with varying numbers of arguments. | ||
macro_rules! syscall { | ||
($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => { | ||
$( | ||
/// Performs a system call with arguments. | ||
/// | ||
/// # Safety | ||
/// | ||
/// This function is unsafe because it performs a system call. | ||
/// The kernel should check the syscall number and return the | ||
/// expected result back. | ||
#[allow(dead_code)] | ||
pub unsafe fn $name($a: u64, $($b: u64, $($c: u64, $($d: u64, $($e: u64, $($f: u64)?)?)?)?)?) -> Result<u64, SysCallError> { | ||
let mut ret = $a; | ||
asm!( | ||
"int 0x80", | ||
inout("rax") ret, | ||
$( | ||
in("rdi") $b, | ||
$( | ||
in("rsi") $c, | ||
$( | ||
in("r8") $d, | ||
$( | ||
in("r9") $e, | ||
$( | ||
in("r10") $f, | ||
)? | ||
)? | ||
)? | ||
)? | ||
)? | ||
out("rcx") _, | ||
out("r11") _, | ||
options(nostack), | ||
); | ||
|
||
if ret > (u64::MAX - u64::from(u16::MAX)) { | ||
return Err(SysCallError::from(ret as i32)); | ||
} | ||
Ok(ret) | ||
} | ||
)+ | ||
}; | ||
} | ||
|
||
syscall! { | ||
syscall0(a,); | ||
syscall1(a, b,); | ||
syscall2(a, b, c,); | ||
syscall3(a, b, c, d,); | ||
syscall4(a, b, c, d, e,); | ||
syscall5(a, b, c, d, e, f,); | ||
} | ||
|
||
#[derive(Clone, Copy, Debug)] | ||
pub enum SysCallError { | ||
EINVAL = -1, | ||
ENOSYS = -2, | ||
ENOMEM = -3, | ||
EPERM = -4, | ||
EFAULT = -5, | ||
EBUSY = -6, | ||
ENOTFOUND = -7, | ||
ENOTSUPP = -8, | ||
EEXIST = -9, | ||
UNKNOWN = -128, | ||
} | ||
|
||
impl From<i32> for SysCallError { | ||
fn from(e: i32) -> SysCallError { | ||
match e { | ||
-1 => SysCallError::EINVAL, | ||
-2 => SysCallError::ENOSYS, | ||
-3 => SysCallError::ENOMEM, | ||
-4 => SysCallError::EPERM, | ||
-5 => SysCallError::EFAULT, | ||
-6 => SysCallError::EBUSY, | ||
-7 => SysCallError::ENOTFOUND, | ||
-8 => SysCallError::ENOTSUPP, | ||
-9 => SysCallError::EEXIST, | ||
_ => SysCallError::UNKNOWN, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,8 +5,10 @@ | |
// Author: Joerg Roedel <[email protected]> | ||
#![no_std] | ||
|
||
mod call; | ||
mod numbers; | ||
mod obj; | ||
|
||
pub use call::SysCallError; | ||
pub use numbers::*; | ||
pub use obj::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters