Commit 9900aa2f authored by H. Peter Anvin's avatar H. Peter Anvin Committed by H. Peter Anvin

x86-64: Handle exception table entries during early boot

If we get an exception during early boot, walk the exception table to
see if we should intercept it.  The main use case for this is to allow
rdmsr_safe()/wrmsr_safe() during CPU initialization.

Since the exception table is currently sorted at runtime, and fairly
late in startup, this code walks the exception table linearly.  We
obviously don't need to worry about modules, however: none have been
loaded at this point.

[ v2: Use early_fixup_exception() instead of linear search ]

Link: http://lkml.kernel.org/r/1334794610-5546-5-git-send-email-hpa@zytor.comSigned-off-by: default avatarH. Peter Anvin <hpa@linux.intel.com>
parent 6a1ea279
...@@ -213,7 +213,7 @@ ...@@ -213,7 +213,7 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][10]; extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][2+2+5];
/* /*
* Load a segment. Fall back on loading the zero * Load a segment. Fall back on loading the zero
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <asm/cache.h> #include <asm/cache.h>
#include <asm/processor-flags.h> #include <asm/processor-flags.h>
#include <asm/percpu.h> #include <asm/percpu.h>
#include <asm/nops.h>
#ifdef CONFIG_PARAVIRT #ifdef CONFIG_PARAVIRT
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
...@@ -26,6 +27,7 @@ ...@@ -26,6 +27,7 @@
#define GET_CR2_INTO(reg) GET_CR2_INTO_RAX ; movq %rax, reg #define GET_CR2_INTO(reg) GET_CR2_INTO_RAX ; movq %rax, reg
#else #else
#define GET_CR2_INTO(reg) movq %cr2, reg #define GET_CR2_INTO(reg) movq %cr2, reg
#define INTERRUPT_RETURN iretq
#endif #endif
/* we are not able to switch in one step to the final KERNEL ADDRESS SPACE /* we are not able to switch in one step to the final KERNEL ADDRESS SPACE
...@@ -271,35 +273,56 @@ bad_address: ...@@ -271,35 +273,56 @@ bad_address:
jmp bad_address jmp bad_address
.section ".init.text","ax" .section ".init.text","ax"
#ifdef CONFIG_EARLY_PRINTK
.globl early_idt_handlers .globl early_idt_handlers
early_idt_handlers: early_idt_handlers:
# 104(%rsp) %rflags
# 96(%rsp) %cs
# 88(%rsp) %rip
# 80(%rsp) error code
i = 0 i = 0
.rept NUM_EXCEPTION_VECTORS .rept NUM_EXCEPTION_VECTORS
movl $i, %esi .if (EXCEPTION_ERRCODE_MASK >> i) & 1
ASM_NOP2
.else
pushq $0 # Dummy error code, to make stack frame uniform
.endif
pushq $i # 72(%rsp) Vector number
jmp early_idt_handler jmp early_idt_handler
i = i + 1 i = i + 1
.endr .endr
#endif
ENTRY(early_idt_handler) ENTRY(early_idt_handler)
#ifdef CONFIG_EARLY_PRINTK cld
cmpl $2,early_recursion_flag(%rip) cmpl $2,early_recursion_flag(%rip)
jz 1f jz 1f
incl early_recursion_flag(%rip) incl early_recursion_flag(%rip)
GET_CR2_INTO(%r9)
xorl %r8d,%r8d # zero for error code pushq %rax # 64(%rsp)
movl %esi,%ecx # get vector number pushq %rcx # 56(%rsp)
# Test %ecx against mask of vectors that push error code. pushq %rdx # 48(%rsp)
cmpl $31,%ecx pushq %rsi # 40(%rsp)
ja 0f pushq %rdi # 32(%rsp)
movl $1,%eax pushq %r8 # 24(%rsp)
salq %cl,%rax pushq %r9 # 16(%rsp)
testl $EXCEPTION_ERRCODE_MASK,%eax pushq %r10 # 8(%rsp)
je 0f pushq %r11 # 0(%rsp)
popq %r8 # get error code
0: movq 0(%rsp),%rcx # get ip cmpl $__KERNEL_CS,96(%rsp)
movq 8(%rsp),%rdx # get cs jne 10f
leaq 88(%rsp),%rdi # Pointer to %rip
call early_fixup_exception
andl %eax,%eax
jnz 20f # Found an exception entry
10:
#ifdef CONFIG_EARLY_PRINTK
GET_CR2_INTO(%r9) # can clobber any volatile register if pv
movl 80(%rsp),%r8d # error code
movl 72(%rsp),%esi # vector number
movl 96(%rsp),%edx # %cs
movq 88(%rsp),%rcx # %rip
xorl %eax,%eax xorl %eax,%eax
leaq early_idt_msg(%rip),%rdi leaq early_idt_msg(%rip),%rdi
call early_printk call early_printk
...@@ -308,17 +331,32 @@ ENTRY(early_idt_handler) ...@@ -308,17 +331,32 @@ ENTRY(early_idt_handler)
call dump_stack call dump_stack
#ifdef CONFIG_KALLSYMS #ifdef CONFIG_KALLSYMS
leaq early_idt_ripmsg(%rip),%rdi leaq early_idt_ripmsg(%rip),%rdi
movq 0(%rsp),%rsi # get rip again movq 40(%rsp),%rsi # %rip again
call __print_symbol call __print_symbol
#endif #endif
#endif /* EARLY_PRINTK */ #endif /* EARLY_PRINTK */
1: hlt 1: hlt
jmp 1b jmp 1b
#ifdef CONFIG_EARLY_PRINTK 20: # Exception table entry found
popq %r11
popq %r10
popq %r9
popq %r8
popq %rdi
popq %rsi
popq %rdx
popq %rcx
popq %rax
addq $16,%rsp # drop vector number and error code
decl early_recursion_flag(%rip)
INTERRUPT_RETURN
.balign 4
early_recursion_flag: early_recursion_flag:
.long 0 .long 0
#ifdef CONFIG_EARLY_PRINTK
early_idt_msg: early_idt_msg:
.asciz "PANIC: early exception %02lx rip %lx:%lx error %lx cr2 %lx\n" .asciz "PANIC: early exception %02lx rip %lx:%lx error %lx cr2 %lx\n"
early_idt_ripmsg: early_idt_ripmsg:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment