-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
task/tasks: Add support for launching tasks at CPL-3
The Task structure contains the 'user' field that optionally provides information about the CPL-3 support of the task. This commit adds the user_create() function which initialises this field and allows the entry point of the task to be launched at CPL-3. In order to prevent the CPL-3 code from manipulating kernel structures and execution flow, the task code that runs at CPL-3 does not share the task kernel stack. Instead a new user-mode stack is created which is swapped in the transition from CPL-0 to 3 and back. The task entry point is called from launch_user_entry() which runs at CPL-0 and is responsible for performing the privilege level switch as well as storing the kernel context for returning to CPL-0 via syscall. The syscall handler that performs this switch is already present from a previous commit in task/syscall.rs. Signed-off-by: Roy Hopkins <rhopkins@suse.de>
- Loading branch information
1 parent
20c9a1b
commit d1b3e5a
Showing
4 changed files
with
219 additions
and
3 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 |
---|---|---|
@@ -0,0 +1,127 @@ | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
// | ||
// Copyright (c) 2022-2023 SUSE LLC | ||
// | ||
// Author: Joerg Roedel <jroedel@suse.de> | ||
// Author: Roy Hopkins <rhopkins@suse.de> | ||
|
||
use super::VirtualMapping; | ||
use crate::address::{PhysAddr, VirtAddr}; | ||
use crate::error::SvsmError; | ||
use crate::mm::address_space::STACK_SIZE; | ||
use crate::mm::pagetable::PTEntryFlags; | ||
use crate::types::{PAGE_SHIFT, PAGE_SIZE}; | ||
use crate::utils::page_align_up; | ||
|
||
use super::rawalloc::RawAllocMapping; | ||
use super::Mapping; | ||
|
||
/// Mapping to be used as a user mode stack. This maps a stack including guard | ||
/// pages at the top and bottom. | ||
#[derive(Default, Debug)] | ||
pub struct VMUserStack { | ||
/// Allocation for stack pages | ||
alloc: RawAllocMapping, | ||
/// Number of guard pages to reserve address space for | ||
guard_pages: usize, | ||
} | ||
|
||
impl VMUserStack { | ||
/// Returns the virtual address for the top of this user mode stack | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `base` - Virtual base address this stack is mapped at (including | ||
/// guard pages). | ||
/// | ||
/// # Returns | ||
/// | ||
/// Virtual address to program into the hardware stack register | ||
pub fn top_of_stack(&self, base: VirtAddr) -> VirtAddr { | ||
let guard_size = self.guard_pages * PAGE_SIZE; | ||
base + guard_size + self.alloc.mapping_size() | ||
} | ||
|
||
/// Create a new [`VMUserStack`] with a given size. This function will | ||
/// already allocate the backing pages for the stack. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `size` - Size of the user stack, without guard pages | ||
/// | ||
/// # Returns | ||
/// | ||
/// Initialized stack on success, Err(SvsmError::Mem) on error | ||
pub fn new_size(size: usize) -> Result<Self, SvsmError> { | ||
// Make sure size is page-aligned | ||
let size = page_align_up(size); | ||
// At least two guard-pages needed | ||
let total_size = (size + 2 * PAGE_SIZE).next_power_of_two(); | ||
let guard_pages = ((total_size - size) >> PAGE_SHIFT) / 2; | ||
let mut stack = VMUserStack { | ||
alloc: RawAllocMapping::new(size), | ||
guard_pages, | ||
}; | ||
stack.alloc_pages()?; | ||
|
||
Ok(stack) | ||
} | ||
|
||
/// Create a new [`VMUserStack`] with the default size. This function | ||
/// will already allocate the backing pages for the stack. | ||
/// | ||
/// # Returns | ||
/// | ||
/// Initialized stack on success, Err(SvsmError::Mem) on error | ||
pub fn new() -> Result<Self, SvsmError> { | ||
VMUserStack::new_size(STACK_SIZE) | ||
} | ||
|
||
/// Create a new [`VMUserStack`] with the default size, packed into a | ||
/// [`Mapping`]. This function / will already allocate the backing pages for | ||
/// the stack. | ||
/// | ||
/// # Returns | ||
/// | ||
/// Initialized Mapping to stack on success, Err(SvsmError::Mem) on error | ||
pub fn new_mapping() -> Result<Mapping, SvsmError> { | ||
Ok(Mapping::new(Self::new()?)) | ||
} | ||
|
||
fn alloc_pages(&mut self) -> Result<(), SvsmError> { | ||
self.alloc.alloc_pages() | ||
} | ||
} | ||
|
||
impl VirtualMapping for VMUserStack { | ||
fn mapping_size(&self) -> usize { | ||
self.alloc.mapping_size() + ((self.guard_pages * 2) << PAGE_SHIFT) | ||
} | ||
|
||
fn map(&self, offset: usize) -> Option<PhysAddr> { | ||
let pfn = offset >> PAGE_SHIFT; | ||
let guard_offset = self.guard_pages << PAGE_SHIFT; | ||
|
||
if pfn >= self.guard_pages { | ||
self.alloc.map(offset - guard_offset) | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
fn unmap(&self, offset: usize) { | ||
let pfn = offset >> PAGE_SHIFT; | ||
|
||
if pfn >= self.guard_pages { | ||
self.alloc.unmap(pfn - self.guard_pages); | ||
} | ||
} | ||
|
||
fn pt_flags(&self, _offset: usize) -> PTEntryFlags { | ||
PTEntryFlags::WRITABLE | ||
| PTEntryFlags::NX | ||
| PTEntryFlags::ACCESSED | ||
| PTEntryFlags::DIRTY | ||
| PTEntryFlags::USER | ||
} | ||
} |
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