savectx() has not been used for fork(2) for about 15 years. [1]

Do not clobber FPU thread's PCB as it is more harmful.  When we resume CPU,
unconditionally reload FPU state.

Pointed out by:	bde [1]
This commit is contained in:
jkim 2010-08-03 15:32:08 +00:00
parent 3327e87142
commit c530d20c6a
3 changed files with 61 additions and 103 deletions

View File

@ -34,11 +34,11 @@
#include "acpi_wakedata.h"
#include "assym.s"
#define WAKEUP_CTX(member) wakeup_ ## member - wakeup_ctx(%rdi)
#define WAKEUP_CTX(member) wakeup_ ## member - wakeup_ctx(%rsi)
ENTRY(acpi_restorecpu)
/* Switch to KPML4phys. */
movq %rsi, %rax
movq %rdi, %rax
movq %rax, %cr3
/* Restore GDT. */
@ -47,7 +47,7 @@ ENTRY(acpi_restorecpu)
1:
/* Fetch PCB. */
movq WAKEUP_CTX(pcb), %rsi
movq WAKEUP_CTX(pcb), %rdi
/* Force kernel segment registers. */
movl $KDSEL, %eax
@ -60,16 +60,16 @@ ENTRY(acpi_restorecpu)
movw %ax, %gs
movl $MSR_FSBASE, %ecx
movl PCB_FSBASE(%rsi), %eax
movl 4 + PCB_FSBASE(%rsi), %edx
movl PCB_FSBASE(%rdi), %eax
movl 4 + PCB_FSBASE(%rdi), %edx
wrmsr
movl $MSR_GSBASE, %ecx
movl PCB_GSBASE(%rsi), %eax
movl 4 + PCB_GSBASE(%rsi), %edx
movl PCB_GSBASE(%rdi), %eax
movl 4 + PCB_GSBASE(%rdi), %edx
wrmsr
movl $MSR_KGSBASE, %ecx
movl PCB_KGSBASE(%rsi), %eax
movl 4 + PCB_KGSBASE(%rsi), %edx
movl PCB_KGSBASE(%rdi), %eax
movl 4 + PCB_KGSBASE(%rdi), %edx
wrmsr
/* Restore EFER. */
@ -101,20 +101,20 @@ ENTRY(acpi_restorecpu)
wrmsr
/* Restore CR0 except for FPU mode. */
movq PCB_CR0(%rsi), %rax
movq PCB_CR0(%rdi), %rax
movq %rax, %rcx
andq $~(CR0_EM | CR0_TS), %rax
movq %rax, %cr0
/* Restore CR2 and CR4. */
movq PCB_CR2(%rsi), %rax
movq PCB_CR2(%rdi), %rax
movq %rax, %cr2
movq PCB_CR4(%rsi), %rax
movq PCB_CR4(%rdi), %rax
movq %rax, %cr4
/* Restore descriptor tables. */
lidt PCB_IDT(%rsi)
lldt PCB_LDT(%rsi)
lidt PCB_IDT(%rdi)
lldt PCB_LDT(%rdi)
#define SDT_SYSTSS 9
#define SDT_SYSBSY 11
@ -122,58 +122,44 @@ ENTRY(acpi_restorecpu)
/* Clear "task busy" bit and reload TR. */
movq PCPU(TSS), %rax
andb $(~SDT_SYSBSY | SDT_SYSTSS), 5(%rax)
movw PCB_TR(%rsi), %ax
movw PCB_TR(%rdi), %ax
ltr %ax
#undef SDT_SYSTSS
#undef SDT_SYSBSY
/* Restore other callee saved registers. */
movq PCB_R15(%rsi), %r15
movq PCB_R14(%rsi), %r14
movq PCB_R13(%rsi), %r13
movq PCB_R12(%rsi), %r12
movq PCB_RBP(%rsi), %rbp
movq PCB_RSP(%rsi), %rsp
movq PCB_RBX(%rsi), %rbx
movq PCB_R15(%rdi), %r15
movq PCB_R14(%rdi), %r14
movq PCB_R13(%rdi), %r13
movq PCB_R12(%rdi), %r12
movq PCB_RBP(%rdi), %rbp
movq PCB_RSP(%rdi), %rsp
movq PCB_RBX(%rdi), %rbx
/* Restore debug registers. */
movq PCB_DR0(%rsi), %rax
movq PCB_DR0(%rdi), %rax
movq %rax, %dr0
movq PCB_DR1(%rsi), %rax
movq PCB_DR1(%rdi), %rax
movq %rax, %dr1
movq PCB_DR2(%rsi), %rax
movq PCB_DR2(%rdi), %rax
movq %rax, %dr2
movq PCB_DR3(%rsi), %rax
movq PCB_DR3(%rdi), %rax
movq %rax, %dr3
movq PCB_DR6(%rsi), %rax
movq PCB_DR6(%rdi), %rax
movq %rax, %dr6
movq PCB_DR7(%rsi), %rax
movq PCB_DR7(%rdi), %rax
movq %rax, %dr7
#define __INITIAL_FPUCW__ 0x037f
#define __INITIAL_MXCSR__ 0x1f80
/* Initialize FPU and restore state if necessary. */
/* Restore FPU state. */
fninit
movw $__INITIAL_FPUCW__, -2(%rsp)
fldcw -2(%rsp)
movl $__INITIAL_MXCSR__, -4(%rsp)
ldmxcsr -4(%rsp)
movq PCPU(FPCURTHREAD), %rax
testq %rax, %rax
je 1f
fxrstor PCB_USERFPU(%rsi)
1:
#undef __INITIAL_FPUCW__
#undef __INITIAL_MXCSR__
fxrstor PCB_USERFPU(%rdi)
/* Reload CR0. */
movq %rcx, %cr0
/* Restore return address. */
movq PCB_RIP(%rsi), %rax
movq PCB_RIP(%rdi), %rax
movq %rax, (%rsp)
/* Indicate the CPU is resumed. */

View File

@ -210,8 +210,8 @@ wakeup_64:
mov %ax, %ds
/* Restore arguments and return. */
movq wakeup_ctx - wakeup_start(%rbx), %rdi
movq wakeup_kpml4 - wakeup_start(%rbx), %rsi
movq wakeup_kpml4 - wakeup_start(%rbx), %rdi
movq wakeup_ctx - wakeup_start(%rbx), %rsi
movq wakeup_retaddr - wakeup_start(%rbx), %rax
jmp *%rax

View File

@ -302,93 +302,65 @@ END(cpu_switch)
* Update pcb, saving current processor state.
*/
ENTRY(savectx)
/* Fetch PCB. */
movq %rdi,%rsi
/* Save caller's return address. */
movq (%rsp),%rax
movq %rax,PCB_RIP(%rsi)
movq %rax,PCB_RIP(%rdi)
movq %rbx,PCB_RBX(%rsi)
movq %rsp,PCB_RSP(%rsi)
movq %rbp,PCB_RBP(%rsi)
movq %r12,PCB_R12(%rsi)
movq %r13,PCB_R13(%rsi)
movq %r14,PCB_R14(%rsi)
movq %r15,PCB_R15(%rsi)
movq %rbx,PCB_RBX(%rdi)
movq %rsp,PCB_RSP(%rdi)
movq %rbp,PCB_RBP(%rdi)
movq %r12,PCB_R12(%rdi)
movq %r13,PCB_R13(%rdi)
movq %r14,PCB_R14(%rdi)
movq %r15,PCB_R15(%rdi)
movq %cr0,%rsi
movq %rsi,PCB_CR0(%rdi)
movq %cr2,%rax
movq %rax,PCB_CR2(%rsi)
movq %rax,PCB_CR2(%rdi)
movq %cr3,%rax
movq %rax,PCB_CR3(%rsi)
movq %rax,PCB_CR3(%rdi)
movq %cr4,%rax
movq %rax,PCB_CR4(%rsi)
movq %rax,PCB_CR4(%rdi)
movq %dr0,%rax
movq %rax,PCB_DR0(%rsi)
movq %rax,PCB_DR0(%rdi)
movq %dr1,%rax
movq %rax,PCB_DR1(%rsi)
movq %rax,PCB_DR1(%rdi)
movq %dr2,%rax
movq %rax,PCB_DR2(%rsi)
movq %rax,PCB_DR2(%rdi)
movq %dr3,%rax
movq %rax,PCB_DR3(%rsi)
movq %rax,PCB_DR3(%rdi)
movq %dr6,%rax
movq %rax,PCB_DR6(%rsi)
movq %rax,PCB_DR6(%rdi)
movq %dr7,%rax
movq %rax,PCB_DR7(%rsi)
movq %rax,PCB_DR7(%rdi)
movl $MSR_FSBASE,%ecx
rdmsr
shlq $32,%rdx
leaq (%rax,%rdx),%rax
movq %rax,PCB_FSBASE(%rsi)
movq %rax,PCB_FSBASE(%rdi)
movl $MSR_GSBASE,%ecx
rdmsr
shlq $32,%rdx
leaq (%rax,%rdx),%rax
movq %rax,PCB_GSBASE(%rsi)
movq %rax,PCB_GSBASE(%rdi)
movl $MSR_KGSBASE,%ecx
rdmsr
shlq $32,%rdx
leaq (%rax,%rdx),%rax
movq %rax,PCB_KGSBASE(%rsi)
movq %rax,PCB_KGSBASE(%rdi)
sgdt PCB_GDT(%rsi)
sidt PCB_IDT(%rsi)
sldt PCB_LDT(%rsi)
str PCB_TR(%rsi)
sgdt PCB_GDT(%rdi)
sidt PCB_IDT(%rdi)
sldt PCB_LDT(%rdi)
str PCB_TR(%rdi)
movq %cr0,%rax
movq %rax,PCB_CR0(%rsi)
leaq PCB_USERFPU(%rsi),%rdi
pushfq
cli
clts
fxsave (%rdi)
movq %rax,%cr0
fxsave PCB_USERFPU(%rdi)
movq %rsi,%cr0 /* The previous %cr0 is saved in %rsi. */
/*
* If fpcurthread == NULL, then the fpu h/w state is irrelevant and the
* state had better already be in the pcb. This is true for forks
* but not for dumps (the old book-keeping with FP flags in the pcb
* always lost for dumps because the dump pcb has 0 flags).
*
* If fpcurthread != NULL, then we have to copy the fpu h/w state to
* fpcurthread's pcb, or reload from the requested pcb. Copying is
* easier because we would have to handle h/w bugs for reloading.
*/
movq PCPU(FPCURTHREAD),%rax
testq %rax,%rax
je 1f
/* arg 1 (%rdi) already loaded */
movq TD_PCB(%rax),%rax
movq PCB_SAVEFPU(%rax),%rsi /* arg 2 */
movq $PCB_SAVEFPU_SIZE,%rdx /* arg 3 */
call bcopy
1:
popfq
movl $1,%eax
ret
END(savectx)