mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
x86: init_hypercall_page() cleanup
The various pieces of the hypercall page infrastructure have grown organically over time and ended up in a bit of a mess. * Rename all functions to be of the form *_init_hypercall_page(). This makes them somewhat shorter, and means they can actually be grepped for in one go. * Move init_hypercall_page() to domain.c. The 64-bit traps.c isn't a terribly appropriate place for it to live. * Drop an obsolete comment from hvm_init_hypercall_page() and drop the domain parameter from hvm_funcs.init_hypercall_page() as it isn't necessary. * Rearrange the logic in the each function to avoid needing extra local variables, and to write the page in one single pass. No functional change. Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> Reviewed-by: Wei Liu <wei.liu2@citrix.com> Acked-by: Jan Beulich <jbeulich@suse.com> Reviewed-by: Kevin Tian <kevin.tian@intel.com>
This commit is contained in:
1 parent
df4e4cafd2
commit
e99203f4d2
12 files changed
+75
-80
No files matched your search
@@ -175,6 +175,20 @@ static void noreturn continue_idle_domain(struct vcpu *v)
|
||||
reset_stack_and_jump(idle_loop);
|
||||
}
|
||||
|
||||
void init_hypercall_page(struct domain *d, void *ptr)
|
||||
{
|
||||
memset(ptr, 0xcc, PAGE_SIZE);
|
||||
|
||||
if ( is_hvm_domain(d) )
|
||||
hvm_init_hypercall_page(d, ptr);
|
||||
else if ( is_pv_64bit_domain(d) )
|
||||
pv_ring3_init_hypercall_page(ptr);
|
||||
else if ( is_pv_32bit_domain(d) )
|
||||
pv_ring1_init_hypercall_page(ptr);
|
||||
else
|
||||
ASSERT_UNREACHABLE();
|
||||
}
|
||||
|
||||
void dump_pageframe_info(struct domain *d)
|
||||
{
|
||||
struct page_info *page;
|
||||
|
||||
@@ -517,7 +517,7 @@ long arch_do_domctl(
|
||||
}
|
||||
|
||||
hypercall_page = __map_domain_page(page);
|
||||
hypercall_page_initialise(d, hypercall_page);
|
||||
init_hypercall_page(d, hypercall_page);
|
||||
unmap_domain_page(hypercall_page);
|
||||
|
||||
put_page_and_type(page);
|
||||
|
||||
@@ -3807,13 +3807,11 @@ static void hvm_latch_shinfo_size(struct domain *d)
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise a hypercall transfer page for a VMX domain using
|
||||
paravirtualised drivers. */
|
||||
void hvm_hypercall_page_initialise(struct domain *d,
|
||||
void *hypercall_page)
|
||||
void hvm_init_hypercall_page(struct domain *d, void *ptr)
|
||||
{
|
||||
hvm_latch_shinfo_size(d);
|
||||
alternative_vcall(hvm_funcs.init_hypercall_page, d, hypercall_page);
|
||||
|
||||
alternative_vcall(hvm_funcs.init_hypercall_page, ptr);
|
||||
}
|
||||
|
||||
void hvm_vcpu_reset_state(struct vcpu *v, uint16_t cs, uint16_t ip)
|
||||
|
||||
+10
-10
@@ -916,17 +916,20 @@ static unsigned int svm_get_insn_bytes(struct vcpu *v, uint8_t *buf)
|
||||
return len;
|
||||
}
|
||||
|
||||
static void svm_init_hypercall_page(struct domain *d, void *hypercall_page)
|
||||
static void svm_init_hypercall_page(void *p)
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
unsigned int i;
|
||||
|
||||
for ( i = 0; i < (PAGE_SIZE / 32); i++ )
|
||||
for ( i = 0; i < (PAGE_SIZE / 32); i++, p += 32 )
|
||||
{
|
||||
if ( i == __HYPERVISOR_iret )
|
||||
continue;
|
||||
if ( unlikely(i == __HYPERVISOR_iret) )
|
||||
{
|
||||
/* HYPERVISOR_iret isn't supported */
|
||||
*(u16 *)p = 0x0b0f; /* ud2 */
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
p = (char *)(hypercall_page + (i * 32));
|
||||
*(u8 *)(p + 0) = 0xb8; /* mov imm32, %eax */
|
||||
*(u32 *)(p + 1) = i;
|
||||
*(u8 *)(p + 5) = 0x0f; /* vmmcall */
|
||||
@@ -934,9 +937,6 @@ static void svm_init_hypercall_page(struct domain *d, void *hypercall_page)
|
||||
*(u8 *)(p + 7) = 0xd9;
|
||||
*(u8 *)(p + 8) = 0xc3; /* ret */
|
||||
}
|
||||
|
||||
/* Don't support HYPERVISOR_iret at the moment */
|
||||
*(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */
|
||||
}
|
||||
|
||||
static inline void svm_tsc_ratio_save(struct vcpu *v)
|
||||
|
||||
+10
-10
@@ -1262,17 +1262,20 @@ static void vmx_set_descriptor_access_exiting(struct vcpu *v, bool enable)
|
||||
vmx_vmcs_exit(v);
|
||||
}
|
||||
|
||||
static void vmx_init_hypercall_page(struct domain *d, void *hypercall_page)
|
||||
static void vmx_init_hypercall_page(void *p)
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
unsigned int i;
|
||||
|
||||
for ( i = 0; i < (PAGE_SIZE / 32); i++ )
|
||||
for ( i = 0; i < (PAGE_SIZE / 32); i++, p += 32 )
|
||||
{
|
||||
if ( i == __HYPERVISOR_iret )
|
||||
continue;
|
||||
if ( unlikely(i == __HYPERVISOR_iret) )
|
||||
{
|
||||
/* HYPERVISOR_iret isn't supported */
|
||||
*(u16 *)p = 0x0b0f; /* ud2 */
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
p = (char *)(hypercall_page + (i * 32));
|
||||
*(u8 *)(p + 0) = 0xb8; /* mov imm32, %eax */
|
||||
*(u32 *)(p + 1) = i;
|
||||
*(u8 *)(p + 5) = 0x0f; /* vmcall */
|
||||
@@ -1280,9 +1283,6 @@ static void vmx_init_hypercall_page(struct domain *d, void *hypercall_page)
|
||||
*(u8 *)(p + 7) = 0xc1;
|
||||
*(u8 *)(p + 8) = 0xc3; /* ret */
|
||||
}
|
||||
|
||||
/* Don't support HYPERVISOR_iret at the moment */
|
||||
*(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */
|
||||
}
|
||||
|
||||
static unsigned int vmx_get_interrupt_shadow(struct vcpu *v)
|
||||
|
||||
@@ -739,8 +739,7 @@ int __init dom0_construct_pv(struct domain *d,
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
hypercall_page_initialise(
|
||||
d, (void *)(unsigned long)parms.virt_hypercall);
|
||||
init_hypercall_page(d, _p(parms.virt_hypercall));
|
||||
}
|
||||
|
||||
/* Free temporary buffers. */
|
||||
|
||||
+30
-33
@@ -267,16 +267,28 @@ enum mc_disposition arch_do_multicall_call(struct mc_state *state)
|
||||
? mc_continue : mc_preempt;
|
||||
}
|
||||
|
||||
void hypercall_page_initialise_ring3_kernel(void *hypercall_page)
|
||||
void pv_ring3_init_hypercall_page(void *p)
|
||||
{
|
||||
void *p = hypercall_page;
|
||||
unsigned int i;
|
||||
|
||||
/* Fill in all the transfer points with template machine code. */
|
||||
for ( i = 0; i < (PAGE_SIZE / 32); i++, p += 32 )
|
||||
{
|
||||
if ( i == __HYPERVISOR_iret )
|
||||
if ( unlikely(i == __HYPERVISOR_iret) )
|
||||
{
|
||||
/*
|
||||
* HYPERVISOR_iret is special because it doesn't return and
|
||||
* expects a special stack frame. Guests jump at this transfer
|
||||
* point instead of calling it.
|
||||
*/
|
||||
*(u8 *)(p+ 0) = 0x51; /* push %rcx */
|
||||
*(u16 *)(p+ 1) = 0x5341; /* push %r11 */
|
||||
*(u8 *)(p+ 3) = 0x50; /* push %rax */
|
||||
*(u8 *)(p+ 4) = 0xb8; /* mov $__HYPERVISOR_iret, %eax */
|
||||
*(u32 *)(p+ 5) = __HYPERVISOR_iret;
|
||||
*(u16 *)(p+ 9) = 0x050f; /* syscall */
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
*(u8 *)(p+ 0) = 0x51; /* push %rcx */
|
||||
*(u16 *)(p+ 1) = 0x5341; /* push %r11 */
|
||||
@@ -287,49 +299,34 @@ void hypercall_page_initialise_ring3_kernel(void *hypercall_page)
|
||||
*(u8 *)(p+12) = 0x59; /* pop %rcx */
|
||||
*(u8 *)(p+13) = 0xc3; /* ret */
|
||||
}
|
||||
|
||||
/*
|
||||
* HYPERVISOR_iret is special because it doesn't return and expects a
|
||||
* special stack frame. Guests jump at this transfer point instead of
|
||||
* calling it.
|
||||
*/
|
||||
p = hypercall_page + (__HYPERVISOR_iret * 32);
|
||||
*(u8 *)(p+ 0) = 0x51; /* push %rcx */
|
||||
*(u16 *)(p+ 1) = 0x5341; /* push %r11 */
|
||||
*(u8 *)(p+ 3) = 0x50; /* push %rax */
|
||||
*(u8 *)(p+ 4) = 0xb8; /* mov $__HYPERVISOR_iret,%eax */
|
||||
*(u32 *)(p+ 5) = __HYPERVISOR_iret;
|
||||
*(u16 *)(p+ 9) = 0x050f; /* syscall */
|
||||
}
|
||||
|
||||
void hypercall_page_initialise_ring1_kernel(void *hypercall_page)
|
||||
void pv_ring1_init_hypercall_page(void *p)
|
||||
{
|
||||
void *p = hypercall_page;
|
||||
unsigned int i;
|
||||
|
||||
/* Fill in all the transfer points with template machine code. */
|
||||
|
||||
for ( i = 0; i < (PAGE_SIZE / 32); i++, p += 32 )
|
||||
{
|
||||
if ( i == __HYPERVISOR_iret )
|
||||
if ( unlikely(i == __HYPERVISOR_iret) )
|
||||
{
|
||||
/*
|
||||
* HYPERVISOR_iret is special because it doesn't return and
|
||||
* expects a special stack frame. Guests jump at this transfer
|
||||
* point instead of calling it.
|
||||
*/
|
||||
*(u8 *)(p+ 0) = 0x50; /* push %eax */
|
||||
*(u8 *)(p+ 1) = 0xb8; /* mov $__HYPERVISOR_iret, %eax */
|
||||
*(u32 *)(p+ 2) = __HYPERVISOR_iret;
|
||||
*(u16 *)(p+ 6) = (HYPERCALL_VECTOR << 8) | 0xcd; /* int $xx */
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
*(u8 *)(p+ 0) = 0xb8; /* mov $<i>,%eax */
|
||||
*(u32 *)(p+ 1) = i;
|
||||
*(u16 *)(p+ 5) = (HYPERCALL_VECTOR << 8) | 0xcd; /* int $xx */
|
||||
*(u8 *)(p+ 7) = 0xc3; /* ret */
|
||||
}
|
||||
|
||||
/*
|
||||
* HYPERVISOR_iret is special because it doesn't return and expects a
|
||||
* special stack frame. Guests jump at this transfer point instead of
|
||||
* calling it.
|
||||
*/
|
||||
p = hypercall_page + (__HYPERVISOR_iret * 32);
|
||||
*(u8 *)(p+ 0) = 0x50; /* push %eax */
|
||||
*(u8 *)(p+ 1) = 0xb8; /* mov $__HYPERVISOR_iret,%eax */
|
||||
*(u32 *)(p+ 2) = __HYPERVISOR_iret;
|
||||
*(u16 *)(p+ 6) = (HYPERCALL_VECTOR << 8) | 0xcd; /* int $xx */
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -828,7 +828,7 @@ int guest_wrmsr_xen(struct vcpu *v, uint32_t idx, uint64_t val)
|
||||
}
|
||||
|
||||
hypercall_page = __map_domain_page(page);
|
||||
hypercall_page_initialise(d, hypercall_page);
|
||||
init_hypercall_page(d, hypercall_page);
|
||||
unmap_domain_page(hypercall_page);
|
||||
|
||||
put_page_and_type(page);
|
||||
|
||||
@@ -360,19 +360,6 @@ void subarch_percpu_traps_init(void)
|
||||
wrmsrl(MSR_SYSCALL_MASK, XEN_SYSCALL_MASK);
|
||||
}
|
||||
|
||||
void hypercall_page_initialise(struct domain *d, void *hypercall_page)
|
||||
{
|
||||
memset(hypercall_page, 0xCC, PAGE_SIZE);
|
||||
if ( is_hvm_domain(d) )
|
||||
hvm_hypercall_page_initialise(d, hypercall_page);
|
||||
else if ( is_pv_64bit_domain(d) )
|
||||
hypercall_page_initialise_ring3_kernel(hypercall_page);
|
||||
else if ( is_pv_32bit_domain(d) )
|
||||
hypercall_page_initialise_ring1_kernel(hypercall_page);
|
||||
else
|
||||
ASSERT_UNREACHABLE();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
|
||||
@@ -83,7 +83,7 @@ void cpuid_policy_updated(struct vcpu *v);
|
||||
* Initialise a hypercall-transfer page. The given pointer must be mapped
|
||||
* in Xen virtual address space (accesses are not validated or checked).
|
||||
*/
|
||||
void hypercall_page_initialise(struct domain *d, void *);
|
||||
void init_hypercall_page(struct domain *d, void *);
|
||||
|
||||
/************************************************/
|
||||
/* shadow paging extension */
|
||||
|
||||
@@ -152,7 +152,7 @@ struct hvm_function_table {
|
||||
|
||||
void (*inject_event)(const struct x86_event *event);
|
||||
|
||||
void (*init_hypercall_page)(struct domain *d, void *hypercall_page);
|
||||
void (*init_hypercall_page)(void *ptr);
|
||||
|
||||
bool (*event_pending)(const struct vcpu *v);
|
||||
bool (*get_pending_event)(struct vcpu *v, struct x86_event *info);
|
||||
@@ -272,7 +272,7 @@ int hvm_girq_dest_2_vcpu_id(struct domain *d, uint8_t dest, uint8_t dest_mode);
|
||||
enum hvm_intblk
|
||||
hvm_interrupt_blocked(struct vcpu *v, struct hvm_intack intack);
|
||||
|
||||
void hvm_hypercall_page_initialise(struct domain *d, void *hypercall_page);
|
||||
void hvm_init_hypercall_page(struct domain *d, void *ptr);
|
||||
|
||||
void hvm_get_segment_register(struct vcpu *v, enum x86_segment seg,
|
||||
struct segment_register *reg);
|
||||
|
||||
@@ -30,8 +30,8 @@ extern const hypercall_table_t pv_hypercall_table[];
|
||||
void pv_hypercall(struct cpu_user_regs *regs);
|
||||
#endif
|
||||
|
||||
void hypercall_page_initialise_ring3_kernel(void *hypercall_page);
|
||||
void hypercall_page_initialise_ring1_kernel(void *hypercall_page);
|
||||
void pv_ring1_init_hypercall_page(void *ptr);
|
||||
void pv_ring3_init_hypercall_page(void *ptr);
|
||||
|
||||
/*
|
||||
* Both do_mmuext_op() and do_mmu_update():
|
||||
|
||||