179 lines
7.7 KiB
NASM
179 lines
7.7 KiB
NASM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; Microsoft Research Singularity
|
|
;;;
|
|
;;; Copyright (c) Microsoft Corporation. All rights reserved.
|
|
;;;
|
|
;;; This file contains x86-specific assembly code related to context save and restore.
|
|
;;; The key goal here is to keep this set of code as small as possible, in favor
|
|
;;; of portable C++ or C# code.
|
|
|
|
CODE32
|
|
|
|
AREA |.text|, CODE, ARM
|
|
|
|
|defining ?m_Save@Struct_Microsoft_Singularity_Isal_SpillContext@@SA_NPAU1@@Z| EQU 1
|
|
|defining ?m_Save@Struct_Microsoft_Singularity_Isal_SpillContext@@SA_NPAU1@PAUStruct_Microsoft_Singularity_Isal_InterruptContext@@@Z| EQU 1
|
|
|defining ?m_Resume@Struct_Microsoft_Singularity_Isal_SpillContext@@SAXPAU1@@Z| EQU 1
|
|
|defining ?g_ResetCurrent@Struct_Microsoft_Singularity_Isal_SpillContext@@SAXXZ| EQU 1
|
|
|
|
include hal.inc
|
|
|
|
;;; Save takes one argument - a context record to save the context in. It saves all the
|
|
;;; nonvolatile state (it does not bother saving caller save regs.)
|
|
;;;
|
|
;;; This function returns true after saving the context. When the context is resumed, control
|
|
;;; resumption will occur at the point this function returned, but with a false
|
|
;;; return value.
|
|
;;;
|
|
;;; Calling conventions are normal __fastcall.
|
|
|
|
;; __fastcall bool SaveContext(Context *context)
|
|
|
|
LEAF_ENTRY ?m_Save@Struct_Microsoft_Singularity_Isal_SpillContext@@SA_NPAU1@@Z
|
|
|
|
;; Save the bulk of the registers (r0-r12).
|
|
stmia r0, {r0-r12}
|
|
|
|
;; Save sp and (stale) lr.
|
|
str sp, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___sp]
|
|
str lr, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___lr]
|
|
|
|
;; Save lr as the pc.
|
|
str lr, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___pc]
|
|
|
|
;; Save cpsr
|
|
mrs r1, cpsr
|
|
str r1, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___cpsr]
|
|
|
|
;; Overright r0, so the return value contains zero on context resume
|
|
ldr r1, =0
|
|
str r1, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___r0]
|
|
|
|
;; Save stack limit
|
|
GET_THREAD_FIELD_ADDR r2, r12, #Struct_Microsoft_Singularity_Isal_ThreadRecord___activeStackLimit
|
|
ldr r2, [r2]
|
|
str r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___stackLimit]
|
|
|
|
;; Set spilled flag
|
|
ldr r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___spillFlags]
|
|
orr r2, r2, #Struct_Microsoft_Singularity_Isal_SpillContext_ContentsSpilled
|
|
str r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___spillFlags]
|
|
|
|
;; return true for initial save
|
|
ldr r0, =1
|
|
bx lr
|
|
|
|
LEAF_END
|
|
|
|
;;; Save takes two arguments - a context record to save the context in, and
|
|
;;; an interrupt frame to describe an interruption location.
|
|
;;;
|
|
;;; Calling conventions are normal __fastcall.
|
|
|
|
;; __fastcall bool SaveContext(Context *context, InterruptContext *interrupt)
|
|
|
|
LEAF_ENTRY ?m_Save@Struct_Microsoft_Singularity_Isal_SpillContext@@SA_NPAU1@PAUStruct_Microsoft_Singularity_Isal_InterruptContext@@@Z
|
|
|
|
;; Pick up registers from the interrupt context
|
|
|
|
ldr r2, [r1, #Struct_Microsoft_Singularity_Isal_InterruptContext___r0]
|
|
str r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___r0]
|
|
|
|
ldr r2, [r1, #Struct_Microsoft_Singularity_Isal_InterruptContext___r1]
|
|
str r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___r1]
|
|
|
|
ldr r2, [r1, #Struct_Microsoft_Singularity_Isal_InterruptContext___r2]
|
|
str r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___r2]
|
|
|
|
ldr r2, [r1, #Struct_Microsoft_Singularity_Isal_InterruptContext___r3]
|
|
str r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___r3]
|
|
|
|
ldr r2, [r1, #Struct_Microsoft_Singularity_Isal_InterruptContext___r12]
|
|
str r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___r12]
|
|
|
|
ldr r2, [r1, #Struct_Microsoft_Singularity_Isal_InterruptContext___lr]
|
|
str r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___lr]
|
|
|
|
ldr r2, [r1, #Struct_Microsoft_Singularity_Isal_InterruptContext___sp]
|
|
str r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___sp]
|
|
|
|
ldr r2, [r1, #Struct_Microsoft_Singularity_Isal_InterruptContext___pc]
|
|
str r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___pc]
|
|
|
|
ldr r2, [r1, #Struct_Microsoft_Singularity_Isal_InterruptContext___cpsr]
|
|
str r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___cpsr]
|
|
|
|
ldr r2, [r1, #Struct_Microsoft_Singularity_Isal_InterruptContext___instruction]
|
|
str r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___instruction]
|
|
|
|
;; Save the rest of the registers from the current state
|
|
add r2, r0, #Struct_Microsoft_Singularity_Isal_SpillContext___r4
|
|
stmia r2, {r4-r11}
|
|
|
|
;; Save stack limit
|
|
GET_THREAD_FIELD_ADDR r2, r12, #Struct_Microsoft_Singularity_Isal_ThreadRecord___activeStackLimit
|
|
ldr r2, [r2]
|
|
str r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___stackLimit]
|
|
|
|
;; Set spilled flag
|
|
ldr r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___spillFlags]
|
|
orr r2, r2, #Struct_Microsoft_Singularity_Isal_SpillContext_ContentsSpilled
|
|
str r2, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___spillFlags]
|
|
|
|
;; We're done
|
|
bx lr
|
|
|
|
LEAF_END
|
|
|
|
|
|
;;; Resume restores the processor state to the state described in the given
|
|
;;; context record.
|
|
;;;
|
|
;;; __fastcall void ResumeContext(Struct_Microsoft_Singularity_Isal_SpillContext *context);
|
|
|
|
|?m_Resume@Struct_Microsoft_Singularity_Isal_SpillContext@@SAXPAU1@@Z| PROC
|
|
|
|
;; Switch to supervisor mode so we can get an atomic resume including CPSR.
|
|
mrs r1, cpsr
|
|
bic r1, r1, #Struct_Microsoft_Singularity_Isal_Arm_ProcessorMode_Mask
|
|
orr r1, r1, #Struct_Microsoft_Singularity_Isal_Arm_ProcessorMode_Supervisor
|
|
msr cpsr_c, r1
|
|
|
|
;; Clear spilled flag.
|
|
ldr r1, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___spillFlags]
|
|
bic r1, r1, #Struct_Microsoft_Singularity_Isal_SpillContext_ContentsSpilled
|
|
str r1, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___spillFlags]
|
|
|
|
;; Restore stack limit.
|
|
ldr r1, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___stackLimit]
|
|
GET_THREAD_FIELD_ADDR r2, r12, #Struct_Microsoft_Singularity_Isal_ThreadRecord___activeStackLimit
|
|
str r1, [r2]
|
|
|
|
;; Move saved CPSR into SPSR.
|
|
ldr r1, [r0, #Struct_Microsoft_Singularity_Isal_SpillContext___cpsr]
|
|
msr spsr, r1
|
|
|
|
;; Restore banked pre-interrupt registers (use R3 as pointer to banked registers).
|
|
add r3, r0, #Struct_Microsoft_Singularity_Isal_SpillContext___sp
|
|
ldmia r3, {sp,lr}^
|
|
|
|
;; Resume unbanked pre-interrupt state.
|
|
ldmia r0, {r0-r12,pc}^
|
|
|
|
ENDP
|
|
|
|
;;; ResetContext resets the current context fp & debug register state to a canonical state
|
|
;;; for interrupt handler code. This should only be used after saving the current context.
|
|
;;;
|
|
;;; Calling conventions are normal __fastcall.
|
|
;;;
|
|
;;; __fastcall void ResetCurrent();
|
|
|
|
LEAF_ENTRY ?g_ResetCurrent@Struct_Microsoft_Singularity_Isal_SpillContext@@SAXXZ
|
|
bx lr
|
|
LEAF_END
|
|
|
|
END
|
|
|