unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf, unsigned long addr, unsigned len) { void *opfunc = get_call_destination(type); unsigned ret; if (opfunc == NULL) /* If there's no function, patch it with a ud2a (BUG) */ ret = paravirt_patch_insns(insnbuf, len, ud2a, ud2a+sizeof(ud2a)); else if (opfunc == _paravirt_nop) /* If the operation is a nop, then nop the callsite */ ret = paravirt_patch_nop(); /* identity functions just return their single argument */ else if (opfunc == _paravirt_ident_32) ret = paravirt_patch_ident_32(insnbuf, len); else if (opfunc == _paravirt_ident_64) ret = paravirt_patch_ident_64(insnbuf, len); else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) || #ifdef CONFIG_X86_32 type == PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit) || #endif type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret32) || type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret64)) /* If operation requires a jmp, then jmp */ ret = paravirt_patch_jmp(insnbuf, opfunc, addr, len); else /* Otherwise call the function; assume target could clobber any caller-save reg */ ret = paravirt_patch_call(insnbuf, opfunc, CLBR_ANY, addr, clobbers, len); return ret; }
static unsigned native_patch(u8 type, u16 clobbers, void *ibuf, unsigned long addr, unsigned 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(ibuf, 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, ibuf, addr, len); break; } return ret; }
unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf, unsigned long addr, unsigned len) { void *opfunc = *((void **)¶virt_ops + type); unsigned ret; if (opfunc == NULL) /* If there's no function, patch it with a ud2a (BUG) */ ret = paravirt_patch_insns(insnbuf, 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, insnbuf, addr, len); else /* Otherwise call the function; assume target could clobber any caller-save reg */ ret = paravirt_patch_call(insnbuf, opfunc, CLBR_ANY, addr, clobbers, len); return ret; }