Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 53862
b: refs/heads/master
c: 63f7027
h: refs/heads/master
v: v3
  • Loading branch information
Jeremy Fitzhardinge authored and Andi Kleen committed May 2, 2007
1 parent e767281 commit 0ee57b2
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 28 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: 294688c028e80fd467cdd22da79f62c5f311eaf5
refs/heads/master: 63f70270ccd981ce40a8ff58c03a8c2e97e368be
5 changes: 4 additions & 1 deletion trunk/arch/i386/kernel/alternative.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,11 +336,14 @@ void apply_paravirt(struct paravirt_patch_site *start,
used = paravirt_ops.patch(p->instrtype, p->clobbers, p->instr,
p->len);

BUG_ON(used > p->len);

/* Pad the rest with nops */
nop_out(p->instr + used, p->len - used);
}

/* Sync to be conservative, in case we patched following instructions */
/* Sync to be conservative, in case we patched following
* instructions */
sync_core();
}
extern struct paravirt_patch_site __start_parainstructions[],
Expand Down
154 changes: 128 additions & 26 deletions trunk/arch/i386/kernel/paravirt.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,40 +54,142 @@ char *memory_setup(void)
#define DEF_NATIVE(name, code) \
extern const char start_##name[], end_##name[]; \
asm("start_" #name ": " code "; end_" #name ":")
DEF_NATIVE(cli, "cli");
DEF_NATIVE(sti, "sti");
DEF_NATIVE(popf, "push %eax; popf");
DEF_NATIVE(pushf, "pushf; pop %eax");

DEF_NATIVE(irq_disable, "cli");
DEF_NATIVE(irq_enable, "sti");
DEF_NATIVE(restore_fl, "push %eax; popf");
DEF_NATIVE(save_fl, "pushf; pop %eax");
DEF_NATIVE(iret, "iret");
DEF_NATIVE(sti_sysexit, "sti; sysexit");
DEF_NATIVE(irq_enable_sysexit, "sti; sysexit");
DEF_NATIVE(read_cr2, "mov %cr2, %eax");
DEF_NATIVE(write_cr3, "mov %eax, %cr3");
DEF_NATIVE(read_cr3, "mov %cr3, %eax");
DEF_NATIVE(clts, "clts");
DEF_NATIVE(read_tsc, "rdtsc");

static const struct native_insns
{
const char *start, *end;
} native_insns[] = {
[PARAVIRT_PATCH(irq_disable)] = { start_cli, end_cli },
[PARAVIRT_PATCH(irq_enable)] = { start_sti, end_sti },
[PARAVIRT_PATCH(restore_fl)] = { start_popf, end_popf },
[PARAVIRT_PATCH(save_fl)] = { start_pushf, end_pushf },
[PARAVIRT_PATCH(iret)] = { start_iret, end_iret },
[PARAVIRT_PATCH(irq_enable_sysexit)] = { start_sti_sysexit, end_sti_sysexit },
};
DEF_NATIVE(ud2a, "ud2a");

static unsigned native_patch(u8 type, u16 clobbers, void *insns, unsigned len)
{
unsigned int insn_len;
const unsigned char *start, *end;
unsigned ret;

switch(type) {
#define SITE(x) case PARAVIRT_PATCH(x): start = start_##x; end = end_##x; goto patch_site
SITE(irq_disable);
SITE(irq_enable);
SITE(restore_fl);
SITE(save_fl);
SITE(iret);
SITE(irq_enable_sysexit);
SITE(read_cr2);
SITE(read_cr3);
SITE(write_cr3);
SITE(clts);
SITE(read_tsc);
#undef SITE

patch_site:
ret = paravirt_patch_insns(insns, len, start, end);
break;

case PARAVIRT_PATCH(make_pgd):
case PARAVIRT_PATCH(make_pte):
case PARAVIRT_PATCH(pgd_val):
case PARAVIRT_PATCH(pte_val):
#ifdef CONFIG_X86_PAE
case PARAVIRT_PATCH(make_pmd):
case PARAVIRT_PATCH(pmd_val):
#endif
/* These functions end up returning exactly what
they're passed, in the same registers. */
ret = paravirt_patch_nop();
break;

default:
ret = paravirt_patch_default(type, clobbers, insns, len);
break;
}

return ret;
}

unsigned paravirt_patch_nop(void)
{
return 0;
}

unsigned paravirt_patch_ignore(unsigned len)
{
return len;
}

unsigned paravirt_patch_call(void *target, u16 tgt_clobbers,
void *site, u16 site_clobbers,
unsigned len)
{
unsigned char *call = site;
unsigned long delta = (unsigned long)target - (unsigned long)(call+5);

if (tgt_clobbers & ~site_clobbers)
return len; /* target would clobber too much for this site */
if (len < 5)
return len; /* call too long for patch site */

*call++ = 0xe8; /* call */
*(unsigned long *)call = delta;

return 5;
}

unsigned paravirt_patch_jmp(void *target, void *site, unsigned len)
{
unsigned char *jmp = site;
unsigned long delta = (unsigned long)target - (unsigned long)(jmp+5);

/* Don't touch it if we don't have a replacement */
if (type >= ARRAY_SIZE(native_insns) || !native_insns[type].start)
return len;
if (len < 5)
return len; /* call too long for patch site */

insn_len = native_insns[type].end - native_insns[type].start;
*jmp++ = 0xe9; /* jmp */
*(unsigned long *)jmp = delta;

return 5;
}

unsigned paravirt_patch_default(u8 type, u16 clobbers, void *site, unsigned len)
{
void *opfunc = *((void **)&paravirt_ops + type);
unsigned ret;

if (opfunc == NULL)
/* If there's no function, patch it with a ud2a (BUG) */
ret = paravirt_patch_insns(site, len, start_ud2a, end_ud2a);
else if (opfunc == paravirt_nop)
/* If the operation is a nop, then nop the callsite */
ret = paravirt_patch_nop();
else if (type == PARAVIRT_PATCH(iret) ||
type == PARAVIRT_PATCH(irq_enable_sysexit))
/* If operation requires a jmp, then jmp */
ret = paravirt_patch_jmp(opfunc, site, len);
else
/* Otherwise call the function; assume target could
clobber any caller-save reg */
ret = paravirt_patch_call(opfunc, CLBR_ANY,
site, clobbers, len);

return ret;
}

unsigned paravirt_patch_insns(void *site, unsigned len,
const char *start, const char *end)
{
unsigned insn_len = end - start;

/* Similarly if we can't fit replacement. */
if (len < insn_len)
return len;
if (insn_len > len || start == NULL)
insn_len = len;
else
memcpy(site, start, insn_len);

memcpy(insns, native_insns[type].start, insn_len);
return insn_len;
}

Expand All @@ -110,7 +212,7 @@ static void native_flush_tlb_global(void)
__native_flush_tlb_global();
}

static void native_flush_tlb_single(u32 addr)
static void native_flush_tlb_single(unsigned long addr)
{
__native_flush_tlb_single(addr);
}
Expand Down
12 changes: 12 additions & 0 deletions trunk/include/asm-i386/paravirt.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,18 @@ extern struct paravirt_ops paravirt_ops;
#define paravirt_alt(insn_string) \
_paravirt_alt(insn_string, "%c[paravirt_typenum]", "%c[paravirt_clobber]")

unsigned paravirt_patch_nop(void);
unsigned paravirt_patch_ignore(unsigned len);
unsigned paravirt_patch_call(void *target, u16 tgt_clobbers,
void *site, u16 site_clobbers,
unsigned len);
unsigned paravirt_patch_jmp(void *target, void *site, unsigned len);
unsigned paravirt_patch_default(u8 type, u16 clobbers, void *site, unsigned len);

unsigned paravirt_patch_insns(void *site, unsigned len,
const char *start, const char *end);


/*
* This generates an indirect call based on the operation type number.
* The type number, computed in PARAVIRT_PATCH, is derived from the
Expand Down

0 comments on commit 0ee57b2

Please sign in to comment.