x86, um: ... and asm-x86 move
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
24
arch/x86/include/asm/xen/events.h
Normal file
24
arch/x86/include/asm/xen/events.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef ASM_X86__XEN__EVENTS_H
|
||||
#define ASM_X86__XEN__EVENTS_H
|
||||
|
||||
enum ipi_vector {
|
||||
XEN_RESCHEDULE_VECTOR,
|
||||
XEN_CALL_FUNCTION_VECTOR,
|
||||
XEN_CALL_FUNCTION_SINGLE_VECTOR,
|
||||
XEN_SPIN_UNLOCK_VECTOR,
|
||||
|
||||
XEN_NR_IPIS,
|
||||
};
|
||||
|
||||
static inline int xen_irqs_disabled(struct pt_regs *regs)
|
||||
{
|
||||
return raw_irqs_disabled_flags(regs->flags);
|
||||
}
|
||||
|
||||
static inline void xen_do_IRQ(int irq, struct pt_regs *regs)
|
||||
{
|
||||
regs->orig_ax = ~irq;
|
||||
do_IRQ(regs);
|
||||
}
|
||||
|
||||
#endif /* ASM_X86__XEN__EVENTS_H */
|
7
arch/x86/include/asm/xen/grant_table.h
Normal file
7
arch/x86/include/asm/xen/grant_table.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef ASM_X86__XEN__GRANT_TABLE_H
|
||||
#define ASM_X86__XEN__GRANT_TABLE_H
|
||||
|
||||
#define xen_alloc_vm_area(size) alloc_vm_area(size)
|
||||
#define xen_free_vm_area(area) free_vm_area(area)
|
||||
|
||||
#endif /* ASM_X86__XEN__GRANT_TABLE_H */
|
527
arch/x86/include/asm/xen/hypercall.h
Normal file
527
arch/x86/include/asm/xen/hypercall.h
Normal file
@@ -0,0 +1,527 @@
|
||||
/******************************************************************************
|
||||
* hypercall.h
|
||||
*
|
||||
* Linux-specific hypervisor handling.
|
||||
*
|
||||
* Copyright (c) 2002-2004, K A Fraser
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation; or, when distributed
|
||||
* separately from the Linux kernel or incorporated into other
|
||||
* software packages, subject to the following license:
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this source file (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify,
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ASM_X86__XEN__HYPERCALL_H
|
||||
#define ASM_X86__XEN__HYPERCALL_H
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <xen/interface/xen.h>
|
||||
#include <xen/interface/sched.h>
|
||||
#include <xen/interface/physdev.h>
|
||||
|
||||
/*
|
||||
* The hypercall asms have to meet several constraints:
|
||||
* - Work on 32- and 64-bit.
|
||||
* The two architectures put their arguments in different sets of
|
||||
* registers.
|
||||
*
|
||||
* - Work around asm syntax quirks
|
||||
* It isn't possible to specify one of the rNN registers in a
|
||||
* constraint, so we use explicit register variables to get the
|
||||
* args into the right place.
|
||||
*
|
||||
* - Mark all registers as potentially clobbered
|
||||
* Even unused parameters can be clobbered by the hypervisor, so we
|
||||
* need to make sure gcc knows it.
|
||||
*
|
||||
* - Avoid compiler bugs.
|
||||
* This is the tricky part. Because x86_32 has such a constrained
|
||||
* register set, gcc versions below 4.3 have trouble generating
|
||||
* code when all the arg registers and memory are trashed by the
|
||||
* asm. There are syntactically simpler ways of achieving the
|
||||
* semantics below, but they cause the compiler to crash.
|
||||
*
|
||||
* The only combination I found which works is:
|
||||
* - assign the __argX variables first
|
||||
* - list all actually used parameters as "+r" (__argX)
|
||||
* - clobber the rest
|
||||
*
|
||||
* The result certainly isn't pretty, and it really shows up cpp's
|
||||
* weakness as as macro language. Sorry. (But let's just give thanks
|
||||
* there aren't more than 5 arguments...)
|
||||
*/
|
||||
|
||||
extern struct { char _entry[32]; } hypercall_page[];
|
||||
|
||||
#define __HYPERCALL "call hypercall_page+%c[offset]"
|
||||
#define __HYPERCALL_ENTRY(x) \
|
||||
[offset] "i" (__HYPERVISOR_##x * sizeof(hypercall_page[0]))
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
#define __HYPERCALL_RETREG "eax"
|
||||
#define __HYPERCALL_ARG1REG "ebx"
|
||||
#define __HYPERCALL_ARG2REG "ecx"
|
||||
#define __HYPERCALL_ARG3REG "edx"
|
||||
#define __HYPERCALL_ARG4REG "esi"
|
||||
#define __HYPERCALL_ARG5REG "edi"
|
||||
#else
|
||||
#define __HYPERCALL_RETREG "rax"
|
||||
#define __HYPERCALL_ARG1REG "rdi"
|
||||
#define __HYPERCALL_ARG2REG "rsi"
|
||||
#define __HYPERCALL_ARG3REG "rdx"
|
||||
#define __HYPERCALL_ARG4REG "r10"
|
||||
#define __HYPERCALL_ARG5REG "r8"
|
||||
#endif
|
||||
|
||||
#define __HYPERCALL_DECLS \
|
||||
register unsigned long __res asm(__HYPERCALL_RETREG); \
|
||||
register unsigned long __arg1 asm(__HYPERCALL_ARG1REG) = __arg1; \
|
||||
register unsigned long __arg2 asm(__HYPERCALL_ARG2REG) = __arg2; \
|
||||
register unsigned long __arg3 asm(__HYPERCALL_ARG3REG) = __arg3; \
|
||||
register unsigned long __arg4 asm(__HYPERCALL_ARG4REG) = __arg4; \
|
||||
register unsigned long __arg5 asm(__HYPERCALL_ARG5REG) = __arg5;
|
||||
|
||||
#define __HYPERCALL_0PARAM "=r" (__res)
|
||||
#define __HYPERCALL_1PARAM __HYPERCALL_0PARAM, "+r" (__arg1)
|
||||
#define __HYPERCALL_2PARAM __HYPERCALL_1PARAM, "+r" (__arg2)
|
||||
#define __HYPERCALL_3PARAM __HYPERCALL_2PARAM, "+r" (__arg3)
|
||||
#define __HYPERCALL_4PARAM __HYPERCALL_3PARAM, "+r" (__arg4)
|
||||
#define __HYPERCALL_5PARAM __HYPERCALL_4PARAM, "+r" (__arg5)
|
||||
|
||||
#define __HYPERCALL_0ARG()
|
||||
#define __HYPERCALL_1ARG(a1) \
|
||||
__HYPERCALL_0ARG() __arg1 = (unsigned long)(a1);
|
||||
#define __HYPERCALL_2ARG(a1,a2) \
|
||||
__HYPERCALL_1ARG(a1) __arg2 = (unsigned long)(a2);
|
||||
#define __HYPERCALL_3ARG(a1,a2,a3) \
|
||||
__HYPERCALL_2ARG(a1,a2) __arg3 = (unsigned long)(a3);
|
||||
#define __HYPERCALL_4ARG(a1,a2,a3,a4) \
|
||||
__HYPERCALL_3ARG(a1,a2,a3) __arg4 = (unsigned long)(a4);
|
||||
#define __HYPERCALL_5ARG(a1,a2,a3,a4,a5) \
|
||||
__HYPERCALL_4ARG(a1,a2,a3,a4) __arg5 = (unsigned long)(a5);
|
||||
|
||||
#define __HYPERCALL_CLOBBER5 "memory"
|
||||
#define __HYPERCALL_CLOBBER4 __HYPERCALL_CLOBBER5, __HYPERCALL_ARG5REG
|
||||
#define __HYPERCALL_CLOBBER3 __HYPERCALL_CLOBBER4, __HYPERCALL_ARG4REG
|
||||
#define __HYPERCALL_CLOBBER2 __HYPERCALL_CLOBBER3, __HYPERCALL_ARG3REG
|
||||
#define __HYPERCALL_CLOBBER1 __HYPERCALL_CLOBBER2, __HYPERCALL_ARG2REG
|
||||
#define __HYPERCALL_CLOBBER0 __HYPERCALL_CLOBBER1, __HYPERCALL_ARG1REG
|
||||
|
||||
#define _hypercall0(type, name) \
|
||||
({ \
|
||||
__HYPERCALL_DECLS; \
|
||||
__HYPERCALL_0ARG(); \
|
||||
asm volatile (__HYPERCALL \
|
||||
: __HYPERCALL_0PARAM \
|
||||
: __HYPERCALL_ENTRY(name) \
|
||||
: __HYPERCALL_CLOBBER0); \
|
||||
(type)__res; \
|
||||
})
|
||||
|
||||
#define _hypercall1(type, name, a1) \
|
||||
({ \
|
||||
__HYPERCALL_DECLS; \
|
||||
__HYPERCALL_1ARG(a1); \
|
||||
asm volatile (__HYPERCALL \
|
||||
: __HYPERCALL_1PARAM \
|
||||
: __HYPERCALL_ENTRY(name) \
|
||||
: __HYPERCALL_CLOBBER1); \
|
||||
(type)__res; \
|
||||
})
|
||||
|
||||
#define _hypercall2(type, name, a1, a2) \
|
||||
({ \
|
||||
__HYPERCALL_DECLS; \
|
||||
__HYPERCALL_2ARG(a1, a2); \
|
||||
asm volatile (__HYPERCALL \
|
||||
: __HYPERCALL_2PARAM \
|
||||
: __HYPERCALL_ENTRY(name) \
|
||||
: __HYPERCALL_CLOBBER2); \
|
||||
(type)__res; \
|
||||
})
|
||||
|
||||
#define _hypercall3(type, name, a1, a2, a3) \
|
||||
({ \
|
||||
__HYPERCALL_DECLS; \
|
||||
__HYPERCALL_3ARG(a1, a2, a3); \
|
||||
asm volatile (__HYPERCALL \
|
||||
: __HYPERCALL_3PARAM \
|
||||
: __HYPERCALL_ENTRY(name) \
|
||||
: __HYPERCALL_CLOBBER3); \
|
||||
(type)__res; \
|
||||
})
|
||||
|
||||
#define _hypercall4(type, name, a1, a2, a3, a4) \
|
||||
({ \
|
||||
__HYPERCALL_DECLS; \
|
||||
__HYPERCALL_4ARG(a1, a2, a3, a4); \
|
||||
asm volatile (__HYPERCALL \
|
||||
: __HYPERCALL_4PARAM \
|
||||
: __HYPERCALL_ENTRY(name) \
|
||||
: __HYPERCALL_CLOBBER4); \
|
||||
(type)__res; \
|
||||
})
|
||||
|
||||
#define _hypercall5(type, name, a1, a2, a3, a4, a5) \
|
||||
({ \
|
||||
__HYPERCALL_DECLS; \
|
||||
__HYPERCALL_5ARG(a1, a2, a3, a4, a5); \
|
||||
asm volatile (__HYPERCALL \
|
||||
: __HYPERCALL_5PARAM \
|
||||
: __HYPERCALL_ENTRY(name) \
|
||||
: __HYPERCALL_CLOBBER5); \
|
||||
(type)__res; \
|
||||
})
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_set_trap_table(struct trap_info *table)
|
||||
{
|
||||
return _hypercall1(int, set_trap_table, table);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_mmu_update(struct mmu_update *req, int count,
|
||||
int *success_count, domid_t domid)
|
||||
{
|
||||
return _hypercall4(int, mmu_update, req, count, success_count, domid);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_mmuext_op(struct mmuext_op *op, int count,
|
||||
int *success_count, domid_t domid)
|
||||
{
|
||||
return _hypercall4(int, mmuext_op, op, count, success_count, domid);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_set_gdt(unsigned long *frame_list, int entries)
|
||||
{
|
||||
return _hypercall2(int, set_gdt, frame_list, entries);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp)
|
||||
{
|
||||
return _hypercall2(int, stack_switch, ss, esp);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
static inline int
|
||||
HYPERVISOR_set_callbacks(unsigned long event_selector,
|
||||
unsigned long event_address,
|
||||
unsigned long failsafe_selector,
|
||||
unsigned long failsafe_address)
|
||||
{
|
||||
return _hypercall4(int, set_callbacks,
|
||||
event_selector, event_address,
|
||||
failsafe_selector, failsafe_address);
|
||||
}
|
||||
#else /* CONFIG_X86_64 */
|
||||
static inline int
|
||||
HYPERVISOR_set_callbacks(unsigned long event_address,
|
||||
unsigned long failsafe_address,
|
||||
unsigned long syscall_address)
|
||||
{
|
||||
return _hypercall3(int, set_callbacks,
|
||||
event_address, failsafe_address,
|
||||
syscall_address);
|
||||
}
|
||||
#endif /* CONFIG_X86_{32,64} */
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_callback_op(int cmd, void *arg)
|
||||
{
|
||||
return _hypercall2(int, callback_op, cmd, arg);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_fpu_taskswitch(int set)
|
||||
{
|
||||
return _hypercall1(int, fpu_taskswitch, set);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_sched_op(int cmd, void *arg)
|
||||
{
|
||||
return _hypercall2(int, sched_op_new, cmd, arg);
|
||||
}
|
||||
|
||||
static inline long
|
||||
HYPERVISOR_set_timer_op(u64 timeout)
|
||||
{
|
||||
unsigned long timeout_hi = (unsigned long)(timeout>>32);
|
||||
unsigned long timeout_lo = (unsigned long)timeout;
|
||||
return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_set_debugreg(int reg, unsigned long value)
|
||||
{
|
||||
return _hypercall2(int, set_debugreg, reg, value);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
HYPERVISOR_get_debugreg(int reg)
|
||||
{
|
||||
return _hypercall1(unsigned long, get_debugreg, reg);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_update_descriptor(u64 ma, u64 desc)
|
||||
{
|
||||
return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_memory_op(unsigned int cmd, void *arg)
|
||||
{
|
||||
return _hypercall2(int, memory_op, cmd, arg);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_multicall(void *call_list, int nr_calls)
|
||||
{
|
||||
return _hypercall2(int, multicall, call_list, nr_calls);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_update_va_mapping(unsigned long va, pte_t new_val,
|
||||
unsigned long flags)
|
||||
{
|
||||
if (sizeof(new_val) == sizeof(long))
|
||||
return _hypercall3(int, update_va_mapping, va,
|
||||
new_val.pte, flags);
|
||||
else
|
||||
return _hypercall4(int, update_va_mapping, va,
|
||||
new_val.pte, new_val.pte >> 32, flags);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_event_channel_op(int cmd, void *arg)
|
||||
{
|
||||
int rc = _hypercall2(int, event_channel_op, cmd, arg);
|
||||
if (unlikely(rc == -ENOSYS)) {
|
||||
struct evtchn_op op;
|
||||
op.cmd = cmd;
|
||||
memcpy(&op.u, arg, sizeof(op.u));
|
||||
rc = _hypercall1(int, event_channel_op_compat, &op);
|
||||
memcpy(arg, &op.u, sizeof(op.u));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_xen_version(int cmd, void *arg)
|
||||
{
|
||||
return _hypercall2(int, xen_version, cmd, arg);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_console_io(int cmd, int count, char *str)
|
||||
{
|
||||
return _hypercall3(int, console_io, cmd, count, str);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_physdev_op(int cmd, void *arg)
|
||||
{
|
||||
int rc = _hypercall2(int, physdev_op, cmd, arg);
|
||||
if (unlikely(rc == -ENOSYS)) {
|
||||
struct physdev_op op;
|
||||
op.cmd = cmd;
|
||||
memcpy(&op.u, arg, sizeof(op.u));
|
||||
rc = _hypercall1(int, physdev_op_compat, &op);
|
||||
memcpy(arg, &op.u, sizeof(op.u));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count)
|
||||
{
|
||||
return _hypercall3(int, grant_table_op, cmd, uop, count);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_update_va_mapping_otherdomain(unsigned long va, pte_t new_val,
|
||||
unsigned long flags, domid_t domid)
|
||||
{
|
||||
if (sizeof(new_val) == sizeof(long))
|
||||
return _hypercall4(int, update_va_mapping_otherdomain, va,
|
||||
new_val.pte, flags, domid);
|
||||
else
|
||||
return _hypercall5(int, update_va_mapping_otherdomain, va,
|
||||
new_val.pte, new_val.pte >> 32,
|
||||
flags, domid);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_vm_assist(unsigned int cmd, unsigned int type)
|
||||
{
|
||||
return _hypercall2(int, vm_assist, cmd, type);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_vcpu_op(int cmd, int vcpuid, void *extra_args)
|
||||
{
|
||||
return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
static inline int
|
||||
HYPERVISOR_set_segment_base(int reg, unsigned long value)
|
||||
{
|
||||
return _hypercall2(int, set_segment_base, reg, value);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_suspend(unsigned long srec)
|
||||
{
|
||||
return _hypercall3(int, sched_op, SCHEDOP_shutdown,
|
||||
SHUTDOWN_suspend, srec);
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_nmi_op(unsigned long op, unsigned long arg)
|
||||
{
|
||||
return _hypercall2(int, nmi_op, op, arg);
|
||||
}
|
||||
|
||||
static inline void
|
||||
MULTI_fpu_taskswitch(struct multicall_entry *mcl, int set)
|
||||
{
|
||||
mcl->op = __HYPERVISOR_fpu_taskswitch;
|
||||
mcl->args[0] = set;
|
||||
}
|
||||
|
||||
static inline void
|
||||
MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va,
|
||||
pte_t new_val, unsigned long flags)
|
||||
{
|
||||
mcl->op = __HYPERVISOR_update_va_mapping;
|
||||
mcl->args[0] = va;
|
||||
if (sizeof(new_val) == sizeof(long)) {
|
||||
mcl->args[1] = new_val.pte;
|
||||
mcl->args[2] = flags;
|
||||
} else {
|
||||
mcl->args[1] = new_val.pte;
|
||||
mcl->args[2] = new_val.pte >> 32;
|
||||
mcl->args[3] = flags;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
MULTI_grant_table_op(struct multicall_entry *mcl, unsigned int cmd,
|
||||
void *uop, unsigned int count)
|
||||
{
|
||||
mcl->op = __HYPERVISOR_grant_table_op;
|
||||
mcl->args[0] = cmd;
|
||||
mcl->args[1] = (unsigned long)uop;
|
||||
mcl->args[2] = count;
|
||||
}
|
||||
|
||||
static inline void
|
||||
MULTI_update_va_mapping_otherdomain(struct multicall_entry *mcl, unsigned long va,
|
||||
pte_t new_val, unsigned long flags,
|
||||
domid_t domid)
|
||||
{
|
||||
mcl->op = __HYPERVISOR_update_va_mapping_otherdomain;
|
||||
mcl->args[0] = va;
|
||||
if (sizeof(new_val) == sizeof(long)) {
|
||||
mcl->args[1] = new_val.pte;
|
||||
mcl->args[2] = flags;
|
||||
mcl->args[3] = domid;
|
||||
} else {
|
||||
mcl->args[1] = new_val.pte;
|
||||
mcl->args[2] = new_val.pte >> 32;
|
||||
mcl->args[3] = flags;
|
||||
mcl->args[4] = domid;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
MULTI_update_descriptor(struct multicall_entry *mcl, u64 maddr,
|
||||
struct desc_struct desc)
|
||||
{
|
||||
mcl->op = __HYPERVISOR_update_descriptor;
|
||||
if (sizeof(maddr) == sizeof(long)) {
|
||||
mcl->args[0] = maddr;
|
||||
mcl->args[1] = *(unsigned long *)&desc;
|
||||
} else {
|
||||
mcl->args[0] = maddr;
|
||||
mcl->args[1] = maddr >> 32;
|
||||
mcl->args[2] = desc.a;
|
||||
mcl->args[3] = desc.b;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
MULTI_memory_op(struct multicall_entry *mcl, unsigned int cmd, void *arg)
|
||||
{
|
||||
mcl->op = __HYPERVISOR_memory_op;
|
||||
mcl->args[0] = cmd;
|
||||
mcl->args[1] = (unsigned long)arg;
|
||||
}
|
||||
|
||||
static inline void
|
||||
MULTI_mmu_update(struct multicall_entry *mcl, struct mmu_update *req,
|
||||
int count, int *success_count, domid_t domid)
|
||||
{
|
||||
mcl->op = __HYPERVISOR_mmu_update;
|
||||
mcl->args[0] = (unsigned long)req;
|
||||
mcl->args[1] = count;
|
||||
mcl->args[2] = (unsigned long)success_count;
|
||||
mcl->args[3] = domid;
|
||||
}
|
||||
|
||||
static inline void
|
||||
MULTI_mmuext_op(struct multicall_entry *mcl, struct mmuext_op *op, int count,
|
||||
int *success_count, domid_t domid)
|
||||
{
|
||||
mcl->op = __HYPERVISOR_mmuext_op;
|
||||
mcl->args[0] = (unsigned long)op;
|
||||
mcl->args[1] = count;
|
||||
mcl->args[2] = (unsigned long)success_count;
|
||||
mcl->args[3] = domid;
|
||||
}
|
||||
|
||||
static inline void
|
||||
MULTI_set_gdt(struct multicall_entry *mcl, unsigned long *frames, int entries)
|
||||
{
|
||||
mcl->op = __HYPERVISOR_set_gdt;
|
||||
mcl->args[0] = (unsigned long)frames;
|
||||
mcl->args[1] = entries;
|
||||
}
|
||||
|
||||
static inline void
|
||||
MULTI_stack_switch(struct multicall_entry *mcl,
|
||||
unsigned long ss, unsigned long esp)
|
||||
{
|
||||
mcl->op = __HYPERVISOR_stack_switch;
|
||||
mcl->args[0] = ss;
|
||||
mcl->args[1] = esp;
|
||||
}
|
||||
|
||||
#endif /* ASM_X86__XEN__HYPERCALL_H */
|
82
arch/x86/include/asm/xen/hypervisor.h
Normal file
82
arch/x86/include/asm/xen/hypervisor.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/******************************************************************************
|
||||
* hypervisor.h
|
||||
*
|
||||
* Linux-specific hypervisor handling.
|
||||
*
|
||||
* Copyright (c) 2002-2004, K A Fraser
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation; or, when distributed
|
||||
* separately from the Linux kernel or incorporated into other
|
||||
* software packages, subject to the following license:
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this source file (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify,
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ASM_X86__XEN__HYPERVISOR_H
|
||||
#define ASM_X86__XEN__HYPERVISOR_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <xen/interface/xen.h>
|
||||
#include <xen/interface/version.h>
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/desc.h>
|
||||
#if defined(__i386__)
|
||||
# ifdef CONFIG_X86_PAE
|
||||
# include <asm-generic/pgtable-nopud.h>
|
||||
# else
|
||||
# include <asm-generic/pgtable-nopmd.h>
|
||||
# endif
|
||||
#endif
|
||||
#include <asm/xen/hypercall.h>
|
||||
|
||||
/* arch/i386/kernel/setup.c */
|
||||
extern struct shared_info *HYPERVISOR_shared_info;
|
||||
extern struct start_info *xen_start_info;
|
||||
|
||||
/* arch/i386/mach-xen/evtchn.c */
|
||||
/* Force a proper event-channel callback from Xen. */
|
||||
extern void force_evtchn_callback(void);
|
||||
|
||||
/* Turn jiffies into Xen system time. */
|
||||
u64 jiffies_to_st(unsigned long jiffies);
|
||||
|
||||
|
||||
#define MULTI_UVMFLAGS_INDEX 3
|
||||
#define MULTI_UVMDOMID_INDEX 4
|
||||
|
||||
enum xen_domain_type {
|
||||
XEN_NATIVE,
|
||||
XEN_PV_DOMAIN,
|
||||
XEN_HVM_DOMAIN,
|
||||
};
|
||||
|
||||
extern enum xen_domain_type xen_domain_type;
|
||||
|
||||
#define xen_domain() (xen_domain_type != XEN_NATIVE)
|
||||
#define xen_pv_domain() (xen_domain_type == XEN_PV_DOMAIN)
|
||||
#define xen_initial_domain() (xen_pv_domain() && xen_start_info->flags & SIF_INITDOMAIN)
|
||||
#define xen_hvm_domain() (xen_domain_type == XEN_HVM_DOMAIN)
|
||||
|
||||
#endif /* ASM_X86__XEN__HYPERVISOR_H */
|
175
arch/x86/include/asm/xen/interface.h
Normal file
175
arch/x86/include/asm/xen/interface.h
Normal file
@@ -0,0 +1,175 @@
|
||||
/******************************************************************************
|
||||
* arch-x86_32.h
|
||||
*
|
||||
* Guest OS interface to x86 Xen.
|
||||
*
|
||||
* Copyright (c) 2004, K A Fraser
|
||||
*/
|
||||
|
||||
#ifndef ASM_X86__XEN__INTERFACE_H
|
||||
#define ASM_X86__XEN__INTERFACE_H
|
||||
|
||||
#ifdef __XEN__
|
||||
#define __DEFINE_GUEST_HANDLE(name, type) \
|
||||
typedef struct { type *p; } __guest_handle_ ## name
|
||||
#else
|
||||
#define __DEFINE_GUEST_HANDLE(name, type) \
|
||||
typedef type * __guest_handle_ ## name
|
||||
#endif
|
||||
|
||||
#define DEFINE_GUEST_HANDLE_STRUCT(name) \
|
||||
__DEFINE_GUEST_HANDLE(name, struct name)
|
||||
#define DEFINE_GUEST_HANDLE(name) __DEFINE_GUEST_HANDLE(name, name)
|
||||
#define GUEST_HANDLE(name) __guest_handle_ ## name
|
||||
|
||||
#ifdef __XEN__
|
||||
#if defined(__i386__)
|
||||
#define set_xen_guest_handle(hnd, val) \
|
||||
do { \
|
||||
if (sizeof(hnd) == 8) \
|
||||
*(uint64_t *)&(hnd) = 0; \
|
||||
(hnd).p = val; \
|
||||
} while (0)
|
||||
#elif defined(__x86_64__)
|
||||
#define set_xen_guest_handle(hnd, val) do { (hnd).p = val; } while (0)
|
||||
#endif
|
||||
#else
|
||||
#if defined(__i386__)
|
||||
#define set_xen_guest_handle(hnd, val) \
|
||||
do { \
|
||||
if (sizeof(hnd) == 8) \
|
||||
*(uint64_t *)&(hnd) = 0; \
|
||||
(hnd) = val; \
|
||||
} while (0)
|
||||
#elif defined(__x86_64__)
|
||||
#define set_xen_guest_handle(hnd, val) do { (hnd) = val; } while (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/* Guest handles for primitive C types. */
|
||||
__DEFINE_GUEST_HANDLE(uchar, unsigned char);
|
||||
__DEFINE_GUEST_HANDLE(uint, unsigned int);
|
||||
__DEFINE_GUEST_HANDLE(ulong, unsigned long);
|
||||
DEFINE_GUEST_HANDLE(char);
|
||||
DEFINE_GUEST_HANDLE(int);
|
||||
DEFINE_GUEST_HANDLE(long);
|
||||
DEFINE_GUEST_HANDLE(void);
|
||||
#endif
|
||||
|
||||
#ifndef HYPERVISOR_VIRT_START
|
||||
#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
|
||||
#endif
|
||||
|
||||
#ifndef machine_to_phys_mapping
|
||||
#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
|
||||
#endif
|
||||
|
||||
/* Maximum number of virtual CPUs in multi-processor guests. */
|
||||
#define MAX_VIRT_CPUS 32
|
||||
|
||||
/*
|
||||
* SEGMENT DESCRIPTOR TABLES
|
||||
*/
|
||||
/*
|
||||
* A number of GDT entries are reserved by Xen. These are not situated at the
|
||||
* start of the GDT because some stupid OSes export hard-coded selector values
|
||||
* in their ABI. These hard-coded values are always near the start of the GDT,
|
||||
* so Xen places itself out of the way, at the far end of the GDT.
|
||||
*/
|
||||
#define FIRST_RESERVED_GDT_PAGE 14
|
||||
#define FIRST_RESERVED_GDT_BYTE (FIRST_RESERVED_GDT_PAGE * 4096)
|
||||
#define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8)
|
||||
|
||||
/*
|
||||
* Send an array of these to HYPERVISOR_set_trap_table()
|
||||
* The privilege level specifies which modes may enter a trap via a software
|
||||
* interrupt. On x86/64, since rings 1 and 2 are unavailable, we allocate
|
||||
* privilege levels as follows:
|
||||
* Level == 0: Noone may enter
|
||||
* Level == 1: Kernel may enter
|
||||
* Level == 2: Kernel may enter
|
||||
* Level == 3: Everyone may enter
|
||||
*/
|
||||
#define TI_GET_DPL(_ti) ((_ti)->flags & 3)
|
||||
#define TI_GET_IF(_ti) ((_ti)->flags & 4)
|
||||
#define TI_SET_DPL(_ti, _dpl) ((_ti)->flags |= (_dpl))
|
||||
#define TI_SET_IF(_ti, _if) ((_ti)->flags |= ((!!(_if))<<2))
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
struct trap_info {
|
||||
uint8_t vector; /* exception vector */
|
||||
uint8_t flags; /* 0-3: privilege level; 4: clear event enable? */
|
||||
uint16_t cs; /* code selector */
|
||||
unsigned long address; /* code offset */
|
||||
};
|
||||
DEFINE_GUEST_HANDLE_STRUCT(trap_info);
|
||||
|
||||
struct arch_shared_info {
|
||||
unsigned long max_pfn; /* max pfn that appears in table */
|
||||
/* Frame containing list of mfns containing list of mfns containing p2m. */
|
||||
unsigned long pfn_to_mfn_frame_list_list;
|
||||
unsigned long nmi_reason;
|
||||
};
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
#include "interface_32.h"
|
||||
#else
|
||||
#include "interface_64.h"
|
||||
#endif
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/*
|
||||
* The following is all CPU context. Note that the fpu_ctxt block is filled
|
||||
* in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used.
|
||||
*/
|
||||
struct vcpu_guest_context {
|
||||
/* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */
|
||||
struct { char x[512]; } fpu_ctxt; /* User-level FPU registers */
|
||||
#define VGCF_I387_VALID (1<<0)
|
||||
#define VGCF_HVM_GUEST (1<<1)
|
||||
#define VGCF_IN_KERNEL (1<<2)
|
||||
unsigned long flags; /* VGCF_* flags */
|
||||
struct cpu_user_regs user_regs; /* User-level CPU registers */
|
||||
struct trap_info trap_ctxt[256]; /* Virtual IDT */
|
||||
unsigned long ldt_base, ldt_ents; /* LDT (linear address, # ents) */
|
||||
unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
|
||||
unsigned long kernel_ss, kernel_sp; /* Virtual TSS (only SS1/SP1) */
|
||||
/* NB. User pagetable on x86/64 is placed in ctrlreg[1]. */
|
||||
unsigned long ctrlreg[8]; /* CR0-CR7 (control registers) */
|
||||
unsigned long debugreg[8]; /* DB0-DB7 (debug registers) */
|
||||
#ifdef __i386__
|
||||
unsigned long event_callback_cs; /* CS:EIP of event callback */
|
||||
unsigned long event_callback_eip;
|
||||
unsigned long failsafe_callback_cs; /* CS:EIP of failsafe callback */
|
||||
unsigned long failsafe_callback_eip;
|
||||
#else
|
||||
unsigned long event_callback_eip;
|
||||
unsigned long failsafe_callback_eip;
|
||||
unsigned long syscall_callback_eip;
|
||||
#endif
|
||||
unsigned long vm_assist; /* VMASST_TYPE_* bitmap */
|
||||
#ifdef __x86_64__
|
||||
/* Segment base addresses. */
|
||||
uint64_t fs_base;
|
||||
uint64_t gs_base_kernel;
|
||||
uint64_t gs_base_user;
|
||||
#endif
|
||||
};
|
||||
DEFINE_GUEST_HANDLE_STRUCT(vcpu_guest_context);
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
/*
|
||||
* Prefix forces emulation of some non-trapping instructions.
|
||||
* Currently only CPUID.
|
||||
*/
|
||||
#ifdef __ASSEMBLY__
|
||||
#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ;
|
||||
#define XEN_CPUID XEN_EMULATE_PREFIX cpuid
|
||||
#else
|
||||
#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; "
|
||||
#define XEN_CPUID XEN_EMULATE_PREFIX "cpuid"
|
||||
#endif
|
||||
|
||||
#endif /* ASM_X86__XEN__INTERFACE_H */
|
97
arch/x86/include/asm/xen/interface_32.h
Normal file
97
arch/x86/include/asm/xen/interface_32.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/******************************************************************************
|
||||
* arch-x86_32.h
|
||||
*
|
||||
* Guest OS interface to x86 32-bit Xen.
|
||||
*
|
||||
* Copyright (c) 2004, K A Fraser
|
||||
*/
|
||||
|
||||
#ifndef ASM_X86__XEN__INTERFACE_32_H
|
||||
#define ASM_X86__XEN__INTERFACE_32_H
|
||||
|
||||
|
||||
/*
|
||||
* These flat segments are in the Xen-private section of every GDT. Since these
|
||||
* are also present in the initial GDT, many OSes will be able to avoid
|
||||
* installing their own GDT.
|
||||
*/
|
||||
#define FLAT_RING1_CS 0xe019 /* GDT index 259 */
|
||||
#define FLAT_RING1_DS 0xe021 /* GDT index 260 */
|
||||
#define FLAT_RING1_SS 0xe021 /* GDT index 260 */
|
||||
#define FLAT_RING3_CS 0xe02b /* GDT index 261 */
|
||||
#define FLAT_RING3_DS 0xe033 /* GDT index 262 */
|
||||
#define FLAT_RING3_SS 0xe033 /* GDT index 262 */
|
||||
|
||||
#define FLAT_KERNEL_CS FLAT_RING1_CS
|
||||
#define FLAT_KERNEL_DS FLAT_RING1_DS
|
||||
#define FLAT_KERNEL_SS FLAT_RING1_SS
|
||||
#define FLAT_USER_CS FLAT_RING3_CS
|
||||
#define FLAT_USER_DS FLAT_RING3_DS
|
||||
#define FLAT_USER_SS FLAT_RING3_SS
|
||||
|
||||
/* And the trap vector is... */
|
||||
#define TRAP_INSTR "int $0x82"
|
||||
|
||||
/*
|
||||
* Virtual addresses beyond this are not modifiable by guest OSes. The
|
||||
* machine->physical mapping table starts at this address, read-only.
|
||||
*/
|
||||
#define __HYPERVISOR_VIRT_START 0xF5800000
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
struct cpu_user_regs {
|
||||
uint32_t ebx;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
uint32_t esi;
|
||||
uint32_t edi;
|
||||
uint32_t ebp;
|
||||
uint32_t eax;
|
||||
uint16_t error_code; /* private */
|
||||
uint16_t entry_vector; /* private */
|
||||
uint32_t eip;
|
||||
uint16_t cs;
|
||||
uint8_t saved_upcall_mask;
|
||||
uint8_t _pad0;
|
||||
uint32_t eflags; /* eflags.IF == !saved_upcall_mask */
|
||||
uint32_t esp;
|
||||
uint16_t ss, _pad1;
|
||||
uint16_t es, _pad2;
|
||||
uint16_t ds, _pad3;
|
||||
uint16_t fs, _pad4;
|
||||
uint16_t gs, _pad5;
|
||||
};
|
||||
DEFINE_GUEST_HANDLE_STRUCT(cpu_user_regs);
|
||||
|
||||
typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */
|
||||
|
||||
struct arch_vcpu_info {
|
||||
unsigned long cr2;
|
||||
unsigned long pad[5]; /* sizeof(struct vcpu_info) == 64 */
|
||||
};
|
||||
|
||||
struct xen_callback {
|
||||
unsigned long cs;
|
||||
unsigned long eip;
|
||||
};
|
||||
typedef struct xen_callback xen_callback_t;
|
||||
|
||||
#define XEN_CALLBACK(__cs, __eip) \
|
||||
((struct xen_callback){ .cs = (__cs), .eip = (unsigned long)(__eip) })
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
|
||||
/*
|
||||
* Page-directory addresses above 4GB do not fit into architectural %cr3.
|
||||
* When accessing %cr3, or equivalent field in vcpu_guest_context, guests
|
||||
* must use the following accessor macros to pack/unpack valid MFNs.
|
||||
*
|
||||
* Note that Xen is using the fact that the pagetable base is always
|
||||
* page-aligned, and putting the 12 MSB of the address into the 12 LSB
|
||||
* of cr3.
|
||||
*/
|
||||
#define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20))
|
||||
#define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20))
|
||||
|
||||
#endif /* ASM_X86__XEN__INTERFACE_32_H */
|
159
arch/x86/include/asm/xen/interface_64.h
Normal file
159
arch/x86/include/asm/xen/interface_64.h
Normal file
@@ -0,0 +1,159 @@
|
||||
#ifndef ASM_X86__XEN__INTERFACE_64_H
|
||||
#define ASM_X86__XEN__INTERFACE_64_H
|
||||
|
||||
/*
|
||||
* 64-bit segment selectors
|
||||
* These flat segments are in the Xen-private section of every GDT. Since these
|
||||
* are also present in the initial GDT, many OSes will be able to avoid
|
||||
* installing their own GDT.
|
||||
*/
|
||||
|
||||
#define FLAT_RING3_CS32 0xe023 /* GDT index 260 */
|
||||
#define FLAT_RING3_CS64 0xe033 /* GDT index 261 */
|
||||
#define FLAT_RING3_DS32 0xe02b /* GDT index 262 */
|
||||
#define FLAT_RING3_DS64 0x0000 /* NULL selector */
|
||||
#define FLAT_RING3_SS32 0xe02b /* GDT index 262 */
|
||||
#define FLAT_RING3_SS64 0xe02b /* GDT index 262 */
|
||||
|
||||
#define FLAT_KERNEL_DS64 FLAT_RING3_DS64
|
||||
#define FLAT_KERNEL_DS32 FLAT_RING3_DS32
|
||||
#define FLAT_KERNEL_DS FLAT_KERNEL_DS64
|
||||
#define FLAT_KERNEL_CS64 FLAT_RING3_CS64
|
||||
#define FLAT_KERNEL_CS32 FLAT_RING3_CS32
|
||||
#define FLAT_KERNEL_CS FLAT_KERNEL_CS64
|
||||
#define FLAT_KERNEL_SS64 FLAT_RING3_SS64
|
||||
#define FLAT_KERNEL_SS32 FLAT_RING3_SS32
|
||||
#define FLAT_KERNEL_SS FLAT_KERNEL_SS64
|
||||
|
||||
#define FLAT_USER_DS64 FLAT_RING3_DS64
|
||||
#define FLAT_USER_DS32 FLAT_RING3_DS32
|
||||
#define FLAT_USER_DS FLAT_USER_DS64
|
||||
#define FLAT_USER_CS64 FLAT_RING3_CS64
|
||||
#define FLAT_USER_CS32 FLAT_RING3_CS32
|
||||
#define FLAT_USER_CS FLAT_USER_CS64
|
||||
#define FLAT_USER_SS64 FLAT_RING3_SS64
|
||||
#define FLAT_USER_SS32 FLAT_RING3_SS32
|
||||
#define FLAT_USER_SS FLAT_USER_SS64
|
||||
|
||||
#define __HYPERVISOR_VIRT_START 0xFFFF800000000000
|
||||
#define __HYPERVISOR_VIRT_END 0xFFFF880000000000
|
||||
#define __MACH2PHYS_VIRT_START 0xFFFF800000000000
|
||||
#define __MACH2PHYS_VIRT_END 0xFFFF804000000000
|
||||
|
||||
#ifndef HYPERVISOR_VIRT_START
|
||||
#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
|
||||
#define HYPERVISOR_VIRT_END mk_unsigned_long(__HYPERVISOR_VIRT_END)
|
||||
#endif
|
||||
|
||||
#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START)
|
||||
#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END)
|
||||
#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>3)
|
||||
#ifndef machine_to_phys_mapping
|
||||
#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* int HYPERVISOR_set_segment_base(unsigned int which, unsigned long base)
|
||||
* @which == SEGBASE_* ; @base == 64-bit base address
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
#define SEGBASE_FS 0
|
||||
#define SEGBASE_GS_USER 1
|
||||
#define SEGBASE_GS_KERNEL 2
|
||||
#define SEGBASE_GS_USER_SEL 3 /* Set user %gs specified in base[15:0] */
|
||||
|
||||
/*
|
||||
* int HYPERVISOR_iret(void)
|
||||
* All arguments are on the kernel stack, in the following format.
|
||||
* Never returns if successful. Current kernel context is lost.
|
||||
* The saved CS is mapped as follows:
|
||||
* RING0 -> RING3 kernel mode.
|
||||
* RING1 -> RING3 kernel mode.
|
||||
* RING2 -> RING3 kernel mode.
|
||||
* RING3 -> RING3 user mode.
|
||||
* However RING0 indicates that the guest kernel should return to iteself
|
||||
* directly with
|
||||
* orb $3,1*8(%rsp)
|
||||
* iretq
|
||||
* If flags contains VGCF_in_syscall:
|
||||
* Restore RAX, RIP, RFLAGS, RSP.
|
||||
* Discard R11, RCX, CS, SS.
|
||||
* Otherwise:
|
||||
* Restore RAX, R11, RCX, CS:RIP, RFLAGS, SS:RSP.
|
||||
* All other registers are saved on hypercall entry and restored to user.
|
||||
*/
|
||||
/* Guest exited in SYSCALL context? Return to guest with SYSRET? */
|
||||
#define _VGCF_in_syscall 8
|
||||
#define VGCF_in_syscall (1<<_VGCF_in_syscall)
|
||||
#define VGCF_IN_SYSCALL VGCF_in_syscall
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
struct iret_context {
|
||||
/* Top of stack (%rsp at point of hypercall). */
|
||||
uint64_t rax, r11, rcx, flags, rip, cs, rflags, rsp, ss;
|
||||
/* Bottom of iret stack frame. */
|
||||
};
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
/* Anonymous union includes both 32- and 64-bit names (e.g., eax/rax). */
|
||||
#define __DECL_REG(name) union { \
|
||||
uint64_t r ## name, e ## name; \
|
||||
uint32_t _e ## name; \
|
||||
}
|
||||
#else
|
||||
/* Non-gcc sources must always use the proper 64-bit name (e.g., rax). */
|
||||
#define __DECL_REG(name) uint64_t r ## name
|
||||
#endif
|
||||
|
||||
struct cpu_user_regs {
|
||||
uint64_t r15;
|
||||
uint64_t r14;
|
||||
uint64_t r13;
|
||||
uint64_t r12;
|
||||
__DECL_REG(bp);
|
||||
__DECL_REG(bx);
|
||||
uint64_t r11;
|
||||
uint64_t r10;
|
||||
uint64_t r9;
|
||||
uint64_t r8;
|
||||
__DECL_REG(ax);
|
||||
__DECL_REG(cx);
|
||||
__DECL_REG(dx);
|
||||
__DECL_REG(si);
|
||||
__DECL_REG(di);
|
||||
uint32_t error_code; /* private */
|
||||
uint32_t entry_vector; /* private */
|
||||
__DECL_REG(ip);
|
||||
uint16_t cs, _pad0[1];
|
||||
uint8_t saved_upcall_mask;
|
||||
uint8_t _pad1[3];
|
||||
__DECL_REG(flags); /* rflags.IF == !saved_upcall_mask */
|
||||
__DECL_REG(sp);
|
||||
uint16_t ss, _pad2[3];
|
||||
uint16_t es, _pad3[3];
|
||||
uint16_t ds, _pad4[3];
|
||||
uint16_t fs, _pad5[3]; /* Non-zero => takes precedence over fs_base. */
|
||||
uint16_t gs, _pad6[3]; /* Non-zero => takes precedence over gs_base_usr. */
|
||||
};
|
||||
DEFINE_GUEST_HANDLE_STRUCT(cpu_user_regs);
|
||||
|
||||
#undef __DECL_REG
|
||||
|
||||
#define xen_pfn_to_cr3(pfn) ((unsigned long)(pfn) << 12)
|
||||
#define xen_cr3_to_pfn(cr3) ((unsigned long)(cr3) >> 12)
|
||||
|
||||
struct arch_vcpu_info {
|
||||
unsigned long cr2;
|
||||
unsigned long pad; /* sizeof(vcpu_info_t) == 64 */
|
||||
};
|
||||
|
||||
typedef unsigned long xen_callback_t;
|
||||
|
||||
#define XEN_CALLBACK(__cs, __rip) \
|
||||
((unsigned long)(__rip))
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
|
||||
#endif /* ASM_X86__XEN__INTERFACE_64_H */
|
165
arch/x86/include/asm/xen/page.h
Normal file
165
arch/x86/include/asm/xen/page.h
Normal file
@@ -0,0 +1,165 @@
|
||||
#ifndef ASM_X86__XEN__PAGE_H
|
||||
#define ASM_X86__XEN__PAGE_H
|
||||
|
||||
#include <linux/pfn.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
#include <xen/features.h>
|
||||
|
||||
/* Xen machine address */
|
||||
typedef struct xmaddr {
|
||||
phys_addr_t maddr;
|
||||
} xmaddr_t;
|
||||
|
||||
/* Xen pseudo-physical address */
|
||||
typedef struct xpaddr {
|
||||
phys_addr_t paddr;
|
||||
} xpaddr_t;
|
||||
|
||||
#define XMADDR(x) ((xmaddr_t) { .maddr = (x) })
|
||||
#define XPADDR(x) ((xpaddr_t) { .paddr = (x) })
|
||||
|
||||
/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
|
||||
#define INVALID_P2M_ENTRY (~0UL)
|
||||
#define FOREIGN_FRAME_BIT (1UL<<31)
|
||||
#define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT)
|
||||
|
||||
/* Maximum amount of memory we can handle in a domain in pages */
|
||||
#define MAX_DOMAIN_PAGES \
|
||||
((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE))
|
||||
|
||||
|
||||
extern unsigned long get_phys_to_machine(unsigned long pfn);
|
||||
extern void set_phys_to_machine(unsigned long pfn, unsigned long mfn);
|
||||
|
||||
static inline unsigned long pfn_to_mfn(unsigned long pfn)
|
||||
{
|
||||
if (xen_feature(XENFEAT_auto_translated_physmap))
|
||||
return pfn;
|
||||
|
||||
return get_phys_to_machine(pfn) & ~FOREIGN_FRAME_BIT;
|
||||
}
|
||||
|
||||
static inline int phys_to_machine_mapping_valid(unsigned long pfn)
|
||||
{
|
||||
if (xen_feature(XENFEAT_auto_translated_physmap))
|
||||
return 1;
|
||||
|
||||
return get_phys_to_machine(pfn) != INVALID_P2M_ENTRY;
|
||||
}
|
||||
|
||||
static inline unsigned long mfn_to_pfn(unsigned long mfn)
|
||||
{
|
||||
unsigned long pfn;
|
||||
|
||||
if (xen_feature(XENFEAT_auto_translated_physmap))
|
||||
return mfn;
|
||||
|
||||
#if 0
|
||||
if (unlikely((mfn >> machine_to_phys_order) != 0))
|
||||
return max_mapnr;
|
||||
#endif
|
||||
|
||||
pfn = 0;
|
||||
/*
|
||||
* The array access can fail (e.g., device space beyond end of RAM).
|
||||
* In such cases it doesn't matter what we return (we return garbage),
|
||||
* but we must handle the fault without crashing!
|
||||
*/
|
||||
__get_user(pfn, &machine_to_phys_mapping[mfn]);
|
||||
|
||||
return pfn;
|
||||
}
|
||||
|
||||
static inline xmaddr_t phys_to_machine(xpaddr_t phys)
|
||||
{
|
||||
unsigned offset = phys.paddr & ~PAGE_MASK;
|
||||
return XMADDR(PFN_PHYS(pfn_to_mfn(PFN_DOWN(phys.paddr))) | offset);
|
||||
}
|
||||
|
||||
static inline xpaddr_t machine_to_phys(xmaddr_t machine)
|
||||
{
|
||||
unsigned offset = machine.maddr & ~PAGE_MASK;
|
||||
return XPADDR(PFN_PHYS(mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* We detect special mappings in one of two ways:
|
||||
* 1. If the MFN is an I/O page then Xen will set the m2p entry
|
||||
* to be outside our maximum possible pseudophys range.
|
||||
* 2. If the MFN belongs to a different domain then we will certainly
|
||||
* not have MFN in our p2m table. Conversely, if the page is ours,
|
||||
* then we'll have p2m(m2p(MFN))==MFN.
|
||||
* If we detect a special mapping then it doesn't have a 'struct page'.
|
||||
* We force !pfn_valid() by returning an out-of-range pointer.
|
||||
*
|
||||
* NB. These checks require that, for any MFN that is not in our reservation,
|
||||
* there is no PFN such that p2m(PFN) == MFN. Otherwise we can get confused if
|
||||
* we are foreign-mapping the MFN, and the other domain as m2p(MFN) == PFN.
|
||||
* Yikes! Various places must poke in INVALID_P2M_ENTRY for safety.
|
||||
*
|
||||
* NB2. When deliberately mapping foreign pages into the p2m table, you *must*
|
||||
* use FOREIGN_FRAME(). This will cause pte_pfn() to choke on it, as we
|
||||
* require. In all the cases we care about, the FOREIGN_FRAME bit is
|
||||
* masked (e.g., pfn_to_mfn()) so behaviour there is correct.
|
||||
*/
|
||||
static inline unsigned long mfn_to_local_pfn(unsigned long mfn)
|
||||
{
|
||||
extern unsigned long max_mapnr;
|
||||
unsigned long pfn = mfn_to_pfn(mfn);
|
||||
if ((pfn < max_mapnr)
|
||||
&& !xen_feature(XENFEAT_auto_translated_physmap)
|
||||
&& (get_phys_to_machine(pfn) != mfn))
|
||||
return max_mapnr; /* force !pfn_valid() */
|
||||
/* XXX fixme; not true with sparsemem */
|
||||
return pfn;
|
||||
}
|
||||
|
||||
/* VIRT <-> MACHINE conversion */
|
||||
#define virt_to_machine(v) (phys_to_machine(XPADDR(__pa(v))))
|
||||
#define virt_to_mfn(v) (pfn_to_mfn(PFN_DOWN(__pa(v))))
|
||||
#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT))
|
||||
|
||||
static inline unsigned long pte_mfn(pte_t pte)
|
||||
{
|
||||
return (pte.pte & PTE_PFN_MASK) >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
static inline pte_t mfn_pte(unsigned long page_nr, pgprot_t pgprot)
|
||||
{
|
||||
pte_t pte;
|
||||
|
||||
pte.pte = ((phys_addr_t)page_nr << PAGE_SHIFT) |
|
||||
(pgprot_val(pgprot) & __supported_pte_mask);
|
||||
|
||||
return pte;
|
||||
}
|
||||
|
||||
static inline pteval_t pte_val_ma(pte_t pte)
|
||||
{
|
||||
return pte.pte;
|
||||
}
|
||||
|
||||
static inline pte_t __pte_ma(pteval_t x)
|
||||
{
|
||||
return (pte_t) { .pte = x };
|
||||
}
|
||||
|
||||
#define pmd_val_ma(v) ((v).pmd)
|
||||
#ifdef __PAGETABLE_PUD_FOLDED
|
||||
#define pud_val_ma(v) ((v).pgd.pgd)
|
||||
#else
|
||||
#define pud_val_ma(v) ((v).pud)
|
||||
#endif
|
||||
#define __pmd_ma(x) ((pmd_t) { (x) } )
|
||||
|
||||
#define pgd_val_ma(x) ((x).pgd)
|
||||
|
||||
|
||||
xmaddr_t arbitrary_virt_to_machine(void *address);
|
||||
void make_lowmem_page_readonly(void *vaddr);
|
||||
void make_lowmem_page_readwrite(void *vaddr);
|
||||
|
||||
#endif /* ASM_X86__XEN__PAGE_H */
|
Reference in New Issue
Block a user