Skip to content

Commit e9ce129

Browse files
committed
Function: Added the initial extable framework.
Signed-off-by: John Sanpe <[email protected]>
1 parent 0f0cf84 commit e9ce129

File tree

14 files changed

+216
-9
lines changed

14 files changed

+216
-9
lines changed

arch/x86/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# SPDX-License-Identifier: GPL-2.0-or-later
22
obj-y += boot/ lib/ mm/
33
obj-y += setup.o nmi.o
4-
obj-y += idt.o irq.o traps.o
4+
obj-y += idt.o irq.o traps.o extable.o
55
obj-y += e820.o tsc.o syscall.o
66
obj-y += earlycon-vga.o earlycon-serial.o
77

arch/x86/extable.c

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/*
3+
* Copyright(c) 2022 Sanpe <[email protected]>
4+
*/
5+
6+
#include <bitfield.h>
7+
#include <once.h>
8+
#include <crash.h>
9+
#include <extable.h>
10+
11+
static inline void
12+
extable_handler_generic(struct regs *regs, struct extable_entry *extable)
13+
{
14+
unsigned int flags = FIELD_GET(EXTABLE_FLAG_MASK, extable->data);
15+
16+
if (flags & EXTABLE_FLAG_CLEAR_AX)
17+
regs->ax = 0;
18+
19+
if (flags & EXTABLE_FLAG_CLEAR_DX)
20+
regs->dx = 0;
21+
22+
regs->ip = extable->fixup;
23+
}
24+
25+
static inline void
26+
extable_handler_msr(struct regs *regs, struct extable_entry *extable,
27+
bool safe, bool wrmsr, unsigned int reg)
28+
{
29+
if (DO_ONCE_DONE(!safe && !wrmsr)) {
30+
pr_warn("unchecked msr access error: rdmsr form %#010x\n",
31+
(unsigned int)regs->cx);
32+
}
33+
34+
if (DO_ONCE_DONE(!safe && wrmsr)) {
35+
pr_warn("unchecked msr access error: WDMSR to %#010x (tried to write %#010x%08x)\n",
36+
(unsigned int)regs->cx, (unsigned int)regs->dx,
37+
(unsigned int)regs->ax);
38+
}
39+
40+
if (!wrmsr) {
41+
regs->ax = 0;
42+
regs->dx = 0;
43+
}
44+
45+
extable_handler_generic(regs, extable);
46+
}
47+
48+
void extable_fixup(struct regs *regs, struct extable_entry *extable)
49+
{
50+
unsigned int type, reg;
51+
52+
type = FIELD_GET(EXTABLE_TYPE_MASK, extable->data);
53+
reg = FIELD_GET(EXTABLE_REG_MASK, extable->data);
54+
55+
switch (type) {
56+
case EXTABLE_TYPE_RDMSR:
57+
extable_handler_msr(regs, extable, false, false, reg);
58+
break;
59+
60+
case EXTABLE_TYPE_WRMSR:
61+
extable_handler_msr(regs, extable, false, true, reg);
62+
break;
63+
64+
case EXTABLE_TYPE_RDMSR_SAFE:
65+
extable_handler_msr(regs, extable, true, false, reg);
66+
break;
67+
68+
case EXTABLE_TYPE_WRMSR_SAFE:
69+
extable_handler_msr(regs, extable, true, true, reg);
70+
break;
71+
72+
default:
73+
BUG();
74+
}
75+
}

