mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
x86/pv: Export pv_hypercall_table[] rather than working around it in several ways
The functions in compat.c are thing wrappers around the main hypercalls, massaging certain parameters. However, they second-guess the content of pv_hypercall_table[], which is problematic for the shim case. Instead, arrange for them to call via function pointer, which removes the need for pv_get_hypercall_handler(). With pv_hypercall_table[] exported, there is no need for pv_hypercall_table_replace(), so its single callsite gets modified to cope. The backing code behind __va(__pa()) is substantial, and there is no need to calculate it repeatedly (Xen's .rodata is also contiguous in the directmap). While adjusting the declarations, guard content in arch/x86/pv with CONFIG_PV. The net difference is: add/remove: 0/2 grow/shrink: 4/1 up/down: 176/-321 (-145) function old new delta pv_shim_setup_dom 1130 1266 +136 do_sched_op_compat 176 192 +16 compat_physdev_op_compat 90 106 +16 do_physdev_op_compat 98 106 +8 do_event_channel_op_compat 145 123 -22 pv_get_hypercall_handler 28 - -28 pv_hypercall_table_replace 271 - -271 Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> Reviewed-by: Roger Pau Monné <roger.pau@citrix.com> Reviewed-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
1 parent
a5579ee79e
commit
1252e28231
4 files changed
+29
-31
No files matched your search
+10
-4
@@ -17,12 +17,14 @@ typedef long ret_t;
|
||||
/* Legacy hypercall (as of 0x00030202). */
|
||||
ret_t do_physdev_op_compat(XEN_GUEST_HANDLE(physdev_op_t) uop)
|
||||
{
|
||||
typeof(do_physdev_op) *fn =
|
||||
(void *)pv_hypercall_table[__HYPERVISOR_physdev_op].native;
|
||||
struct physdev_op op;
|
||||
|
||||
if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
|
||||
return -EFAULT;
|
||||
|
||||
return do_physdev_op(op.cmd, guest_handle_from_ptr(&uop.p->u, void));
|
||||
return fn(op.cmd, guest_handle_from_ptr(&uop.p->u, void));
|
||||
}
|
||||
|
||||
#ifndef COMPAT
|
||||
@@ -30,11 +32,14 @@ ret_t do_physdev_op_compat(XEN_GUEST_HANDLE(physdev_op_t) uop)
|
||||
/* Legacy hypercall (as of 0x00030101). */
|
||||
long do_sched_op_compat(int cmd, unsigned long arg)
|
||||
{
|
||||
typeof(do_sched_op) *fn =
|
||||
(void *)pv_hypercall_table[__HYPERVISOR_sched_op].native;
|
||||
|
||||
switch ( cmd )
|
||||
{
|
||||
case SCHEDOP_yield:
|
||||
case SCHEDOP_block:
|
||||
return do_sched_op(cmd, guest_handle_from_ptr(NULL, void));
|
||||
return fn(cmd, guest_handle_from_ptr(NULL, void));
|
||||
|
||||
case SCHEDOP_shutdown:
|
||||
TRACE_3D(TRC_SCHED_SHUTDOWN,
|
||||
@@ -52,6 +57,8 @@ long do_sched_op_compat(int cmd, unsigned long arg)
|
||||
/* Legacy hypercall (as of 0x00030202). */
|
||||
long do_event_channel_op_compat(XEN_GUEST_HANDLE_PARAM(evtchn_op_t) uop)
|
||||
{
|
||||
typeof(do_event_channel_op) *fn =
|
||||
(void *)pv_hypercall_table[__HYPERVISOR_event_channel_op].native;
|
||||
struct evtchn_op op;
|
||||
|
||||
if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
|
||||
@@ -69,8 +76,7 @@ long do_event_channel_op_compat(XEN_GUEST_HANDLE_PARAM(evtchn_op_t) uop)
|
||||
case EVTCHNOP_bind_ipi:
|
||||
case EVTCHNOP_bind_vcpu:
|
||||
case EVTCHNOP_unmask:
|
||||
return pv_get_hypercall_handler(__HYPERVISOR_event_channel_op, false)
|
||||
(op.cmd, (unsigned long)&uop.p->u, 0, 0, 0, 0);
|
||||
return fn(op.cmd, guest_handle_from_ptr(&uop.p->u, void));
|
||||
|
||||
default:
|
||||
return -ENOSYS;
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
#define do_arch_1 paging_domctl_continuation
|
||||
|
||||
static const hypercall_table_t pv_hypercall_table[] = {
|
||||
const hypercall_table_t pv_hypercall_table[] = {
|
||||
COMPAT_CALL(set_trap_table),
|
||||
HYPERCALL(mmu_update),
|
||||
COMPAT_CALL(set_gdt),
|
||||
@@ -320,23 +320,6 @@ void hypercall_page_initialise_ring1_kernel(void *hypercall_page)
|
||||
*(u16 *)(p+ 6) = (HYPERCALL_VECTOR << 8) | 0xcd; /* int $xx */
|
||||
}
|
||||
|
||||
void __init pv_hypercall_table_replace(unsigned int hypercall,
|
||||
hypercall_fn_t * native,
|
||||
hypercall_fn_t *compat)
|
||||
{
|
||||
#define HANDLER_POINTER(f) \
|
||||
((unsigned long *)__va(__pa(&pv_hypercall_table[hypercall].f)))
|
||||
write_atomic(HANDLER_POINTER(native), (unsigned long)native);
|
||||
write_atomic(HANDLER_POINTER(compat), (unsigned long)compat);
|
||||
#undef HANDLER_POINTER
|
||||
}
|
||||
|
||||
hypercall_fn_t *pv_get_hypercall_handler(unsigned int hypercall, bool compat)
|
||||
{
|
||||
return compat ? pv_hypercall_table[hypercall].compat
|
||||
: pv_hypercall_table[hypercall].native;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
|
||||
+15
-6
@@ -160,6 +160,7 @@ void __init pv_shim_setup_dom(struct domain *d, l4_pgentry_t *l4start,
|
||||
unsigned long console_va, unsigned long vphysmap,
|
||||
start_info_t *si)
|
||||
{
|
||||
hypercall_table_t *rw_pv_hypercall_table;
|
||||
uint64_t param = 0;
|
||||
long rc;
|
||||
|
||||
@@ -205,12 +206,20 @@ void __init pv_shim_setup_dom(struct domain *d, l4_pgentry_t *l4start,
|
||||
mfn_x(console_mfn), vphysmap);
|
||||
consoled_set_ring_addr(page);
|
||||
}
|
||||
pv_hypercall_table_replace(__HYPERVISOR_event_channel_op,
|
||||
(hypercall_fn_t *)pv_shim_event_channel_op,
|
||||
(hypercall_fn_t *)pv_shim_event_channel_op);
|
||||
pv_hypercall_table_replace(__HYPERVISOR_grant_table_op,
|
||||
(hypercall_fn_t *)pv_shim_grant_table_op,
|
||||
(hypercall_fn_t *)pv_shim_grant_table_op);
|
||||
|
||||
/*
|
||||
* Locate pv_hypercall_table[] (usually .rodata) in the directmap (which
|
||||
* is writeable) and insert some shim-specific hypercall handlers.
|
||||
*/
|
||||
rw_pv_hypercall_table = __va(__pa(pv_hypercall_table));
|
||||
rw_pv_hypercall_table[__HYPERVISOR_event_channel_op].native =
|
||||
rw_pv_hypercall_table[__HYPERVISOR_event_channel_op].compat =
|
||||
(hypercall_fn_t *)pv_shim_event_channel_op;
|
||||
|
||||
rw_pv_hypercall_table[__HYPERVISOR_grant_table_op].native =
|
||||
rw_pv_hypercall_table[__HYPERVISOR_grant_table_op].compat =
|
||||
(hypercall_fn_t *)pv_shim_grant_table_op;
|
||||
|
||||
guest = d;
|
||||
|
||||
/*
|
||||
|
||||
@@ -25,12 +25,12 @@ typedef struct {
|
||||
|
||||
extern const hypercall_args_t hypercall_args_table[NR_hypercalls];
|
||||
|
||||
#ifdef CONFIG_PV
|
||||
extern const hypercall_table_t pv_hypercall_table[];
|
||||
void pv_hypercall(struct cpu_user_regs *regs);
|
||||
void hypercall_page_initialise_ring3_kernel(void *hypercall_page);
|
||||
void hypercall_page_initialise_ring1_kernel(void *hypercall_page);
|
||||
void pv_hypercall_table_replace(unsigned int hypercall, hypercall_fn_t * native,
|
||||
hypercall_fn_t *compat);
|
||||
hypercall_fn_t *pv_get_hypercall_handler(unsigned int hypercall, bool compat);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Both do_mmuext_op() and do_mmu_update():
|
||||
|
||||