Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #6
0
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;
}
Example #7
0
unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
				unsigned long addr, 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(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);
}