mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-10 13:56:48 +00:00
Fix the kernel stack alignment
This commit is contained in:
parent
afc4bf7520
commit
e3cb4d25e3
@ -1,5 +1,4 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
use core::mem::size_of;
|
|
||||||
|
|
||||||
use intrusive_collections::{intrusive_adapter, LinkedListAtomicLink};
|
use intrusive_collections::{intrusive_adapter, LinkedListAtomicLink};
|
||||||
|
|
||||||
@ -101,6 +100,10 @@ impl Drop for KernelStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A task that executes a function to the end.
|
/// A task that executes a function to the end.
|
||||||
|
///
|
||||||
|
/// Each task is associated with per-task data and an optional user space.
|
||||||
|
/// If having a user space, the task can switch to the user space to
|
||||||
|
/// execute user code. Multiple tasks can share a single user space.
|
||||||
pub struct Task {
|
pub struct Task {
|
||||||
func: Box<dyn Fn() + Send + Sync>,
|
func: Box<dyn Fn() + Send + Sync>,
|
||||||
data: Box<dyn Any + Send + Sync>,
|
data: Box<dyn Any + Send + Sync>,
|
||||||
@ -251,11 +254,11 @@ impl TaskOptions {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a new task but not run it immediately.
|
/// Build a new task without running it immediately.
|
||||||
pub fn build(self) -> Result<Arc<Task>> {
|
pub fn build(self) -> Result<Arc<Task>> {
|
||||||
/// all task will entering this function
|
/// all task will entering this function
|
||||||
/// this function is mean to executing the task_fn in Task
|
/// this function is mean to executing the task_fn in Task
|
||||||
fn kernel_task_entry() {
|
extern "sysv64" fn kernel_task_entry() {
|
||||||
let current_task = current_task()
|
let current_task = current_task()
|
||||||
.expect("no current task, it should have current task in kernel task entry");
|
.expect("no current task, it should have current task in kernel task entry");
|
||||||
current_task.func.call(());
|
current_task.func.call(());
|
||||||
@ -278,52 +281,23 @@ impl TaskOptions {
|
|||||||
|
|
||||||
result.task_inner.lock().task_status = TaskStatus::Runnable;
|
result.task_inner.lock().task_status = TaskStatus::Runnable;
|
||||||
result.task_inner.lock().ctx.rip = kernel_task_entry as usize;
|
result.task_inner.lock().ctx.rip = kernel_task_entry as usize;
|
||||||
// Subtract 8 bytes to reserve space for the return address, otherwise
|
// We should reserve space for the return address in the stack, otherwise
|
||||||
// we will write across the page bondary.
|
// we will write across the page boundary due to the implementation of
|
||||||
|
// the context switch.
|
||||||
|
// According to the System V AMD64 ABI, the stack pointer should be aligned
|
||||||
|
// to at least 16 bytes. And a larger alignment is needed if larger arguments
|
||||||
|
// are passed to the function. The `kernel_task_entry` function does not
|
||||||
|
// have any arguments, so we only need to align the stack pointer to 16 bytes.
|
||||||
result.task_inner.lock().ctx.regs.rsp =
|
result.task_inner.lock().ctx.regs.rsp =
|
||||||
(crate::vm::paddr_to_vaddr(result.kstack.end_paddr() - size_of::<u64>())) as u64;
|
(crate::vm::paddr_to_vaddr(result.kstack.end_paddr() - 16)) as u64;
|
||||||
|
|
||||||
Ok(Arc::new(result))
|
Ok(Arc::new(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a new task and run it immediately.
|
/// Build a new task and run it immediately.
|
||||||
///
|
|
||||||
/// Each task is associated with a per-task data and an optional user space.
|
|
||||||
/// If having a user space, then the task can switch to the user space to
|
|
||||||
/// execute user code. Multiple tasks can share a single user space.
|
|
||||||
pub fn spawn(self) -> Result<Arc<Task>> {
|
pub fn spawn(self) -> Result<Arc<Task>> {
|
||||||
/// all task will entering this function
|
let task = self.build()?;
|
||||||
/// this function is mean to executing the task_fn in Task
|
task.run();
|
||||||
fn kernel_task_entry() {
|
Ok(task)
|
||||||
let current_task = current_task()
|
|
||||||
.expect("no current task, it should have current task in kernel task entry");
|
|
||||||
current_task.func.call(());
|
|
||||||
current_task.exit();
|
|
||||||
}
|
|
||||||
let result = Task {
|
|
||||||
func: self.func.unwrap(),
|
|
||||||
data: self.data.unwrap(),
|
|
||||||
user_space: self.user_space,
|
|
||||||
task_inner: SpinLock::new(TaskInner {
|
|
||||||
task_status: TaskStatus::Runnable,
|
|
||||||
ctx: TaskContext::default(),
|
|
||||||
}),
|
|
||||||
exit_code: 0,
|
|
||||||
kstack: KernelStack::new_with_guard_page()?,
|
|
||||||
link: LinkedListAtomicLink::new(),
|
|
||||||
priority: self.priority,
|
|
||||||
cpu_affinity: self.cpu_affinity,
|
|
||||||
};
|
|
||||||
|
|
||||||
result.task_inner.lock().task_status = TaskStatus::Runnable;
|
|
||||||
result.task_inner.lock().ctx.rip = kernel_task_entry as usize;
|
|
||||||
// Subtract 8 bytes to reserve space for the return address, otherwise
|
|
||||||
// we will write across the page bondary.
|
|
||||||
result.task_inner.lock().ctx.regs.rsp =
|
|
||||||
(crate::vm::paddr_to_vaddr(result.kstack.end_paddr() - size_of::<u64>())) as u64;
|
|
||||||
|
|
||||||
let arc_self = Arc::new(result);
|
|
||||||
arc_self.run();
|
|
||||||
Ok(arc_self)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user