Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 305459
b: refs/heads/master
c: 7062765
h: refs/heads/master
i:
  305457: c8fd2da
  305455: 63ab68e
v: v3
  • Loading branch information
H. Peter Anvin committed Apr 21, 2012
1 parent 04a7603 commit 87473ab
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 23 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: fa574a48a1e9706bba38188d3bf61ecb66546a77
refs/heads/master: 706276543b699d80f546e45f8b12574e7b18d952
20 changes: 12 additions & 8 deletions trunk/arch/x86/include/asm/asm.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,30 @@
#ifdef __ASSEMBLY__
# define _ASM_EXTABLE(from,to) \
.pushsection "__ex_table","a" ; \
_ASM_ALIGN ; \
_ASM_PTR from , to ; \
.balign 8 ; \
.long (from) - . ; \
.long (to) - . ; \
.popsection

# define _ASM_EXTABLE_EX(from,to) \
.pushsection "__ex_table","a" ; \
_ASM_ALIGN ; \
_ASM_PTR from , (to) - (from) ; \
.balign 8 ; \
.long (from) - . ; \
.long (to) - . + 0x7ffffff0 ; \
.popsection
#else
# define _ASM_EXTABLE(from,to) \
" .pushsection \"__ex_table\",\"a\"\n" \
_ASM_ALIGN "\n" \
_ASM_PTR #from "," #to "\n" \
" .balign 8\n" \
" .long (" #from ") - .\n" \
" .long (" #to ") - .\n" \
" .popsection\n"

# define _ASM_EXTABLE_EX(from,to) \
" .pushsection \"__ex_table\",\"a\"\n" \
_ASM_ALIGN "\n" \
_ASM_PTR #from ",(" #to ")-(" #from ")\n" \
" .balign 8\n" \
" .long (" #from ") - .\n" \
" .long (" #to ") - . + 0x7ffffff0\n" \
" .popsection\n"
#endif

Expand Down
17 changes: 11 additions & 6 deletions trunk/arch/x86/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,12 @@
#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0))

/*
* The exception table consists of pairs of addresses: 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 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.
*
* 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,
Expand All @@ -92,10 +93,14 @@
*/

struct exception_table_entry {
unsigned long insn, fixup;
int insn, fixup;
};
/* 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 early_fixup_exception(unsigned long *ip);

/*
* These are the main single-value transfer routines. They automatically
Expand Down
131 changes: 123 additions & 8 deletions trunk/arch/x86/mm/extable.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/sort.h>
#include <asm/uaccess.h>

static inline unsigned long
ex_insn_addr(const struct exception_table_entry *x)
{
return (unsigned long)&x->insn + x->insn;
}
static inline unsigned long
ex_fixup_addr(const struct exception_table_entry *x)
{
return (unsigned long)&x->fixup + x->fixup;
}

int fixup_exception(struct pt_regs *regs)
{
const struct exception_table_entry *fixup;
unsigned long new_ip;

#ifdef CONFIG_PNPBIOS
if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) {
Expand All @@ -23,13 +35,14 @@ int fixup_exception(struct pt_regs *regs)

fixup = search_exception_tables(regs->ip);
if (fixup) {
/* If fixup is less than 16, it means uaccess error */
if (fixup->fixup < 16) {
new_ip = ex_fixup_addr(fixup);

if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) {
/* Special hack for uaccess_err */
current_thread_info()->uaccess_err = 1;
regs->ip += fixup->fixup;
return 1;
new_ip -= 0x7ffffff0;
}
regs->ip = fixup->fixup;
regs->ip = new_ip;
return 1;
}

Expand All @@ -40,15 +53,117 @@ int fixup_exception(struct pt_regs *regs)
int __init early_fixup_exception(unsigned long *ip)
{
const struct exception_table_entry *fixup;
unsigned long new_ip;

fixup = search_exception_tables(*ip);
if (fixup) {
if (fixup->fixup < 16)
return 0; /* Not supported during early boot */
new_ip = ex_fixup_addr(fixup);

if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) {
/* uaccess handling not supported during early boot */
return 0;
}

*ip = fixup->fixup;
*ip = new_ip;
return 1;
}

return 0;
}

/*
* Search one exception table for an entry corresponding to the
* given instruction address, and return the address of the entry,
* or NULL if none is found.
* We use a binary search, and thus we assume that the table is
* already sorted.
*/
const struct exception_table_entry *
search_extable(const struct exception_table_entry *first,
const struct exception_table_entry *last,
unsigned long value)
{
while (first <= last) {
const struct exception_table_entry *mid;
unsigned long addr;

mid = ((last - first) >> 1) + first;
addr = ex_insn_addr(mid);
if (addr < value)
first = mid + 1;
else if (addr > value)
last = mid - 1;
else
return mid;
}
return NULL;
}

/*
* The exception table needs to be sorted so that the binary
* search that we use to find entries in it works properly.
* This is used both for the kernel exception table and for
* the exception tables of modules that get loaded.
*
*/
static int cmp_ex(const void *a, const void *b)
{
const struct exception_table_entry *x = a, *y = b;

/*
* This value will always end up fittin in an int, because on
* both i386 and x86-64 the kernel symbol-reachable address
* space is < 2 GiB.
*
* This compare is only valid after normalization.
*/
return x->insn - y->insn;
}

void sort_extable(struct exception_table_entry *start,
struct exception_table_entry *finish)
{
struct exception_table_entry *p;
int i;

/* Convert all entries to being relative to the start of the section */
i = 0;
for (p = start; p < finish; p++) {
p->insn += i;
i += 4;
p->fixup += i;
i += 4;
}

sort(start, finish - start, sizeof(struct exception_table_entry),
cmp_ex, NULL);

/* Denormalize all entries */
i = 0;
for (p = start; p < finish; p++) {
p->insn -= i;
i += 4;
p->fixup -= i;
i += 4;
}
}

#ifdef CONFIG_MODULES
/*
* If the exception table is sorted, any referring to the module init
* will be at the beginning or the end.
*/
void trim_init_extable(struct module *m)
{
/*trim the beginning*/
while (m->num_exentries &&
within_module_init(ex_insn_addr(&m->extable[0]), m)) {
m->extable++;
m->num_exentries--;
}
/*trim the end*/
while (m->num_exentries &&
within_module_init(ex_insn_addr(&m->extable[m->num_exentries-1]), m))
m->num_exentries--;
}
#endif /* CONFIG_MODULES */

0 comments on commit 87473ab

Please sign in to comment.