arch/x86/include/asm/extable.h

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
#ifndef _ASM_X86_EXTABLE_H_
3+
#define _ASM_X86_EXTABLE_H_
4+
5+
#define EXTABLE_TYPE_SHIFT 0
6+
#define EXTABLE_REG_SHIFT 8
7+
#define EXTABLE_FLAG_SHIFT 12
8+
#define EXTABLE_IMM_SHIFT 16
9+
10+
#define EXTABLE_TYPE_MASK 0x000000ff
11+
#define EXTABLE_REG_MASK 0x00000f00
12+
#define EXTABLE_FLAG_MASK 0x0000f000
13+
#define EXTABLE_IMM_MASK 0xffff0000
14+
15+
/* extable types */
16+
#define EXTABLE_TYPE_NONE (0 << EXTABLE_TYPE_SHIFT)
17+
#define EXTABLE_TYPE_DEFAULT (1 << EXTABLE_TYPE_SHIFT)
18+
#define EXTABLE_TYPE_FAULT (2 << EXTABLE_TYPE_SHIFT)
19+
#define EXTABLE_TYPE_UACCESS (3 << EXTABLE_TYPE_SHIFT)
20+
#define EXTABLE_TYPE_COPY (4 << EXTABLE_TYPE_SHIFT)
21+
#define EXTABLE_TYPE_CLEAR_FS (5 << EXTABLE_TYPE_SHIFT)
22+
#define EXTABLE_TYPE_FPU_RESTORE (6 << EXTABLE_TYPE_SHIFT)
23+
#define EXTABLE_TYPE_BPF (7 << EXTABLE_TYPE_SHIFT)
24+
#define EXTABLE_TYPE_RDMSR (8 << EXTABLE_TYPE_SHIFT)
25+
#define EXTABLE_TYPE_WRMSR (9 << EXTABLE_TYPE_SHIFT)
26+
#define EXTABLE_TYPE_RDMSR_SAFE (10 << EXTABLE_TYPE_SHIFT)
27+
#define EXTABLE_TYPE_WRMSR_SAFE (11 << EXTABLE_TYPE_SHIFT)
28+
29+
/* extable flags */
30+
#define EXTABLE_FLAG_CLEAR_AX (1 << EXTABLE_FLAG_SHIFT)
31+
#define EXTABLE_FLAG_CLEAR_DX (2 << EXTABLE_FLAG_SHIFT)
32+
#define EXTABLE_FLAG_CLEAR_AXDX (3 << EXTABLE_FLAG_SHIFT)
33+
34+
#include <asm-generic/extable.h>
35+
36+
#endif /* _ASM_X86_EXTABLE_H_ */

arch/x86/include/asm/regs.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <stddef.h>
1111
#include <limits.h>
1212
#include <asm/asm.h>
13+
#include <asm/extable.h>
1314
#include <arch/x86/regs.h>
1415
#include <arch/x86/cpuid.h>
1516
#include <arch/x86/msr.h>
@@ -193,7 +194,9 @@ static inline uint64_t msr_get(unsigned int msr)
193194
DECLARE_ARGS(val, low, high);
194195

195196
asm volatile (
196-
"rdmsr\n"
197+
"1: rdmsr \n"
198+
"2: \n"
199+
EXTABLE_ASM(1b, 2b, EXTABLE_TYPE_RDMSR)
197200
: EAX_EDX_RET(val, low, high)
198201
: "c" (msr)
199202
);
@@ -209,7 +212,9 @@ static inline void msr_set(unsigned int msr, uint64_t val)
209212
high = val >> 32;
210213

211214
asm volatile (
212-
"1: wrmsr\n"
215+
"1: wrmsr \n"
216+
"2: \n"
217+
EXTABLE_ASM(1b, 2b, EXTABLE_TYPE_WRMSR)
213218
:: "c"(msr), "a"(low), "d"(high)
214219
: "memory"
215220
);

arch/x86/include/asm/traps.h

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <asm/regs.h>
66
#include <asm/segment.h>
7+
#include <extable.h>
78

89
static inline bool trap_v8086_mode(struct regs *regs)
910
{
@@ -23,4 +24,6 @@ static inline bool trap_user_mode(struct regs *regs)
2324
#endif
2425
}
2526

27+
extern void extable_fixup(struct regs *regs, struct extable_entry *extable);
28+
2629
#endif /* _ASM_X86_TRAPS_H_ */

arch/x86/traps.c

