@@ -22,7 +22,7 @@ use crate::address::{Address, VirtAddr};
2222use crate :: cpu:: IrqGuard ;
2323use crate :: cpu:: ShadowStackInit ;
2424use crate :: cpu:: features:: { Feature , cpu_has_feat} ;
25- use crate :: cpu:: idt:: svsm:: return_new_task ;
25+ use crate :: cpu:: idt:: svsm:: { default_return , thread_entry_asm } ;
2626use crate :: cpu:: irq_state:: EFLAGS_IF ;
2727use crate :: cpu:: irqs_enable;
2828use crate :: cpu:: irqs_enabled;
@@ -231,29 +231,29 @@ pub struct TaskContext {
231231#[ derive( Default , Debug , Clone , Copy ) ]
232232struct KernelTaskContext {
233233 pub task_context : TaskContext ,
234+ pub thread_routine : u64 ,
234235 pub exit_addr : u64 ,
235236}
236237
237238#[ repr( C ) ]
238239#[ derive( Default , Debug , Clone , Copy ) ]
239240struct UserTaskContext {
240241 pub task_context : TaskContext ,
242+ pub thread_routine : u64 ,
243+ pub exit_addr : u64 ,
241244 pub excp_context : X86ExceptionContext ,
242245}
243246
244247// To ensure stack frames are 16b-aligned, ret_addr must be 16b-aligned
245248// so that (%rsp + 8) is 16b-aligned after the ret instruction in
246249// switch_context
247250const _: ( ) = assert ! (
248- ( size_of:: <KernelTaskContext >( ) - offset_of!( KernelTaskContext , task_context. ret_addr) ) % 16
251+ ( ( size_of:: <KernelTaskContext >( ) - offset_of!( KernelTaskContext , task_context. ret_addr) ) % 16 )
252+ - 8
249253 == 0
250254) ;
251-
252- // User-task return to return_new_task which is asm code, so %rsp must be
253- // 16b-aligned after the ret instruction in switch_context to ensure stack
254- // frames are 16b-aligned
255255const _: ( ) = assert ! (
256- ( size_of:: <UserTaskContext >( ) - offset_of!( UserTaskContext , task_context. ret_addr) - 8 ) % 16
256+ ( ( size_of:: <UserTaskContext >( ) - offset_of!( UserTaskContext , task_context. ret_addr) ) % 16 ) - 8
257257 == 0
258258) ;
259259
@@ -442,11 +442,17 @@ impl Task {
442442
443443 // Determine which kernel-mode entry/exit routines will be used for
444444 // this task.
445- let ( entry_return, exit_return) = match args. start_info {
446- ThreadStartInfo :: User ( _) => ( return_new_task as * const ( ) as usize , None ) ,
447- ThreadStartInfo :: Kernel ( ref info) => {
448- ( info. start_routine , Some ( task_exit as * const ( ) as usize ) )
449- }
445+ let ( entry_return, exit_return, iret_frame) = match args. start_info {
446+ ThreadStartInfo :: User ( _) => (
447+ thread_entry_asm as * const ( ) as usize ,
448+ default_return as * const ( ) as usize ,
449+ true ,
450+ ) ,
451+ ThreadStartInfo :: Kernel ( _) => (
452+ thread_entry_asm as * const ( ) as usize ,
453+ task_exit as * const ( ) as usize ,
454+ false ,
455+ ) ,
450456 } ;
451457
452458 let mut shadow_stack_offset = VirtAddr :: null ( ) ;
@@ -470,6 +476,7 @@ impl Task {
470476 ShadowStackInit :: Normal {
471477 entry_return,
472478 exit_return,
479+ iret_frame,
473480 } ,
474481 ) ;
475482
@@ -713,13 +720,15 @@ impl Task {
713720 let task_context = KernelTaskContext {
714721 task_context : TaskContext {
715722 regs : X86TaskSwitchRegs {
716- rsi : entry,
717- rdx : xsa_addr,
718- rcx : start_parameter,
723+ rsi : xsa_addr,
724+ // Put these into callee-safed registers
725+ r14 : entry,
726+ r15 : start_parameter,
719727 ..Default :: default ( )
720728 } ,
721- ret_addr : start_routine as u64 ,
729+ ret_addr : thread_entry_asm as * const ( ) as u64 ,
722730 } ,
731+ thread_routine : start_routine as u64 ,
723732 exit_addr : task_exit as * const ( ) as u64 ,
724733 } ;
725734
@@ -744,11 +753,13 @@ impl Task {
744753 rsi : xsa_addr, // XSAVE area addr
745754 ..Default :: default ( )
746755 } ,
747- ret_addr : VirtAddr :: from ( return_new_task as * const ( ) )
748- . bits ( )
749- . try_into ( )
750- . unwrap ( ) ,
756+ ret_addr : thread_entry_asm as * const ( ) as u64 ,
751757 } ,
758+ thread_routine : run_user_task as * const ( ) as u64 ,
759+ exit_addr : VirtAddr :: from ( default_return as * const ( ) )
760+ . bits ( )
761+ . try_into ( )
762+ . unwrap ( ) ,
752763 // Setup IRQ return frame. User-mode tasks always run with
753764 // interrupts enabled.
754765 excp_context : X86ExceptionContext {
@@ -995,23 +1006,8 @@ fn task_attach_console() {
9951006 . expect ( "Failed to attach console" ) ;
9961007}
9971008
998- /// Runs the first time a new task is scheduled, in the context of the new
999- /// task. Any first-time initialization and setup work for a new task that
1000- /// needs to happen in its context must be done here.
1001- /// # Safety
1002- /// The caller is required to verify the correctness of the save area address.
10031009#[ unsafe( no_mangle) ]
1004- unsafe fn setup_user_task ( prev : usize , xsa_addr : u64 ) {
1005- // SAFETY: caller needs to make sure that the previous task pointer and
1006- // xsa_addr are valid.
1007- unsafe {
1008- // Needs to be the first function called here.
1009- setup_new_task_common ( xsa_addr, complete_task_switch ( prev) ) ;
1010- }
1011- task_attach_console ( ) ;
1012- }
1013-
1014- unsafe fn setup_new_task_common ( xsa_addr : u64 , prev_task : Option < TaskPointer > ) {
1010+ unsafe fn complete_new_thread ( prev : usize , xsa_addr : u64 ) {
10151011 // Re-enable IRQs here, as they are still disabled from the
10161012 // schedule()/sched_init() functions. After the context switch the IrqGuard
10171013 // from the previous task is not dropped, which causes IRQs to stay
@@ -1021,6 +1017,9 @@ unsafe fn setup_new_task_common(xsa_addr: u64, prev_task: Option<TaskPointer>) {
10211017 // is dropped, re-enabling IRQs.
10221018 irqs_enable ( ) ;
10231019
1020+ // SAFETY: the scheduler passes the correct pointer to the previous task.
1021+ let prev_task = unsafe { complete_task_switch ( prev) } ;
1022+
10241023 // Drop the previous task reference now that interrupts are reenabled.
10251024 // This ensures that the task destructor will run with interrupts enabled.
10261025 drop ( prev_task) ;
@@ -1032,25 +1031,22 @@ unsafe fn setup_new_task_common(xsa_addr: u64, prev_task: Option<TaskPointer>) {
10321031 }
10331032}
10341033
1034+ /// Runs the first time a new task is scheduled, in the context of the new
1035+ /// task. Any first-time initialization specific to user-tasks need to happen
1036+ /// here.
1037+ /// # Safety
1038+ /// This is called from assembly code. The caller needs to ensure the
1039+ /// parameters are passed correctly.
1040+ #[ unsafe( no_mangle) ]
1041+ unsafe fn run_user_task ( ) {
1042+ task_attach_console ( ) ;
1043+ }
1044+
10351045/// # Safety
10361046/// This function must only be invoked as a thread start function, and must
10371047/// be invoked according to the start parameter data type expected by the entry
10381048/// point.
1039- unsafe fn run_kernel_task < T : KernelThreadStartParameter > (
1040- prev : usize ,
1041- entry : fn ( T ) ,
1042- xsa_addr : u64 ,
1043- start_parameter : usize ,
1044- ) {
1045- // SAFETY: the scheduler passes the correct pointer to the previous task.
1046- let prev_task = unsafe { complete_task_switch ( prev) } ;
1047-
1048- // SAFETY: the save area address is provided by the context switch assembly
1049- // code.
1050- unsafe {
1051- setup_new_task_common ( xsa_addr, prev_task) ;
1052- }
1053-
1049+ unsafe fn run_kernel_task < T : KernelThreadStartParameter > ( entry : fn ( T ) , start_parameter : usize ) {
10541050 // SAFETY: the `usize` start parameter was generated from an earlier call
10551051 // to `KernelThreadStartParameter::to_usize` when the start argument was
10561052 // prepared for use in the initial stack context, and therefore the safety
0 commit comments