summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/cpu_switch.S90
1 files changed, 73 insertions, 17 deletions
diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S
index c860ec3..7b49d0d 100644
--- a/sys/amd64/amd64/cpu_switch.S
+++ b/sys/amd64/amd64/cpu_switch.S
@@ -38,6 +38,7 @@
*/
#include <machine/asmacros.h>
+#include <machine/specialreg.h>
#include "assym.s"
@@ -130,16 +131,36 @@ ENTRY(cpu_switch)
movl %fs,PCB_FS(%r8)
movl %gs,PCB_GS(%r8)
+ /* Test if debug registers should be saved. */
+ testl $PCB_DBREGS,PCB_FLAGS(%r8)
+ jz 1f /* no, skip over */
+ movq %dr7,%rax /* yes, do the save */
+ movq %rax,PCB_DR7(%r8)
+ andq $0x0000fc00, %rax /* disable all watchpoints */
+ movq %rax,%dr7
+ movq %dr6,%rax
+ movq %rax,PCB_DR6(%r8)
+ movq %dr3,%rax
+ movq %rax,PCB_DR3(%r8)
+ movq %dr2,%rax
+ movq %rax,PCB_DR2(%r8)
+ movq %dr1,%rax
+ movq %rax,PCB_DR1(%r8)
+ movq %dr0,%rax
+ movq %rax,PCB_DR0(%r8)
+1:
+
/* have we used fp, and need a save? */
cmpq %rdi,PCPU(FPCURTHREAD)
jne 1f
- pushq %rdi
- pushq %rsi
- addq $PCB_SAVEFPU,%r8 /* h/w bugs make saving complicated */
- movq %r8, %rdi
- call fpusave /* do it in a big C function */
- popq %rsi
- popq %rdi
+ addq $PCB_SAVEFPU,%r8
+ clts
+ fxsave (%r8)
+ smsw %ax
+ orb $CR0_TS,%al
+ lmsw %ax
+ xorq %rax,%rax
+ movq %rax,PCPU(FPCURTHREAD)
1:
/* Save is done. Now fire up new thread. Leave old vmspace. */
@@ -148,12 +169,19 @@ ENTRY(cpu_switch)
jz badsw3 /* no, panic */
#endif
movq TD_PCB(%rsi),%r8
- movl PCPU(CPUID), %eax
/* switch address space */
movq PCB_CR3(%r8),%rdx
+#ifdef LAZY_SWITCH
+ cmpq %rdx,KPML4phys /* Kernel address space? */
+ je sw1
+#endif
+ movq %cr3,%rax
+ cmpq %rdx,%rax /* Same address space? */
+ je sw1
movq %rdx,%cr3 /* new address space */
+ movl PCPU(CPUID), %eax
/* Release bit from old pmap->pm_active */
movq TD_PROC(%rdi), %rdx /* oldproc */
movq P_VMSPACE(%rdx), %rdx
@@ -223,6 +251,28 @@ sw1:
movq %r8, PCPU(CURPCB)
movq %rsi, PCPU(CURTHREAD) /* into next thread */
+ /* Test if debug registers should be restored. */
+ testl $PCB_DBREGS,PCB_FLAGS(%r8)
+ jz 1f
+ movq PCB_DR6(%r8),%rax
+ movq %rax,%dr6
+ movq PCB_DR3(%r8),%rax
+ movq %rax,%dr3
+ movq PCB_DR2(%r8),%rax
+ movq %rax,%dr2
+ movq PCB_DR1(%r8),%rax
+ movq %rax,%dr1
+ movq PCB_DR0(%r8),%rax
+ movq %rax,%dr0
+ /* But preserve reserved bits in %dr7 */
+ movq %dr7,%rax
+ andq $0x0000fc00,%rax
+ movq PCB_DR7(%r8),%rcx
+ andq $~0x0000fc00,%rcx
+ orq %rcx,%rax
+ movq %rax,%dr7
+1:
+
ret
#ifdef INVARIANTS
@@ -242,7 +292,9 @@ badsw1:
pushq %r13
pushq %r14
pushq %r15
- pushq $sw0_1
+ movq $0,%rdi
+ movq $0,%rsi
+ leaq sw0_1,%rdx
call __panic
sw0_1: .asciz "cpu_throw: no newthread supplied"
@@ -262,7 +314,9 @@ badsw2:
pushq %r13
pushq %r14
pushq %r15
- pushq $sw0_2
+ movq $0,%rdi
+ movq $0,%rsi
+ leaq sw0_2,%rdx
call __panic
sw0_2: .asciz "cpu_switch: no curthread supplied"
@@ -282,7 +336,9 @@ badsw3:
pushq %r13
pushq %r14
pushq %r15
- pushq $sw0_3
+ movq $0,%rdi
+ movq $0,%rsi
+ leaq sw0_3,%rdx
call __panic
sw0_3: .asciz "cpu_switch: no newthread supplied"
#endif
@@ -332,17 +388,17 @@ ENTRY(savectx)
testq %rax,%rax
je 1f
- pushq %rcx
- pushq %rax
movq TD_PCB(%rax),%rdi
leaq PCB_SAVEFPU(%rdi),%rdi
- call fpusave
- popq %rax
- popq %rcx
+ clts
+ fxsave (%rdi)
+ smsw %ax
+ orb $CR0_TS,%al
+ lmsw %ax
movq $PCB_SAVEFPU_SIZE,%rdx /* arg 3 */
leaq PCB_SAVEFPU(%rcx),%rsi /* arg 2 */
- movq %rax,%rdi /* arg 1 */
+ /* arg 1 (%rdi) already loaded */
call bcopy
1:
popfq
OpenPOWER on IntegriCloud