+7
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,20 @@ static bool trap_crash(struct regs *regs)
4242
static bool kernel_trap(struct regs *regs, unsigned long error_code,
4343
unsigned long vector, const char *type)
4444
{
45+
struct extable_entry *extable;
46+
4547
if (trap_v8086_mode(regs)) {
4648
if (vector < TRAP_UD) {
4749
return true;
4850
}
4951
} else if (trap_user_mode(regs)) {
5052
return true;
5153
} else { /* kernel mode */
54+
if ((extable = extable_find(regs->ip))) {
55+
extable_fixup(regs, extable);
56+
return true;
57+
}
58+
5259
oops(regs, error_code, type);
5360
}
5461

include/asm-generic/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mandatory-y += barrier.h
44
mandatory-y += bitops.h
55
mandatory-y += bug.h
66
mandatory-y += errno.h
7+
mandatory-y += extable.h
78
mandatory-y += delay.h
89
mandatory-y += io.h
910
mandatory-y += linkage.h

include/asm-generic/extable.h

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
#ifndef _ASM_GENERIC_EXTABLE_H_
3+
#define _ASM_GENERIC_EXTABLE_H_
4+
5+
#include <types.h>
6+
#include <stddef.h>
7+
8+
#ifndef __ASSEMBLY__
9+
10+
struct extable_entry {
11+
uintptr_t addr;
12+
uintptr_t fixup;
13+
unsigned int data;
14+
};
15+
16+
#ifndef EXTABLE_ASM
17+
# define EXTABLE_ASM(addr, fixup, data) \
18+
".pushsection .data.extable, \"aw\" \n" \
19+
" .long " __stringify(addr) " \n" \
20+
" .long " __stringify(fixup) " \n" \
21+
" .int " __stringify(data) " \n" \
22+
".popsection \n"
23+
#endif
24+
25+
#endif /* __ASSEMBLY__ */
26+
#endif /* _ASM_GENERIC_EXTABLE_H_ */

include/asm-generic/kernel.lds.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,9 @@
169169

170170
#define EXCEPTION_TABLE(align) \
171171
. = ALIGN(align); \
172-
_ld_extable_start = .; \
173-
KEEP(*(.extable)) \
174-
_ld_extable_end = .;
172+
_ld_data_extable_start = .; \
173+
KEEP(*(.data.extable)) \
174+
_ld_data_extable_end = .;
175175

176176
#define ONCE_TABLE(align) \
177177
. = ALIGN(align); \

include/extable.h

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
#ifndef _EXTABLE_H_
3+
#define _EXTABLE_H_
4+
5+
#include <asm/extable.h>
6+
7+
extern struct extable_entry *extable_find(uintptr_t addr);
8+
extern void __init extable_init(void);
9+
10+
#endif /* _EXTABLE_H_ */

include/sections.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ extern void *_ld_reserve_end[];
2929

3030
extern void *_ld_data_bug_table_start[];
3131
extern void *_ld_data_bug_table_end[];
32-
extern void *_ld_extable_start[];
33-
extern void *_ld_extable_end[];
32+
extern void *_ld_data_extable_start[];
33+
extern void *_ld_data_extable_end[];
3434

3535
#ifdef CONFIG_BUILTIN_DTB
3636
extern void *_ld_init_dtb_start[];

init/start.c

+3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <logo.h>
2525
#include <console.h>
2626
#include <printk.h>
27+
#include <extable.h>
2728
#include <panic.h>
2829

2930
#include <driver/clk.h>
@@ -72,6 +73,8 @@ asmlinkage __visible __init __noreturn void kernel_start(void)
7273
earlyargs_init(boot_args);
7374

7475
crash_init();
76+
extable_init();
77+
7578
mem_init();
7679
idr_init();
7780
lrc_init();

kernel/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ obj-y += printk/ binfmt/ time/
55
obj-y += namespace/ task/
66
obj-y += kthread.o kcoro.o entry.o
77
obj-y += notifier.o pevent.o
8-
obj-y += crash.o panic.o
8+
obj-y += crash.o extable.o panic.o
99
obj-y += syscall.o random.o
1010
obj-y += resource.o power.o
1111
obj-$(CONFIG_UBSAN) += ubsan.o

kernel/extable.c

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/*
3+
* Copyright(c) 2022 Sanpe <[email protected]>
4+
*/
5+
6+
#include <extable.h>
7+
#include <sort.h>
8+
#include <bsearch.h>
9+
#include <sections.h>
10+
11+
static long extable_search(const void *key, void *pdata)
12+
{
13+
const struct extable_entry *extable = key;
14+
uintptr_t addr = (uintptr_t)pdata;
15+
if (extable->addr == addr) return 0;
16+
return extable->addr > addr ? 1 : -1;
17+
}
18+
19+
static long extable_sort(const void *nodea, const void *nodeb, void *pdata)
20+
{
21+
const struct extable_entry *extablea = nodea;
22+
const struct extable_entry *extableb = nodeb;
23+
if (extablea->addr == extableb->addr) return 0;
24+
return extablea->addr > extableb->addr ? 1 : -1;
25+
}
26+
27+
struct extable_entry *extable_find(uintptr_t addr)
28+
{
29+
struct extable_entry *walk;
30+
walk = bsearch(_ld_data_extable_start, ((uintptr_t)_ld_data_extable_end -
31+
(uintptr_t)_ld_data_extable_start) / sizeof(struct extable_entry),
32+
sizeof(struct extable_entry), extable_search, (void *)addr);
33+
return walk;
34+
}
35+
36+
void __init extable_init(void)
37+
{
38+
qsort(_ld_data_extable_start, ((uintptr_t)_ld_data_extable_end -
39+
(uintptr_t)_ld_data_extable_start) / sizeof(struct extable_entry),
40+
sizeof(struct extable_entry), extable_sort, NULL);
41+
}

0 commit comments

Comments
 (0)