Fix the kernel stack alignment

This commit is contained in:
Zhang Junyang 2024-04-09 11:52:56 +08:00 committed by Tate, Hongliang Tian
parent afc4bf7520
commit e3cb4d25e3

View File

@ -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)
} }
} }