123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- /*++
- Copyright (c) 2017 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- ctxswap.S
- Abstract:
- This module implements context switching on AMD64.
- Author:
- Evan Green 11-Jun-2017
- Environment:
- Kernel mode
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/x64.inc>
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ----------------------------------------------------------------------- Code
- //
- ASSEMBLY_FILE_HEADER
- //
- // VOID
- // KepContextSwap (
- // PVOID *SavedStackLocation,
- // PVOID NewStack,
- // PVOID NewThreadPointer,
- // BOOL FirstTime
- // )
- //
- /*++
- Routine Description:
- This routine switches context to the given thread.
- Arguments:
- SavedStackLocation - Supplies a pointer where the old stack pointer will
- be saved.
- NewStack - Supplies the new stack address.
- NewThreadPointer - Supplies the new thread pointer data.
- FirstTime - Supplies a boolean indicating whether the thread has never been
- run before.
- Return Value:
- None.
- --*/
- FUNCTION(KepContextSwap)
- pushq %rbp # Function prologue (also saves rbp).
- movq %rsp, %rbp #
- pushq %rbx # Save nonvolatile registers.
- pushq %r12
- pushq %r13
- pushq %r14
- pushq %r15
- pushfq
- subq $16, %rsp # Grab some extra stack space, aligned.
- movl $CONTEXT_SWAP_MAGIC, (%rsp) # Save a sentinal on the stack.
- //
- // Save the current thread's stack pointer. This effectively freezes the
- // current thread. When this thread is swapped back in, the stack pointer
- // will be restored, and execution of this function will continue. It's
- // crucial that the stack pointer not change between a normal context swap
- // and a first-time context swap, otherwise the thread that created the
- // context swap will have an incorrect stack next time it is swapped in.
- //
- movq %rsp, (%rdi) # Save stack pointer.
- //
- // Switch to the new stack and perform work than can only be done once off
- // of the old stack. Access the new stack before switching to it to trigger
- // any PML4 updates needed to see the new stack from old CR3.
- //
- movl (%rsi), %eax # Poke the new stack to trigger page faults.
- movq %rsi, %rsp # Switch to the new stack.
- xorq %rbp, %rbp # Zero out rbp so the call stack stops here.
- movq %rcx, %r12 # Move FirstTime parameter to non-volatile.
- //
- // Switch to the new thread pointer. The kernel doesn't use FS, so it's no
- // biggie.
- //
- movl $X86_MSR_FSBASE, %ecx # Set the MSR.
- movl %edx, %eax # Copy the low word into eax.
- shlq $32, %rdx # Shift rdx into its high word.
- wrmsr # Write the new FS base for user mode.
- //
- // Perform any post-stack switch work needed on the old thread.
- //
- call KepPostContextSwapWork # Perform post swap work.
- //
- // Determine whether to do a first-time return or a normal one. The only
- // difference is that a first-time execution has been set up to do an iret,
- // and a normal context swap doesn't need that because the stack is already
- // set up correctly.
- //
- cmpl $FALSE, %r12d # Compare FirstTime to FALSE.
- je KepContextSwapRestore # Special case a first run.
- KepContextSwapFirstTime:
- movq %rsp, %rdi # 1st argument is the trap frame pointer.
- call KepPreThreadStartWork # Do any thread setup needed.
- call ArRestoreTrapFrame # Set up CPU context.
- iretq # Return from the artificial exception.
- KepContextSwapRestore:
- movl (%rsp), %eax # Check the sentinal value.
- cmpl $CONTEXT_SWAP_MAGIC, %eax # Compare.
- jne KepContextSwapBadMagic # Jump out of line if it's bad.
- KepContextSwapReturn:
- addq $16, %rsp # Undo previous alignment adjustment.
- popfq # Restore registers.
- popq %r15
- popq %r14
- popq %r13
- popq %r12
- popq %rbx
- popq %rbp
- ret
- KepContextSwapBadMagic:
- int $0x3 # Break on bad context.
- jmp KepContextSwapReturn # If we break here, WATCH OUT.
- END_FUNCTION(KepContextSwap)
|