unsigned native_patch(u8 type, u16 clobbers, void *ibuf, unsigned long addr, unsigned len) { const unsigned char *start, *end; unsigned ret; #define PATCH_SITE(ops, x) \ case PARAVIRT_PATCH(ops.x): \ start = start_##ops##_##x; \ end = end_##ops##_##x; \ goto patch_site switch(type) { PATCH_SITE(pv_irq_ops, irq_disable); PATCH_SITE(pv_irq_ops, irq_enable); PATCH_SITE(pv_irq_ops, restore_fl); PATCH_SITE(pv_irq_ops, save_fl); PATCH_SITE(pv_cpu_ops, iret); PATCH_SITE(pv_cpu_ops, irq_enable_syscall_ret); PATCH_SITE(pv_mmu_ops, read_cr2); PATCH_SITE(pv_mmu_ops, read_cr3); PATCH_SITE(pv_mmu_ops, write_cr3); PATCH_SITE(pv_cpu_ops, clts); PATCH_SITE(pv_cpu_ops, read_tsc); patch_site: ret = paravirt_patch_insns(ibuf, len, start, end); break; default: ret = paravirt_patch_default(type, clobbers, ibuf, addr, len); break; } #undef PATCH_SITE return ret; }
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 xen_patch(u8 type, u16 clobbers, void *insnbuf, unsigned long addr, unsigned len) { char *start, *end, *reloc; unsigned ret; start = end = reloc = NULL; #define SITE(op, x) \ case PARAVIRT_PATCH(op.x): \ if (have_vcpu_info_placement) { \ start = (char *)xen_##x##_direct; \ end = xen_##x##_direct_end; \ reloc = xen_##x##_direct_reloc; \ } \ goto patch_site switch (type) { SITE(pv_irq_ops, irq_enable); SITE(pv_irq_ops, irq_disable); SITE(pv_irq_ops, save_fl); SITE(pv_irq_ops, restore_fl); #undef SITE patch_site: if (start == NULL || (end-start) > len) goto default_patch; ret = paravirt_patch_insns(insnbuf, len, start, end); /* Note: because reloc is assigned from something that appears to be an array, gcc assumes it's non-null, but doesn't know its relationship with start and end. */ if (reloc > start && reloc < end) { int reloc_off = reloc - start; long *relocp = (long *)(insnbuf + reloc_off); long delta = start - (char *)addr; *relocp += delta; } break; default_patch: default: ret = paravirt_patch_default(type, clobbers, insnbuf, addr, len); break; } return ret; }
unsigned native_patch(u8 type, u16 clobbers, void *ibuf, unsigned long addr, unsigned len) { const unsigned char *start, *end; unsigned ret; #define PATCH_SITE(ops, x) \ case PARAVIRT_PATCH(ops.x): \ start = start_##ops##_##x; \ end = end_##ops##_##x; \ goto patch_site switch (type) { PATCH_SITE(pv_irq_ops, irq_disable); PATCH_SITE(pv_irq_ops, irq_enable); PATCH_SITE(pv_irq_ops, restore_fl); PATCH_SITE(pv_irq_ops, save_fl); PATCH_SITE(pv_cpu_ops, iret); PATCH_SITE(pv_mmu_ops, read_cr2); PATCH_SITE(pv_mmu_ops, read_cr3); PATCH_SITE(pv_mmu_ops, write_cr3); PATCH_SITE(pv_cpu_ops, clts); #if defined(CONFIG_PARAVIRT_SPINLOCKS) case PARAVIRT_PATCH(pv_lock_ops.queued_spin_unlock): if (pv_is_native_spin_unlock()) { start = start_pv_lock_ops_queued_spin_unlock; end = end_pv_lock_ops_queued_spin_unlock; goto patch_site; } goto patch_default; case PARAVIRT_PATCH(pv_lock_ops.vcpu_is_preempted): if (pv_is_native_vcpu_is_preempted()) { start = start_pv_lock_ops_vcpu_is_preempted; end = end_pv_lock_ops_vcpu_is_preempted; goto patch_site; } goto patch_default; #endif default: patch_default: ret = paravirt_patch_default(type, clobbers, ibuf, addr, len); break; patch_site: ret = paravirt_patch_insns(ibuf, len, start, end); break; } #undef PATCH_SITE return ret; }
static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf, unsigned long addr, unsigned len) { char *start, *end, *reloc; unsigned ret; start = end = reloc = NULL; #define SITE(op, x) \ case PARAVIRT_PATCH(op.x): \ if (have_vcpu_info_placement) { \ start = (char *)xen_##x##_direct; \ end = xen_##x##_direct_end; \ reloc = xen_##x##_direct_reloc; \ } \ goto patch_site switch (type) { SITE(pv_irq_ops, irq_enable); SITE(pv_irq_ops, irq_disable); SITE(pv_irq_ops, save_fl); SITE(pv_irq_ops, restore_fl); #undef SITE patch_site: if (start == NULL || (end-start) > len) goto default_patch; ret = paravirt_patch_insns(insnbuf, len, start, end); if (reloc > start && reloc < end) { int reloc_off = reloc - start; long *relocp = (long *)(insnbuf + reloc_off); long delta = start - (char *)addr; *relocp += delta; } break; default_patch: default: ret = paravirt_patch_default(type, clobbers, insnbuf, addr, len); break; } 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; }
unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len) { return paravirt_patch_insns(insnbuf, len, start__mov64, end__mov64); }
unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len) { return paravirt_patch_insns(insnbuf, len, start__mov32, end__mov32); }