mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Enable compatibility mode operation for HYPERVISOR_domctl. Also add logic
to switch a domain to/from compatibility mode (supposed to happen early after domain creation only). Signed-off-by: Jan Beulich <jbeulich@novell.com>
This commit is contained in:
1 parent
a6f33d81e1
commit
97a138cbdd
24 files changed
+637
-117
No files matched your search
@@ -522,14 +522,14 @@ void arch_domain_destroy(struct domain *d)
|
||||
deallocate_rid_range(d);
|
||||
}
|
||||
|
||||
void arch_getdomaininfo_ctxt(struct vcpu *v, struct vcpu_guest_context *c)
|
||||
void arch_get_info_guest(struct vcpu *v, vcpu_guest_context_u c)
|
||||
{
|
||||
int i;
|
||||
struct vcpu_extra_regs *er = &c->extra_regs;
|
||||
struct vcpu_extra_regs *er = &c.nat->extra_regs;
|
||||
|
||||
c->user_regs = *vcpu_regs (v);
|
||||
c->privregs_pfn = get_gpfn_from_mfn(virt_to_maddr(v->arch.privregs) >>
|
||||
PAGE_SHIFT);
|
||||
c.nat->user_regs = *vcpu_regs(v);
|
||||
c.nat->privregs_pfn = get_gpfn_from_mfn(virt_to_maddr(v->arch.privregs) >>
|
||||
PAGE_SHIFT);
|
||||
|
||||
/* Fill extra regs. */
|
||||
for (i = 0; i < 8; i++) {
|
||||
@@ -549,12 +549,12 @@ void arch_getdomaininfo_ctxt(struct vcpu *v, struct vcpu_guest_context *c)
|
||||
er->iva = v->arch.iva;
|
||||
}
|
||||
|
||||
int arch_set_info_guest(struct vcpu *v, struct vcpu_guest_context *c)
|
||||
int arch_set_info_guest(struct vcpu *v, vcpu_guest_context_u c)
|
||||
{
|
||||
struct pt_regs *regs = vcpu_regs (v);
|
||||
struct domain *d = v->domain;
|
||||
|
||||
*regs = c->user_regs;
|
||||
*regs = c.nat->user_regs;
|
||||
|
||||
if (!d->arch.is_vti) {
|
||||
/* domain runs at PL2/3 */
|
||||
@@ -562,9 +562,9 @@ int arch_set_info_guest(struct vcpu *v, struct vcpu_guest_context *c)
|
||||
regs->ar_rsc |= (2 << 2); /* force PL2/3 */
|
||||
}
|
||||
|
||||
if (c->flags & VGCF_EXTRA_REGS) {
|
||||
if (c.nat->flags & VGCF_EXTRA_REGS) {
|
||||
int i;
|
||||
struct vcpu_extra_regs *er = &c->extra_regs;
|
||||
struct vcpu_extra_regs *er = &c.nat->extra_regs;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
vcpu_set_itr(v, i, er->itrs[i].pte,
|
||||
|
||||
@@ -150,9 +150,9 @@ void vcpu_destroy(struct vcpu *v)
|
||||
{
|
||||
}
|
||||
|
||||
int arch_set_info_guest(struct vcpu *v, vcpu_guest_context_t *c)
|
||||
int arch_set_info_guest(struct vcpu *v, vcpu_guest_context_u c)
|
||||
{
|
||||
memcpy(&v->arch.ctxt, &c->user_regs, sizeof(c->user_regs));
|
||||
memcpy(&v->arch.ctxt, &c.nat->user_regs, sizeof(c.nat->user_regs));
|
||||
|
||||
printk("Domain[%d].%d: initializing\n",
|
||||
v->domain->domain_id, v->vcpu_id);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <xen/types.h>
|
||||
#include <xen/lib.h>
|
||||
#include <xen/sched.h>
|
||||
#include <xen/domain.h>
|
||||
#include <xen/guest_access.h>
|
||||
#include <xen/shadow.h>
|
||||
#include <public/xen.h>
|
||||
@@ -29,10 +30,9 @@
|
||||
#include <public/sysctl.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
void arch_getdomaininfo_ctxt(struct vcpu *, vcpu_guest_context_t *);
|
||||
void arch_getdomaininfo_ctxt(struct vcpu *v, vcpu_guest_context_t *c)
|
||||
void arch_get_info_guest(struct vcpu *v, vcpu_guest_context_u c)
|
||||
{
|
||||
memcpy(&c->user_regs, &v->arch.ctxt, sizeof(struct cpu_user_regs));
|
||||
memcpy(&c.nat->user_regs, &v->arch.ctxt, sizeof(struct cpu_user_regs));
|
||||
/* XXX fill in rest of vcpu_guest_context_t */
|
||||
}
|
||||
|
||||
|
||||
+140
-23
@@ -16,6 +16,7 @@
|
||||
#include <xen/lib.h>
|
||||
#include <xen/errno.h>
|
||||
#include <xen/sched.h>
|
||||
#include <xen/domain.h>
|
||||
#include <xen/smp.h>
|
||||
#include <xen/delay.h>
|
||||
#include <xen/softirq.h>
|
||||
@@ -250,6 +251,69 @@ static void release_compat_l4(struct vcpu *v)
|
||||
v->arch.guest_table_user = pagetable_null();
|
||||
}
|
||||
|
||||
static inline int may_switch_mode(struct domain *d)
|
||||
{
|
||||
return 1; /* XXX */
|
||||
}
|
||||
|
||||
int switch_native(struct domain *d)
|
||||
{
|
||||
l1_pgentry_t gdt_l1e;
|
||||
unsigned int vcpuid;
|
||||
|
||||
if ( !d )
|
||||
return -EINVAL;
|
||||
if ( !may_switch_mode(d) )
|
||||
return -EACCES;
|
||||
if ( !IS_COMPAT(d) )
|
||||
return 0;
|
||||
|
||||
clear_bit(_DOMF_compat, &d->domain_flags);
|
||||
release_arg_xlat_area(d);
|
||||
|
||||
/* switch gdt */
|
||||
gdt_l1e = l1e_from_page(virt_to_page(gdt_table), PAGE_HYPERVISOR);
|
||||
for ( vcpuid = 0; vcpuid < MAX_VIRT_CPUS; vcpuid++ )
|
||||
{
|
||||
d->arch.mm_perdomain_pt[((vcpuid << GDT_LDT_VCPU_SHIFT) +
|
||||
FIRST_RESERVED_GDT_PAGE)] = gdt_l1e;
|
||||
if (d->vcpu[vcpuid])
|
||||
release_compat_l4(d->vcpu[vcpuid]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int switch_compat(struct domain *d)
|
||||
{
|
||||
l1_pgentry_t gdt_l1e;
|
||||
unsigned int vcpuid;
|
||||
|
||||
if ( !d )
|
||||
return -EINVAL;
|
||||
if ( compat_disabled )
|
||||
return -ENOSYS;
|
||||
if ( !may_switch_mode(d) )
|
||||
return -EACCES;
|
||||
if ( IS_COMPAT(d) )
|
||||
return 0;
|
||||
|
||||
set_bit(_DOMF_compat, &d->domain_flags);
|
||||
|
||||
/* switch gdt */
|
||||
gdt_l1e = l1e_from_page(virt_to_page(compat_gdt_table), PAGE_HYPERVISOR);
|
||||
for ( vcpuid = 0; vcpuid < MAX_VIRT_CPUS; vcpuid++ )
|
||||
{
|
||||
d->arch.mm_perdomain_pt[((vcpuid << GDT_LDT_VCPU_SHIFT) +
|
||||
FIRST_RESERVED_GDT_PAGE)] = gdt_l1e;
|
||||
if (d->vcpu[vcpuid]
|
||||
&& setup_compat_l4(d->vcpu[vcpuid]) != 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define release_arg_xlat_area(d) ((void)0)
|
||||
#define setup_compat_l4(v) 0
|
||||
@@ -416,43 +480,80 @@ void arch_domain_destroy(struct domain *d)
|
||||
|
||||
/* This is called by arch_final_setup_guest and do_boot_vcpu */
|
||||
int arch_set_info_guest(
|
||||
struct vcpu *v, struct vcpu_guest_context *c)
|
||||
struct vcpu *v, vcpu_guest_context_u c)
|
||||
{
|
||||
struct domain *d = v->domain;
|
||||
#ifdef CONFIG_COMPAT
|
||||
#define c(fld) (!IS_COMPAT(d) ? (c.nat->fld) : (c.cmp->fld))
|
||||
#else
|
||||
#define c(fld) (c.nat->fld)
|
||||
#endif
|
||||
unsigned long cr3_pfn = INVALID_MFN;
|
||||
unsigned long flags = c(flags);
|
||||
int i, rc;
|
||||
|
||||
if ( !is_hvm_vcpu(v) )
|
||||
{
|
||||
fixup_guest_stack_selector(d, c->user_regs.ss);
|
||||
fixup_guest_stack_selector(d, c->kernel_ss);
|
||||
fixup_guest_code_selector(d, c->user_regs.cs);
|
||||
|
||||
if ( CONFIG_PAGING_LEVELS < 4 || IS_COMPAT(d) )
|
||||
if ( !IS_COMPAT(d) )
|
||||
{
|
||||
fixup_guest_code_selector(d, c->event_callback_cs);
|
||||
fixup_guest_code_selector(d, c->failsafe_callback_cs);
|
||||
fixup_guest_stack_selector(d, c.nat->user_regs.ss);
|
||||
fixup_guest_stack_selector(d, c.nat->kernel_ss);
|
||||
fixup_guest_code_selector(d, c.nat->user_regs.cs);
|
||||
#ifdef __i386__
|
||||
fixup_guest_code_selector(d, c.nat->event_callback_cs);
|
||||
fixup_guest_code_selector(d, c.nat->failsafe_callback_cs);
|
||||
#endif
|
||||
|
||||
for ( i = 0; i < 256; i++ )
|
||||
fixup_guest_code_selector(d, c.nat->trap_ctxt[i].cs);
|
||||
|
||||
/* LDT safety checks. */
|
||||
if ( ((c.nat->ldt_base & (PAGE_SIZE-1)) != 0) ||
|
||||
(c.nat->ldt_ents > 8192) ||
|
||||
!array_access_ok(c.nat->ldt_base,
|
||||
c.nat->ldt_ents,
|
||||
LDT_ENTRY_SIZE) )
|
||||
return -EINVAL;
|
||||
}
|
||||
#ifdef CONFIG_COMPAT
|
||||
else
|
||||
{
|
||||
fixup_guest_stack_selector(d, c.cmp->user_regs.ss);
|
||||
fixup_guest_stack_selector(d, c.cmp->kernel_ss);
|
||||
fixup_guest_code_selector(d, c.cmp->user_regs.cs);
|
||||
fixup_guest_code_selector(d, c.cmp->event_callback_cs);
|
||||
fixup_guest_code_selector(d, c.cmp->failsafe_callback_cs);
|
||||
|
||||
for ( i = 0; i < 256; i++ )
|
||||
fixup_guest_code_selector(d, c->trap_ctxt[i].cs);
|
||||
for ( i = 0; i < 256; i++ )
|
||||
fixup_guest_code_selector(d, c.cmp->trap_ctxt[i].cs);
|
||||
|
||||
/* LDT safety checks. */
|
||||
if ( ((c->ldt_base & (PAGE_SIZE-1)) != 0) ||
|
||||
(c->ldt_ents > 8192) ||
|
||||
!array_access_ok(c->ldt_base, c->ldt_ents, LDT_ENTRY_SIZE) )
|
||||
return -EINVAL;
|
||||
/* LDT safety checks. */
|
||||
if ( ((c.cmp->ldt_base & (PAGE_SIZE-1)) != 0) ||
|
||||
(c.cmp->ldt_ents > 8192) ||
|
||||
!compat_array_access_ok(c.cmp->ldt_base,
|
||||
c.cmp->ldt_ents,
|
||||
LDT_ENTRY_SIZE) )
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
clear_bit(_VCPUF_fpu_initialised, &v->vcpu_flags);
|
||||
if ( c->flags & VGCF_i387_valid )
|
||||
if ( flags & VGCF_I387_VALID )
|
||||
set_bit(_VCPUF_fpu_initialised, &v->vcpu_flags);
|
||||
|
||||
v->arch.flags &= ~TF_kernel_mode;
|
||||
if ( (c->flags & VGCF_in_kernel) || is_hvm_vcpu(v)/*???*/ )
|
||||
if ( (flags & VGCF_in_kernel) || is_hvm_vcpu(v)/*???*/ )
|
||||
v->arch.flags |= TF_kernel_mode;
|
||||
|
||||
memcpy(&v->arch.guest_context, c, sizeof(*c));
|
||||
if ( !IS_COMPAT(v->domain) )
|
||||
memcpy(&v->arch.guest_context, c.nat, sizeof(*c.nat));
|
||||
#ifdef CONFIG_COMPAT
|
||||
else
|
||||
{
|
||||
XLAT_vcpu_guest_context(&v->arch.guest_context, c.cmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Only CR0.TS is modifiable by guest or admin. */
|
||||
v->arch.guest_context.ctrlreg[0] &= X86_CR0_TS;
|
||||
@@ -480,19 +581,34 @@ int arch_set_info_guest(
|
||||
memset(v->arch.guest_context.debugreg, 0,
|
||||
sizeof(v->arch.guest_context.debugreg));
|
||||
for ( i = 0; i < 8; i++ )
|
||||
(void)set_debugreg(v, i, c->debugreg[i]);
|
||||
(void)set_debugreg(v, i, c(debugreg[i]));
|
||||
|
||||
if ( v->vcpu_id == 0 )
|
||||
d->vm_assist = c->vm_assist;
|
||||
d->vm_assist = c(vm_assist);
|
||||
|
||||
if ( !is_hvm_vcpu(v) )
|
||||
{
|
||||
if ( (rc = (int)set_gdt(v, c->gdt_frames, c->gdt_ents)) != 0 )
|
||||
if ( !IS_COMPAT(d) )
|
||||
rc = (int)set_gdt(v, c.nat->gdt_frames, c.nat->gdt_ents);
|
||||
#ifdef CONFIG_COMPAT
|
||||
else
|
||||
{
|
||||
unsigned long gdt_frames[ARRAY_SIZE(c.cmp->gdt_frames)];
|
||||
unsigned int i, n = (c.cmp->gdt_ents + 511) / 512;
|
||||
|
||||
if ( n > ARRAY_SIZE(c.cmp->gdt_frames) )
|
||||
return -EINVAL;
|
||||
for ( i = 0; i < n; ++i )
|
||||
gdt_frames[i] = c.cmp->gdt_frames[i];
|
||||
rc = (int)set_gdt(v, gdt_frames, c.cmp->gdt_ents);
|
||||
}
|
||||
#endif
|
||||
if ( rc != 0 )
|
||||
return rc;
|
||||
|
||||
if ( !IS_COMPAT(d) )
|
||||
{
|
||||
cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c->ctrlreg[3]));
|
||||
cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c.nat->ctrlreg[3]));
|
||||
|
||||
if ( shadow_mode_refcounts(d)
|
||||
? !get_page(mfn_to_page(cr3_pfn), d)
|
||||
@@ -510,7 +626,7 @@ int arch_set_info_guest(
|
||||
{
|
||||
l4_pgentry_t *l4tab;
|
||||
|
||||
cr3_pfn = gmfn_to_mfn(d, compat_cr3_to_pfn(c->ctrlreg[3]));
|
||||
cr3_pfn = gmfn_to_mfn(d, compat_cr3_to_pfn(c.cmp->ctrlreg[3]));
|
||||
|
||||
if ( shadow_mode_refcounts(d)
|
||||
? !get_page(mfn_to_page(cr3_pfn), d)
|
||||
@@ -539,6 +655,7 @@ int arch_set_info_guest(
|
||||
update_cr3(v);
|
||||
|
||||
return 0;
|
||||
#undef c
|
||||
}
|
||||
|
||||
long
|
||||
|
||||
+70
-27
@@ -11,6 +11,7 @@
|
||||
#include <xen/guest_access.h>
|
||||
#include <public/domctl.h>
|
||||
#include <xen/sched.h>
|
||||
#include <xen/domain.h>
|
||||
#include <xen/event.h>
|
||||
#include <xen/domain_page.h>
|
||||
#include <asm/msr.h>
|
||||
@@ -23,12 +24,21 @@
|
||||
#include <asm/hvm/support.h>
|
||||
#include <asm/processor.h>
|
||||
#include <public/hvm/e820.h>
|
||||
#ifdef CONFIG_COMPAT
|
||||
#include <compat/xen.h>
|
||||
#endif
|
||||
|
||||
long arch_do_domctl(
|
||||
#ifndef COMPAT
|
||||
#define _long long
|
||||
#define copy_from_xxx_offset copy_from_guest_offset
|
||||
#define copy_to_xxx_offset copy_to_guest_offset
|
||||
#endif
|
||||
|
||||
_long arch_do_domctl(
|
||||
struct xen_domctl *domctl,
|
||||
XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
|
||||
{
|
||||
long ret = 0;
|
||||
_long ret = 0;
|
||||
|
||||
switch ( domctl->cmd )
|
||||
{
|
||||
@@ -40,7 +50,9 @@ long arch_do_domctl(
|
||||
d = find_domain_by_id(domctl->domain);
|
||||
if ( d != NULL )
|
||||
{
|
||||
ret = shadow_domctl(d, &domctl->u.shadow_op, u_domctl);
|
||||
ret = shadow_domctl(d,
|
||||
&domctl->u.shadow_op,
|
||||
guest_handle_cast(u_domctl, void));
|
||||
put_domain(d);
|
||||
copy_to_guest(u_domctl, domctl, 1);
|
||||
}
|
||||
@@ -123,12 +135,12 @@ long arch_do_domctl(
|
||||
|
||||
case XEN_DOMCTL_getpageframeinfo2:
|
||||
{
|
||||
#define GPF2_BATCH (PAGE_SIZE / sizeof(long))
|
||||
#define GPF2_BATCH (PAGE_SIZE / sizeof(_long))
|
||||
int n,j;
|
||||
int num = domctl->u.getpageframeinfo2.num;
|
||||
domid_t dom = domctl->domain;
|
||||
struct domain *d;
|
||||
unsigned long *l_arr;
|
||||
unsigned _long *l_arr;
|
||||
ret = -ESRCH;
|
||||
|
||||
if ( unlikely((d = find_domain_by_id(dom)) == NULL) )
|
||||
@@ -148,9 +160,9 @@ long arch_do_domctl(
|
||||
{
|
||||
int k = ((num-n)>GPF2_BATCH)?GPF2_BATCH:(num-n);
|
||||
|
||||
if ( copy_from_guest_offset(l_arr,
|
||||
domctl->u.getpageframeinfo2.array,
|
||||
n, k) )
|
||||
if ( copy_from_xxx_offset(l_arr,
|
||||
domctl->u.getpageframeinfo2.array,
|
||||
n, k) )
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
@@ -159,13 +171,13 @@ long arch_do_domctl(
|
||||
for ( j = 0; j < k; j++ )
|
||||
{
|
||||
struct page_info *page;
|
||||
unsigned long mfn = l_arr[j];
|
||||
unsigned _long mfn = l_arr[j];
|
||||
|
||||
page = mfn_to_page(mfn);
|
||||
|
||||
if ( likely(mfn_valid(mfn) && get_page(page, d)) )
|
||||
{
|
||||
unsigned long type = 0;
|
||||
unsigned _long type = 0;
|
||||
|
||||
switch( page->u.inuse.type_info & PGT_type_mask )
|
||||
{
|
||||
@@ -193,8 +205,8 @@ long arch_do_domctl(
|
||||
|
||||
}
|
||||
|
||||
if ( copy_to_guest_offset(domctl->u.getpageframeinfo2.array,
|
||||
n, l_arr, k) )
|
||||
if ( copy_to_xxx_offset(domctl->u.getpageframeinfo2.array,
|
||||
n, l_arr, k) )
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
@@ -214,7 +226,7 @@ long arch_do_domctl(
|
||||
int i;
|
||||
struct domain *d = find_domain_by_id(domctl->domain);
|
||||
unsigned long max_pfns = domctl->u.getmemlist.max_pfns;
|
||||
unsigned long mfn;
|
||||
xen_pfn_t mfn;
|
||||
struct list_head *list_ent;
|
||||
|
||||
ret = -EINVAL;
|
||||
@@ -229,8 +241,8 @@ long arch_do_domctl(
|
||||
{
|
||||
mfn = page_to_mfn(list_entry(
|
||||
list_ent, struct page_info, list));
|
||||
if ( copy_to_guest_offset(domctl->u.getmemlist.buffer,
|
||||
i, &mfn, 1) )
|
||||
if ( copy_to_xxx_offset(domctl->u.getmemlist.buffer,
|
||||
i, &mfn, 1) )
|
||||
{
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
@@ -289,37 +301,68 @@ long arch_do_domctl(
|
||||
return ret;
|
||||
}
|
||||
|
||||
void arch_getdomaininfo_ctxt(
|
||||
struct vcpu *v, struct vcpu_guest_context *c)
|
||||
#ifndef COMPAT
|
||||
void arch_get_info_guest(struct vcpu *v, vcpu_guest_context_u c)
|
||||
{
|
||||
memcpy(c, &v->arch.guest_context, sizeof(*c));
|
||||
#ifdef CONFIG_COMPAT
|
||||
#define c(fld) (!IS_COMPAT(v->domain) ? (c.nat->fld) : (c.cmp->fld))
|
||||
#else
|
||||
#define c(fld) (c.nat->fld)
|
||||
#endif
|
||||
unsigned long flags;
|
||||
|
||||
if ( !IS_COMPAT(v->domain) )
|
||||
memcpy(c.nat, &v->arch.guest_context, sizeof(*c.nat));
|
||||
#ifdef CONFIG_COMPAT
|
||||
else
|
||||
{
|
||||
XLAT_vcpu_guest_context(c.cmp, &v->arch.guest_context);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( is_hvm_vcpu(v) )
|
||||
{
|
||||
hvm_store_cpu_guest_regs(v, &c->user_regs, c->ctrlreg);
|
||||
if ( !IS_COMPAT(v->domain) )
|
||||
hvm_store_cpu_guest_regs(v, &c.nat->user_regs, c.nat->ctrlreg);
|
||||
#ifdef CONFIG_COMPAT
|
||||
else
|
||||
{
|
||||
struct cpu_user_regs user_regs;
|
||||
typeof(c.nat->ctrlreg) ctrlreg;
|
||||
unsigned i;
|
||||
|
||||
hvm_store_cpu_guest_regs(v, &user_regs, ctrlreg);
|
||||
XLAT_cpu_user_regs(&c.cmp->user_regs, &user_regs);
|
||||
for ( i = 0; i < ARRAY_SIZE(c.cmp->ctrlreg); ++i )
|
||||
c.cmp->ctrlreg[i] = ctrlreg[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* IOPL privileges are virtualised: merge back into returned eflags. */
|
||||
BUG_ON((c->user_regs.eflags & EF_IOPL) != 0);
|
||||
c->user_regs.eflags |= v->arch.iopl << 12;
|
||||
BUG_ON((c(user_regs.eflags) & EF_IOPL) != 0);
|
||||
c(user_regs.eflags |= v->arch.iopl << 12);
|
||||
}
|
||||
|
||||
c->flags = 0;
|
||||
flags = 0;
|
||||
if ( test_bit(_VCPUF_fpu_initialised, &v->vcpu_flags) )
|
||||
c->flags |= VGCF_i387_valid;
|
||||
flags |= VGCF_i387_valid;
|
||||
if ( guest_kernel_mode(v, &v->arch.guest_context.user_regs) )
|
||||
c->flags |= VGCF_in_kernel;
|
||||
flags |= VGCF_in_kernel;
|
||||
c(flags = flags);
|
||||
|
||||
if ( !IS_COMPAT(v->domain) )
|
||||
c->ctrlreg[3] = xen_pfn_to_cr3(pagetable_get_pfn(v->arch.guest_table));
|
||||
c.nat->ctrlreg[3] = xen_pfn_to_cr3(pagetable_get_pfn(v->arch.guest_table));
|
||||
#ifdef CONFIG_COMPAT
|
||||
else
|
||||
c->ctrlreg[3] = compat_pfn_to_cr3(pagetable_get_pfn(v->arch.guest_table));
|
||||
c.cmp->ctrlreg[3] = compat_pfn_to_cr3(pagetable_get_pfn(v->arch.guest_table));
|
||||
#endif
|
||||
|
||||
c->vm_assist = v->domain->vm_assist;
|
||||
c(vm_assist = v->domain->vm_assist);
|
||||
#undef c
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
||||
@@ -3260,7 +3260,7 @@ void shadow_mark_dirty(struct domain *d, mfn_t gmfn)
|
||||
|
||||
int shadow_domctl(struct domain *d,
|
||||
xen_domctl_shadow_op_t *sc,
|
||||
XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
|
||||
XEN_GUEST_HANDLE(void) u_domctl)
|
||||
{
|
||||
int rc, preempted = 0;
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ unsigned long do_iret(void)
|
||||
|
||||
/*
|
||||
* Pop, fix up and restore EFLAGS. We fix up in a local staging area
|
||||
* to avoid firing the BUG_ON(IOPL) check in arch_getdomaininfo_ctxt.
|
||||
* to avoid firing the BUG_ON(IOPL) check in arch_get_info_guest.
|
||||
*/
|
||||
if ( unlikely(__copy_from_user(&eflags, (void __user *)regs->esp, 4)) )
|
||||
goto exit_and_crash;
|
||||
|
||||
@@ -5,6 +5,7 @@ obj-y += traps.o
|
||||
|
||||
obj-$(CONFIG_COMPAT) += compat.o
|
||||
obj-$(CONFIG_COMPAT) += domain.o
|
||||
obj-$(CONFIG_COMPAT) += domctl.o
|
||||
obj-$(CONFIG_COMPAT) += physdev.o
|
||||
obj-$(CONFIG_COMPAT) += platform_hypercall.o
|
||||
obj-$(CONFIG_COMPAT) += sysctl.o
|
||||
@@ -12,6 +13,7 @@ obj-$(CONFIG_COMPAT) += sysctl.o
|
||||
ifeq ($(CONFIG_COMPAT),y)
|
||||
# extra dependencies
|
||||
compat.o: ../compat.c
|
||||
domctl.o: ../domctl.c
|
||||
entry.o: compat/entry.S
|
||||
mm.o: compat/mm.c
|
||||
physdev.o: ../physdev.c
|
||||
|
||||
@@ -278,8 +278,6 @@ CFIX14:
|
||||
|
||||
.section .rodata, "a", @progbits
|
||||
|
||||
#define compat_domctl domain_crash_synchronous
|
||||
|
||||
ENTRY(compat_hypercall_table)
|
||||
.quad compat_set_trap_table /* 0 */
|
||||
.quad do_mmu_update
|
||||
|
||||
@@ -49,7 +49,7 @@ unsigned int compat_iret(void)
|
||||
|
||||
/*
|
||||
* Fix up and restore EFLAGS. We fix up in a local staging area
|
||||
* to avoid firing the BUG_ON(IOPL) check in arch_getdomaininfo_ctxt.
|
||||
* to avoid firing the BUG_ON(IOPL) check in arch_get_info_guest.
|
||||
*/
|
||||
if ( unlikely(__get_user(eflags, (u32 __user *)regs->rsp + 3)) )
|
||||
goto exit_and_crash;
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/******************************************************************************
|
||||
* Arch-specific compatibility domctl.c
|
||||
*/
|
||||
|
||||
#include <xen/config.h>
|
||||
#include <compat/domctl.h>
|
||||
#include <xen/guest_access.h>
|
||||
#include <asm/shadow.h>
|
||||
|
||||
DEFINE_XEN_GUEST_HANDLE(compat_domctl_t);
|
||||
#define xen_domctl compat_domctl
|
||||
#define xen_domctl_t compat_domctl_t
|
||||
#define arch_do_domctl(x, h) arch_compat_domctl(x, _##h)
|
||||
|
||||
static int compat_shadow_domctl(struct domain *d,
|
||||
compat_domctl_shadow_op_t *csc,
|
||||
XEN_GUEST_HANDLE(void) u_domctl)
|
||||
{
|
||||
xen_domctl_shadow_op_t nsc;
|
||||
int rc, mode;
|
||||
|
||||
#define XLAT_domctl_shadow_op_HNDL_dirty_bitmap(_d_, _s_) \
|
||||
do \
|
||||
{ \
|
||||
if ( (_s_)->op != XEN_DOMCTL_SHADOW_OP_CLEAN \
|
||||
&& (_s_)->op != XEN_DOMCTL_SHADOW_OP_PEEK ) \
|
||||
{ \
|
||||
set_xen_guest_handle((_d_)->dirty_bitmap, NULL); \
|
||||
mode = -1; \
|
||||
} \
|
||||
else if ( compat_handle_is_null((_s_)->dirty_bitmap) \
|
||||
|| (((_s_)->pages - 1) \
|
||||
& (BITS_PER_LONG - COMPAT_BITS_PER_LONG)) \
|
||||
== BITS_PER_LONG - COMPAT_BITS_PER_LONG ) \
|
||||
{ \
|
||||
XEN_GUEST_HANDLE(void) tmp; \
|
||||
guest_from_compat_handle(tmp, (_s_)->dirty_bitmap); \
|
||||
(_d_)->dirty_bitmap = guest_handle_cast(tmp, ulong); \
|
||||
mode = 0; \
|
||||
} \
|
||||
else if ( (_s_)->pages > COMPAT_ARG_XLAT_SIZE * 8 ) \
|
||||
{ \
|
||||
printk("Cannot translate compatibility mode XEN_DOMCTL_SHADOW_OP_{CLEAN,PEEK} (0x%lX)\n", \
|
||||
(_s_)->pages); \
|
||||
return -E2BIG; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
set_xen_guest_handle((_d_)->dirty_bitmap, \
|
||||
(void *)COMPAT_ARG_XLAT_VIRT_START(current->vcpu_id)); \
|
||||
mode = 1; \
|
||||
} \
|
||||
} while (0)
|
||||
XLAT_domctl_shadow_op(&nsc, csc);
|
||||
#undef XLAT_domctl_shadow_op_HNDL_dirty_bitmap
|
||||
rc = shadow_domctl(d, &nsc, u_domctl);
|
||||
if ( rc != __HYPERVISOR_domctl )
|
||||
{
|
||||
BUG_ON(rc > 0);
|
||||
#define XLAT_domctl_shadow_op_HNDL_dirty_bitmap(_d_, _s_) \
|
||||
do \
|
||||
{ \
|
||||
if ( rc == 0 \
|
||||
&& mode > 0 \
|
||||
&& copy_to_compat((_d_)->dirty_bitmap, \
|
||||
(unsigned int *)(_s_)->dirty_bitmap.p, \
|
||||
((_s_)->pages + COMPAT_BITS_PER_LONG - 1) / COMPAT_BITS_PER_LONG) ) \
|
||||
rc = -EFAULT; \
|
||||
} while (0)
|
||||
XLAT_domctl_shadow_op(csc, &nsc);
|
||||
#undef XLAT_domctl_shadow_op_HNDL_dirty_bitmap
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#define xen_domctl_shadow_op compat_domctl_shadow_op
|
||||
#define xen_domctl_shadow_op_t compat_domctl_shadow_op_t
|
||||
#define shadow_domctl(d, sc, u) compat_shadow_domctl(d, sc, u)
|
||||
|
||||
#define xen_domctl_ioport_permission compat_domctl_ioport_permission
|
||||
#define xen_domctl_ioport_permission_t compat_domctl_ioport_permission_t
|
||||
|
||||
#define xen_domctl_getpageframeinfo compat_domctl_getpageframeinfo
|
||||
#define xen_domctl_getpageframeinfo_t compat_domctl_getpageframeinfo_t
|
||||
|
||||
#define xen_domctl_getpageframeinfo2 compat_domctl_getpageframeinfo2
|
||||
#define xen_domctl_getpageframeinfo2_t compat_domctl_getpageframeinfo2_t
|
||||
|
||||
#define xen_domctl_getmemlist compat_domctl_getmemlist
|
||||
#define xen_domctl_getmemlist_t compat_domctl_getmemlist_t
|
||||
#define xen_pfn_t compat_pfn_t
|
||||
|
||||
#define xen_domctl_hypercall_init compat_domctl_hypercall_init
|
||||
#define xen_domctl_hypercall_init_t compat_domctl_hypercall_init_t
|
||||
|
||||
#define COMPAT
|
||||
#define _XEN_GUEST_HANDLE(t) XEN_GUEST_HANDLE(t)
|
||||
#define _long int
|
||||
#define copy_from_xxx_offset copy_from_compat_offset
|
||||
#define copy_to_xxx_offset copy_to_compat_offset
|
||||
|
||||
#include "../domctl.c"
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -1,4 +1,5 @@
|
||||
obj-y += domain.o
|
||||
obj-y += domctl.o
|
||||
obj-y += kernel.o
|
||||
obj-y += memory.o
|
||||
obj-y += multicall.o
|
||||
@@ -6,6 +7,7 @@ obj-y += sysctl.o
|
||||
obj-y += xlat.o
|
||||
|
||||
# extra dependencies
|
||||
domctl.o: ../domctl.c
|
||||
kernel.o: ../kernel.c
|
||||
multicall.o: ../multicall.c
|
||||
sysctl.o: ../sysctl.c
|
||||
@@ -28,7 +28,6 @@ int compat_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
|
||||
case VCPUOP_initialise:
|
||||
{
|
||||
struct compat_vcpu_guest_context *cmp_ctxt;
|
||||
struct vcpu_guest_context *nat_ctxt;
|
||||
|
||||
if ( (cmp_ctxt = xmalloc(struct compat_vcpu_guest_context)) == NULL )
|
||||
{
|
||||
@@ -43,23 +42,13 @@ int compat_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
|
||||
break;
|
||||
}
|
||||
|
||||
if ( (nat_ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
|
||||
{
|
||||
rc = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
memset(nat_ctxt, 0, sizeof(*nat_ctxt));
|
||||
XLAT_vcpu_guest_context(nat_ctxt, cmp_ctxt);
|
||||
xfree(cmp_ctxt);
|
||||
|
||||
LOCK_BIGLOCK(d);
|
||||
rc = -EEXIST;
|
||||
if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
|
||||
rc = boot_vcpu(d, vcpuid, nat_ctxt);
|
||||
rc = boot_vcpu(d, vcpuid, cmp_ctxt);
|
||||
UNLOCK_BIGLOCK(d);
|
||||
|
||||
xfree(nat_ctxt);
|
||||
xfree(cmp_ctxt);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/******************************************************************************
|
||||
* compat/domctl.c
|
||||
*/
|
||||
|
||||
#include <xen/config.h>
|
||||
#include <compat/domctl.h>
|
||||
#include <xen/sched.h>
|
||||
#include <xen/cpumask.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
DEFINE_XEN_GUEST_HANDLE(compat_domctl_t);
|
||||
#define xen_domctl compat_domctl
|
||||
#define xen_domctl_t compat_domctl_t
|
||||
#define do_domctl(h) compat_domctl(_##h)
|
||||
#define arch_do_domctl(x, h) arch_compat_domctl(x, _##h)
|
||||
|
||||
#define xen_domain_handle_t compat_domain_handle_t
|
||||
|
||||
#define xen_domctl_vcpucontext compat_domctl_vcpucontext
|
||||
#define xen_domctl_vcpucontext_t compat_domctl_vcpucontext_t
|
||||
|
||||
#define xen_domctl_createdomain compat_domctl_createdomain
|
||||
#define xen_domctl_createdomain_t compat_domctl_createdomain_t
|
||||
|
||||
#define xen_domctl_max_vcpus compat_domctl_max_vcpus
|
||||
#define xen_domctl_max_vcpus_t compat_domctl_max_vcpus_t
|
||||
|
||||
static void cpumask_to_compat_ctl_cpumap(
|
||||
struct compat_ctl_cpumap *cmpctl_cpumap, cpumask_t *cpumask)
|
||||
{
|
||||
unsigned int guest_bytes, copy_bytes, i;
|
||||
/*static const*/ uint8_t zero = 0;
|
||||
|
||||
if ( compat_handle_is_null(cmpctl_cpumap->bitmap) )
|
||||
return;
|
||||
|
||||
guest_bytes = (cmpctl_cpumap->nr_cpus + 7) / 8;
|
||||
copy_bytes = min_t(unsigned int, guest_bytes, (NR_CPUS + 7) / 8);
|
||||
|
||||
copy_to_compat(cmpctl_cpumap->bitmap,
|
||||
(uint8_t *)cpus_addr(*cpumask),
|
||||
copy_bytes);
|
||||
|
||||
for ( i = copy_bytes; i < guest_bytes; i++ )
|
||||
copy_to_compat_offset(cmpctl_cpumap->bitmap, i, &zero, 1);
|
||||
}
|
||||
#define cpumask_to_xenctl_cpumap cpumask_to_compat_ctl_cpumap
|
||||
|
||||
void compat_ctl_cpumap_to_cpumask(
|
||||
cpumask_t *cpumask, struct compat_ctl_cpumap *cmpctl_cpumap)
|
||||
{
|
||||
unsigned int guest_bytes, copy_bytes;
|
||||
|
||||
guest_bytes = (cmpctl_cpumap->nr_cpus + 7) / 8;
|
||||
copy_bytes = min_t(unsigned int, guest_bytes, (NR_CPUS + 7) / 8);
|
||||
|
||||
cpus_clear(*cpumask);
|
||||
|
||||
if ( compat_handle_is_null(cmpctl_cpumap->bitmap) )
|
||||
return;
|
||||
|
||||
copy_from_compat((uint8_t *)cpus_addr(*cpumask),
|
||||
cmpctl_cpumap->bitmap,
|
||||
copy_bytes);
|
||||
}
|
||||
#define xenctl_cpumap_to_cpumask compat_ctl_cpumap_to_cpumask
|
||||
|
||||
#define xen_domctl_vcpuaffinity compat_domctl_vcpuaffinity
|
||||
#define xen_domctl_vcpuaffinity_t compat_domctl_vcpuaffinity_t
|
||||
|
||||
static int compat_sched_adjust(struct domain *d,
|
||||
struct compat_domctl_scheduler_op *cop)
|
||||
{
|
||||
struct xen_domctl_scheduler_op nop;
|
||||
int ret;
|
||||
enum XLAT_domctl_scheduler_op_u u;
|
||||
|
||||
switch ( cop->sched_id )
|
||||
{
|
||||
case XEN_SCHEDULER_SEDF: u = XLAT_domctl_scheduler_op_u_sedf; break;
|
||||
case XEN_SCHEDULER_CREDIT: u = XLAT_domctl_scheduler_op_u_credit; break;
|
||||
default: return -EINVAL;
|
||||
}
|
||||
XLAT_domctl_scheduler_op(&nop, cop);
|
||||
ret = sched_adjust(d, &nop);
|
||||
XLAT_domctl_scheduler_op(cop, &nop);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#define sched_adjust(d, op) compat_sched_adjust(d, op)
|
||||
#define xen_domctl_scheduler_op compat_domctl_scheduler_op
|
||||
#define xen_domctl_scheduler_op_t compat_domctl_scheduler_op_t
|
||||
|
||||
#define xen_domctl_getdomaininfo compat_domctl_getdomaininfo
|
||||
#define xen_domctl_getdomaininfo_t compat_domctl_getdomaininfo_t
|
||||
#define getdomaininfo(d, i) compat_getdomaininfo(d, i)
|
||||
|
||||
#define xen_domctl_getvcpuinfo compat_domctl_getvcpuinfo
|
||||
#define xen_domctl_getvcpuinfo_t compat_domctl_getvcpuinfo_t
|
||||
|
||||
#define xen_domctl_max_mem compat_domctl_max_mem
|
||||
#define xen_domctl_max_mem_t compat_domctl_max_mem_t
|
||||
|
||||
#define xen_domctl_setdomainhandle compat_domctl_setdomainhandle
|
||||
#define xen_domctl_setdomainhandle_t compat_domctl_setdomainhandle_t
|
||||
|
||||
#define xen_domctl_setdebugging compat_domctl_setdebugging
|
||||
#define xen_domctl_setdebugging_t compat_domctl_setdebugging_t
|
||||
|
||||
#define xen_domctl_irq_permission compat_domctl_irq_permission
|
||||
#define xen_domctl_irq_permission_t compat_domctl_irq_permission_t
|
||||
|
||||
#define xen_domctl_iomem_permission compat_domctl_iomem_permission
|
||||
#define xen_domctl_iomem_permission_t compat_domctl_iomem_permission_t
|
||||
|
||||
#define xen_domctl_settimeoffset compat_domctl_settimeoffset
|
||||
#define xen_domctl_settimeoffset_t compat_domctl_settimeoffset_t
|
||||
|
||||
#define COMPAT
|
||||
#define _XEN_GUEST_HANDLE(t) XEN_GUEST_HANDLE(t)
|
||||
#define _u_domctl u_domctl
|
||||
//#undef guest_handle_cast
|
||||
//#define guest_handle_cast compat_handle_cast
|
||||
//#define copy_to_xxx_offset copy_to_compat_offset
|
||||
typedef int ret_t;
|
||||
|
||||
#include "../domctl.c"
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -40,13 +40,6 @@ static int compat_tb_control(struct compat_sysctl_tbuf_op *cmp_tbc)
|
||||
#define xen_sysctl_sched_id compat_sysctl_sched_id
|
||||
#define xen_sysctl_sched_id_t compat_sysctl_sched_id_t
|
||||
|
||||
static void compat_getdomaininfo(struct domain *d, struct compat_domctl_getdomaininfo *ci)
|
||||
{
|
||||
struct xen_domctl_getdomaininfo ni;
|
||||
|
||||
getdomaininfo(d, &ni);
|
||||
XLAT_domctl_getdomaininfo(ci, &ni);
|
||||
}
|
||||
#define xen_sysctl_getdomaininfolist compat_sysctl_getdomaininfolist
|
||||
#define xen_sysctl_getdomaininfolist_t compat_sysctl_getdomaininfolist_t
|
||||
#define xen_domctl_getdomaininfo compat_domctl_getdomaininfo
|
||||
|
||||
+43
-8
@@ -26,6 +26,9 @@
|
||||
#include <asm/debugger.h>
|
||||
#include <public/sched.h>
|
||||
#include <public/vcpu.h>
|
||||
#ifdef CONFIG_COMPAT
|
||||
#include <compat/domctl.h>
|
||||
#endif
|
||||
|
||||
/* Both these structures are protected by the domlist_lock. */
|
||||
DEFINE_RWLOCK(domlist_lock);
|
||||
@@ -451,32 +454,64 @@ void domain_unpause_by_systemcontroller(struct domain *d)
|
||||
* the userspace dom0 domain builder.
|
||||
*/
|
||||
int set_info_guest(struct domain *d,
|
||||
xen_domctl_vcpucontext_t *vcpucontext)
|
||||
xen_domctl_vcpucontext_u vcpucontext)
|
||||
{
|
||||
int rc = 0;
|
||||
struct vcpu_guest_context *c = NULL;
|
||||
unsigned long vcpu = vcpucontext->vcpu;
|
||||
vcpu_guest_context_u c;
|
||||
#ifdef CONFIG_COMPAT
|
||||
CHECK_FIELD(domctl_vcpucontext, vcpu);
|
||||
#endif
|
||||
unsigned long vcpu = vcpucontext.nat->vcpu;
|
||||
struct vcpu *v;
|
||||
|
||||
if ( (vcpu >= MAX_VIRT_CPUS) || ((v = d->vcpu[vcpu]) == NULL) )
|
||||
return -EINVAL;
|
||||
|
||||
if ( (c = xmalloc(struct vcpu_guest_context)) == NULL )
|
||||
#ifdef CONFIG_COMPAT
|
||||
BUILD_BUG_ON(sizeof(struct vcpu_guest_context)
|
||||
< sizeof(struct compat_vcpu_guest_context));
|
||||
#endif
|
||||
if ( (c.nat = xmalloc(struct vcpu_guest_context)) == NULL )
|
||||
return -ENOMEM;
|
||||
|
||||
domain_pause(d);
|
||||
|
||||
rc = -EFAULT;
|
||||
if ( copy_from_guest(c, vcpucontext->ctxt, 1) == 0 )
|
||||
if ( !IS_COMPAT(v->domain) )
|
||||
{
|
||||
if ( !IS_COMPAT(current->domain)
|
||||
? copy_from_guest(c.nat, vcpucontext.nat->ctxt, 1)
|
||||
#ifndef CONFIG_COMPAT
|
||||
: 0 )
|
||||
#else
|
||||
: copy_from_guest(c.nat,
|
||||
compat_handle_cast(vcpucontext.cmp->ctxt,
|
||||
void),
|
||||
1) )
|
||||
#endif
|
||||
rc = -EFAULT;
|
||||
}
|
||||
#ifdef CONFIG_COMPAT
|
||||
else
|
||||
{
|
||||
if ( !IS_COMPAT(current->domain)
|
||||
? copy_from_guest(c.cmp,
|
||||
guest_handle_cast(vcpucontext.nat->ctxt, void),
|
||||
1)
|
||||
: copy_from_compat(c.cmp, vcpucontext.cmp->ctxt, 1) )
|
||||
rc = -EFAULT;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( rc == 0 )
|
||||
rc = arch_set_info_guest(v, c);
|
||||
|
||||
domain_unpause(d);
|
||||
|
||||
xfree(c);
|
||||
xfree(c.nat);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int boot_vcpu(struct domain *d, int vcpuid, struct vcpu_guest_context *ctxt)
|
||||
int boot_vcpu(struct domain *d, int vcpuid, vcpu_guest_context_u ctxt)
|
||||
{
|
||||
struct vcpu *v = d->vcpu[vcpuid];
|
||||
|
||||
|
||||
+83
-13
@@ -18,14 +18,22 @@
|
||||
#include <xen/console.h>
|
||||
#include <xen/iocap.h>
|
||||
#include <xen/guest_access.h>
|
||||
#ifdef CONFIG_COMPAT
|
||||
#include <xen/compat.h>
|
||||
#endif
|
||||
#include <asm/current.h>
|
||||
#include <public/domctl.h>
|
||||
#include <acm/acm_hooks.h>
|
||||
|
||||
extern long arch_do_domctl(
|
||||
#ifndef COMPAT
|
||||
typedef long ret_t;
|
||||
#define copy_to_xxx_offset copy_to_guest_offset
|
||||
#endif
|
||||
|
||||
extern ret_t arch_do_domctl(
|
||||
struct xen_domctl *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl);
|
||||
extern void arch_getdomaininfo_ctxt(
|
||||
struct vcpu *, struct vcpu_guest_context *);
|
||||
|
||||
#ifndef COMPAT
|
||||
|
||||
void cpumask_to_xenctl_cpumap(
|
||||
struct xenctl_cpumap *xenctl_cpumap, cpumask_t *cpumask)
|
||||
@@ -65,6 +73,8 @@ void xenctl_cpumap_to_cpumask(
|
||||
copy_bytes);
|
||||
}
|
||||
|
||||
#endif /* COMPAT */
|
||||
|
||||
static inline int is_free_domid(domid_t dom)
|
||||
{
|
||||
struct domain *d;
|
||||
@@ -169,9 +179,9 @@ static unsigned int default_vcpu0_location(void)
|
||||
return cpu;
|
||||
}
|
||||
|
||||
long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
|
||||
ret_t do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
|
||||
{
|
||||
long ret = 0;
|
||||
ret_t ret = 0;
|
||||
struct xen_domctl curop, *op = &curop;
|
||||
void *ssid = NULL; /* save security ptr between pre and post/fail hooks */
|
||||
static DEFINE_SPINLOCK(domctl_lock);
|
||||
@@ -283,11 +293,36 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
|
||||
if ( (d = domain_create(dom, domcr_flags)) == NULL )
|
||||
break;
|
||||
|
||||
ret = 0;
|
||||
switch ( (op->u.createdomain.flags >> XEN_DOMCTL_CDF_WORDSIZE_SHIFT)
|
||||
& XEN_DOMCTL_CDF_WORDSIZE_MASK )
|
||||
{
|
||||
case 0:
|
||||
if ( !IS_COMPAT(current->domain) )
|
||||
op->u.createdomain.flags |= BITS_PER_LONG
|
||||
<< XEN_DOMCTL_CDF_WORDSIZE_SHIFT;
|
||||
#ifdef CONFIG_COMPAT
|
||||
else
|
||||
{
|
||||
op->u.createdomain.flags |= COMPAT_BITS_PER_LONG
|
||||
<< XEN_DOMCTL_CDF_WORDSIZE_SHIFT;
|
||||
case COMPAT_BITS_PER_LONG:
|
||||
ret = switch_compat(d);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case BITS_PER_LONG:
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if ( ret )
|
||||
break;
|
||||
|
||||
memcpy(d->handle, op->u.createdomain.handle,
|
||||
sizeof(xen_domain_handle_t));
|
||||
|
||||
ret = 0;
|
||||
|
||||
op->domain = d->domain_id;
|
||||
if ( copy_to_guest(u_domctl, op, 1) )
|
||||
ret = -EFAULT;
|
||||
@@ -446,7 +481,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
|
||||
|
||||
case XEN_DOMCTL_getvcpucontext:
|
||||
{
|
||||
struct vcpu_guest_context *c;
|
||||
vcpu_guest_context_u c;
|
||||
struct domain *d;
|
||||
struct vcpu *v;
|
||||
|
||||
@@ -466,23 +501,48 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
|
||||
if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
|
||||
goto getvcpucontext_out;
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
BUILD_BUG_ON(sizeof(struct vcpu_guest_context)
|
||||
< sizeof(struct compat_vcpu_guest_context));
|
||||
#endif
|
||||
ret = -ENOMEM;
|
||||
if ( (c = xmalloc(struct vcpu_guest_context)) == NULL )
|
||||
if ( (c.nat = xmalloc(struct vcpu_guest_context)) == NULL )
|
||||
goto getvcpucontext_out;
|
||||
|
||||
if ( v != current )
|
||||
vcpu_pause(v);
|
||||
|
||||
arch_getdomaininfo_ctxt(v,c);
|
||||
arch_get_info_guest(v, c);
|
||||
ret = 0;
|
||||
|
||||
if ( v != current )
|
||||
vcpu_unpause(v);
|
||||
|
||||
if ( copy_to_guest(op->u.vcpucontext.ctxt, c, 1) )
|
||||
ret = -EFAULT;
|
||||
if ( !IS_COMPAT(v->domain) )
|
||||
{
|
||||
#ifndef COMPAT
|
||||
if ( copy_to_guest(op->u.vcpucontext.ctxt, c.nat, 1) )
|
||||
#else
|
||||
if ( copy_to_guest(compat_handle_cast(op->u.vcpucontext.ctxt,
|
||||
void),
|
||||
c.nat, 1) )
|
||||
#endif
|
||||
ret = -EFAULT;
|
||||
}
|
||||
#ifdef CONFIG_COMPAT
|
||||
else
|
||||
{
|
||||
#ifndef COMPAT
|
||||
if ( copy_to_guest(guest_handle_cast(op->u.vcpucontext.ctxt, void),
|
||||
c.cmp, 1) )
|
||||
#else
|
||||
if ( copy_to_compat(op->u.vcpucontext.ctxt, c.cmp, 1) )
|
||||
#endif
|
||||
ret = -EFAULT;
|
||||
}
|
||||
#endif
|
||||
|
||||
xfree(c);
|
||||
xfree(c.nat);
|
||||
|
||||
if ( copy_to_guest(u_domctl, op, 1) )
|
||||
ret = -EFAULT;
|
||||
@@ -646,6 +706,16 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
case XEN_DOMCTL_set_compat:
|
||||
ret = switch_compat(find_domain_by_id(op->domain));
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_set_native:
|
||||
ret = switch_native(find_domain_by_id(op->domain));
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
ret = arch_do_domctl(op, u_domctl);
|
||||
break;
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
#include <xen/multicall.h>
|
||||
#include <public/sched.h>
|
||||
|
||||
extern void arch_getdomaininfo_ctxt(struct vcpu *,
|
||||
struct vcpu_guest_context *);
|
||||
/* opt_sched: scheduler - default to credit */
|
||||
static char opt_sched[10] = "credit";
|
||||
string_param("sched", opt_sched);
|
||||
|
||||
@@ -192,7 +192,7 @@ int shadow_enable(struct domain *d, u32 mode);
|
||||
* manipulate the log-dirty bitmap. */
|
||||
int shadow_domctl(struct domain *d,
|
||||
xen_domctl_shadow_op_t *sc,
|
||||
XEN_GUEST_HANDLE(xen_domctl_t) u_domctl);
|
||||
XEN_GUEST_HANDLE(void) u_domctl);
|
||||
|
||||
/* Call when destroying a domain */
|
||||
void shadow_teardown(struct domain *d);
|
||||
|
||||
@@ -53,6 +53,8 @@ struct xen_domctl_createdomain {
|
||||
/* Is this an HVM guest (as opposed to a PV guest)? */
|
||||
#define _XEN_DOMCTL_CDF_hvm_guest 0
|
||||
#define XEN_DOMCTL_CDF_hvm_guest (1U<<_XEN_DOMCTL_CDF_hvm_guest)
|
||||
#define XEN_DOMCTL_CDF_WORDSIZE_MASK 255
|
||||
#define XEN_DOMCTL_CDF_WORDSIZE_SHIFT 24
|
||||
uint32_t flags;
|
||||
};
|
||||
typedef struct xen_domctl_createdomain xen_domctl_createdomain_t;
|
||||
@@ -392,6 +394,9 @@ struct xen_domctl_real_mode_area {
|
||||
typedef struct xen_domctl_real_mode_area xen_domctl_real_mode_area_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xen_domctl_real_mode_area_t);
|
||||
|
||||
#define XEN_DOMCTL_set_compat 42
|
||||
#define XEN_DOMCTL_set_native 43
|
||||
|
||||
struct xen_domctl {
|
||||
uint32_t cmd;
|
||||
uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */
|
||||
|
||||
@@ -166,6 +166,9 @@ void xlat_start_info(struct start_info *, enum XLAT_start_info_console);
|
||||
struct vcpu_runstate_info;
|
||||
void xlat_vcpu_runstate_info(struct vcpu_runstate_info *);
|
||||
|
||||
int switch_compat(struct domain *);
|
||||
int switch_native(struct domain *);
|
||||
|
||||
#define BITS_PER_GUEST_LONG(d) (!IS_COMPAT(d) ? BITS_PER_LONG : COMPAT_BITS_PER_LONG)
|
||||
|
||||
#else
|
||||
|
||||
@@ -2,10 +2,15 @@
|
||||
#ifndef __XEN_DOMAIN_H__
|
||||
#define __XEN_DOMAIN_H__
|
||||
|
||||
typedef union {
|
||||
struct vcpu_guest_context *nat;
|
||||
struct compat_vcpu_guest_context *cmp;
|
||||
} vcpu_guest_context_u __attribute__((__transparent_union__));
|
||||
|
||||
struct vcpu *alloc_vcpu(
|
||||
struct domain *d, unsigned int vcpu_id, unsigned int cpu_id);
|
||||
int boot_vcpu(
|
||||
struct domain *d, int vcpuid, struct vcpu_guest_context *ctxt);
|
||||
struct domain *d, int vcpuid, vcpu_guest_context_u ctxt);
|
||||
struct vcpu *alloc_idle_vcpu(unsigned int cpu_id);
|
||||
|
||||
struct domain *alloc_domain(domid_t domid);
|
||||
@@ -14,6 +19,9 @@ void free_domain(struct domain *d);
|
||||
struct xen_domctl_getdomaininfo;
|
||||
void getdomaininfo(
|
||||
struct domain *d, struct xen_domctl_getdomaininfo *info);
|
||||
struct compat_domctl_getdomaininfo;
|
||||
void compat_getdomaininfo(
|
||||
struct domain *d, struct compat_domctl_getdomaininfo *info);
|
||||
|
||||
/*
|
||||
* Arch-specifics.
|
||||
@@ -37,7 +45,8 @@ int arch_domain_create(struct domain *d);
|
||||
|
||||
void arch_domain_destroy(struct domain *d);
|
||||
|
||||
int arch_set_info_guest(struct vcpu *v, struct vcpu_guest_context *c);
|
||||
int arch_set_info_guest(struct vcpu *, vcpu_guest_context_u);
|
||||
void arch_get_info_guest(struct vcpu *, vcpu_guest_context_u);
|
||||
|
||||
void domain_relinquish_resources(struct domain *d);
|
||||
|
||||
|
||||
@@ -275,7 +275,13 @@ int construct_dom0(
|
||||
unsigned long image_start, unsigned long image_len,
|
||||
unsigned long initrd_start, unsigned long initrd_len,
|
||||
char *cmdline);
|
||||
int set_info_guest(struct domain *d, xen_domctl_vcpucontext_t *);
|
||||
|
||||
typedef union {
|
||||
struct xen_domctl_vcpucontext *nat;
|
||||
struct compat_domctl_vcpucontext *cmp;
|
||||
} xen_domctl_vcpucontext_u __attribute__((__transparent_union__));
|
||||
|
||||
int set_info_guest(struct domain *d, xen_domctl_vcpucontext_u);
|
||||
|
||||
struct domain *find_domain_by_id(domid_t dom);
|
||||
void domain_destroy(struct domain *d);
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
! vcpu_guest_context arch-x86/xen.h
|
||||
? acm_getdecision acm_ops.h
|
||||
! ctl_cpumap domctl.h
|
||||
! domctl_getdomaininfo domctl.h
|
||||
! domctl_scheduler_op domctl.h
|
||||
! domctl_shadow_op domctl.h
|
||||
! domctl_shadow_op_stats domctl.h
|
||||
? evtchn_alloc_unbound event_channel.h
|
||||
? evtchn_bind_interdomain event_channel.h
|
||||
? evtchn_bind_ipi event_channel.h
|
||||
|
||||