Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
319e305c
Commit
319e305c
authored
Feb 25, 2016
by
Ingo Molnar
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ras/core' into core/objtool, to pick up the new exception table format
Signed-off-by:
Ingo Molnar
<
mingo@kernel.org
>
parents
c0853867
b2f9d678
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
321 additions
and
121 deletions
+321
-121
Documentation/x86/exception-tables.txt
Documentation/x86/exception-tables.txt
+35
-0
arch/x86/include/asm/asm.h
arch/x86/include/asm/asm.h
+24
-16
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/msr-index.h
+4
-0
arch/x86/include/asm/uaccess.h
arch/x86/include/asm/uaccess.h
+8
-8
arch/x86/kernel/cpu/mcheck/mce-severity.c
arch/x86/kernel/cpu/mcheck/mce-severity.c
+20
-2
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mcheck/mce.c
+37
-35
arch/x86/kernel/cpu/mcheck/mce_amd.c
arch/x86/kernel/cpu/mcheck/mce_amd.c
+84
-27
arch/x86/kernel/kprobes/core.c
arch/x86/kernel/kprobes/core.c
+1
-1
arch/x86/kernel/traps.c
arch/x86/kernel/traps.c
+3
-3
arch/x86/mm/extable.c
arch/x86/mm/extable.c
+72
-28
arch/x86/mm/fault.c
arch/x86/mm/fault.c
+1
-1
scripts/sortextable.c
scripts/sortextable.c
+32
-0
No files found.
Documentation/x86/exception-tables.txt
View file @
319e305c
...
...
@@ -290,3 +290,38 @@ Due to the way that the exception table is built and needs to be ordered,
only use exceptions for code in the .text section. Any other section
will cause the exception table to not be sorted correctly, and the
exceptions will fail.
Things changed when 64-bit support was added to x86 Linux. Rather than
double the size of the exception table by expanding the two entries
from 32-bits to 64 bits, a clever trick was used to store addresses
as relative offsets from the table itself. The assembly code changed
from:
.long 1b,3b
to:
.long (from) - .
.long (to) - .
and the C-code that uses these values converts back to absolute addresses
like this:
ex_insn_addr(const struct exception_table_entry *x)
{
return (unsigned long)&x->insn + x->insn;
}
In v4.6 the exception table entry was expanded with a new field "handler".
This is also 32-bits wide and contains a third relative function
pointer which points to one of:
1) int ex_handler_default(const struct exception_table_entry *fixup)
This is legacy case that just jumps to the fixup code
2) int ex_handler_fault(const struct exception_table_entry *fixup)
This case provides the fault number of the trap that occurred at
entry->insn. It is used to distinguish page faults from machine
check.
3) int ex_handler_ext(const struct exception_table_entry *fixup)
This case is used for uaccess_err ... we need to set a flag
in the task structure. Before the handler functions existed this
case was handled by adding a large offset to the fixup to tag
it as special.
More functions can easily be added.
arch/x86/include/asm/asm.h
View file @
319e305c
...
...
@@ -44,19 +44,22 @@
/* Exception table entry */
#ifdef __ASSEMBLY__
# define _ASM_EXTABLE
(from,to)
\
# define _ASM_EXTABLE
_HANDLE(from, to, handler)
\
.pushsection "__ex_table","a" ; \
.balign
8
; \
.balign
4
; \
.long (from) - . ; \
.long (to) - . ; \
.long (handler) - . ; \
.popsection
# define _ASM_EXTABLE_EX(from,to) \
.pushsection "__ex_table","a" ; \
.balign 8 ; \
.long (from) - . ; \
.long (to) - . + 0x7ffffff0 ; \
.popsection
# define _ASM_EXTABLE(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_default)
# define _ASM_EXTABLE_FAULT(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
# define _ASM_EXTABLE_EX(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_ext)
# define _ASM_NOKPROBE(entry) \
.pushsection "_kprobe_blacklist","aw" ; \
...
...
@@ -89,19 +92,24 @@
.
endm
#else
# define _ASM_EXTABLE(from,to) \
# define _EXPAND_EXTABLE_HANDLE(x) #x
# define _ASM_EXTABLE_HANDLE(from, to, handler) \
" .pushsection \"__ex_table\",\"a\"\n" \
" .balign
8
\n" \
" .balign
4
\n" \
" .long (" #from ") - .\n" \
" .long (" #to ") - .\n" \
" .long (" _EXPAND_EXTABLE_HANDLE(handler) ") - .\n" \
" .popsection\n"
# define _ASM_EXTABLE_EX(from,to) \
" .pushsection \"__ex_table\",\"a\"\n" \
" .balign 8\n" \
" .long (" #from ") - .\n" \
" .long (" #to ") - . + 0x7ffffff0\n" \
" .popsection\n"
# define _ASM_EXTABLE(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_default)
# define _ASM_EXTABLE_FAULT(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
# define _ASM_EXTABLE_EX(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_ext)
/* For C file, we already have NOKPROBE_SYMBOL macro */
#endif
...
...
arch/x86/include/asm/msr-index.h
View file @
319e305c
...
...
@@ -269,6 +269,10 @@
#define MSR_IA32_MC0_CTL2 0x00000280
#define MSR_IA32_MCx_CTL2(x) (MSR_IA32_MC0_CTL2 + (x))
/* 'SMCA': AMD64 Scalable MCA */
#define MSR_AMD64_SMCA_MC0_CONFIG 0xc0002004
#define MSR_AMD64_SMCA_MCx_CONFIG(x) (MSR_AMD64_SMCA_MC0_CONFIG + 0x10*(x))
#define MSR_P6_PERFCTR0 0x000000c1
#define MSR_P6_PERFCTR1 0x000000c2
#define MSR_P6_EVNTSEL0 0x00000186
...
...
arch/x86/include/asm/uaccess.h
View file @
319e305c
...
...
@@ -90,12 +90,11 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
likely(!__range_not_ok(addr, size, user_addr_max()))
/*
* The exception table consists of pairs of addresses relative to the
* exception table enty itself: the first is the address of an
* instruction that is allowed to fault, and the second is the address
* at which the program should continue. No registers are modified,
* so it is entirely up to the continuation code to figure out what to
* do.
* The exception table consists of triples of addresses relative to the
* exception table entry itself. The first address is of an instruction
* that is allowed to fault, the second is the target at which the program
* should continue. The third is a handler function to deal with the fault
* caused by the instruction in the first field.
*
* All the routines below use bits of fixup code that are out of line
* with the main instruction path. This means when everything is well,
...
...
@@ -104,13 +103,14 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
*/
struct
exception_table_entry
{
int
insn
,
fixup
;
int
insn
,
fixup
,
handler
;
};
/* This is not the generic standard exception_table_entry format */
#define ARCH_HAS_SORT_EXTABLE
#define ARCH_HAS_SEARCH_EXTABLE
extern
int
fixup_exception
(
struct
pt_regs
*
regs
);
extern
int
fixup_exception
(
struct
pt_regs
*
regs
,
int
trapnr
);
extern
bool
ex_has_fault_handler
(
unsigned
long
ip
);
extern
int
early_fixup_exception
(
unsigned
long
*
ip
);
/*
...
...
arch/x86/kernel/cpu/mcheck/mce-severity.c
View file @
319e305c
...
...
@@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/debugfs.h>
#include <asm/mce.h>
#include <asm/uaccess.h>
#include "mce-internal.h"
...
...
@@ -29,7 +30,7 @@
* panic situations)
*/
enum
context
{
IN_KERNEL
=
1
,
IN_USER
=
2
};
enum
context
{
IN_KERNEL
=
1
,
IN_USER
=
2
,
IN_KERNEL_RECOV
=
3
};
enum
ser
{
SER_REQUIRED
=
1
,
NO_SER
=
2
};
enum
exception
{
EXCP_CONTEXT
=
1
,
NO_EXCP
=
2
};
...
...
@@ -48,6 +49,7 @@ static struct severity {
#define MCESEV(s, m, c...) { .sev = MCE_ ## s ## _SEVERITY, .msg = m, ## c }
#define KERNEL .context = IN_KERNEL
#define USER .context = IN_USER
#define KERNEL_RECOV .context = IN_KERNEL_RECOV
#define SER .ser = SER_REQUIRED
#define NOSER .ser = NO_SER
#define EXCP .excp = EXCP_CONTEXT
...
...
@@ -86,6 +88,10 @@ static struct severity {
PANIC
,
"In kernel and no restart IP"
,
EXCP
,
KERNEL
,
MCGMASK
(
MCG_STATUS_RIPV
,
0
)
),
MCESEV
(
PANIC
,
"In kernel and no restart IP"
,
EXCP
,
KERNEL_RECOV
,
MCGMASK
(
MCG_STATUS_RIPV
,
0
)
),
MCESEV
(
DEFERRED
,
"Deferred error"
,
NOSER
,
MASK
(
MCI_STATUS_UC
|
MCI_STATUS_DEFERRED
|
MCI_STATUS_POISON
,
MCI_STATUS_DEFERRED
)
...
...
@@ -122,6 +128,11 @@ static struct severity {
SER
,
MASK
(
MCI_STATUS_OVER
|
MCI_UC_SAR
|
MCI_ADDR
,
MCI_UC_SAR
|
MCI_ADDR
),
MCGMASK
(
MCG_STATUS_RIPV
|
MCG_STATUS_EIPV
,
MCG_STATUS_RIPV
)
),
MCESEV
(
AR
,
"Action required: data load in error recoverable area of kernel"
,
SER
,
MASK
(
MCI_STATUS_OVER
|
MCI_UC_SAR
|
MCI_ADDR
|
MCACOD
,
MCI_UC_SAR
|
MCI_ADDR
|
MCACOD_DATA
),
KERNEL_RECOV
),
MCESEV
(
AR
,
"Action required: data load error in a user process"
,
SER
,
MASK
(
MCI_STATUS_OVER
|
MCI_UC_SAR
|
MCI_ADDR
|
MCACOD
,
MCI_UC_SAR
|
MCI_ADDR
|
MCACOD_DATA
),
...
...
@@ -170,6 +181,9 @@ static struct severity {
)
/* always matches. keep at end */
};
#define mc_recoverable(mcg) (((mcg) & (MCG_STATUS_RIPV|MCG_STATUS_EIPV)) == \
(MCG_STATUS_RIPV|MCG_STATUS_EIPV))
/*
* If mcgstatus indicated that ip/cs on the stack were
* no good, then "m->cs" will be zero and we will have
...
...
@@ -183,7 +197,11 @@ static struct severity {
*/
static
int
error_context
(
struct
mce
*
m
)
{
return
((
m
->
cs
&
3
)
==
3
)
?
IN_USER
:
IN_KERNEL
;
if
((
m
->
cs
&
3
)
==
3
)
return
IN_USER
;
if
(
mc_recoverable
(
m
->
mcgstatus
)
&&
ex_has_fault_handler
(
m
->
ip
))
return
IN_KERNEL_RECOV
;
return
IN_KERNEL
;
}
/*
...
...
arch/x86/kernel/cpu/mcheck/mce.c
View file @
319e305c
...
...
@@ -961,6 +961,20 @@ static void mce_clear_state(unsigned long *toclear)
}
}
static
int
do_memory_failure
(
struct
mce
*
m
)
{
int
flags
=
MF_ACTION_REQUIRED
;
int
ret
;
pr_err
(
"Uncorrected hardware memory error in user-access at %llx"
,
m
->
addr
);
if
(
!
(
m
->
mcgstatus
&
MCG_STATUS_RIPV
))
flags
|=
MF_MUST_KILL
;
ret
=
memory_failure
(
m
->
addr
>>
PAGE_SHIFT
,
MCE_VECTOR
,
flags
);
if
(
ret
)
pr_err
(
"Memory error not recovered"
);
return
ret
;
}
/*
* The actual machine check handler. This only handles real
* exceptions when something got corrupted coming in through int 18.
...
...
@@ -998,8 +1012,6 @@ void do_machine_check(struct pt_regs *regs, long error_code)
DECLARE_BITMAP
(
toclear
,
MAX_NR_BANKS
);
DECLARE_BITMAP
(
valid_banks
,
MAX_NR_BANKS
);
char
*
msg
=
"Unknown"
;
u64
recover_paddr
=
~
0ull
;
int
flags
=
MF_ACTION_REQUIRED
;
int
lmce
=
0
;
/* If this CPU is offline, just bail out. */
...
...
@@ -1136,22 +1148,13 @@ void do_machine_check(struct pt_regs *regs, long error_code)
}
/*
* At insane "tolerant" levels we take no action. Otherwise
* we only die if we have no other choice. For less serious
* issues we try to recover, or limit damage to the current
* process.
* If tolerant is at an insane level we drop requests to kill
* processes and continue even when there is no way out.
*/
if
(
cfg
->
tolerant
<
3
)
{
if
(
no_way_out
)
mce_panic
(
"Fatal machine check on current CPU"
,
&
m
,
msg
);
if
(
worst
==
MCE_AR_SEVERITY
)
{
recover_paddr
=
m
.
addr
;
if
(
!
(
m
.
mcgstatus
&
MCG_STATUS_RIPV
))
flags
|=
MF_MUST_KILL
;
}
else
if
(
kill_it
)
{
force_sig
(
SIGBUS
,
current
);
}
}
if
(
cfg
->
tolerant
==
3
)
kill_it
=
0
;
else
if
(
no_way_out
)
mce_panic
(
"Fatal machine check on current CPU"
,
&
m
,
msg
);
if
(
worst
>
0
)
mce_report_event
(
regs
);
...
...
@@ -1159,25 +1162,24 @@ void do_machine_check(struct pt_regs *regs, long error_code)
out:
sync_core
();
if
(
recover_paddr
==
~
0ull
)
goto
done
;
if
(
worst
!=
MCE_AR_SEVERITY
&&
!
kill_it
)
goto
out_ist
;
pr_err
(
"Uncorrected hardware memory error in user-access at %llx"
,
recover_paddr
);
/*
* We must call memory_failure() here even if the current process is
* doomed. We still need to mark the page as poisoned and alert any
* other users of the page.
*/
ist_begin_non_atomic
(
regs
);
local_irq_enable
();
if
(
memory_failure
(
recover_paddr
>>
PAGE_SHIFT
,
MCE_VECTOR
,
flags
)
<
0
)
{
pr_err
(
"Memory error not recovered"
);
force_sig
(
SIGBUS
,
current
);
/* Fault was in user mode and we need to take some action */
if
((
m
.
cs
&
3
)
==
3
)
{
ist_begin_non_atomic
(
regs
);
local_irq_enable
();
if
(
kill_it
||
do_memory_failure
(
&
m
))
force_sig
(
SIGBUS
,
current
);
local_irq_disable
(
);
ist_end_non_atomic
();
}
else
{
if
(
!
fixup_exception
(
regs
,
X86_TRAP_MC
))
mce_panic
(
"Failed kernel mode recovery"
,
&
m
,
NULL
);
}
local_irq_disable
();
ist_end_non_atomic
();
done:
out_ist:
ist_exit
(
regs
);
}
EXPORT_SYMBOL_GPL
(
do_machine_check
);
...
...
@@ -1628,10 +1630,10 @@ static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c)
case
X86_VENDOR_AMD
:
{
u32
ebx
=
cpuid_ebx
(
0x80000007
);
mce_amd_feature_init
(
c
);
mce_flags
.
overflow_recov
=
!!
(
ebx
&
BIT
(
0
));
mce_flags
.
succor
=
!!
(
ebx
&
BIT
(
1
));
mce_flags
.
smca
=
!!
(
ebx
&
BIT
(
3
));
mce_amd_feature_init
(
c
);
break
;
}
...
...
arch/x86/kernel/cpu/mcheck/mce_amd.c
View file @
319e305c
...
...
@@ -28,7 +28,7 @@
#include <asm/msr.h>
#include <asm/trace/irq_vectors.h>
#define NR_BLOCKS
9
#define NR_BLOCKS
5
#define THRESHOLD_MAX 0xFFF
#define INT_TYPE_APIC 0x00020000
#define MASK_VALID_HI 0x80000000
...
...
@@ -49,6 +49,19 @@
#define DEF_LVT_OFF 0x2
#define DEF_INT_TYPE_APIC 0x2
/* Scalable MCA: */
/* Threshold LVT offset is at MSR0xC0000410[15:12] */
#define SMCA_THR_LVT_OFF 0xF000
/*
* OS is required to set the MCAX bit to acknowledge that it is now using the
* new MSR ranges and new registers under each bank. It also means that the OS
* will configure deferred errors in the new MCx_CONFIG register. If the bit is
* not set, uncorrectable errors will cause a system panic.
*/
#define SMCA_MCAX_EN_OFF 0x1
static
const
char
*
const
th_names
[]
=
{
"load_store"
,
"insn_fetch"
,
...
...
@@ -84,6 +97,13 @@ struct thresh_restart {
static
inline
bool
is_shared_bank
(
int
bank
)
{
/*
* Scalable MCA provides for only one core to have access to the MSRs of
* a shared bank.
*/
if
(
mce_flags
.
smca
)
return
false
;
/* Bank 4 is for northbridge reporting and is thus shared */
return
(
bank
==
4
);
}
...
...
@@ -135,6 +155,14 @@ static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
}
if
(
apic
!=
msr
)
{
/*
* On SMCA CPUs, LVT offset is programmed at a different MSR, and
* the BIOS provides the value. The original field where LVT offset
* was set is reserved. Return early here:
*/
if
(
mce_flags
.
smca
)
return
0
;
pr_err
(
FW_BUG
"cpu %d, invalid threshold interrupt offset %d "
"for bank %d, block %d (MSR%08X=0x%x%08x)
\n
"
,
b
->
cpu
,
apic
,
b
->
bank
,
b
->
block
,
b
->
address
,
hi
,
lo
);
...
...
@@ -247,14 +275,65 @@ static void deferred_error_interrupt_enable(struct cpuinfo_x86 *c)
wrmsr
(
MSR_CU_DEF_ERR
,
low
,
high
);
}
static
int
prepare_threshold_block
(
unsigned
int
bank
,
unsigned
int
block
,
u32
addr
,
int
offset
,
u32
misc_high
)
{
unsigned
int
cpu
=
smp_processor_id
();
struct
threshold_block
b
;
int
new
;
if
(
!
block
)
per_cpu
(
bank_map
,
cpu
)
|=
(
1
<<
bank
);
memset
(
&
b
,
0
,
sizeof
(
b
));
b
.
cpu
=
cpu
;
b
.
bank
=
bank
;
b
.
block
=
block
;
b
.
address
=
addr
;
b
.
interrupt_capable
=
lvt_interrupt_supported
(
bank
,
misc_high
);
if
(
!
b
.
interrupt_capable
)
goto
done
;
b
.
interrupt_enable
=
1
;
if
(
mce_flags
.
smca
)
{
u32
smca_low
,
smca_high
;
u32
smca_addr
=
MSR_AMD64_SMCA_MCx_CONFIG
(
bank
);
if
(
!
rdmsr_safe
(
smca_addr
,
&
smca_low
,
&
smca_high
))
{
smca_high
|=
SMCA_MCAX_EN_OFF
;
wrmsr
(
smca_addr
,
smca_low
,
smca_high
);
}
/* Gather LVT offset for thresholding: */
if
(
rdmsr_safe
(
MSR_CU_DEF_ERR
,
&
smca_low
,
&
smca_high
))
goto
out
;
new
=
(
smca_low
&
SMCA_THR_LVT_OFF
)
>>
12
;
}
else
{
new
=
(
misc_high
&
MASK_LVTOFF_HI
)
>>
20
;
}
offset
=
setup_APIC_mce_threshold
(
offset
,
new
);
if
((
offset
==
new
)
&&
(
mce_threshold_vector
!=
amd_threshold_interrupt
))
mce_threshold_vector
=
amd_threshold_interrupt
;
done:
mce_threshold_block_init
(
&
b
,
offset
);
out:
return
offset
;
}
/* cpu init entry point, called from mce.c with preempt off */
void
mce_amd_feature_init
(
struct
cpuinfo_x86
*
c
)
{
struct
threshold_block
b
;
unsigned
int
cpu
=
smp_processor_id
();
u32
low
=
0
,
high
=
0
,
address
=
0
;
unsigned
int
bank
,
block
;
int
offset
=
-
1
,
new
;
int
offset
=
-
1
;
for
(
bank
=
0
;
bank
<
mca_cfg
.
banks
;
++
bank
)
{
for
(
block
=
0
;
block
<
NR_BLOCKS
;
++
block
)
{
...
...
@@ -279,29 +358,7 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
(
high
&
MASK_LOCKED_HI
))
continue
;
if
(
!
block
)
per_cpu
(
bank_map
,
cpu
)
|=
(
1
<<
bank
);
memset
(
&
b
,
0
,
sizeof
(
b
));
b
.
cpu
=
cpu
;
b
.
bank
=
bank
;
b
.
block
=
block
;
b
.
address
=
address
;
b
.
interrupt_capable
=
lvt_interrupt_supported
(
bank
,
high
);
if
(
!
b
.
interrupt_capable
)
goto
init
;
b
.
interrupt_enable
=
1
;
new
=
(
high
&
MASK_LVTOFF_HI
)
>>
20
;
offset
=
setup_APIC_mce_threshold
(
offset
,
new
);
if
((
offset
==
new
)
&&
(
mce_threshold_vector
!=
amd_threshold_interrupt
))
mce_threshold_vector
=
amd_threshold_interrupt
;
init:
mce_threshold_block_init
(
&
b
,
offset
);
offset
=
prepare_threshold_block
(
bank
,
block
,
address
,
offset
,
high
);
}
}
...
...
arch/x86/kernel/kprobes/core.c
View file @
319e305c
...
...
@@ -987,7 +987,7 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
* In case the user-specified fault handler returned
* zero, try to fix up.
*/
if
(
fixup_exception
(
regs
))
if
(
fixup_exception
(
regs
,
trapnr
))
return
1
;
/*
...
...
arch/x86/kernel/traps.c
View file @
319e305c
...
...
@@ -185,7 +185,7 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
}
if
(
!
user_mode
(
regs
))
{
if
(
!
fixup_exception
(
regs
))
{
if
(
!
fixup_exception
(
regs
,
trapnr
))
{
tsk
->
thread
.
error_code
=
error_code
;
tsk
->
thread
.
trap_nr
=
trapnr
;
die
(
str
,
regs
,
error_code
);
...
...
@@ -439,7 +439,7 @@ do_general_protection(struct pt_regs *regs, long error_code)
tsk
=
current
;
if
(
!
user_mode
(
regs
))
{
if
(
fixup_exception
(
regs
))
if
(
fixup_exception
(
regs
,
X86_TRAP_GP
))
return
;
tsk
->
thread
.
error_code
=
error_code
;
...
...
@@ -690,7 +690,7 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr)
cond_local_irq_enable
(
regs
);
if
(
!
user_mode
(
regs
))
{
if
(
!
fixup_exception
(
regs
))
{
if
(
!
fixup_exception
(
regs
,
trapnr
))
{
task
->
thread
.
error_code
=
error_code
;
task
->
thread
.
trap_nr
=
trapnr
;
die
(
str
,
regs
,
error_code
);
...
...
arch/x86/mm/extable.c
View file @
319e305c
...
...
@@ -3,6 +3,9 @@
#include <linux/sort.h>
#include <asm/uaccess.h>
typedef
bool
(
*
ex_handler_t
)(
const
struct
exception_table_entry
*
,
struct
pt_regs
*
,
int
);
static
inline
unsigned
long
ex_insn_addr
(
const
struct
exception_table_entry
*
x
)
{
...
...
@@ -13,11 +16,56 @@ ex_fixup_addr(const struct exception_table_entry *x)
{
return
(
unsigned
long
)
&
x
->
fixup
+
x
->
fixup
;
}
static
inline
ex_handler_t
ex_fixup_handler
(
const
struct
exception_table_entry
*
x
)
{
return
(
ex_handler_t
)((
unsigned
long
)
&
x
->
handler
+
x
->
handler
);
}
int
fixup_exception
(
struct
pt_regs
*
regs
)
bool
ex_handler_default
(
const
struct
exception_table_entry
*
fixup
,
struct
pt_regs
*
regs
,
int
trapnr
)
{
const
struct
exception_table_entry
*
fixup
;
unsigned
long
new_ip
;
regs
->
ip
=
ex_fixup_addr
(
fixup
);
return
true
;
}
EXPORT_SYMBOL
(
ex_handler_default
);
bool
ex_handler_fault
(
const
struct
exception_table_entry
*
fixup
,
struct
pt_regs
*
regs
,
int
trapnr
)
{
regs
->
ip
=
ex_fixup_addr
(
fixup
);
regs
->
ax
=
trapnr
;
return
true
;
}
EXPORT_SYMBOL_GPL
(
ex_handler_fault
);
bool
ex_handler_ext
(
const
struct
exception_table_entry
*
fixup
,
struct
pt_regs
*
regs
,
int
trapnr
)
{
/* Special hack for uaccess_err */
current_thread_info
()
->
uaccess_err
=
1
;
regs
->
ip
=
ex_fixup_addr
(
fixup
);
return
true
;
}
EXPORT_SYMBOL
(
ex_handler_ext
);
bool
ex_has_fault_handler
(
unsigned
long
ip
)
{
const
struct
exception_table_entry
*
e
;
ex_handler_t
handler
;
e
=
search_exception_tables
(
ip
);
if
(
!
e
)
return
false
;
handler
=
ex_fixup_handler
(
e
);
return
handler
==
ex_handler_fault
;
}
int
fixup_exception
(
struct
pt_regs
*
regs
,
int
trapnr
)
{
const
struct
exception_table_entry
*
e
;
ex_handler_t
handler
;
#ifdef CONFIG_PNPBIOS
if
(
unlikely
(
SEGMENT_IS_PNP_CODE
(
regs
->
cs
)))
{
...
...
@@ -33,42 +81,34 @@ int fixup_exception(struct pt_regs *regs)
}
#endif
fixup
=
search_exception_tables
(
regs
->
ip
);
if
(
fixup
)
{
new_ip
=
ex_fixup_addr
(
fixup
);
if
(
fixup
->
fixup
-
fixup
->
insn
>=
0x7ffffff0
-
4
)
{
/* Special hack for uaccess_err */
current_thread_info
()
->
uaccess_err
=
1
;
new_ip
-=
0x7ffffff0
;
}
regs
->
ip
=
new_ip
;
return
1
;
}
e
=
search_exception_tables
(
regs
->
ip
);
if
(
!
e
)
return
0
;
return
0
;
handler
=
ex_fixup_handler
(
e
);
return
handler
(
e
,
regs
,
trapnr
);
}
/* Restricted version used during very early boot */
int
__init
early_fixup_exception
(
unsigned
long
*
ip
)
{
const
struct
exception_table_entry
*
fixup
;
const
struct
exception_table_entry
*
e
;
unsigned
long
new_ip
;
ex_handler_t
handler
;
fixup
=
search_exception_tables
(
*
ip
);
if
(
fixup
)
{
new_ip
=
ex_fixup_addr
(
fixup
)
;
e
=
search_exception_tables
(
*
ip
);
if
(
!
e
)
return
0
;
if
(
fixup
->
fixup
-
fixup
->
insn
>=
0x7ffffff0
-
4
)
{
/* uaccess handling not supported during early boot */
return
0
;
}
new_ip
=
ex_fixup_addr
(
e
);
handler
=
ex_fixup_handler
(
e
);
*
ip
=
new_ip
;
return
1
;
}
/* special handling not supported during early boot */
if
(
handler
!=
ex_handler_default
)
return
0
;
return
0
;
*
ip
=
new_ip
;
return
1
;
}
/*
...
...
@@ -133,6 +173,8 @@ void sort_extable(struct exception_table_entry *start,
i
+=
4
;
p
->
fixup
+=
i
;
i
+=
4
;
p
->
handler
+=
i
;
i
+=
4
;
}
sort
(
start
,
finish
-
start
,
sizeof
(
struct
exception_table_entry
),
...
...
@@ -145,6 +187,8 @@ void sort_extable(struct exception_table_entry *start,
i
+=
4
;
p
->
fixup
-=
i
;
i
+=
4
;
p
->
handler
-=
i
;
i
+=
4
;
}
}
...
...
arch/x86/mm/fault.c
View file @
319e305c
...
...
@@ -663,7 +663,7 @@ no_context(struct pt_regs *regs, unsigned long error_code,
int
sig
;
/* Are we prepared to handle this kernel fault? */
if
(
fixup_exception
(
regs
))
{
if
(
fixup_exception
(
regs
,
X86_TRAP_PF
))
{
/*
* Any interrupt that takes a fault gets the fixup. This makes
* the below recursive fault logic only apply to a faults from
...
...
scripts/sortextable.c
View file @
319e305c
...
...
@@ -209,6 +209,35 @@ static int compare_relative_table(const void *a, const void *b)
return
0
;
}
static
void
x86_sort_relative_table
(
char
*
extab_image
,
int
image_size
)
{
int
i
;
i
=
0
;
while
(
i
<
image_size
)
{
uint32_t
*
loc
=
(
uint32_t
*
)(
extab_image
+
i
);
w
(
r
(
loc
)
+
i
,
loc
);
w
(
r
(
loc
+
1
)
+
i
+
4
,
loc
+
1
);
w
(
r
(
loc
+
2
)
+
i
+
8
,
loc
+
2
);
i
+=
sizeof
(
uint32_t
)
*
3
;
}
qsort
(
extab_image
,
image_size
/
12
,
12
,
compare_relative_table
);
i
=
0
;
while
(
i
<
image_size
)
{
uint32_t
*
loc
=
(
uint32_t
*
)(
extab_image
+
i
);
w
(
r
(
loc
)
-
i
,
loc
);
w
(
r
(
loc
+
1
)
-
(
i
+
4
),
loc
+
1
);
w
(
r
(
loc
+
2
)
-
(
i
+
8
),
loc
+
2
);
i
+=
sizeof
(
uint32_t
)
*
3
;
}
}
static
void
sort_relative_table
(
char
*
extab_image
,
int
image_size
)
{
int
i
;
...
...
@@ -281,6 +310,9 @@ do_file(char const *const fname)
break
;
case
EM_386
:
case
EM_X86_64
:
custom_sort
=
x86_sort_relative_table
;
break
;
case
EM_S390
:
custom_sort
=
sort_relative_table
;
break
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment