amd64: in double fault handler, do not rely on sane gsbase value.
Typical reasons for doublefault faults are either kernel stack overflow or bugs in the code that manipulates protection CPU state. The later code is the code which often has to set up gsbase for kernel. Switching to explicit load of GSBASE MSR in the fault handler makes it more probable to output a useful information. Now all IST handlers have nmi_pcpu structure on top of their stacks. It would be even more useful to save gsbase value at the moment of the fault. I did not this because I do not want to modify PCB layout now. Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week
This commit is contained in:
parent
a4619d8461
commit
da248a69aa
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=354889
@ -345,10 +345,11 @@ IDTVEC(dblfault)
|
|||||||
pushfq
|
pushfq
|
||||||
andq $~(PSL_D | PSL_AC),(%rsp)
|
andq $~(PSL_D | PSL_AC),(%rsp)
|
||||||
popfq
|
popfq
|
||||||
testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */
|
movq TF_SIZE(%rsp),%rdx
|
||||||
jz 1f /* already running with kernel GS.base */
|
movl %edx,%eax
|
||||||
swapgs
|
shrq $32,%rdx
|
||||||
1: lfence
|
movl $MSR_GSBASE,%ecx
|
||||||
|
wrmsr
|
||||||
movq %cr3,%rax
|
movq %cr3,%rax
|
||||||
movq %rax,PCPU(SAVED_UCR3)
|
movq %rax,PCPU(SAVED_UCR3)
|
||||||
movq PCPU(KCR3),%rax
|
movq PCPU(KCR3),%rax
|
||||||
|
@ -1575,7 +1575,9 @@ amd64_bsp_ist_init(struct pcpu *pc)
|
|||||||
tssp = &pc->pc_common_tss;
|
tssp = &pc->pc_common_tss;
|
||||||
|
|
||||||
/* doublefault stack space, runs on ist1 */
|
/* doublefault stack space, runs on ist1 */
|
||||||
tssp->tss_ist1 = (long)&dblfault_stack[sizeof(dblfault_stack)];
|
np = ((struct nmi_pcpu *)&dblfault_stack[sizeof(dblfault_stack)]) - 1;
|
||||||
|
np->np_pcpu = (register_t)pc;
|
||||||
|
tssp->tss_ist1 = (long)np;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NMI stack, runs on ist2. The pcpu pointer is stored just
|
* NMI stack, runs on ist2. The pcpu pointer is stored just
|
||||||
|
@ -314,18 +314,24 @@ init_secondary(void)
|
|||||||
IOPERM_BITMAP_SIZE;
|
IOPERM_BITMAP_SIZE;
|
||||||
pc->pc_common_tss.tss_rsp0 = 0;
|
pc->pc_common_tss.tss_rsp0 = 0;
|
||||||
|
|
||||||
pc->pc_common_tss.tss_ist1 = (long)&doublefault_stack[PAGE_SIZE];
|
/* The doublefault stack runs on IST1. */
|
||||||
|
np = ((struct nmi_pcpu *)&doublefault_stack[PAGE_SIZE]) - 1;
|
||||||
|
np->np_pcpu = (register_t)pc;
|
||||||
|
pc->pc_common_tss.tss_ist1 = (long)np;
|
||||||
|
|
||||||
/* The NMI stack runs on IST2. */
|
/* The NMI stack runs on IST2. */
|
||||||
np = ((struct nmi_pcpu *) &nmi_stack[PAGE_SIZE]) - 1;
|
np = ((struct nmi_pcpu *) &nmi_stack[PAGE_SIZE]) - 1;
|
||||||
|
np->np_pcpu = (register_t)pc;
|
||||||
pc->pc_common_tss.tss_ist2 = (long)np;
|
pc->pc_common_tss.tss_ist2 = (long)np;
|
||||||
|
|
||||||
/* The MC# stack runs on IST3. */
|
/* The MC# stack runs on IST3. */
|
||||||
np = ((struct nmi_pcpu *) &mce_stack[PAGE_SIZE]) - 1;
|
np = ((struct nmi_pcpu *) &mce_stack[PAGE_SIZE]) - 1;
|
||||||
|
np->np_pcpu = (register_t)pc;
|
||||||
pc->pc_common_tss.tss_ist3 = (long)np;
|
pc->pc_common_tss.tss_ist3 = (long)np;
|
||||||
|
|
||||||
/* The DB# stack runs on IST4. */
|
/* The DB# stack runs on IST4. */
|
||||||
np = ((struct nmi_pcpu *) &dbg_stack[PAGE_SIZE]) - 1;
|
np = ((struct nmi_pcpu *) &dbg_stack[PAGE_SIZE]) - 1;
|
||||||
|
np->np_pcpu = (register_t)pc;
|
||||||
pc->pc_common_tss.tss_ist4 = (long)np;
|
pc->pc_common_tss.tss_ist4 = (long)np;
|
||||||
|
|
||||||
/* Prepare private GDT */
|
/* Prepare private GDT */
|
||||||
@ -341,18 +347,6 @@ init_secondary(void)
|
|||||||
ap_gdt.rd_base = (u_long)gdt;
|
ap_gdt.rd_base = (u_long)gdt;
|
||||||
lgdt(&ap_gdt); /* does magic intra-segment return */
|
lgdt(&ap_gdt); /* does magic intra-segment return */
|
||||||
|
|
||||||
/* Save the per-cpu pointer for use by the NMI handler. */
|
|
||||||
np = ((struct nmi_pcpu *) &nmi_stack[PAGE_SIZE]) - 1;
|
|
||||||
np->np_pcpu = (register_t)pc;
|
|
||||||
|
|
||||||
/* Save the per-cpu pointer for use by the MC# handler. */
|
|
||||||
np = ((struct nmi_pcpu *) &mce_stack[PAGE_SIZE]) - 1;
|
|
||||||
np->np_pcpu = (register_t)pc;
|
|
||||||
|
|
||||||
/* Save the per-cpu pointer for use by the DB# handler. */
|
|
||||||
np = ((struct nmi_pcpu *) &dbg_stack[PAGE_SIZE]) - 1;
|
|
||||||
np->np_pcpu = (register_t)pc;
|
|
||||||
|
|
||||||
wrmsr(MSR_FSBASE, 0); /* User value */
|
wrmsr(MSR_FSBASE, 0); /* User value */
|
||||||
wrmsr(MSR_GSBASE, (u_int64_t)pc);
|
wrmsr(MSR_GSBASE, (u_int64_t)pc);
|
||||||
wrmsr(MSR_KGSBASE, (u_int64_t)pc); /* XXX User value while we're in the kernel */
|
wrmsr(MSR_KGSBASE, (u_int64_t)pc); /* XXX User value while we're in the kernel */
|
||||||
|
Loading…
Reference in New Issue
Block a user