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:
Emmanuel Ackaouy committed 2007-01-05 17:34:39 +00:00
1 parent a6f33d81e1
commit 97a138cbdd
24 files changed
+637 -117

No files matched your search

+9 -9
View File
@@ -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,
+2 -2
View File
@@ -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);
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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:
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+2
View File
@@ -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
-2
View File
@@ -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
+1 -1
View File
@@ -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;
+111
View File
@@ -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:
*/
+2
View File
@@ -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
+2 -13
View File
@@ -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;
}
+137
View File
@@ -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:
*/
-7
View File
@@ -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
View File
@@ -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
View File
@@ -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;
-2
View File
@@ -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);
+1 -1
View File
@@ -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);
+5
View File
@@ -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 */
+3
View File
@@ -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
+11 -2
View File
@@ -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);
+7 -1
View File
@@ -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);
+3 -1
View File
@@ -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
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.