mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
bitkeeper revision 1.1159.1.545 (4208ec60-ql2CB2KKyZRC_8udlW9kA)
Merge tempest.cl.cam.ac.uk:/auto/groups/xeno-xenod/BK/xeno.bk into tempest.cl.cam.ac.uk:/local/scratch/smh22/xen-unstable.bk
This commit is contained in:
commit
f50b658923
74 files changed
+1350
-1288
No files matched your search
@@ -867,8 +867,8 @@
|
||||
3ddb79bcBit4xJXbwtX0kb1hh2uO1Q xen/arch/x86/idle0_task.c
|
||||
3ddb79bcKIkRR0kqWaJhe5VUDkMdxg xen/arch/x86/io_apic.c
|
||||
3ddb79bdqfIcjkz_h9Hvtp8Tk_19Zw xen/arch/x86/irq.c
|
||||
40ec29ffuOa1ZvmJHzFKyZn4k_RcXg xen/arch/x86/memory.c
|
||||
41d54a76qfpO0VnbL2tYs0Jgt3W3XA xen/arch/x86/microcode.c
|
||||
40ec29ffuOa1ZvmJHzFKyZn4k_RcXg xen/arch/x86/mm.c
|
||||
3ddb79bdS4UeWWXDH-FaBKqcpMFcnw xen/arch/x86/mpparse.c
|
||||
41aaf566Z4sTDgJ77eEg0TzzQ1ka6Q xen/arch/x86/mtrr/amd.c
|
||||
41aaf566TOpOBXT00wwQGUh20f1rlA xen/arch/x86/mtrr/centaur.c
|
||||
@@ -1038,6 +1038,7 @@
|
||||
418fbcfe_WliJPToeVM-9VStvym-hw xen/include/asm-x86/x86_32/asm_defns.h
|
||||
3ddb79c2ADvRmdexd9y3AYK9_NTx-Q xen/include/asm-x86/x86_32/current.h
|
||||
3e20b82fl1jmQiKdLy7fxMcutfpjWA xen/include/asm-x86/x86_32/domain_page.h
|
||||
4208e2a3ZNFroNXbX9OYaOB-xtUyDQ xen/include/asm-x86/x86_32/page.h
|
||||
3ddb79c3mbqEM7QQr3zVq7NiBNhouA xen/include/asm-x86/x86_32/regs.h
|
||||
3e7f358aG11EvMI9VJ4_9hD4LUO7rQ xen/include/asm-x86/x86_32/string.h
|
||||
3ddb79c3M2n1ROZH6xk3HbyN4CPDqg xen/include/asm-x86/x86_32/uaccess.h
|
||||
@@ -1045,6 +1046,7 @@
|
||||
404f1b9ceJeGVaPNIENm2FkK0AgEOQ xen/include/asm-x86/x86_64/current.h
|
||||
41febc4b1aCGLsm0Y0b_82h7lFtrEA xen/include/asm-x86/x86_64/domain_page.h
|
||||
404f1badfXZJZ2sU8sh9PS2EZvd19Q xen/include/asm-x86/x86_64/ldt.h
|
||||
4208e2a3Fktw4ZttKdDxbhvTQ6brfQ xen/include/asm-x86/x86_64/page.h
|
||||
404f1bb86rAXB3aLS1vYdcqpJiEcyg xen/include/asm-x86/x86_64/regs.h
|
||||
40e1966azOJZfNI6Ilthe6Q-T3Hewg xen/include/asm-x86/x86_64/string.h
|
||||
404f1bc4tWkB9Qr8RkKtZGW5eMQzhw xen/include/asm-x86/x86_64/uaccess.h
|
||||
|
||||
@@ -915,7 +915,7 @@ static inline void establish_pte(struct vm_area_struct * vma, unsigned long addr
|
||||
#ifdef CONFIG_XEN
|
||||
if ( likely(vma->vm_mm == current->mm) ) {
|
||||
XEN_flush_page_update_queue();
|
||||
HYPERVISOR_update_va_mapping(address>>PAGE_SHIFT, entry, UVMF_INVLPG);
|
||||
HYPERVISOR_update_va_mapping(address, entry, UVMF_INVLPG);
|
||||
} else {
|
||||
set_pte(page_table, entry);
|
||||
flush_tlb_page(vma, address);
|
||||
@@ -1191,7 +1191,7 @@ static int do_swap_page(struct mm_struct * mm,
|
||||
#ifdef CONFIG_XEN
|
||||
if ( likely(vma->vm_mm == current->mm) ) {
|
||||
XEN_flush_page_update_queue();
|
||||
HYPERVISOR_update_va_mapping(address>>PAGE_SHIFT, pte, 0);
|
||||
HYPERVISOR_update_va_mapping(address, pte, 0);
|
||||
} else {
|
||||
set_pte(page_table, pte);
|
||||
XEN_flush_page_update_queue();
|
||||
@@ -1247,7 +1247,7 @@ static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma,
|
||||
#ifdef CONFIG_XEN
|
||||
if ( likely(vma->vm_mm == current->mm) ) {
|
||||
XEN_flush_page_update_queue();
|
||||
HYPERVISOR_update_va_mapping(addr>>PAGE_SHIFT, entry, 0);
|
||||
HYPERVISOR_update_va_mapping(addr, entry, 0);
|
||||
} else {
|
||||
set_pte(page_table, entry);
|
||||
XEN_flush_page_update_queue();
|
||||
@@ -1333,7 +1333,7 @@ static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma,
|
||||
#ifdef CONFIG_XEN
|
||||
if ( likely(vma->vm_mm == current->mm) ) {
|
||||
XEN_flush_page_update_queue();
|
||||
HYPERVISOR_update_va_mapping(address>>PAGE_SHIFT, entry, 0);
|
||||
HYPERVISOR_update_va_mapping(address, entry, 0);
|
||||
} else {
|
||||
set_pte(page_table, entry);
|
||||
XEN_flush_page_update_queue();
|
||||
|
||||
@@ -229,7 +229,9 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code,
|
||||
/* Set the "privileged fault" bit to something sane. */
|
||||
error_code &= 3;
|
||||
error_code |= (regs->xcs & 2) << 1;
|
||||
|
||||
if (regs->eflags & X86_EFLAGS_VM)
|
||||
error_code |= 4;
|
||||
|
||||
if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
|
||||
SIGSEGV) == NOTIFY_STOP)
|
||||
return;
|
||||
|
||||
@@ -95,7 +95,7 @@ static void fast_flush_area(int idx, int nr_pages)
|
||||
for ( i = 0; i < nr_pages; i++ )
|
||||
{
|
||||
mcl[i].op = __HYPERVISOR_update_va_mapping;
|
||||
mcl[i].args[0] = MMAP_VADDR(idx, i) >> PAGE_SHIFT;
|
||||
mcl[i].args[0] = MMAP_VADDR(idx, i);
|
||||
mcl[i].args[1] = 0;
|
||||
mcl[i].args[2] = 0;
|
||||
}
|
||||
@@ -343,14 +343,14 @@ static void dispatch_probe(blkif_t *blkif, blkif_request_t *req)
|
||||
|
||||
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
|
||||
if ( HYPERVISOR_update_va_mapping_otherdomain(
|
||||
MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
|
||||
MMAP_VADDR(pending_idx, 0),
|
||||
(pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
|
||||
0, (blkif->is_blktap ? ID_TO_DOM(req->id) : blkif->domid) ) )
|
||||
|
||||
goto out;
|
||||
#else
|
||||
if ( HYPERVISOR_update_va_mapping_otherdomain(
|
||||
MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
|
||||
MMAP_VADDR(pending_idx, 0),
|
||||
(pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
|
||||
0, blkif->domid) )
|
||||
|
||||
@@ -436,7 +436,7 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
|
||||
for ( i = 0; i < nr_psegs; i++ )
|
||||
{
|
||||
mcl[i].op = __HYPERVISOR_update_va_mapping_otherdomain;
|
||||
mcl[i].args[0] = MMAP_VADDR(pending_idx, i) >> PAGE_SHIFT;
|
||||
mcl[i].args[0] = MMAP_VADDR(pending_idx, i);
|
||||
mcl[i].args[1] = (phys_seg[i].buffer & PAGE_MASK) | remap_prot;
|
||||
mcl[i].args[2] = 0;
|
||||
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "blktap.h"
|
||||
|
||||
int __init xlblk_init(void)
|
||||
int __init xlblktap_init(void)
|
||||
{
|
||||
ctrl_msg_t cmsg;
|
||||
blkif_fe_driver_status_t fe_st;
|
||||
@@ -64,6 +64,7 @@ int __init xlblk_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* tap doesn't handle suspend/resume */
|
||||
void blkdev_suspend(void)
|
||||
{
|
||||
}
|
||||
@@ -81,6 +82,6 @@ void blkdev_resume(void)
|
||||
memcpy(cmsg.msg, &st, sizeof(st));
|
||||
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
__initcall(xlblk_init);
|
||||
__initcall(xlblktap_init);
|
||||
@@ -48,6 +48,12 @@
|
||||
#define WPRINTK(fmt, args...) printk(KERN_WARNING "blk_tap: " fmt, ##args)
|
||||
|
||||
|
||||
/* -------[ state descriptors ]--------------------------------------- */
|
||||
|
||||
#define BLKIF_STATE_CLOSED 0
|
||||
#define BLKIF_STATE_DISCONNECTED 1
|
||||
#define BLKIF_STATE_CONNECTED 2
|
||||
|
||||
/* -------[ connection tracking ]------------------------------------- */
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
@@ -99,7 +105,6 @@ typedef struct {
|
||||
unsigned long mach_fas[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
unsigned long virt_fas[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
int next_free;
|
||||
int inuse; /* debugging */
|
||||
} active_req_t;
|
||||
|
||||
typedef unsigned int ACTIVE_RING_IDX;
|
||||
@@ -181,7 +186,7 @@ extern unsigned long mmap_vstart;
|
||||
* for shared memory rings.
|
||||
*/
|
||||
|
||||
#define RING_PAGES 128
|
||||
#define RING_PAGES 3 /* Ctrl, Front, and Back */
|
||||
extern unsigned long rings_vstart;
|
||||
|
||||
|
||||
@@ -190,11 +195,10 @@ extern unsigned long blktap_mode;
|
||||
|
||||
/* Connection to a single backend domain. */
|
||||
extern blkif_front_ring_t blktap_be_ring;
|
||||
extern unsigned int blktap_be_evtchn;
|
||||
extern unsigned int blktap_be_state;
|
||||
|
||||
/* Event channel to backend domain. */
|
||||
extern unsigned int blkif_ptbe_evtchn;
|
||||
|
||||
/* User ring status... this will soon vanish into a ring struct. */
|
||||
/* User ring status. */
|
||||
extern unsigned long blktap_ring_ok;
|
||||
|
||||
/* -------[ ...and function prototypes. ]----------------------------- */
|
||||
@@ -213,8 +217,7 @@ void blktap_kick_user(void);
|
||||
/* user ring access functions: */
|
||||
int blktap_write_fe_ring(blkif_request_t *req);
|
||||
int blktap_write_be_ring(blkif_response_t *rsp);
|
||||
int blktap_read_fe_ring(void);
|
||||
int blktap_read_be_ring(void);
|
||||
int blktap_write_ctrl_ring(ctrl_msg_t *msg);
|
||||
|
||||
/* fe/be ring access functions: */
|
||||
int write_resp_to_fe_ring(blkif_t *blkif, blkif_response_t *rsp);
|
||||
|
||||
@@ -10,10 +10,6 @@
|
||||
|
||||
#include "blktap.h"
|
||||
|
||||
#define BLKIF_STATE_CLOSED 0
|
||||
#define BLKIF_STATE_DISCONNECTED 1
|
||||
#define BLKIF_STATE_CONNECTED 2
|
||||
|
||||
static char *blkif_state_name[] = {
|
||||
[BLKIF_STATE_CLOSED] = "closed",
|
||||
[BLKIF_STATE_DISCONNECTED] = "disconnected",
|
||||
@@ -26,9 +22,10 @@ static char * blkif_status_name[] = {
|
||||
[BLKIF_INTERFACE_STATUS_CONNECTED] = "connected",
|
||||
[BLKIF_INTERFACE_STATUS_CHANGED] = "changed",
|
||||
};
|
||||
static unsigned int blkif_pt_state = BLKIF_STATE_CLOSED;
|
||||
static unsigned blkif_ptbe_irq;
|
||||
unsigned int blkif_ptbe_evtchn;
|
||||
|
||||
static unsigned blktap_be_irq;
|
||||
unsigned int blktap_be_state = BLKIF_STATE_CLOSED;
|
||||
unsigned int blktap_be_evtchn;
|
||||
|
||||
/*-----[ Control Messages to/from Frontend VMs ]--------------------------*/
|
||||
|
||||
@@ -306,7 +303,7 @@ static void blkif_ptbe_disconnect(void)
|
||||
sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL);
|
||||
SHARED_RING_INIT(BLKIF_RING, sring);
|
||||
FRONT_RING_INIT(BLKIF_RING, &blktap_be_ring, sring);
|
||||
blkif_pt_state = BLKIF_STATE_DISCONNECTED;
|
||||
blktap_be_state = BLKIF_STATE_DISCONNECTED;
|
||||
DPRINTK("Blkif-Passthrough-BE is now DISCONNECTED.\n");
|
||||
blkif_ptbe_send_interface_connect();
|
||||
}
|
||||
@@ -315,10 +312,10 @@ static void blkif_ptbe_connect(blkif_fe_interface_status_t *status)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
blkif_ptbe_evtchn = status->evtchn;
|
||||
blkif_ptbe_irq = bind_evtchn_to_irq(blkif_ptbe_evtchn);
|
||||
blktap_be_evtchn = status->evtchn;
|
||||
blktap_be_irq = bind_evtchn_to_irq(blktap_be_evtchn);
|
||||
|
||||
err = request_irq(blkif_ptbe_irq, blkif_ptbe_int,
|
||||
err = request_irq(blktap_be_irq, blkif_ptbe_int,
|
||||
SA_SAMPLE_RANDOM, "blkif", NULL);
|
||||
if ( err ) {
|
||||
WPRINTK("blkfront request_irq failed (%d)\n", err);
|
||||
@@ -326,7 +323,7 @@ static void blkif_ptbe_connect(blkif_fe_interface_status_t *status)
|
||||
} else {
|
||||
/* transtion to connected in case we need to do a
|
||||
a partion probe on a whole disk */
|
||||
blkif_pt_state = BLKIF_STATE_CONNECTED;
|
||||
blktap_be_state = BLKIF_STATE_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,7 +331,7 @@ static void unexpected(blkif_fe_interface_status_t *status)
|
||||
{
|
||||
WPRINTK(" TAP: Unexpected blkif status %s in state %s\n",
|
||||
blkif_status_name[status->status],
|
||||
blkif_state_name[blkif_pt_state]);
|
||||
blkif_state_name[blktap_be_state]);
|
||||
}
|
||||
|
||||
static void blkif_ptbe_status(
|
||||
@@ -352,7 +349,7 @@ static void blkif_ptbe_status(
|
||||
switch ( status->status )
|
||||
{
|
||||
case BLKIF_INTERFACE_STATUS_CLOSED:
|
||||
switch ( blkif_pt_state )
|
||||
switch ( blktap_be_state )
|
||||
{
|
||||
case BLKIF_STATE_CLOSED:
|
||||
unexpected(status);
|
||||
@@ -366,7 +363,7 @@ static void blkif_ptbe_status(
|
||||
break;
|
||||
|
||||
case BLKIF_INTERFACE_STATUS_DISCONNECTED:
|
||||
switch ( blkif_pt_state )
|
||||
switch ( blktap_be_state )
|
||||
{
|
||||
case BLKIF_STATE_CLOSED:
|
||||
blkif_ptbe_disconnect();
|
||||
@@ -380,7 +377,7 @@ static void blkif_ptbe_status(
|
||||
break;
|
||||
|
||||
case BLKIF_INTERFACE_STATUS_CONNECTED:
|
||||
switch ( blkif_pt_state )
|
||||
switch ( blktap_be_state )
|
||||
{
|
||||
case BLKIF_STATE_CLOSED:
|
||||
unexpected(status);
|
||||
@@ -398,7 +395,7 @@ static void blkif_ptbe_status(
|
||||
break;
|
||||
|
||||
case BLKIF_INTERFACE_STATUS_CHANGED:
|
||||
switch ( blkif_pt_state )
|
||||
switch ( blktap_be_state )
|
||||
{
|
||||
case BLKIF_STATE_CLOSED:
|
||||
case BLKIF_STATE_DISCONNECTED:
|
||||
@@ -440,6 +437,14 @@ void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
|
||||
|
||||
case CMSG_BLKIF_BE:
|
||||
|
||||
/* send a copy of the message to user if wanted */
|
||||
|
||||
if ( (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) ||
|
||||
(blktap_mode & BLKTAP_MODE_COPY_FE) ) {
|
||||
|
||||
blktap_write_ctrl_ring(msg);
|
||||
}
|
||||
|
||||
switch ( msg->subtype )
|
||||
{
|
||||
case CMSG_BLKIF_BE_CREATE:
|
||||
@@ -500,11 +505,13 @@ void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
|
||||
ctrl_if_send_response(msg);
|
||||
}
|
||||
|
||||
/*-----[ All control messages enter here: ]-------------------------------*/
|
||||
/*-----[ Initialization ]-------------------------------------------------*/
|
||||
|
||||
void __init blkif_interface_init(void)
|
||||
{
|
||||
blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t),
|
||||
0, 0, NULL, NULL);
|
||||
memset(blkif_hash, 0, sizeof(blkif_hash));
|
||||
|
||||
blktap_be_ring.sring = NULL;
|
||||
}
|
||||
@@ -40,8 +40,6 @@ inline active_req_t *get_active_req(void)
|
||||
spin_lock_irqsave(&active_req_lock, flags);
|
||||
idx = active_req_ring[MASK_ACTIVE_IDX(active_cons++)];
|
||||
ar = &active_reqs[idx];
|
||||
if (ar->inuse) WPRINTK("AR INUSE! (%lu)\n", ar->id);
|
||||
ar->inuse = 1;
|
||||
spin_unlock_irqrestore(&active_req_lock, flags);
|
||||
|
||||
return ar;
|
||||
@@ -52,7 +50,6 @@ inline void free_active_req(active_req_t *ar)
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&active_req_lock, flags);
|
||||
ar->inuse = 0;
|
||||
active_req_ring[MASK_ACTIVE_IDX(active_prod++)] = ACTIVE_IDX(ar);
|
||||
spin_unlock_irqrestore(&active_req_lock, flags);
|
||||
}
|
||||
@@ -97,11 +94,8 @@ inline int write_resp_to_fe_ring(blkif_t *blkif, blkif_response_t *rsp)
|
||||
blkif_response_t *resp_d;
|
||||
active_req_t *ar;
|
||||
|
||||
/* remap id, and free the active req. blkif lookup goes here too.*/
|
||||
ar = &active_reqs[ID_TO_IDX(rsp->id)];
|
||||
/* WPRINTK("%3u > %3lu\n", ID_TO_IDX(rsp->id), ar->id); */
|
||||
rsp->id = ar->id;
|
||||
free_active_req(ar);
|
||||
|
||||
resp_d = RING_GET_RESPONSE(BLKIF_RING, &blkif->blk_ring,
|
||||
blkif->blk_ring.rsp_prod_pvt);
|
||||
@@ -109,6 +103,9 @@ inline int write_resp_to_fe_ring(blkif_t *blkif, blkif_response_t *rsp)
|
||||
wmb();
|
||||
blkif->blk_ring.rsp_prod_pvt++;
|
||||
|
||||
blkif_put(ar->blkif);
|
||||
free_active_req(ar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -116,6 +113,11 @@ inline int write_req_to_be_ring(blkif_request_t *req)
|
||||
{
|
||||
blkif_request_t *req_d;
|
||||
|
||||
if ( blktap_be_state != BLKIF_STATE_CONNECTED ) {
|
||||
WPRINTK("Tap trying to access an unconnected backend!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
req_d = RING_GET_REQUEST(BLKIF_RING, &blktap_be_ring,
|
||||
blktap_be_ring.req_prod_pvt);
|
||||
memcpy(req_d, req, sizeof(blkif_request_t));
|
||||
@@ -135,9 +137,12 @@ inline void kick_fe_domain(blkif_t *blkif)
|
||||
|
||||
inline void kick_be_domain(void)
|
||||
{
|
||||
if ( blktap_be_state != BLKIF_STATE_CONNECTED )
|
||||
return;
|
||||
|
||||
wmb(); /* Ensure that the frontend can see the requests. */
|
||||
RING_PUSH_REQUESTS(BLKIF_RING, &blktap_be_ring);
|
||||
notify_via_evtchn(blkif_ptbe_evtchn);
|
||||
notify_via_evtchn(blktap_be_evtchn);
|
||||
DPRINTK("notified BE\n");
|
||||
}
|
||||
|
||||
@@ -310,6 +315,7 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do)
|
||||
*/
|
||||
ar = get_active_req();
|
||||
ar->id = req_s->id;
|
||||
blkif_get(blkif);
|
||||
ar->blkif = blkif;
|
||||
req_s->id = MAKE_ID(blkif->domid, ACTIVE_IDX(ar));
|
||||
/* WPRINTK("%3u < %3lu\n", ID_TO_IDX(req_s->id), ar->id); */
|
||||
@@ -458,11 +464,13 @@ void print_vm_ring_idxs(void)
|
||||
blkif->blk_ring.sring->req_prod,
|
||||
blkif->blk_ring.sring->rsp_prod);
|
||||
}
|
||||
WPRINTK("BE Ring: \n--------\n");
|
||||
WPRINTK("BE: rsp_cons: %2d, req_prod_prv: %2d "
|
||||
"| req_prod: %2d, rsp_prod: %2d\n",
|
||||
blktap_be_ring.rsp_cons,
|
||||
blktap_be_ring.req_prod_pvt,
|
||||
blktap_be_ring.sring->req_prod,
|
||||
blktap_be_ring.sring->rsp_prod);
|
||||
if (blktap_be_ring.sring != NULL) {
|
||||
WPRINTK("BE Ring: \n--------\n");
|
||||
WPRINTK("BE: rsp_cons: %2d, req_prod_prv: %2d "
|
||||
"| req_prod: %2d, rsp_prod: %2d\n",
|
||||
blktap_be_ring.rsp_cons,
|
||||
blktap_be_ring.req_prod_pvt,
|
||||
blktap_be_ring.sring->req_prod,
|
||||
blktap_be_ring.sring->rsp_prod);
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/poll.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm-xen/xen-public/io/blkif.h> /* for control ring. */
|
||||
|
||||
#include "blktap.h"
|
||||
|
||||
@@ -40,6 +41,11 @@ unsigned long rings_vstart;
|
||||
/* Rings up to user space. */
|
||||
static blkif_front_ring_t blktap_ufe_ring;
|
||||
static blkif_back_ring_t blktap_ube_ring;
|
||||
static ctrl_front_ring_t blktap_uctrl_ring;
|
||||
|
||||
/* local prototypes */
|
||||
static int blktap_read_fe_ring(void);
|
||||
static int blktap_read_be_ring(void);
|
||||
|
||||
/* -------[ blktap vm ops ]------------------------------------------- */
|
||||
|
||||
@@ -66,16 +72,28 @@ struct vm_operations_struct blktap_vm_ops = {
|
||||
static int blktap_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
blkif_sring_t *sring;
|
||||
ctrl_sring_t *csring;
|
||||
|
||||
if ( test_and_set_bit(0, &blktap_dev_inuse) )
|
||||
return -EBUSY;
|
||||
|
||||
printk(KERN_ALERT "blktap open.\n");
|
||||
|
||||
/* Allocate the ctrl ring. */
|
||||
csring = (ctrl_sring_t *)get_zeroed_page(GFP_KERNEL);
|
||||
if (csring == NULL)
|
||||
goto fail_nomem;
|
||||
|
||||
SetPageReserved(virt_to_page(csring));
|
||||
|
||||
SHARED_RING_INIT(CTRL_RING, csring);
|
||||
FRONT_RING_INIT(CTRL_RING, &blktap_uctrl_ring, csring);
|
||||
|
||||
|
||||
/* Allocate the fe ring. */
|
||||
sring = (blkif_sring_t *)get_zeroed_page(GFP_KERNEL);
|
||||
if (sring == NULL)
|
||||
goto fail_nomem;
|
||||
goto fail_free_ctrl;
|
||||
|
||||
SetPageReserved(virt_to_page(sring));
|
||||
|
||||
@@ -95,6 +113,9 @@ static int blktap_open(struct inode *inode, struct file *filp)
|
||||
DPRINTK(KERN_ALERT "blktap open.\n");
|
||||
|
||||
return 0;
|
||||
|
||||
fail_free_ctrl:
|
||||
free_page( (unsigned long) blktap_uctrl_ring.sring);
|
||||
|
||||
fail_free_fe:
|
||||
free_page( (unsigned long) blktap_ufe_ring.sring);
|
||||
@@ -111,6 +132,9 @@ static int blktap_release(struct inode *inode, struct file *filp)
|
||||
printk(KERN_ALERT "blktap closed.\n");
|
||||
|
||||
/* Free the ring page. */
|
||||
ClearPageReserved(virt_to_page(blktap_uctrl_ring.sring));
|
||||
free_page((unsigned long) blktap_uctrl_ring.sring);
|
||||
|
||||
ClearPageReserved(virt_to_page(blktap_ufe_ring.sring));
|
||||
free_page((unsigned long) blktap_ufe_ring.sring);
|
||||
|
||||
@@ -120,6 +144,15 @@ static int blktap_release(struct inode *inode, struct file *filp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Note on mmap:
|
||||
* remap_pfn_range sets VM_IO on vma->vm_flags. In trying to make libaio
|
||||
* work to do direct page access from userspace, this ended up being a
|
||||
* problem. The bigger issue seems to be that there is no way to map
|
||||
* a foreign page in to user space and have the virtual address of that
|
||||
* page map sanely down to a mfn.
|
||||
* Removing the VM_IO flag results in a loop in get_user_pages, as
|
||||
* pfn_valid() always fails on a foreign page.
|
||||
*/
|
||||
static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
{
|
||||
int size;
|
||||
@@ -148,20 +181,28 @@ static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
/* not sure if I really need to do this... */
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
|
||||
DPRINTK("Mapping be_ring page %lx.\n", __pa(blktap_ube_ring.sring));
|
||||
if (remap_page_range(vma, vma->vm_start,
|
||||
__pa(blktap_ube_ring.sring),
|
||||
DPRINTK("Mapping ctrl_ring page %lx.\n", __pa(blktap_uctrl_ring.sring));
|
||||
if (remap_pfn_range(vma, vma->vm_start,
|
||||
__pa(blktap_uctrl_ring.sring) >> PAGE_SHIFT,
|
||||
PAGE_SIZE, vma->vm_page_prot)) {
|
||||
WPRINTK("be_ring: remap_page_range failure!\n");
|
||||
WPRINTK("ctrl_ring: remap_pfn_range failure!\n");
|
||||
}
|
||||
|
||||
|
||||
DPRINTK("Mapping be_ring page %lx.\n", __pa(blktap_ube_ring.sring));
|
||||
if (remap_pfn_range(vma, vma->vm_start + PAGE_SIZE,
|
||||
__pa(blktap_ube_ring.sring) >> PAGE_SHIFT,
|
||||
PAGE_SIZE, vma->vm_page_prot)) {
|
||||
WPRINTK("be_ring: remap_pfn_range failure!\n");
|
||||
}
|
||||
|
||||
DPRINTK("Mapping fe_ring page %lx.\n", __pa(blktap_ufe_ring.sring));
|
||||
if (remap_page_range(vma, vma->vm_start + PAGE_SIZE,
|
||||
__pa(blktap_ufe_ring.sring),
|
||||
if (remap_pfn_range(vma, vma->vm_start + ( 2 * PAGE_SIZE ),
|
||||
__pa(blktap_ufe_ring.sring) >> PAGE_SHIFT,
|
||||
PAGE_SIZE, vma->vm_page_prot)) {
|
||||
WPRINTK("fe_ring: remap_page_range failure!\n");
|
||||
WPRINTK("fe_ring: remap_pfn_range failure!\n");
|
||||
}
|
||||
|
||||
|
||||
blktap_vma = vma;
|
||||
blktap_ring_ok = 1;
|
||||
|
||||
@@ -211,9 +252,11 @@ static unsigned int blktap_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
poll_wait(file, &blktap_wait, wait);
|
||||
|
||||
if ( RING_HAS_UNPUSHED_REQUESTS(BLKIF_RING, &blktap_ufe_ring) ||
|
||||
if ( RING_HAS_UNPUSHED_REQUESTS(BLKIF_RING, &blktap_uctrl_ring) ||
|
||||
RING_HAS_UNPUSHED_REQUESTS(BLKIF_RING, &blktap_ufe_ring) ||
|
||||
RING_HAS_UNPUSHED_RESPONSES(BLKIF_RING, &blktap_ube_ring) ) {
|
||||
|
||||
RING_PUSH_REQUESTS(BLKIF_RING, &blktap_uctrl_ring);
|
||||
RING_PUSH_REQUESTS(BLKIF_RING, &blktap_ufe_ring);
|
||||
RING_PUSH_RESPONSES(BLKIF_RING, &blktap_ube_ring);
|
||||
return POLLIN | POLLRDNORM;
|
||||
@@ -260,7 +303,6 @@ int blktap_write_fe_ring(blkif_request_t *req)
|
||||
return 0;
|
||||
}
|
||||
|
||||
//target = RING_NEXT_EMPTY_REQUEST(BLKIF_RING, &blktap_ufe_ring);
|
||||
target = RING_GET_REQUEST(BLKIF_RING, &blktap_ufe_ring,
|
||||
blktap_ufe_ring.req_prod_pvt);
|
||||
memcpy(target, req, sizeof(*req));
|
||||
@@ -270,7 +312,7 @@ int blktap_write_fe_ring(blkif_request_t *req)
|
||||
|
||||
error = direct_remap_area_pages(blktap_vma->vm_mm,
|
||||
MMAP_VADDR(ID_TO_IDX(req->id), i),
|
||||
target->frame_and_sects[0] & PAGE_MASK,
|
||||
target->frame_and_sects[i] & PAGE_MASK,
|
||||
PAGE_SIZE,
|
||||
blktap_vma->vm_page_prot,
|
||||
ID_TO_DOM(req->id));
|
||||
@@ -302,7 +344,6 @@ int blktap_write_be_ring(blkif_response_t *rsp)
|
||||
|
||||
/* No test for fullness in the response direction. */
|
||||
|
||||
//target = RING_NEXT_EMPTY_RESPONSE(BLKIF_RING, &blktap_ube_ring);
|
||||
target = RING_GET_RESPONSE(BLKIF_RING, &blktap_ube_ring,
|
||||
blktap_ube_ring.rsp_prod_pvt);
|
||||
memcpy(target, rsp, sizeof(*rsp));
|
||||
@@ -314,7 +355,7 @@ int blktap_write_be_ring(blkif_response_t *rsp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blktap_read_fe_ring(void)
|
||||
static int blktap_read_fe_ring(void)
|
||||
{
|
||||
/* This is called to read responses from the UFE ring. */
|
||||
|
||||
@@ -329,7 +370,6 @@ int blktap_read_fe_ring(void)
|
||||
if (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) {
|
||||
|
||||
/* for each outstanding message on the UFEring */
|
||||
//RING_FOREACH_RESPONSE(BLKIF_RING, &blktap_ufe_ring, prod, resp_s) {
|
||||
rp = blktap_ufe_ring.sring->rsp_prod;
|
||||
rmb();
|
||||
|
||||
@@ -349,7 +389,7 @@ int blktap_read_fe_ring(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blktap_read_be_ring(void)
|
||||
static int blktap_read_be_ring(void)
|
||||
{
|
||||
/* This is called to read requests from the UBE ring. */
|
||||
|
||||
@@ -362,7 +402,6 @@ int blktap_read_be_ring(void)
|
||||
if (blktap_mode & BLKTAP_MODE_INTERCEPT_BE) {
|
||||
|
||||
/* for each outstanding message on the UFEring */
|
||||
//RING_FOREACH_REQUEST(BLKIF_RING, &blktap_ube_ring, prod, req_s) {
|
||||
rp = blktap_ube_ring.sring->req_prod;
|
||||
rmb();
|
||||
for ( i = blktap_ube_ring.req_cons; i != rp; i++ )
|
||||
@@ -379,6 +418,31 @@ int blktap_read_be_ring(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blktap_write_ctrl_ring(ctrl_msg_t *msg)
|
||||
{
|
||||
ctrl_msg_t *target;
|
||||
|
||||
if ( ! blktap_ring_ok ) {
|
||||
DPRINTK("blktap: be_ring not ready for a request!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No test for fullness in the response direction. */
|
||||
|
||||
target = RING_GET_REQUEST(CTRL_RING, &blktap_uctrl_ring,
|
||||
blktap_uctrl_ring.req_prod_pvt);
|
||||
memcpy(target, msg, sizeof(*msg));
|
||||
|
||||
blktap_uctrl_ring.req_prod_pvt++;
|
||||
|
||||
/* currently treat the ring as unidirectional. */
|
||||
blktap_uctrl_ring.rsp_cons = blktap_uctrl_ring.sring->rsp_prod;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* -------[ blktap module setup ]------------------------------------- */
|
||||
|
||||
static struct miscdevice blktap_miscdev = {
|
||||
|
||||
@@ -234,7 +234,7 @@ static void net_rx_action(unsigned long unused)
|
||||
mmu[2].val = MMUEXT_REASSIGN_PAGE;
|
||||
|
||||
mcl[0].op = __HYPERVISOR_update_va_mapping;
|
||||
mcl[0].args[0] = vdata >> PAGE_SHIFT;
|
||||
mcl[0].args[0] = vdata;
|
||||
mcl[0].args[1] = (new_mfn << PAGE_SHIFT) | __PAGE_KERNEL;
|
||||
mcl[0].args[2] = 0;
|
||||
mcl[1].op = __HYPERVISOR_mmu_update;
|
||||
@@ -409,7 +409,7 @@ static void net_tx_action(unsigned long unused)
|
||||
{
|
||||
pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)];
|
||||
mcl[0].op = __HYPERVISOR_update_va_mapping;
|
||||
mcl[0].args[0] = MMAP_VADDR(pending_idx) >> PAGE_SHIFT;
|
||||
mcl[0].args[0] = MMAP_VADDR(pending_idx);
|
||||
mcl[0].args[1] = 0;
|
||||
mcl[0].args[2] = 0;
|
||||
mcl++;
|
||||
@@ -546,7 +546,7 @@ static void net_tx_action(unsigned long unused)
|
||||
skb_reserve(skb, 16);
|
||||
|
||||
mcl[0].op = __HYPERVISOR_update_va_mapping_otherdomain;
|
||||
mcl[0].args[0] = MMAP_VADDR(pending_idx) >> PAGE_SHIFT;
|
||||
mcl[0].args[0] = MMAP_VADDR(pending_idx);
|
||||
mcl[0].args[1] = (txreq.addr & PAGE_MASK) | __PAGE_KERNEL;
|
||||
mcl[0].args[2] = 0;
|
||||
mcl[0].args[3] = netif->domid;
|
||||
|
||||
@@ -392,7 +392,7 @@ static void network_alloc_rx_buffers(struct net_device *dev)
|
||||
= INVALID_P2M_ENTRY;
|
||||
|
||||
rx_mcl[i].op = __HYPERVISOR_update_va_mapping;
|
||||
rx_mcl[i].args[0] = (unsigned long)skb->head >> PAGE_SHIFT;
|
||||
rx_mcl[i].args[0] = (unsigned long)skb->head;
|
||||
rx_mcl[i].args[1] = 0;
|
||||
rx_mcl[i].args[2] = 0;
|
||||
}
|
||||
@@ -593,7 +593,7 @@ static int netif_poll(struct net_device *dev, int *pbudget)
|
||||
mmu->val = __pa(skb->head) >> PAGE_SHIFT;
|
||||
mmu++;
|
||||
mcl->op = __HYPERVISOR_update_va_mapping;
|
||||
mcl->args[0] = (unsigned long)skb->head >> PAGE_SHIFT;
|
||||
mcl->args[0] = (unsigned long)skb->head;
|
||||
mcl->args[1] = (rx->addr & PAGE_MASK) | __PAGE_KERNEL;
|
||||
mcl->args[2] = 0;
|
||||
mcl++;
|
||||
|
||||
@@ -191,7 +191,7 @@ static void fast_flush_area(int idx, int nr_pages)
|
||||
for ( i = 0; i < nr_pages; i++ )
|
||||
{
|
||||
mcl[i].op = __HYPERVISOR_update_va_mapping;
|
||||
mcl[i].args[0] = MMAP_VADDR(idx, i) >> PAGE_SHIFT;
|
||||
mcl[i].args[0] = MMAP_VADDR(idx, i);
|
||||
mcl[i].args[1] = 0;
|
||||
mcl[i].args[2] = 0;
|
||||
}
|
||||
@@ -630,7 +630,7 @@ static void dispatch_usb_io(usbif_priv_t *up, usbif_request_t *req)
|
||||
i++, offset += PAGE_SIZE )
|
||||
{
|
||||
mcl[i].op = __HYPERVISOR_update_va_mapping_otherdomain;
|
||||
mcl[i].args[0] = MMAP_VADDR(pending_idx, i) >> PAGE_SHIFT;
|
||||
mcl[i].args[0] = MMAP_VADDR(pending_idx, i);
|
||||
mcl[i].args[1] = ((buffer_mach & PAGE_MASK) + offset) | remap_prot;
|
||||
mcl[i].args[2] = 0;
|
||||
mcl[i].args[3] = up->domid;
|
||||
@@ -646,7 +646,7 @@ static void dispatch_usb_io(usbif_priv_t *up, usbif_request_t *req)
|
||||
{
|
||||
/* Map in ISO schedule, if necessary. */
|
||||
mcl[i].op = __HYPERVISOR_update_va_mapping_otherdomain;
|
||||
mcl[i].args[0] = MMAP_VADDR(pending_idx, i) >> PAGE_SHIFT;
|
||||
mcl[i].args[0] = MMAP_VADDR(pending_idx, i);
|
||||
mcl[i].args[1] = (req->iso_schedule & PAGE_MASK) | remap_prot;
|
||||
mcl[i].args[2] = 0;
|
||||
mcl[i].args[3] = up->domid;
|
||||
|
||||
@@ -426,7 +426,7 @@ extern pte_t *lookup_address(unsigned long address);
|
||||
if (__dirty) { \
|
||||
if ( likely((__vma)->vm_mm == current->mm) ) { \
|
||||
xen_flush_page_update_queue(); \
|
||||
HYPERVISOR_update_va_mapping((__address)>>PAGE_SHIFT, (__entry), UVMF_INVLPG); \
|
||||
HYPERVISOR_update_va_mapping((__address), (__entry), UVMF_INVLPG); \
|
||||
} else { \
|
||||
xen_l1_entry_update((__ptep), (__entry).pte_low); \
|
||||
flush_tlb_page((__vma), (__address)); \
|
||||
@@ -445,7 +445,7 @@ do { \
|
||||
do { \
|
||||
if (likely((__vma)->vm_mm == current->mm)) { \
|
||||
xen_flush_page_update_queue(); \
|
||||
HYPERVISOR_update_va_mapping((__address)>>PAGE_SHIFT, \
|
||||
HYPERVISOR_update_va_mapping((__address), \
|
||||
__entry, 0); \
|
||||
} else { \
|
||||
xen_l1_entry_update((__ptep), (__entry).pte_low); \
|
||||
|
||||
@@ -438,7 +438,7 @@ HYPERVISOR_multicall(
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_update_va_mapping(
|
||||
unsigned long page_nr, pte_t new_val, unsigned long flags)
|
||||
unsigned long nr, pte_t new_val, unsigned long flags)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2, ign3;
|
||||
@@ -447,13 +447,13 @@ HYPERVISOR_update_va_mapping(
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3)
|
||||
: "0" (__HYPERVISOR_update_va_mapping),
|
||||
"1" (page_nr), "2" ((new_val).pte_low), "3" (flags)
|
||||
"1" (va), "2" ((new_val).pte_low), "3" (flags)
|
||||
: "memory" );
|
||||
|
||||
if ( unlikely(ret < 0) )
|
||||
{
|
||||
printk(KERN_ALERT "Failed update VA mapping: %08lx, %08lx, %08lx\n",
|
||||
page_nr, (new_val).pte_low, flags);
|
||||
va, (new_val).pte_low, flags);
|
||||
BUG();
|
||||
}
|
||||
|
||||
@@ -540,7 +540,7 @@ HYPERVISOR_grant_table_op(
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_update_va_mapping_otherdomain(
|
||||
unsigned long page_nr, pte_t new_val, unsigned long flags, domid_t domid)
|
||||
unsigned long va, pte_t new_val, unsigned long flags, domid_t domid)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2, ign3, ign4;
|
||||
@@ -549,7 +549,7 @@ HYPERVISOR_update_va_mapping_otherdomain(
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4)
|
||||
: "0" (__HYPERVISOR_update_va_mapping_otherdomain),
|
||||
"1" (page_nr), "2" ((new_val).pte_low), "3" (flags), "4" (domid) :
|
||||
"1" (va), "2" ((new_val).pte_low), "3" (flags), "4" (domid) :
|
||||
"memory" );
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -398,7 +398,7 @@ HYPERVISOR_multicall(void *call_list, int nr_calls)
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_update_va_mapping(unsigned long page_nr, unsigned long new_val,
|
||||
HYPERVISOR_update_va_mapping(unsigned long va, unsigned long new_val,
|
||||
unsigned long flags)
|
||||
{
|
||||
int ret;
|
||||
@@ -408,12 +408,12 @@ HYPERVISOR_update_va_mapping(unsigned long page_nr, unsigned long new_val,
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3)
|
||||
: "0" (__HYPERVISOR_update_va_mapping),
|
||||
"1" (page_nr), "2" (new_val), "3" (flags)
|
||||
"1" (va), "2" (new_val), "3" (flags)
|
||||
: "memory" );
|
||||
|
||||
if (__predict_false(ret < 0))
|
||||
panic("Failed update VA mapping: %08lx, %08lx, %08lx",
|
||||
page_nr, new_val, flags);
|
||||
va, new_val, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -494,7 +494,7 @@ HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count)
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_update_va_mapping_otherdomain(unsigned long page_nr,
|
||||
HYPERVISOR_update_va_mapping_otherdomain(unsigned long va,
|
||||
unsigned long new_val, unsigned long flags, domid_t domid)
|
||||
{
|
||||
int ret;
|
||||
@@ -504,7 +504,7 @@ HYPERVISOR_update_va_mapping_otherdomain(unsigned long page_nr,
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4)
|
||||
: "0" (__HYPERVISOR_update_va_mapping_otherdomain),
|
||||
"1" (page_nr), "2" (new_val), "3" (flags), "4" (domid) :
|
||||
"1" (va), "2" (new_val), "3" (flags), "4" (domid) :
|
||||
"memory" );
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -580,7 +580,7 @@ xennet_rx_push_buffer(struct xennet_softc *sc, int id)
|
||||
INVALID_P2M_ENTRY;
|
||||
|
||||
rx_mcl[nr_pfns].op = __HYPERVISOR_update_va_mapping;
|
||||
rx_mcl[nr_pfns].args[0] = sc->sc_rx_bufa[id].xb_rx.xbrx_va >> PAGE_SHIFT;
|
||||
rx_mcl[nr_pfns].args[0] = sc->sc_rx_bufa[id].xb_rx.xbrx_va;
|
||||
rx_mcl[nr_pfns].args[1] = 0;
|
||||
rx_mcl[nr_pfns].args[2] = 0;
|
||||
|
||||
@@ -679,7 +679,7 @@ xen_network_handler(void *arg)
|
||||
mmu->val = (pa - XPMAP_OFFSET) >> PAGE_SHIFT;
|
||||
mmu++;
|
||||
mcl->op = __HYPERVISOR_update_va_mapping;
|
||||
mcl->args[0] = sc->sc_rx_bufa[rx->id].xb_rx.xbrx_va >> PAGE_SHIFT;
|
||||
mcl->args[0] = sc->sc_rx_bufa[rx->id].xb_rx.xbrx_va;
|
||||
mcl->args[1] = (rx->addr & PG_FRAME) | PG_V|PG_KW;
|
||||
mcl->args[2] = UVMF_FLUSH_TLB; // 0;
|
||||
mcl++;
|
||||
@@ -872,7 +872,7 @@ network_alloc_rx_buffers(struct xennet_softc *sc)
|
||||
INVALID_P2M_ENTRY;
|
||||
|
||||
rx_mcl[nr_pfns].op = __HYPERVISOR_update_va_mapping;
|
||||
rx_mcl[nr_pfns].args[0] = va >> PAGE_SHIFT;
|
||||
rx_mcl[nr_pfns].args[0] = va;
|
||||
rx_mcl[nr_pfns].args[1] = 0;
|
||||
rx_mcl[nr_pfns].args[2] = 0;
|
||||
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
#vgaromimage: $BXSHARE/VGABIOS-lgpl-latest
|
||||
floppya: 1_44=a.img, status=inserted
|
||||
floppyb: 1_44=b.img, status=inserted
|
||||
#ata0-master: type=disk, path=minibootable.img, cylinders=900, heads=15, spt=17
|
||||
# if you don't use absolute paths below, bochs looks under the cwd of xend,
|
||||
# which is usually "/"
|
||||
ata0-master: type=disk, path=/tmp/min-fc2-i386.img, cylinders=800, heads=4, spt=32
|
||||
#ata0-master: type=disk, path=/var/images/min-el3-i386.img, cylinders=800, heads=4, spt=32
|
||||
i440fxsupport: enabled=1
|
||||
ne2k: ioaddr=0x300, irq=9, mac=b0:c4:22:01:00:00, ethmod=linux, ethdev=eth0
|
||||
ata0-master: type=disk, path=/var/images/1g-el3-i386.img, mode=flat, cylinders=2048, heads=16, spt=63
|
||||
boot: c
|
||||
|
||||
log: /tmp/bochsout.txt
|
||||
@@ -16,4 +18,3 @@ error: action=report
|
||||
panic: action=ask
|
||||
|
||||
mouse: enabled=0
|
||||
ips: 1500000
|
||||
@@ -37,8 +37,8 @@ domain=${domain:?}
|
||||
vif=${vif:?}
|
||||
ip=${ip:?}
|
||||
|
||||
# better way to strip /netmask from the ip?
|
||||
vif_ip=`echo ${ip} | awk -F. '{print $1"."$2"."$3"."$4}'`
|
||||
# strip /netmask
|
||||
vif_ip=`echo ${ip} | awk -F/ '{print $1}'`
|
||||
|
||||
main_ip=`ifconfig eth0 | grep "inet addr:" | sed -e 's/.*inet addr:\(\w\w*\.\w\w*\.\w\w*\.\w\w*\).*/\1/'`
|
||||
|
||||
|
||||
@@ -687,13 +687,13 @@ typedef
|
||||
#define BX_NUM_SIMULATORS 1
|
||||
|
||||
// limited i440FX PCI support
|
||||
#define BX_PCI_SUPPORT 0
|
||||
#define BX_PCI_SUPPORT 1
|
||||
|
||||
// Experimental VGA on PCI
|
||||
#define BX_PCI_VGA_SUPPORT 1
|
||||
|
||||
// limited USB on PCI
|
||||
#define BX_PCI_USB_SUPPORT 0
|
||||
#define BX_PCI_USB_SUPPORT 1
|
||||
|
||||
#if (BX_PCI_USB_SUPPORT && !BX_PCI_SUPPORT)
|
||||
#error To enable USB, you must also enable PCI
|
||||
|
||||
@@ -45,6 +45,13 @@ BOCHSAPI extern class bx_pc_system_c bx_pc_system;
|
||||
extern double m_ips;
|
||||
#endif
|
||||
|
||||
#ifdef BX_USE_VMX
|
||||
extern unsigned int tsc_per_bx_tick;
|
||||
|
||||
#define rdtscll(val) \
|
||||
__asm__ __volatile__("rdtsc" : "=A" (val))
|
||||
#endif
|
||||
|
||||
class BOCHSAPI bx_pc_system_c : private logfunctions {
|
||||
private:
|
||||
|
||||
@@ -87,6 +94,26 @@ private:
|
||||
double m_ips; // Millions of Instructions Per Second
|
||||
#endif
|
||||
|
||||
#ifdef BX_USE_VMX
|
||||
static Bit64s get_clock(void) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv.tv_sec * 1000000LL + tv.tv_usec;
|
||||
}
|
||||
|
||||
static Bit64u cpu_calibrate_ticks(void) {
|
||||
Bit64s usec, t1, t2;
|
||||
|
||||
usec = get_clock();
|
||||
rdtscll(t1);
|
||||
|
||||
usleep(50 * 1000);
|
||||
usec = get_clock() - usec;
|
||||
rdtscll(t2);
|
||||
|
||||
return (((t2 - t1) * 1000000LL + (usec >> 1)) / usec);
|
||||
}
|
||||
#endif
|
||||
// This handler is called when the function which decrements the clock
|
||||
// ticks finds that an event has occurred.
|
||||
void countdownEvent(void);
|
||||
|
||||
@@ -180,7 +180,8 @@ bx_cpu_c::cpu_loop(int max_instr_count)
|
||||
FD_ZERO(&rfds);
|
||||
|
||||
while (1) {
|
||||
unsigned long t1, t2;
|
||||
static unsigned long long t1 = 0;
|
||||
unsigned long long t2;
|
||||
|
||||
/* Wait up to one seconds. */
|
||||
tv.tv_sec = 0;
|
||||
@@ -188,18 +189,30 @@ bx_cpu_c::cpu_loop(int max_instr_count)
|
||||
FD_SET(evtchn_fd, &rfds);
|
||||
|
||||
send_event = 0;
|
||||
rdtscl(t1);
|
||||
|
||||
if (t1 == 0) // the first time
|
||||
rdtscll(t1);
|
||||
|
||||
retval = select(evtchn_fd+1, &rfds, NULL, NULL, &tv);
|
||||
rdtscl(t2);
|
||||
if (retval == -1) {
|
||||
perror("select");
|
||||
return;
|
||||
}
|
||||
//stime_usec = 1000000 * (1 - tv.tv_sec) - tv.tv_usec;
|
||||
if (t2 > t1)
|
||||
BX_TICKN((t2 - t1) / 2000); // should match ips in bochsrc
|
||||
|
||||
rdtscll(t2);
|
||||
|
||||
#if __WORDSIZE == 32
|
||||
#define ULONGLONG_MAX 0xffffffffffffffffULL
|
||||
#else
|
||||
#define ULONGLONG_MAX ULONG_MAX
|
||||
#endif
|
||||
|
||||
if (t2 <= t1)
|
||||
BX_TICKN((t2 + ULONGLONG_MAX - t1) / tsc_per_bx_tick);
|
||||
else
|
||||
BX_TICKN((MAXINT - t1 + t2) / 2000); // should match ips in bochsrc
|
||||
BX_TICKN((t2 - t1) / tsc_per_bx_tick);
|
||||
t1 = t2;
|
||||
|
||||
timer_handler();
|
||||
if (BX_CPU_INTR) {
|
||||
#if BX_SUPPORT_APIC
|
||||
@@ -248,7 +261,7 @@ bx_cpu_c::interrupt(Bit8u vector)
|
||||
// page.
|
||||
|
||||
rdtscl(tscl);
|
||||
BX_INFO(("%lx: injecting vector: %x\n", tscl, vector));
|
||||
BX_DEBUG(("%lx: injecting vector: %x\n", tscl, vector));
|
||||
intr = &(((vcpu_iodata_t *) shared_page)->vp_intr[0]);
|
||||
set_bit(vector, intr);
|
||||
|
||||
|
||||
@@ -44,6 +44,10 @@ unsigned long ips_count=0;
|
||||
double m_ips; // Millions of Instructions Per Second
|
||||
#endif
|
||||
|
||||
#ifdef BX_USE_VMX
|
||||
unsigned int tsc_per_bx_tick;
|
||||
#endif
|
||||
|
||||
// Option for turning off BX_TIMER_DEBUG?
|
||||
// Check out m_ips and ips
|
||||
|
||||
@@ -98,6 +102,16 @@ bx_pc_system_c::init_ips(Bit32u ips)
|
||||
a20_mask = 0xffffffff;
|
||||
#endif
|
||||
|
||||
#ifdef BX_USE_VMX
|
||||
Bit64u phy_cpu_freq = cpu_calibrate_ticks();
|
||||
|
||||
if (ips == 500000) { //default ips: we use fixed scaling factor to calulate ips
|
||||
tsc_per_bx_tick = 2000;
|
||||
ips = phy_cpu_freq / tsc_per_bx_tick;
|
||||
} else //use uesr defined ips to calulate factor
|
||||
tsc_per_bx_tick = ((phy_cpu_freq + (ips>>1)) / ips);
|
||||
#endif
|
||||
|
||||
// parameter 'ips' is the processor speed in Instructions-Per-Second
|
||||
m_ips = double(ips) / 1000000.0L;
|
||||
|
||||
|
||||
@@ -558,10 +558,10 @@ static int parseelfimage(char *elfbase,
|
||||
phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
|
||||
if ( !is_loadable_phdr(phdr) )
|
||||
continue;
|
||||
if ( phdr->p_vaddr < kernstart )
|
||||
kernstart = phdr->p_vaddr;
|
||||
if ( (phdr->p_vaddr + phdr->p_memsz) > kernend )
|
||||
kernend = phdr->p_vaddr + phdr->p_memsz;
|
||||
if ( phdr->p_paddr < kernstart )
|
||||
kernstart = phdr->p_paddr;
|
||||
if ( (phdr->p_paddr + phdr->p_memsz) > kernend )
|
||||
kernend = phdr->p_paddr + phdr->p_memsz;
|
||||
}
|
||||
|
||||
if ( (kernstart > kernend) ||
|
||||
@@ -611,7 +611,7 @@ loadelfimage(
|
||||
|
||||
for ( done = 0; done < phdr->p_filesz; done += chunksz )
|
||||
{
|
||||
pa = (phdr->p_vaddr + done) - vstart;
|
||||
pa = (phdr->p_paddr + done) - vstart;
|
||||
va = xc_map_foreign_range(
|
||||
xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
|
||||
chunksz = phdr->p_filesz - done;
|
||||
@@ -624,7 +624,7 @@ loadelfimage(
|
||||
|
||||
for ( ; done < phdr->p_memsz; done += chunksz )
|
||||
{
|
||||
pa = (phdr->p_vaddr + done) - vstart;
|
||||
pa = (phdr->p_paddr + done) - vstart;
|
||||
va = xc_map_foreign_range(
|
||||
xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
|
||||
chunksz = phdr->p_memsz - done;
|
||||
|
||||
@@ -629,10 +629,10 @@ static int parseelfimage(char *elfbase,
|
||||
phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
|
||||
if ( !is_loadable_phdr(phdr) )
|
||||
continue;
|
||||
if ( phdr->p_vaddr < kernstart )
|
||||
kernstart = phdr->p_vaddr;
|
||||
if ( (phdr->p_vaddr + phdr->p_memsz) > kernend )
|
||||
kernend = phdr->p_vaddr + phdr->p_memsz;
|
||||
if ( phdr->p_paddr < kernstart )
|
||||
kernstart = phdr->p_paddr;
|
||||
if ( (phdr->p_paddr + phdr->p_memsz) > kernend )
|
||||
kernend = phdr->p_paddr + phdr->p_memsz;
|
||||
}
|
||||
|
||||
if ( (kernstart > kernend) ||
|
||||
@@ -676,7 +676,7 @@ loadelfimage(
|
||||
|
||||
for ( done = 0; done < phdr->p_filesz; done += chunksz )
|
||||
{
|
||||
pa = (phdr->p_vaddr + done) - vstart - LINUX_PAGE_OFFSET;
|
||||
pa = (phdr->p_paddr + done) - vstart - LINUX_PAGE_OFFSET;
|
||||
va = xc_map_foreign_range(
|
||||
xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
|
||||
chunksz = phdr->p_filesz - done;
|
||||
@@ -689,7 +689,7 @@ loadelfimage(
|
||||
|
||||
for ( ; done < phdr->p_memsz; done += chunksz )
|
||||
{
|
||||
pa = (phdr->p_vaddr + done) - vstart - LINUX_PAGE_OFFSET;
|
||||
pa = (phdr->p_paddr + done) - vstart - LINUX_PAGE_OFFSET;
|
||||
va = xc_map_foreign_range(
|
||||
xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
|
||||
chunksz = phdr->p_memsz - done;
|
||||
|
||||
@@ -1337,6 +1337,7 @@ add_config_handler('memory', vm_field_ignore)
|
||||
add_config_handler('cpu', vm_field_ignore)
|
||||
add_config_handler('cpu_weight', vm_field_ignore)
|
||||
add_config_handler('console', vm_field_ignore)
|
||||
add_config_handler('restart', vm_field_ignore)
|
||||
add_config_handler('image', vm_field_ignore)
|
||||
add_config_handler('device', vm_field_ignore)
|
||||
add_config_handler('backend', vm_field_ignore)
|
||||
|
||||
@@ -486,10 +486,12 @@ class Daemon:
|
||||
# XXX KAF: Why doesn't this capture output from C extensions that
|
||||
# fprintf(stdout) or fprintf(stderr) ??
|
||||
os.open('/var/log/xend-debug.log', os.O_WRONLY|os.O_CREAT)
|
||||
os.dup(1)
|
||||
else:
|
||||
os.open('/dev/null', os.O_RDWR)
|
||||
os.dup(0)
|
||||
os.dup(1)
|
||||
os.open('/var/log/xend-debug.log', os.O_WRONLY|os.O_CREAT)
|
||||
|
||||
|
||||
def start(self, trace=0):
|
||||
"""Attempts to start the daemons.
|
||||
|
||||
@@ -245,6 +245,12 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* End the image on a page boundary. This gets round alignment bugs
|
||||
* in the boot- or chain-loader (e.g., kexec on the XenoBoot CD).
|
||||
*/
|
||||
mem_siz += -(loadbase + mem_siz) & 0xfff;
|
||||
|
||||
out_ehdr.e_entry = loadbase;
|
||||
out_ehdr.e_shoff = RAW_OFFSET + dat_siz;
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ ENTRY(gdt_table)
|
||||
.org 0x1000
|
||||
ENTRY(idle_pg_table) # Initial page directory is 4kB
|
||||
.org 0x2000
|
||||
ENTRY(cpu0_stack) # Initial stack is 8kB
|
||||
.org 0x4000
|
||||
ENTRY(cpu0_stack)
|
||||
.org 0x2000 + STACK_SIZE
|
||||
ENTRY(stext)
|
||||
ENTRY(_stext)
|
||||
@@ -193,8 +193,8 @@ ENTRY(gdt_table)
|
||||
.quad 0x00af9a000000ffff /* 0x0810 ring 0 code, 64-bit mode */
|
||||
.quad 0x00cf92000000ffff /* 0x0818 ring 0 data */
|
||||
.quad 0x00cffa000000ffff /* 0x0823 ring 3 code, compatibility */
|
||||
.quad 0x00affa000000ffff /* 0x082b ring 3 code, 64-bit mode */
|
||||
.quad 0x00cff2000000ffff /* 0x0833 ring 3 data */
|
||||
.quad 0x00cff2000000ffff /* 0x082b ring 3 data */
|
||||
.quad 0x00affa000000ffff /* 0x0833 ring 3 code, 64-bit mode */
|
||||
.quad 0x0000000000000000 /* unused */
|
||||
.fill 4*NR_CPUS,8,0 /* space for TSS and LDT per CPU */
|
||||
|
||||
@@ -243,8 +243,8 @@ ENTRY(idle_pg_table_l2)
|
||||
identmap /* Too orangey for crows :-) */
|
||||
|
||||
.org 0x4000
|
||||
ENTRY(cpu0_stack) # Initial stack is 8kB
|
||||
ENTRY(cpu0_stack)
|
||||
|
||||
.org 0x6000
|
||||
.org 0x4000 + STACK_SIZE
|
||||
ENTRY(stext)
|
||||
ENTRY(_stext)
|
||||
@@ -376,7 +376,7 @@ void arch_getdomaininfo_ctxt(
|
||||
{
|
||||
for ( i = 0; i < 16; i++ )
|
||||
c->gdt_frames[i] =
|
||||
l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i]);
|
||||
l1_pgentry_to_pfn(ed->arch.perdomain_ptes[i]);
|
||||
c->gdt_ents = GET_GDT_ENTRIES(ed);
|
||||
}
|
||||
c->guestos_ss = ed->arch.guestos_ss;
|
||||
|
||||
+39
-27
@@ -304,7 +304,7 @@ void arch_vmx_do_launch(struct exec_domain *ed)
|
||||
static void monitor_mk_pagetable(struct exec_domain *ed)
|
||||
{
|
||||
unsigned long mpfn;
|
||||
l2_pgentry_t *mpl2e;
|
||||
l2_pgentry_t *mpl2e, *phys_table;
|
||||
struct pfn_info *mpfn_info;
|
||||
struct domain *d = ed->domain;
|
||||
|
||||
@@ -312,20 +312,26 @@ static void monitor_mk_pagetable(struct exec_domain *ed)
|
||||
ASSERT( mpfn_info );
|
||||
|
||||
mpfn = (unsigned long) (mpfn_info - frame_table);
|
||||
mpl2e = (l2_pgentry_t *) map_domain_mem(mpfn << L1_PAGETABLE_SHIFT);
|
||||
mpl2e = (l2_pgentry_t *) map_domain_mem(mpfn << PAGE_SHIFT);
|
||||
memset(mpl2e, 0, PAGE_SIZE);
|
||||
|
||||
memcpy(&mpl2e[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
|
||||
&idle_pg_table[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
|
||||
HYPERVISOR_ENTRIES_PER_L2_PAGETABLE * sizeof(l2_pgentry_t));
|
||||
|
||||
ed->arch.monitor_table = mk_pagetable(mpfn << L1_PAGETABLE_SHIFT);
|
||||
ed->arch.monitor_table = mk_pagetable(mpfn << PAGE_SHIFT);
|
||||
d->arch.shadow_mode = SHM_full_32;
|
||||
|
||||
mpl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
|
||||
mk_l2_pgentry((__pa(d->arch.mm_perdomain_pt) & PAGE_MASK)
|
||||
| __PAGE_HYPERVISOR);
|
||||
|
||||
phys_table = (l2_pgentry_t *) map_domain_mem(pagetable_val(
|
||||
ed->arch.phys_table));
|
||||
memcpy(d->arch.mm_perdomain_pt, phys_table,
|
||||
ENTRIES_PER_L1_PAGETABLE * sizeof(l1_pgentry_t));
|
||||
|
||||
unmap_domain_mem(phys_table);
|
||||
unmap_domain_mem(mpl2e);
|
||||
}
|
||||
|
||||
@@ -466,6 +472,7 @@ int arch_final_setup_guestos(
|
||||
|
||||
phys_basetab = c->pt_base;
|
||||
d->arch.pagetable = mk_pagetable(phys_basetab);
|
||||
d->arch.phys_table = d->arch.pagetable;
|
||||
if ( !get_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT], d->domain,
|
||||
PGT_base_page_table) )
|
||||
return -EINVAL;
|
||||
@@ -628,12 +635,11 @@ long do_iopl(domid_t domain, unsigned int new_io_pl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long hypercall_create_continuation(
|
||||
unsigned long __hypercall_create_continuation(
|
||||
unsigned int op, unsigned int nr_args, ...)
|
||||
{
|
||||
struct mc_state *mcs = &mc_state[smp_processor_id()];
|
||||
execution_context_t *ec;
|
||||
unsigned long *preg;
|
||||
unsigned int i;
|
||||
va_list args;
|
||||
|
||||
@@ -653,10 +659,34 @@ unsigned long hypercall_create_continuation(
|
||||
ec->eax = op;
|
||||
ec->eip -= 2; /* re-execute 'int 0x82' */
|
||||
|
||||
for ( i = 0, preg = &ec->ebx; i < nr_args; i++, preg++ )
|
||||
*preg = va_arg(args, unsigned long);
|
||||
#else
|
||||
preg = NULL; /* XXX x86/64 */
|
||||
for ( i = 0; i < nr_args; i++ )
|
||||
{
|
||||
switch ( i )
|
||||
{
|
||||
case 0: ec->ebx = va_arg(args, unsigned long); break;
|
||||
case 1: ec->ecx = va_arg(args, unsigned long); break;
|
||||
case 2: ec->edx = va_arg(args, unsigned long); break;
|
||||
case 3: ec->esi = va_arg(args, unsigned long); break;
|
||||
case 4: ec->edi = va_arg(args, unsigned long); break;
|
||||
case 5: ec->ebp = va_arg(args, unsigned long); break;
|
||||
}
|
||||
}
|
||||
#elif defined(__x86_64__)
|
||||
ec->rax = op;
|
||||
ec->rip -= 2; /* re-execute 'syscall' */
|
||||
|
||||
for ( i = 0; i < nr_args; i++ )
|
||||
{
|
||||
switch ( i )
|
||||
{
|
||||
case 0: ec->rdi = va_arg(args, unsigned long); break;
|
||||
case 1: ec->rsi = va_arg(args, unsigned long); break;
|
||||
case 2: ec->rdx = va_arg(args, unsigned long); break;
|
||||
case 3: ec->r10 = va_arg(args, unsigned long); break;
|
||||
case 4: ec->r8 = va_arg(args, unsigned long); break;
|
||||
case 5: ec->r9 = va_arg(args, unsigned long); break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -726,8 +756,6 @@ static void relinquish_list(struct domain *d, struct list_head *list)
|
||||
#ifdef CONFIG_VMX
|
||||
static void vmx_domain_relinquish_memory(struct exec_domain *ed)
|
||||
{
|
||||
struct domain *d = ed->domain;
|
||||
|
||||
/*
|
||||
* Free VMCS
|
||||
*/
|
||||
@@ -736,22 +764,6 @@ static void vmx_domain_relinquish_memory(struct exec_domain *ed)
|
||||
ed->arch.arch_vmx.vmcs = 0;
|
||||
|
||||
monitor_rm_pagetable(ed);
|
||||
|
||||
if (ed == d->exec_domain[0]) {
|
||||
int i;
|
||||
unsigned long pfn;
|
||||
|
||||
for (i = 0; i < ENTRIES_PER_L1_PAGETABLE; i++) {
|
||||
unsigned long l1e;
|
||||
|
||||
l1e = l1_pgentry_val(d->arch.mm_perdomain_pt[i]);
|
||||
if (l1e & _PAGE_PRESENT) {
|
||||
pfn = l1e >> PAGE_SHIFT;
|
||||
free_domheap_page(&frame_table[pfn]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
|
||||
/******************************************************************************
|
||||
* arch/x86/memory.c
|
||||
* arch/x86/mm.c
|
||||
*
|
||||
* Copyright (c) 2002-2004 K A Fraser
|
||||
* Copyright (c) 2002-2005 K A Fraser
|
||||
* Copyright (c) 2004 Christian Limpach
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -200,14 +200,14 @@ void write_ptbase(struct exec_domain *ed)
|
||||
unsigned long pa;
|
||||
|
||||
#ifdef CONFIG_VMX
|
||||
if ( unlikely(d->arch.shadow_mode) )
|
||||
pa = ((d->arch.shadow_mode == SHM_full_32) ?
|
||||
if ( unlikely(shadow_mode(d)) )
|
||||
pa = ((shadow_mode(d) == SHM_full_32) ?
|
||||
pagetable_val(ed->arch.monitor_table) :
|
||||
pagetable_val(ed->arch.shadow_table));
|
||||
else
|
||||
pa = pagetable_val(ed->arch.pagetable);
|
||||
#else
|
||||
if ( unlikely(d->arch.shadow_mode) )
|
||||
if ( unlikely(shadow_mode(d)) )
|
||||
pa = pagetable_val(ed->arch.shadow_table);
|
||||
else
|
||||
pa = pagetable_val(ed->arch.pagetable);
|
||||
@@ -226,7 +226,7 @@ static void __invalidate_shadow_ldt(struct exec_domain *d)
|
||||
|
||||
for ( i = 16; i < 32; i++ )
|
||||
{
|
||||
pfn = l1_pgentry_to_pagenr(d->arch.perdomain_ptes[i]);
|
||||
pfn = l1_pgentry_to_pfn(d->arch.perdomain_ptes[i]);
|
||||
if ( pfn == 0 ) continue;
|
||||
d->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
|
||||
page = &frame_table[pfn];
|
||||
@@ -249,11 +249,13 @@ static inline void invalidate_shadow_ldt(struct exec_domain *d)
|
||||
|
||||
static int alloc_segdesc_page(struct pfn_info *page)
|
||||
{
|
||||
unsigned long *descs = map_domain_mem((page-frame_table) << PAGE_SHIFT);
|
||||
struct desc_struct *descs;
|
||||
int i;
|
||||
|
||||
descs = map_domain_mem((page-frame_table) << PAGE_SHIFT);
|
||||
|
||||
for ( i = 0; i < 512; i++ )
|
||||
if ( unlikely(!check_descriptor(&descs[i*2])) )
|
||||
if ( unlikely(!check_descriptor(&descs[i])) )
|
||||
goto fail;
|
||||
|
||||
unmap_domain_mem(descs);
|
||||
@@ -275,8 +277,8 @@ int map_ldt_shadow_page(unsigned int off)
|
||||
if ( unlikely(in_irq()) )
|
||||
BUG();
|
||||
|
||||
__get_user(l1e, (unsigned long *)&linear_pg_table[(ed->arch.ldt_base >>
|
||||
PAGE_SHIFT) + off]);
|
||||
__get_user(l1e, (unsigned long *)
|
||||
&linear_pg_table[l1_linear_offset(ed->arch.ldt_base) + off]);
|
||||
|
||||
if ( unlikely(!(l1e & _PAGE_PRESENT)) ||
|
||||
unlikely(!get_page_and_type(&frame_table[l1e >> PAGE_SHIFT],
|
||||
@@ -362,14 +364,14 @@ get_linear_pagetable(
|
||||
if ( (l2_pgentry_val(l2e) >> PAGE_SHIFT) != pfn )
|
||||
{
|
||||
/* Make sure the mapped frame belongs to the correct domain. */
|
||||
if ( unlikely(!get_page_from_pagenr(l2_pgentry_to_pagenr(l2e), d)) )
|
||||
if ( unlikely(!get_page_from_pagenr(l2_pgentry_to_pfn(l2e), d)) )
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Make sure that the mapped frame is an already-validated L2 table.
|
||||
* If so, atomically increment the count (checking for overflow).
|
||||
*/
|
||||
page = &frame_table[l2_pgentry_to_pagenr(l2e)];
|
||||
page = &frame_table[l2_pgentry_to_pfn(l2e)];
|
||||
y = page->u.inuse.type_info;
|
||||
do {
|
||||
x = y;
|
||||
@@ -393,7 +395,7 @@ get_page_from_l1e(
|
||||
l1_pgentry_t l1e, struct domain *d)
|
||||
{
|
||||
unsigned long l1v = l1_pgentry_val(l1e);
|
||||
unsigned long pfn = l1_pgentry_to_pagenr(l1e);
|
||||
unsigned long pfn = l1_pgentry_to_pfn(l1e);
|
||||
struct pfn_info *page = &frame_table[pfn];
|
||||
extern int domain_iomem_in_pfn(struct domain *d, unsigned long pfn);
|
||||
|
||||
@@ -447,7 +449,7 @@ get_page_from_l2e(
|
||||
}
|
||||
|
||||
rc = get_page_and_type_from_pagenr(
|
||||
l2_pgentry_to_pagenr(l2e),
|
||||
l2_pgentry_to_pfn(l2e),
|
||||
PGT_l1_page_table | (va_idx<<PGT_va_shift), d);
|
||||
|
||||
if ( unlikely(!rc) )
|
||||
@@ -460,7 +462,7 @@ get_page_from_l2e(
|
||||
static void put_page_from_l1e(l1_pgentry_t l1e, struct domain *d)
|
||||
{
|
||||
unsigned long l1v = l1_pgentry_val(l1e);
|
||||
unsigned long pfn = l1_pgentry_to_pagenr(l1e);
|
||||
unsigned long pfn = l1_pgentry_to_pfn(l1e);
|
||||
struct pfn_info *page = &frame_table[pfn];
|
||||
struct domain *e;
|
||||
|
||||
@@ -510,7 +512,7 @@ static void put_page_from_l2e(l2_pgentry_t l2e, unsigned long pfn)
|
||||
{
|
||||
if ( (l2_pgentry_val(l2e) & _PAGE_PRESENT) &&
|
||||
((l2_pgentry_val(l2e) >> PAGE_SHIFT) != pfn) )
|
||||
put_page_and_type(&frame_table[l2_pgentry_to_pagenr(l2e)]);
|
||||
put_page_and_type(&frame_table[l2_pgentry_to_pfn(l2e)]);
|
||||
}
|
||||
|
||||
|
||||
@@ -705,7 +707,7 @@ static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e)
|
||||
|
||||
if ( l1_pgentry_val(nl1e) & _PAGE_PRESENT )
|
||||
{
|
||||
/* Differ in mapping (bits 12-31), r/w (bit 1), or presence (bit 0)? */
|
||||
/* Same mapping (bits 12-31), r/w (bit 1), and presence (bit 0)? */
|
||||
if ( ((l1_pgentry_val(ol1e) ^ l1_pgentry_val(nl1e)) & ~0xffc) == 0 )
|
||||
return update_l1e(pl1e, ol1e, nl1e);
|
||||
|
||||
@@ -770,7 +772,7 @@ void free_page_type(struct pfn_info *page, unsigned int type)
|
||||
BUG();
|
||||
}
|
||||
|
||||
if ( unlikely(d->arch.shadow_mode) &&
|
||||
if ( unlikely(shadow_mode(d)) &&
|
||||
(get_shadow_status(d, page_to_pfn(page)) & PSH_shadowed) )
|
||||
{
|
||||
unshadow_table(page_to_pfn(page), type);
|
||||
@@ -1327,7 +1329,7 @@ int do_mmu_update(
|
||||
struct pfn_info *page;
|
||||
int rc = 0, okay = 1, i = 0, cpu = smp_processor_id();
|
||||
unsigned int cmd, done = 0;
|
||||
unsigned long prev_spfn = 0;
|
||||
unsigned long prev_smfn = 0;
|
||||
l1_pgentry_t *prev_spl1e = 0;
|
||||
struct exec_domain *ed = current;
|
||||
struct domain *d = ed->domain;
|
||||
@@ -1338,6 +1340,9 @@ int do_mmu_update(
|
||||
|
||||
cleanup_writable_pagetable(d);
|
||||
|
||||
if ( unlikely(shadow_mode(d)) )
|
||||
check_pagetable(d, ed->arch.pagetable, "pre-mmu"); /* debug */
|
||||
|
||||
/*
|
||||
* If we are resuming after preemption, read how much work we have already
|
||||
* done. This allows us to set the @done output parameter correctly.
|
||||
@@ -1378,8 +1383,8 @@ int do_mmu_update(
|
||||
{
|
||||
if ( hypercall_preempt_check() )
|
||||
{
|
||||
rc = hypercall_create_continuation(
|
||||
__HYPERVISOR_mmu_update, 3, ureqs,
|
||||
rc = hypercall3_create_continuation(
|
||||
__HYPERVISOR_mmu_update, ureqs,
|
||||
(count - i) |
|
||||
(FOREIGNDOM->id << MMU_UPDATE_PREEMPT_FDOM_SHIFT) |
|
||||
MMU_UPDATE_PREEMPTED, pdone);
|
||||
@@ -1432,12 +1437,12 @@ int do_mmu_update(
|
||||
okay = mod_l1_entry((l1_pgentry_t *)va,
|
||||
mk_l1_pgentry(req.val));
|
||||
|
||||
if ( unlikely(d->arch.shadow_mode) && okay &&
|
||||
if ( unlikely(shadow_mode(d)) && okay &&
|
||||
(get_shadow_status(d, page-frame_table) &
|
||||
PSH_shadowed) )
|
||||
{
|
||||
shadow_l1_normal_pt_update(
|
||||
req.ptr, req.val, &prev_spfn, &prev_spl1e);
|
||||
req.ptr, req.val, &prev_smfn, &prev_spl1e);
|
||||
put_shadow_status(d);
|
||||
}
|
||||
|
||||
@@ -1451,7 +1456,7 @@ int do_mmu_update(
|
||||
mk_l2_pgentry(req.val),
|
||||
pfn);
|
||||
|
||||
if ( unlikely(d->arch.shadow_mode) && okay &&
|
||||
if ( unlikely(shadow_mode(d)) && okay &&
|
||||
(get_shadow_status(d, page-frame_table) &
|
||||
PSH_shadowed) )
|
||||
{
|
||||
@@ -1489,7 +1494,7 @@ int do_mmu_update(
|
||||
* If in log-dirty mode, mark the corresponding pseudo-physical
|
||||
* page as dirty.
|
||||
*/
|
||||
if ( unlikely(d->arch.shadow_mode == SHM_logdirty) &&
|
||||
if ( unlikely(shadow_mode(d) == SHM_logdirty) &&
|
||||
mark_dirty(d, pfn) )
|
||||
d->arch.shadow_dirty_block_count++;
|
||||
|
||||
@@ -1545,12 +1550,15 @@ int do_mmu_update(
|
||||
if ( unlikely(pdone != NULL) )
|
||||
__put_user(done + i, pdone);
|
||||
|
||||
if ( unlikely(shadow_mode(d)) )
|
||||
check_pagetable(d, ed->arch.pagetable, "post-mmu"); /* debug */
|
||||
|
||||
UNLOCK_BIGLOCK(d);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int do_update_va_mapping(unsigned long page_nr,
|
||||
int do_update_va_mapping(unsigned long va,
|
||||
unsigned long val,
|
||||
unsigned long flags)
|
||||
{
|
||||
@@ -1562,7 +1570,7 @@ int do_update_va_mapping(unsigned long page_nr,
|
||||
|
||||
perfc_incrc(calls_to_update_va);
|
||||
|
||||
if ( unlikely(page_nr >= (HYPERVISOR_VIRT_START >> PAGE_SHIFT)) )
|
||||
if ( unlikely(!__addr_ok(va)) )
|
||||
return -EINVAL;
|
||||
|
||||
LOCK_BIGLOCK(d);
|
||||
@@ -1574,18 +1582,18 @@ int do_update_va_mapping(unsigned long page_nr,
|
||||
* the case of updating L2 entries.
|
||||
*/
|
||||
|
||||
if ( unlikely(!mod_l1_entry(&linear_pg_table[page_nr],
|
||||
if ( unlikely(!mod_l1_entry(&linear_pg_table[l1_linear_offset(va)],
|
||||
mk_l1_pgentry(val))) )
|
||||
err = -EINVAL;
|
||||
|
||||
if ( unlikely(d->arch.shadow_mode) )
|
||||
if ( unlikely(shadow_mode(d)) )
|
||||
{
|
||||
unsigned long sval;
|
||||
unsigned long sval = 0;
|
||||
|
||||
l1pte_propagate_from_guest(d, &val, &sval);
|
||||
|
||||
if ( unlikely(__put_user(sval, ((unsigned long *)(
|
||||
&shadow_linear_pg_table[page_nr])))) )
|
||||
&shadow_linear_pg_table[l1_linear_offset(va)])))) )
|
||||
{
|
||||
/*
|
||||
* Since L2's are guranteed RW, failure indicates the page was not
|
||||
@@ -1599,8 +1607,8 @@ int do_update_va_mapping(unsigned long page_nr,
|
||||
* the PTE in the PT-holding page. We need the machine frame number
|
||||
* for this.
|
||||
*/
|
||||
if ( d->arch.shadow_mode == SHM_logdirty )
|
||||
mark_dirty(d, va_to_l1mfn(page_nr << PAGE_SHIFT));
|
||||
if ( shadow_mode(d) == SHM_logdirty )
|
||||
mark_dirty(d, va_to_l1mfn(va));
|
||||
|
||||
check_pagetable(d, ed->arch.pagetable, "va"); /* debug */
|
||||
}
|
||||
@@ -1612,7 +1620,7 @@ int do_update_va_mapping(unsigned long page_nr,
|
||||
unlikely(flags & UVMF_FLUSH_TLB) )
|
||||
local_flush_tlb();
|
||||
else if ( unlikely(flags & UVMF_INVLPG) )
|
||||
__flush_tlb_one(page_nr << PAGE_SHIFT);
|
||||
__flush_tlb_one(va);
|
||||
|
||||
if ( unlikely(deferred_ops & DOP_RELOAD_LDT) )
|
||||
(void)map_ldt_shadow_page(0);
|
||||
@@ -1622,7 +1630,7 @@ int do_update_va_mapping(unsigned long page_nr,
|
||||
return err;
|
||||
}
|
||||
|
||||
int do_update_va_mapping_otherdomain(unsigned long page_nr,
|
||||
int do_update_va_mapping_otherdomain(unsigned long va,
|
||||
unsigned long val,
|
||||
unsigned long flags,
|
||||
domid_t domid)
|
||||
@@ -1641,7 +1649,7 @@ int do_update_va_mapping_otherdomain(unsigned long page_nr,
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
rc = do_update_va_mapping(page_nr, val, flags);
|
||||
rc = do_update_va_mapping(va, val, flags);
|
||||
|
||||
put_domain(d);
|
||||
percpu_info[cpu].foreign = NULL;
|
||||
@@ -1651,6 +1659,182 @@ int do_update_va_mapping_otherdomain(unsigned long page_nr,
|
||||
|
||||
|
||||
|
||||
/*************************
|
||||
* Descriptor Tables
|
||||
*/
|
||||
|
||||
void destroy_gdt(struct exec_domain *ed)
|
||||
{
|
||||
int i;
|
||||
unsigned long pfn;
|
||||
|
||||
for ( i = 0; i < 16; i++ )
|
||||
{
|
||||
if ( (pfn = l1_pgentry_to_pfn(ed->arch.perdomain_ptes[i])) != 0 )
|
||||
put_page_and_type(&frame_table[pfn]);
|
||||
ed->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
long set_gdt(struct exec_domain *ed,
|
||||
unsigned long *frames,
|
||||
unsigned int entries)
|
||||
{
|
||||
struct domain *d = ed->domain;
|
||||
/* NB. There are 512 8-byte entries per GDT page. */
|
||||
int i = 0, nr_pages = (entries + 511) / 512;
|
||||
struct desc_struct *vgdt;
|
||||
unsigned long pfn;
|
||||
|
||||
/* Check the first page in the new GDT. */
|
||||
if ( (pfn = frames[0]) >= max_page )
|
||||
goto fail;
|
||||
|
||||
/* The first page is special because Xen owns a range of entries in it. */
|
||||
if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
|
||||
{
|
||||
/* GDT checks failed: try zapping the Xen reserved entries. */
|
||||
if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
|
||||
goto fail;
|
||||
vgdt = map_domain_mem(pfn << PAGE_SHIFT);
|
||||
memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
|
||||
NR_RESERVED_GDT_ENTRIES*8);
|
||||
unmap_domain_mem(vgdt);
|
||||
put_page_and_type(&frame_table[pfn]);
|
||||
|
||||
/* Okay, we zapped the entries. Now try the GDT checks again. */
|
||||
if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check the remaining pages in the new GDT. */
|
||||
for ( i = 1; i < nr_pages; i++ )
|
||||
if ( ((pfn = frames[i]) >= max_page) ||
|
||||
!get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
|
||||
goto fail;
|
||||
|
||||
/* Copy reserved GDT entries to the new GDT. */
|
||||
vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
|
||||
memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY,
|
||||
gdt_table + FIRST_RESERVED_GDT_ENTRY,
|
||||
NR_RESERVED_GDT_ENTRIES*8);
|
||||
unmap_domain_mem(vgdt);
|
||||
|
||||
/* Tear down the old GDT. */
|
||||
destroy_gdt(ed);
|
||||
|
||||
/* Install the new GDT. */
|
||||
for ( i = 0; i < nr_pages; i++ )
|
||||
ed->arch.perdomain_ptes[i] =
|
||||
mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
|
||||
|
||||
SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
|
||||
SET_GDT_ENTRIES(ed, entries);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
while ( i-- > 0 )
|
||||
put_page_and_type(&frame_table[frames[i]]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
long do_set_gdt(unsigned long *frame_list, unsigned int entries)
|
||||
{
|
||||
int nr_pages = (entries + 511) / 512;
|
||||
unsigned long frames[16];
|
||||
long ret;
|
||||
|
||||
if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) )
|
||||
return -EINVAL;
|
||||
|
||||
if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
|
||||
return -EFAULT;
|
||||
|
||||
LOCK_BIGLOCK(current->domain);
|
||||
|
||||
if ( (ret = set_gdt(current, frames, entries)) == 0 )
|
||||
{
|
||||
local_flush_tlb();
|
||||
__asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
|
||||
}
|
||||
|
||||
UNLOCK_BIGLOCK(current->domain);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
long do_update_descriptor(
|
||||
unsigned long pa, unsigned long word1, unsigned long word2)
|
||||
{
|
||||
unsigned long pfn = pa >> PAGE_SHIFT;
|
||||
struct desc_struct *gdt_pent, d;
|
||||
struct pfn_info *page;
|
||||
struct exec_domain *ed;
|
||||
long ret = -EINVAL;
|
||||
|
||||
d.a = (u32)word1;
|
||||
d.b = (u32)word2;
|
||||
|
||||
LOCK_BIGLOCK(current->domain);
|
||||
|
||||
if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(&d) ) {
|
||||
UNLOCK_BIGLOCK(current->domain);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
page = &frame_table[pfn];
|
||||
if ( unlikely(!get_page(page, current->domain)) ) {
|
||||
UNLOCK_BIGLOCK(current->domain);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if the given frame is in use in an unsafe context. */
|
||||
switch ( page->u.inuse.type_info & PGT_type_mask )
|
||||
{
|
||||
case PGT_gdt_page:
|
||||
/* Disallow updates of Xen-reserved descriptors in the current GDT. */
|
||||
for_each_exec_domain(current->domain, ed) {
|
||||
if ( (l1_pgentry_to_pfn(ed->arch.perdomain_ptes[0]) == pfn) &&
|
||||
(((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
|
||||
(((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
|
||||
goto out;
|
||||
}
|
||||
if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
|
||||
goto out;
|
||||
break;
|
||||
case PGT_ldt_page:
|
||||
if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
|
||||
goto out;
|
||||
break;
|
||||
default:
|
||||
if ( unlikely(!get_page_type(page, PGT_writable_page)) )
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
|
||||
/* All is good so make the update. */
|
||||
gdt_pent = map_domain_mem(pa);
|
||||
memcpy(gdt_pent, &d, 8);
|
||||
unmap_domain_mem(gdt_pent);
|
||||
|
||||
put_page_type(page);
|
||||
|
||||
ret = 0; /* success */
|
||||
|
||||
out:
|
||||
put_page(page);
|
||||
|
||||
UNLOCK_BIGLOCK(current->domain);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************
|
||||
* Writable Pagetables
|
||||
*/
|
||||
@@ -1696,7 +1880,7 @@ void ptwr_flush(const int which)
|
||||
PTWR_PRINT_WHICH, ptep, pte);
|
||||
pte &= ~_PAGE_RW;
|
||||
|
||||
if ( unlikely(d->arch.shadow_mode) )
|
||||
if ( unlikely(shadow_mode(d)) )
|
||||
{
|
||||
/* Write-protect the p.t. page in the shadow page table. */
|
||||
l1pte_propagate_from_guest(d, &pte, &spte);
|
||||
@@ -1755,7 +1939,7 @@ void ptwr_flush(const int which)
|
||||
l1pte_propagate_from_guest(
|
||||
d, &l1_pgentry_val(nl1e),
|
||||
&l1_pgentry_val(sl1e[i]));
|
||||
put_page_type(&frame_table[l1_pgentry_to_pagenr(nl1e)]);
|
||||
put_page_type(&frame_table[l1_pgentry_to_pfn(nl1e)]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -1788,7 +1972,7 @@ void ptwr_flush(const int which)
|
||||
* STEP 3. Reattach the L1 p.t. page into the current address space.
|
||||
*/
|
||||
|
||||
if ( (which == PTWR_PT_ACTIVE) && likely(!d->arch.shadow_mode) )
|
||||
if ( (which == PTWR_PT_ACTIVE) && likely(!shadow_mode(d)) )
|
||||
{
|
||||
pl2e = &linear_l2_table[ptwr_info[cpu].ptinfo[which].l2_idx];
|
||||
*pl2e = mk_l2_pgentry(l2_pgentry_val(*pl2e) | _PAGE_PRESENT);
|
||||
@@ -1816,6 +2000,10 @@ int ptwr_do_page_fault(unsigned long addr)
|
||||
int which, cpu = smp_processor_id();
|
||||
u32 l2_idx;
|
||||
|
||||
#ifdef __x86_64__
|
||||
return 0; /* Writable pagetables need fixing for x86_64. */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Attempt to read the PTE that maps the VA being accessed. By checking for
|
||||
* PDE validity in the L2 we avoid many expensive fixups in __get_user().
|
||||
@@ -1892,7 +2080,7 @@ int ptwr_do_page_fault(unsigned long addr)
|
||||
|
||||
/* For safety, disconnect the L1 p.t. page from current space. */
|
||||
if ( (which == PTWR_PT_ACTIVE) &&
|
||||
likely(!current->domain->arch.shadow_mode) )
|
||||
likely(!shadow_mode(current->domain)) )
|
||||
{
|
||||
*pl2e = mk_l2_pgentry(l2e & ~_PAGE_PRESENT);
|
||||
#if 1
|
||||
@@ -2313,7 +2501,6 @@ void audit_domain(struct domain *d)
|
||||
}
|
||||
|
||||
/* PHASE 3 */
|
||||
|
||||
list_ent = d->page_list.next;
|
||||
for ( i = 0; (list_ent != &d->page_list); i++ )
|
||||
{
|
||||
@@ -2334,7 +2521,12 @@ void audit_domain(struct domain *d)
|
||||
if ( pt[i] & _PAGE_PRESENT )
|
||||
{
|
||||
unsigned long l1pfn = pt[i]>>PAGE_SHIFT;
|
||||
struct pfn_info *l1page = &frame_table[l1pfn];
|
||||
struct pfn_info *l1page;
|
||||
|
||||
if (l1pfn>max_page)
|
||||
continue;
|
||||
|
||||
l1page = &frame_table[l1pfn];
|
||||
|
||||
if ( page_get_owner(l1page) == d )
|
||||
adjust(l1page, 1, 1);
|
||||
@@ -2355,7 +2547,12 @@ void audit_domain(struct domain *d)
|
||||
if ( pt[i] & _PAGE_PRESENT )
|
||||
{
|
||||
unsigned long l1pfn = pt[i]>>PAGE_SHIFT;
|
||||
struct pfn_info *l1page = &frame_table[l1pfn];
|
||||
struct pfn_info *l1page;
|
||||
|
||||
if (l1pfn>max_page)
|
||||
continue;
|
||||
|
||||
l1page = &frame_table[l1pfn];
|
||||
|
||||
if ( (page_get_owner(l1page) != d) ||
|
||||
(l1pfn < 0x100) || (l1pfn > max_page) )
|
||||
@@ -298,19 +298,21 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
|
||||
unsigned long cpu_initialized;
|
||||
void __init cpu_init(void)
|
||||
{
|
||||
extern void percpu_traps_init(void);
|
||||
int nr = smp_processor_id();
|
||||
struct tss_struct *t = &init_tss[nr];
|
||||
unsigned char idt_load[10];
|
||||
|
||||
if ( test_and_set_bit(nr, &cpu_initialized) )
|
||||
panic("CPU#%d already initialized!!!\n", nr);
|
||||
printk("Initializing CPU#%d\n", nr);
|
||||
|
||||
/* Set up GDT and IDT. */
|
||||
SET_GDT_ENTRIES(current, DEFAULT_GDT_ENTRIES);
|
||||
SET_GDT_ADDRESS(current, DEFAULT_GDT_ADDRESS);
|
||||
__asm__ __volatile__ ( "lgdt %0" : "=m" (*current->arch.gdt) );
|
||||
__asm__ __volatile__ ( "lidt %0" : "=m" (idt_descr) );
|
||||
|
||||
*(unsigned short *)(&idt_load[0]) = (IDT_ENTRIES*sizeof(idt_entry_t))-1;
|
||||
*(unsigned long *)(&idt_load[2]) = (unsigned long)idt_tables[nr];
|
||||
__asm__ __volatile__ ( "lidt %0" : "=m" (idt_load) );
|
||||
|
||||
/* No nested task. */
|
||||
__asm__ __volatile__ ( "pushf ; andw $0xbfff,(%"__OP"sp) ; popf" );
|
||||
@@ -336,8 +338,6 @@ void __init cpu_init(void)
|
||||
CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7);
|
||||
#undef CD
|
||||
|
||||
percpu_traps_init();
|
||||
|
||||
/* Install correct page table. */
|
||||
write_ptbase(current);
|
||||
|
||||
|
||||
+130
-107
@@ -73,11 +73,11 @@ static void free_shadow_state(struct domain *d)
|
||||
|
||||
/* Free the head page. */
|
||||
free_shadow_page(
|
||||
d, &frame_table[x->spfn_and_flags & PSH_pfn_mask]);
|
||||
d, &frame_table[x->smfn_and_flags & PSH_pfn_mask]);
|
||||
|
||||
/* Reinitialise the head node. */
|
||||
x->pfn = 0;
|
||||
x->spfn_and_flags = 0;
|
||||
x->smfn_and_flags = 0;
|
||||
n = x->next;
|
||||
x->next = NULL;
|
||||
|
||||
@@ -88,11 +88,11 @@ static void free_shadow_state(struct domain *d)
|
||||
{
|
||||
/* Free the shadow page. */
|
||||
free_shadow_page(
|
||||
d, &frame_table[x->spfn_and_flags & PSH_pfn_mask]);
|
||||
d, &frame_table[x->smfn_and_flags & PSH_pfn_mask]);
|
||||
|
||||
/* Re-initialise the chain node. */
|
||||
x->pfn = 0;
|
||||
x->spfn_and_flags = 0;
|
||||
x->smfn_and_flags = 0;
|
||||
|
||||
/* Add to the free list. */
|
||||
n = x->next;
|
||||
@@ -113,14 +113,14 @@ static inline int clear_shadow_page(
|
||||
{
|
||||
unsigned long *p;
|
||||
int restart = 0;
|
||||
struct pfn_info *spage = &frame_table[x->spfn_and_flags & PSH_pfn_mask];
|
||||
struct pfn_info *spage = &frame_table[x->smfn_and_flags & PSH_pfn_mask];
|
||||
|
||||
switch ( spage->u.inuse.type_info & PGT_type_mask )
|
||||
{
|
||||
/* We clear L2 pages by zeroing the guest entries. */
|
||||
case PGT_l2_page_table:
|
||||
p = map_domain_mem((spage - frame_table) << PAGE_SHIFT);
|
||||
if (d->arch.shadow_mode == SHM_full_32)
|
||||
if ( shadow_mode(d) == SHM_full_32 )
|
||||
memset(p, 0, ENTRIES_PER_L2_PAGETABLE * sizeof(*p));
|
||||
else
|
||||
memset(p, 0, DOMAIN_ENTRIES_PER_L2_PAGETABLE * sizeof(*p));
|
||||
@@ -419,7 +419,7 @@ static inline struct pfn_info *alloc_shadow_page(struct domain *d)
|
||||
|
||||
void unshadow_table(unsigned long gpfn, unsigned int type)
|
||||
{
|
||||
unsigned long spfn;
|
||||
unsigned long smfn;
|
||||
struct domain *d = page_get_owner(&frame_table[gpfn]);
|
||||
|
||||
SH_VLOG("unshadow_table type=%08x gpfn=%08lx", type, gpfn);
|
||||
@@ -431,15 +431,15 @@ void unshadow_table(unsigned long gpfn, unsigned int type)
|
||||
* guests there won't be a race here as this CPU was the one that
|
||||
* cmpxchg'ed the page to invalid.
|
||||
*/
|
||||
spfn = __shadow_status(d, gpfn) & PSH_pfn_mask;
|
||||
smfn = __shadow_status(d, gpfn) & PSH_pfn_mask;
|
||||
delete_shadow_status(d, gpfn);
|
||||
free_shadow_page(d, &frame_table[spfn]);
|
||||
free_shadow_page(d, &frame_table[smfn]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VMX
|
||||
void vmx_shadow_clear_state(struct domain *d)
|
||||
{
|
||||
SH_VVLOG("vmx_clear_shadow_state: \n");
|
||||
SH_VVLOG("vmx_clear_shadow_state:");
|
||||
clear_shadow_state(d);
|
||||
}
|
||||
#endif
|
||||
@@ -453,7 +453,7 @@ unsigned long shadow_l2_table(
|
||||
l2_pgentry_t *spl2e = 0;
|
||||
unsigned long guest_gpfn;
|
||||
|
||||
__get_machine_to_phys(d, guest_gpfn, gpfn);
|
||||
guest_gpfn = __mfn_to_gpfn(d, gpfn);
|
||||
|
||||
SH_VVLOG("shadow_l2_table( %08lx )", gpfn);
|
||||
|
||||
@@ -471,9 +471,13 @@ unsigned long shadow_l2_table(
|
||||
|
||||
#ifdef __i386__
|
||||
/* Install hypervisor and 2x linear p.t. mapings. */
|
||||
if ( d->arch.shadow_mode == SHM_full_32 )
|
||||
if ( shadow_mode(d) == SHM_full_32 )
|
||||
{
|
||||
#ifdef CONFIG_VMX
|
||||
vmx_update_shadow_state(d->exec_domain[0], gpfn, spfn);
|
||||
#else
|
||||
panic("Shadow Full 32 not yet implemented without VMX\n");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -499,7 +503,7 @@ unsigned long shadow_l2_table(
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( d->arch.shadow_mode != SHM_full_32 )
|
||||
if ( shadow_mode(d) != SHM_full_32 )
|
||||
unmap_domain_mem(spl2e);
|
||||
|
||||
SH_VLOG("shadow_l2_table( %08lx -> %08lx)", gpfn, spfn);
|
||||
@@ -510,13 +514,13 @@ static void shadow_map_l1_into_current_l2(unsigned long va)
|
||||
{
|
||||
struct exec_domain *ed = current;
|
||||
struct domain *d = ed->domain;
|
||||
unsigned long *gpl1e, *spl1e, gpl2e, spl2e, gl1pfn, sl1pfn=0, sl1ss;
|
||||
unsigned long *gpl1e, *spl1e, gl2e, sl2e, gl1pfn, sl1pfn=0, sl1ss;
|
||||
struct pfn_info *sl1pfn_info;
|
||||
int i;
|
||||
|
||||
__guest_get_pl2e(ed, va, &gpl2e);
|
||||
__guest_get_l2e(ed, va, &gl2e);
|
||||
|
||||
gl1pfn = gpl2e >> PAGE_SHIFT;
|
||||
gl1pfn = gl2e >> PAGE_SHIFT;
|
||||
|
||||
sl1ss = __shadow_status(d, gl1pfn);
|
||||
if ( !(sl1ss & PSH_shadowed) )
|
||||
@@ -534,10 +538,10 @@ static void shadow_map_l1_into_current_l2(unsigned long va)
|
||||
|
||||
set_shadow_status(d, gl1pfn, PSH_shadowed | sl1pfn);
|
||||
|
||||
l2pde_general(d, &gpl2e, &spl2e, sl1pfn);
|
||||
l2pde_general(d, &gl2e, &sl2e, sl1pfn);
|
||||
|
||||
__guest_set_pl2e(ed, va, gpl2e);
|
||||
__shadow_set_pl2e(ed, va, spl2e);
|
||||
__guest_set_l2e(ed, va, gl2e);
|
||||
__shadow_set_l2e(ed, va, sl2e);
|
||||
|
||||
gpl1e = (unsigned long *) &(linear_pg_table[
|
||||
(va>>L1_PAGETABLE_SHIFT) & ~(ENTRIES_PER_L1_PAGETABLE-1)]);
|
||||
@@ -554,9 +558,9 @@ static void shadow_map_l1_into_current_l2(unsigned long va)
|
||||
SH_VVLOG("4b: was shadowed, l2 missing ( %08lx )", sl1pfn);
|
||||
|
||||
sl1pfn = sl1ss & PSH_pfn_mask;
|
||||
l2pde_general(d, &gpl2e, &spl2e, sl1pfn);
|
||||
__guest_set_pl2e(ed, va, gpl2e);
|
||||
__shadow_set_pl2e(ed, va, spl2e);
|
||||
l2pde_general(d, &gl2e, &sl2e, sl1pfn);
|
||||
__guest_set_l2e(ed, va, gl2e);
|
||||
__shadow_set_l2e(ed, va, sl2e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,7 +580,7 @@ void vmx_shadow_invlpg(struct domain *d, unsigned long va)
|
||||
return;
|
||||
}
|
||||
|
||||
host_pfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT];
|
||||
host_pfn = phys_to_machine_mapping(gpte >> PAGE_SHIFT);
|
||||
spte = (host_pfn << PAGE_SHIFT) | (gpte & ~PAGE_MASK);
|
||||
|
||||
if (__put_user(spte, (unsigned long *)
|
||||
@@ -588,7 +592,7 @@ void vmx_shadow_invlpg(struct domain *d, unsigned long va)
|
||||
|
||||
int shadow_fault(unsigned long va, long error_code)
|
||||
{
|
||||
unsigned long gpte, spte;
|
||||
unsigned long gpte, spte = 0;
|
||||
struct exec_domain *ed = current;
|
||||
struct domain *d = ed->domain;
|
||||
|
||||
@@ -628,14 +632,14 @@ int shadow_fault(unsigned long va, long error_code)
|
||||
if ( unlikely(__get_user(gpte, (unsigned long *)
|
||||
&linear_pg_table[va >> PAGE_SHIFT])) )
|
||||
{
|
||||
SH_VVLOG("shadow_fault - EXIT: read gpte faulted" );
|
||||
SH_VVLOG("shadow_fault - EXIT: read gpte faulted2" );
|
||||
shadow_unlock(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( unlikely(!(gpte & _PAGE_PRESENT)) )
|
||||
{
|
||||
SH_VVLOG("shadow_fault - EXIT: gpte not present (%lx)",gpte );
|
||||
SH_VVLOG("shadow_fault - EXIT: gpte not present2 (%lx)",gpte );
|
||||
shadow_unlock(d);
|
||||
return 0;
|
||||
}
|
||||
@@ -691,20 +695,20 @@ int shadow_fault(unsigned long va, long error_code)
|
||||
|
||||
void shadow_l1_normal_pt_update(
|
||||
unsigned long pa, unsigned long gpte,
|
||||
unsigned long *prev_spfn_ptr,
|
||||
unsigned long *prev_smfn_ptr,
|
||||
l1_pgentry_t **prev_spl1e_ptr)
|
||||
{
|
||||
unsigned long spfn, spte, prev_spfn = *prev_spfn_ptr;
|
||||
unsigned long smfn, spte, prev_smfn = *prev_smfn_ptr;
|
||||
l1_pgentry_t *spl1e, *prev_spl1e = *prev_spl1e_ptr;
|
||||
|
||||
/* N.B. To get here, we know the l1 page *must* be shadowed. */
|
||||
SH_VVLOG("shadow_l1_normal_pt_update pa=%08lx, gpte=%08lx, "
|
||||
"prev_spfn=%08lx, prev_spl1e=%p\n",
|
||||
pa, gpte, prev_spfn, prev_spl1e);
|
||||
"prev_smfn=%08lx, prev_spl1e=%p",
|
||||
pa, gpte, prev_smfn, prev_spl1e);
|
||||
|
||||
spfn = __shadow_status(current->domain, pa >> PAGE_SHIFT) & PSH_pfn_mask;
|
||||
smfn = __shadow_status(current->domain, pa >> PAGE_SHIFT) & PSH_pfn_mask;
|
||||
|
||||
if ( spfn == prev_spfn )
|
||||
if ( smfn == prev_smfn )
|
||||
{
|
||||
spl1e = prev_spl1e;
|
||||
}
|
||||
@@ -712,8 +716,8 @@ void shadow_l1_normal_pt_update(
|
||||
{
|
||||
if ( prev_spl1e != NULL )
|
||||
unmap_domain_mem( prev_spl1e );
|
||||
spl1e = (l1_pgentry_t *)map_domain_mem(spfn << PAGE_SHIFT);
|
||||
*prev_spfn_ptr = spfn;
|
||||
spl1e = (l1_pgentry_t *)map_domain_mem(smfn << PAGE_SHIFT);
|
||||
*prev_smfn_ptr = smfn;
|
||||
*prev_spl1e_ptr = spl1e;
|
||||
}
|
||||
|
||||
@@ -721,24 +725,24 @@ void shadow_l1_normal_pt_update(
|
||||
spl1e[(pa & ~PAGE_MASK) / sizeof(l1_pgentry_t)] = mk_l1_pgentry(spte);
|
||||
}
|
||||
|
||||
void shadow_l2_normal_pt_update(unsigned long pa, unsigned long gpte)
|
||||
void shadow_l2_normal_pt_update(unsigned long pa, unsigned long gpde)
|
||||
{
|
||||
unsigned long spfn, spte;
|
||||
unsigned long sl2mfn, spde;
|
||||
l2_pgentry_t *spl2e;
|
||||
unsigned long s_sh;
|
||||
unsigned long sl1mfn;
|
||||
|
||||
/* N.B. To get here, we know the l2 page *must* be shadowed. */
|
||||
SH_VVLOG("shadow_l2_normal_pt_update pa=%08lx, gpte=%08lx",pa,gpte);
|
||||
SH_VVLOG("shadow_l2_normal_pt_update pa=%08lx, gpde=%08lx",pa,gpde);
|
||||
|
||||
spfn = __shadow_status(current->domain, pa >> PAGE_SHIFT) & PSH_pfn_mask;
|
||||
sl2mfn = __shadow_status(current->domain, pa >> PAGE_SHIFT) & PSH_pfn_mask;
|
||||
|
||||
s_sh = (gpte & _PAGE_PRESENT) ?
|
||||
__shadow_status(current->domain, gpte >> PAGE_SHIFT) : 0;
|
||||
sl1mfn = (gpde & _PAGE_PRESENT) ?
|
||||
__shadow_status(current->domain, gpde >> PAGE_SHIFT) : 0;
|
||||
|
||||
/* XXXX Should mark guest pte as DIRTY and ACCESSED too! */
|
||||
l2pde_general(current->domain, &gpte, &spte, s_sh);
|
||||
spl2e = (l2_pgentry_t *)map_domain_mem(spfn << PAGE_SHIFT);
|
||||
spl2e[(pa & ~PAGE_MASK) / sizeof(l2_pgentry_t)] = mk_l2_pgentry(spte);
|
||||
l2pde_general(current->domain, &gpde, &spde, sl1mfn);
|
||||
spl2e = (l2_pgentry_t *)map_domain_mem(sl2mfn << PAGE_SHIFT);
|
||||
spl2e[(pa & ~PAGE_MASK) / sizeof(l2_pgentry_t)] = mk_l2_pgentry(spde);
|
||||
unmap_domain_mem(spl2e);
|
||||
}
|
||||
|
||||
@@ -751,23 +755,36 @@ void shadow_l2_normal_pt_update(unsigned long pa, unsigned long gpte)
|
||||
|
||||
#if SHADOW_DEBUG
|
||||
|
||||
// BUG: these are not SMP safe...
|
||||
static int sh_l2_present;
|
||||
static int sh_l1_present;
|
||||
static int errors;
|
||||
char * sh_check_name;
|
||||
|
||||
#define FAIL(_f, _a...) \
|
||||
do { \
|
||||
printk("XXX %s-FAIL (%d,%d)" _f " g=%08lx s=%08lx\n", \
|
||||
sh_check_name, level, i, ## _a , gpte, spte); \
|
||||
BUG(); \
|
||||
#define virt_to_phys2(adr) ({ \
|
||||
unsigned long _a = (unsigned long)(adr); \
|
||||
unsigned long _pte = l1_pgentry_val( \
|
||||
shadow_linear_pg_table[_a >> PAGE_SHIFT]); \
|
||||
unsigned long _pa = _pte & PAGE_MASK; \
|
||||
_pa | (_a & ~PAGE_MASK); \
|
||||
})
|
||||
|
||||
#define FAIL(_f, _a...) \
|
||||
do { \
|
||||
printk("XXX %s-FAIL (%d,%d)" _f " g=%08lx s=%08lx &g=%08lx &s=%08lx" \
|
||||
" pa(&g)=%08lx pa(&s)=%08lx\n", \
|
||||
sh_check_name, level, i, ## _a , gpte, spte, pgpte, pspte, \
|
||||
virt_to_phys2(pgpte), virt_to_phys2(pspte)); \
|
||||
errors++; \
|
||||
} while ( 0 )
|
||||
|
||||
static int check_pte(
|
||||
struct domain *d, unsigned long gpte, unsigned long spte,
|
||||
struct domain *d, unsigned long *pgpte, unsigned long *pspte,
|
||||
int level, int i)
|
||||
{
|
||||
unsigned long mask, gpfn, spfn;
|
||||
unsigned long guest_gpfn;
|
||||
unsigned gpte = *pgpte;
|
||||
unsigned spte = *pspte;
|
||||
unsigned long mask, gpfn, smfn;
|
||||
|
||||
if ( (spte == 0) || (spte == 0xdeadface) || (spte == 0x00000E00) )
|
||||
return 1; /* always safe */
|
||||
@@ -781,7 +798,7 @@ static int check_pte(
|
||||
if ( !(gpte & _PAGE_PRESENT) )
|
||||
FAIL("Guest not present yet shadow is");
|
||||
|
||||
mask = ~(_PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_RW|0xFFFFF000);
|
||||
mask = ~(_PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_RW|PAGE_MASK);
|
||||
|
||||
if ( (spte & mask) != (gpte & mask) )
|
||||
FAIL("Corrupt?");
|
||||
@@ -798,10 +815,10 @@ static int check_pte(
|
||||
if ( (spte & _PAGE_RW ) && !((gpte & _PAGE_RW) && (gpte & _PAGE_DIRTY)) )
|
||||
FAIL("RW2 coherence");
|
||||
|
||||
spfn = spte >> PAGE_SHIFT;
|
||||
smfn = spte >> PAGE_SHIFT;
|
||||
gpfn = gpte >> PAGE_SHIFT;
|
||||
|
||||
if ( gpfn == spfn )
|
||||
if ( gpfn == smfn )
|
||||
{
|
||||
if ( level > 1 )
|
||||
FAIL("Linear map ???"); /* XXX this will fail on BSD */
|
||||
@@ -811,20 +828,9 @@ static int check_pte(
|
||||
if ( level < 2 )
|
||||
FAIL("Shadow in L1 entry?");
|
||||
|
||||
if (d->arch.shadow_mode == SHM_full_32) {
|
||||
|
||||
guest_gpfn = phys_to_machine_mapping[gpfn];
|
||||
|
||||
if ( __shadow_status(d, guest_gpfn) != (PSH_shadowed | spfn) )
|
||||
FAIL("spfn problem g.sf=%08lx",
|
||||
__shadow_status(d, guest_gpfn) );
|
||||
|
||||
} else {
|
||||
if ( __shadow_status(d, gpfn) != (PSH_shadowed | spfn) )
|
||||
FAIL("spfn problem g.sf=%08lx",
|
||||
__shadow_status(d, gpfn) );
|
||||
}
|
||||
|
||||
if ( __shadow_status(d, gpfn) != (PSH_shadowed | smfn) )
|
||||
FAIL("smfn problem g.sf=%08lx",
|
||||
__shadow_status(d, gpfn) );
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -832,17 +838,17 @@ static int check_pte(
|
||||
|
||||
|
||||
static int check_l1_table(
|
||||
struct domain *d, unsigned long va,
|
||||
unsigned long g2, unsigned long s2)
|
||||
struct domain *d,
|
||||
unsigned long g2mfn, unsigned long s2mfn)
|
||||
{
|
||||
int i;
|
||||
unsigned long *gpl1e, *spl1e;
|
||||
|
||||
gpl1e = map_domain_mem(g2 << PAGE_SHIFT);
|
||||
spl1e = map_domain_mem(s2 << PAGE_SHIFT);
|
||||
gpl1e = map_domain_mem(g2mfn << PAGE_SHIFT);
|
||||
spl1e = map_domain_mem(s2mfn << PAGE_SHIFT);
|
||||
|
||||
for ( i = 0; i < ENTRIES_PER_L1_PAGETABLE; i++ )
|
||||
check_pte(d, gpl1e[i], spl1e[i], 1, i);
|
||||
check_pte(d, &gpl1e[i], &spl1e[i], 1, i);
|
||||
|
||||
unmap_domain_mem(spl1e);
|
||||
unmap_domain_mem(gpl1e);
|
||||
@@ -853,49 +859,46 @@ static int check_l1_table(
|
||||
#define FAILPT(_f, _a...) \
|
||||
do { \
|
||||
printk("XXX FAIL %s-PT" _f "\n", s, ## _a ); \
|
||||
BUG(); \
|
||||
errors++; \
|
||||
} while ( 0 )
|
||||
|
||||
int check_pagetable(struct domain *d, pagetable_t pt, char *s)
|
||||
void check_pagetable(struct domain *d, pagetable_t pt, char *s)
|
||||
{
|
||||
unsigned long gptbase = pagetable_val(pt);
|
||||
unsigned long gpfn, spfn;
|
||||
unsigned long ptbase_pfn, smfn, ss;
|
||||
unsigned long i;
|
||||
l2_pgentry_t *gpl2e, *spl2e;
|
||||
unsigned long host_gpfn = 0;
|
||||
unsigned long ptbase_mfn = 0;
|
||||
int cpu = current->processor;
|
||||
|
||||
errors = 0;
|
||||
sh_check_name = s;
|
||||
|
||||
SH_VVLOG("%s-PT Audit", s);
|
||||
|
||||
sh_l2_present = sh_l1_present = 0;
|
||||
|
||||
gpfn = gptbase >> PAGE_SHIFT;
|
||||
ptbase_pfn = gptbase >> PAGE_SHIFT;
|
||||
ptbase_mfn = __gpfn_to_mfn(d, ptbase_pfn);
|
||||
|
||||
__get_phys_to_machine(d, host_gpfn, gpfn);
|
||||
ss = __shadow_status(d, ptbase_pfn);
|
||||
|
||||
if ( ! (__shadow_status(d, gpfn) & PSH_shadowed) )
|
||||
if ( ! (ss & PSH_shadowed) )
|
||||
{
|
||||
printk("%s-PT %08lx not shadowed\n", s, gptbase);
|
||||
|
||||
if( __shadow_status(d, gpfn) != 0 ) BUG();
|
||||
return 0;
|
||||
if ( ss != 0 )
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
|
||||
spfn = __shadow_status(d, gpfn) & PSH_pfn_mask;
|
||||
smfn = ss & PSH_pfn_mask;
|
||||
|
||||
if ( ! __shadow_status(d, gpfn) == (PSH_shadowed | spfn) )
|
||||
FAILPT("ptbase shadow inconsistent1");
|
||||
if ( ss != (PSH_shadowed | smfn) )
|
||||
FAILPT("ptbase shadow inconsistent1");
|
||||
|
||||
if (d->arch.shadow_mode == SHM_full_32)
|
||||
{
|
||||
host_gpfn = phys_to_machine_mapping[gpfn];
|
||||
gpl2e = (l2_pgentry_t *) map_domain_mem( host_gpfn << PAGE_SHIFT );
|
||||
|
||||
} else
|
||||
gpl2e = (l2_pgentry_t *) map_domain_mem( gpfn << PAGE_SHIFT );
|
||||
|
||||
spl2e = (l2_pgentry_t *) map_domain_mem( spfn << PAGE_SHIFT );
|
||||
gpl2e = (l2_pgentry_t *) map_domain_mem( ptbase_mfn << PAGE_SHIFT );
|
||||
spl2e = (l2_pgentry_t *) map_domain_mem( smfn << PAGE_SHIFT );
|
||||
|
||||
if ( memcmp(&spl2e[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
|
||||
&gpl2e[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
|
||||
@@ -916,40 +919,60 @@ int check_pagetable(struct domain *d, pagetable_t pt, char *s)
|
||||
|
||||
if ( (l2_pgentry_val(spl2e[SH_LINEAR_PT_VIRT_START >>
|
||||
L2_PAGETABLE_SHIFT]) !=
|
||||
((spfn << PAGE_SHIFT) | __PAGE_HYPERVISOR)) )
|
||||
((smfn << PAGE_SHIFT) | __PAGE_HYPERVISOR)) )
|
||||
FAILPT("hypervisor shadow linear map inconsistent %08lx %08lx",
|
||||
l2_pgentry_val(spl2e[SH_LINEAR_PT_VIRT_START >>
|
||||
L2_PAGETABLE_SHIFT]),
|
||||
(spfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
|
||||
(smfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
|
||||
|
||||
if (d->arch.shadow_mode != SHM_full_32) {
|
||||
if ( shadow_mode(d) != SHM_full_32 ) {
|
||||
// BUG: this shouldn't be using exec_domain[0] here...
|
||||
if ( (l2_pgentry_val(spl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT]) !=
|
||||
((__pa(page_get_owner(&frame_table[gpfn])->arch.mm_perdomain_pt) |
|
||||
((__pa(page_get_owner(&frame_table[ptbase_pfn])->arch.mm_perdomain_pt) |
|
||||
__PAGE_HYPERVISOR))) )
|
||||
FAILPT("hypervisor per-domain map inconsistent");
|
||||
}
|
||||
|
||||
/* Check the whole L2. */
|
||||
for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
|
||||
check_pte(d, l2_pgentry_val(gpl2e[i]), l2_pgentry_val(spl2e[i]), 2, i);
|
||||
check_pte(d, &l2_pgentry_val(gpl2e[i]), &l2_pgentry_val(spl2e[i]), 2, i);
|
||||
|
||||
/* Go back and recurse. */
|
||||
for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
|
||||
{
|
||||
unsigned long gl1pfn = l2_pgentry_val(gpl2e[i]) >> PAGE_SHIFT;
|
||||
unsigned long gl1mfn = __gpfn_to_mfn(d, gl1pfn);
|
||||
unsigned long sl1mfn = l2_pgentry_val(spl2e[i]) >> PAGE_SHIFT;
|
||||
|
||||
if ( l2_pgentry_val(spl2e[i]) != 0 )
|
||||
check_l1_table(
|
||||
d, i << L2_PAGETABLE_SHIFT,
|
||||
l2_pgentry_val(gpl2e[i]) >> PAGE_SHIFT,
|
||||
l2_pgentry_val(spl2e[i]) >> PAGE_SHIFT);
|
||||
{
|
||||
// First check to see if this guest page is currently the active
|
||||
// PTWR page. If so, then we compare the (old) cached copy of the
|
||||
// guest page to the shadow, and not the currently writable (and
|
||||
// thus potentially out-of-sync) guest page.
|
||||
//
|
||||
if ( ptwr_info[cpu].ptinfo[PTWR_PT_ACTIVE].l1va &&
|
||||
(i == ptwr_info[cpu].ptinfo[PTWR_PT_ACTIVE].l2_idx) &&
|
||||
likely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables)) )
|
||||
{
|
||||
gl1mfn = (__pa(ptwr_info[cpu].ptinfo[PTWR_PT_ACTIVE].page) >>
|
||||
PAGE_SHIFT);
|
||||
}
|
||||
|
||||
check_l1_table(d, gl1mfn, sl1mfn);
|
||||
}
|
||||
}
|
||||
|
||||
unmap_domain_mem(spl2e);
|
||||
unmap_domain_mem(gpl2e);
|
||||
|
||||
SH_VVLOG("PT verified : l2_present = %d, l1_present = %d\n",
|
||||
SH_VVLOG("PT verified : l2_present = %d, l1_present = %d",
|
||||
sh_l2_present, sh_l1_present);
|
||||
|
||||
return 1;
|
||||
if ( errors )
|
||||
BUG();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // SHADOW_DEBUG
|
||||
+10
-16
@@ -388,33 +388,27 @@ static int cpucount;
|
||||
void __init start_secondary(void)
|
||||
{
|
||||
unsigned int cpu = cpucount;
|
||||
/* 6 bytes suitable for passing to LIDT instruction. */
|
||||
unsigned char idt_load[6];
|
||||
|
||||
extern void percpu_traps_init(void);
|
||||
extern void cpu_init(void);
|
||||
|
||||
set_current(idle_task[cpu]);
|
||||
|
||||
/*
|
||||
* Dont put anything before smp_callin(), SMP
|
||||
* booting is too fragile that we want to limit the
|
||||
* things done here to the most necessary things.
|
||||
*/
|
||||
cpu_init();
|
||||
smp_callin();
|
||||
|
||||
while (!atomic_read(&smp_commenced))
|
||||
rep_nop();
|
||||
|
||||
/*
|
||||
* At this point, boot CPU has fully initialised the IDT. It is
|
||||
* now safe to make ourselves a private copy.
|
||||
*/
|
||||
idt_tables[cpu] = xmalloc_array(idt_entry_t, IDT_ENTRIES);
|
||||
memcpy(idt_tables[cpu], idt_table, IDT_ENTRIES*sizeof(idt_entry_t));
|
||||
*(unsigned short *)(&idt_load[0]) = (IDT_ENTRIES*sizeof(idt_entry_t))-1;
|
||||
*(unsigned long *)(&idt_load[2]) = (unsigned long)idt_tables[cpu];
|
||||
__asm__ __volatile__ ( "lidt %0" : "=m" (idt_load) );
|
||||
|
||||
percpu_traps_init();
|
||||
|
||||
cpu_init();
|
||||
|
||||
smp_callin();
|
||||
|
||||
while (!atomic_read(&smp_commenced))
|
||||
rep_nop();
|
||||
|
||||
/*
|
||||
* low-memory mappings have been cleared, flush them from the local TLBs
|
||||
|
||||
+89
-38
@@ -149,6 +149,11 @@ static inline int do_trap(int trapnr, char *str,
|
||||
if ( !GUEST_FAULT(regs) )
|
||||
goto xen_fault;
|
||||
|
||||
#ifndef NDEBUG
|
||||
if ( (ed->arch.traps[trapnr].address == 0) && (ed->domain->id == 0) )
|
||||
goto xen_fault;
|
||||
#endif
|
||||
|
||||
ti = current->arch.traps + trapnr;
|
||||
tb->flags = TBF_EXCEPTION;
|
||||
tb->cs = ti->cs;
|
||||
@@ -267,6 +272,12 @@ asmlinkage int do_page_fault(struct xen_regs *regs)
|
||||
|
||||
perfc_incrc(page_faults);
|
||||
|
||||
#if 0
|
||||
printk("do_page_fault(addr=0x%08lx, error_code=%d)\n",
|
||||
addr, regs->error_code);
|
||||
show_registers(regs);
|
||||
#endif
|
||||
|
||||
if ( likely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables)) )
|
||||
{
|
||||
LOCK_BIGLOCK(d);
|
||||
@@ -314,6 +325,11 @@ asmlinkage int do_page_fault(struct xen_regs *regs)
|
||||
if ( !GUEST_FAULT(regs) )
|
||||
goto xen_fault;
|
||||
|
||||
#ifndef NDEBUG
|
||||
if ( (ed->arch.traps[TRAP_page_fault].address == 0) && (d->id == 0) )
|
||||
goto xen_fault;
|
||||
#endif
|
||||
|
||||
propagate_page_fault(addr, regs->error_code);
|
||||
return 0;
|
||||
|
||||
@@ -512,7 +528,7 @@ asmlinkage int do_general_protection(struct xen_regs *regs)
|
||||
|
||||
/* Emulate some simple privileged instructions when exec'ed in ring 1. */
|
||||
if ( (regs->error_code == 0) &&
|
||||
RING_1(regs) &&
|
||||
GUESTOS_FAULT(regs) &&
|
||||
emulate_privileged_op(regs) )
|
||||
return 0;
|
||||
|
||||
@@ -523,6 +539,12 @@ asmlinkage int do_general_protection(struct xen_regs *regs)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
if ( (ed->arch.traps[TRAP_gp_fault].address == 0) &&
|
||||
(ed->domain->id == 0) )
|
||||
goto gp_in_kernel;
|
||||
#endif
|
||||
|
||||
/* Pass on GPF as is. */
|
||||
ti = current->arch.traps + 13;
|
||||
tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
|
||||
@@ -553,19 +575,55 @@ asmlinkage int do_general_protection(struct xen_regs *regs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long nmi_softirq_reason;
|
||||
static void nmi_softirq(void)
|
||||
{
|
||||
if ( dom0 == NULL )
|
||||
return;
|
||||
|
||||
if ( test_and_clear_bit(0, &nmi_softirq_reason) )
|
||||
send_guest_virq(dom0->exec_domain[0], VIRQ_PARITY_ERR);
|
||||
|
||||
if ( test_and_clear_bit(1, &nmi_softirq_reason) )
|
||||
send_guest_virq(dom0->exec_domain[0], VIRQ_IO_ERR);
|
||||
}
|
||||
|
||||
asmlinkage void mem_parity_error(struct xen_regs *regs)
|
||||
{
|
||||
console_force_unlock();
|
||||
printk("\n\nNMI - MEMORY ERROR\n");
|
||||
fatal_trap(TRAP_nmi, regs);
|
||||
/* Clear and disable the parity-error line. */
|
||||
outb((inb(0x61)&15)|4,0x61);
|
||||
|
||||
switch ( opt_nmi[0] )
|
||||
{
|
||||
case 'd': /* 'dom0' */
|
||||
set_bit(0, &nmi_softirq_reason);
|
||||
raise_softirq(NMI_SOFTIRQ);
|
||||
case 'i': /* 'ignore' */
|
||||
break;
|
||||
default: /* 'fatal' */
|
||||
console_force_unlock();
|
||||
printk("\n\nNMI - MEMORY ERROR\n");
|
||||
fatal_trap(TRAP_nmi, regs);
|
||||
}
|
||||
}
|
||||
|
||||
asmlinkage void io_check_error(struct xen_regs *regs)
|
||||
{
|
||||
console_force_unlock();
|
||||
/* Clear and disable the I/O-error line. */
|
||||
outb((inb(0x61)&15)|8,0x61);
|
||||
|
||||
printk("\n\nNMI - I/O ERROR\n");
|
||||
fatal_trap(TRAP_nmi, regs);
|
||||
switch ( opt_nmi[0] )
|
||||
{
|
||||
case 'd': /* 'dom0' */
|
||||
set_bit(0, &nmi_softirq_reason);
|
||||
raise_softirq(NMI_SOFTIRQ);
|
||||
case 'i': /* 'ignore' */
|
||||
break;
|
||||
default: /* 'fatal' */
|
||||
console_force_unlock();
|
||||
printk("\n\nNMI - I/O ERROR\n");
|
||||
fatal_trap(TRAP_nmi, regs);
|
||||
}
|
||||
}
|
||||
|
||||
static void unknown_nmi_error(unsigned char reason)
|
||||
@@ -579,27 +637,17 @@ asmlinkage void do_nmi(struct xen_regs *regs, unsigned long reason)
|
||||
{
|
||||
++nmi_count(smp_processor_id());
|
||||
|
||||
#if CONFIG_X86_LOCAL_APIC
|
||||
if ( nmi_watchdog )
|
||||
nmi_watchdog_tick(regs);
|
||||
else
|
||||
#endif
|
||||
|
||||
if ( reason & 0x80 )
|
||||
mem_parity_error(regs);
|
||||
else if ( reason & 0x40 )
|
||||
io_check_error(regs);
|
||||
else if ( !nmi_watchdog )
|
||||
unknown_nmi_error((unsigned char)(reason&0xff));
|
||||
}
|
||||
|
||||
unsigned long nmi_softirq_reason;
|
||||
static void nmi_softirq(void)
|
||||
{
|
||||
if ( dom0 == NULL )
|
||||
return;
|
||||
|
||||
if ( test_and_clear_bit(0, &nmi_softirq_reason) )
|
||||
send_guest_virq(dom0->exec_domain[0], VIRQ_PARITY_ERR);
|
||||
|
||||
if ( test_and_clear_bit(1, &nmi_softirq_reason) )
|
||||
send_guest_virq(dom0->exec_domain[0], VIRQ_IO_ERR);
|
||||
}
|
||||
|
||||
asmlinkage int math_state_restore(struct xen_regs *regs)
|
||||
{
|
||||
/* Prevent recursion. */
|
||||
@@ -706,8 +754,8 @@ void set_tss_desc(unsigned int n, void *addr)
|
||||
|
||||
void __init trap_init(void)
|
||||
{
|
||||
extern void doublefault_init(void);
|
||||
doublefault_init();
|
||||
extern void percpu_traps_init(void);
|
||||
extern void cpu_init(void);
|
||||
|
||||
/*
|
||||
* Note that interrupt gates are always used, rather than trap gates. We
|
||||
@@ -745,13 +793,9 @@ void __init trap_init(void)
|
||||
/* CPU0 uses the master IDT. */
|
||||
idt_tables[0] = idt_table;
|
||||
|
||||
/*
|
||||
* Should be a barrier for any external CPU state.
|
||||
*/
|
||||
{
|
||||
extern void cpu_init(void);
|
||||
cpu_init();
|
||||
}
|
||||
percpu_traps_init();
|
||||
|
||||
cpu_init();
|
||||
|
||||
open_softirq(NMI_SOFTIRQ, nmi_softirq);
|
||||
}
|
||||
@@ -769,8 +813,8 @@ long do_set_trap_table(trap_info_t *traps)
|
||||
if ( hypercall_preempt_check() )
|
||||
{
|
||||
UNLOCK_BIGLOCK(current->domain);
|
||||
return hypercall_create_continuation(
|
||||
__HYPERVISOR_set_trap_table, 1, traps);
|
||||
return hypercall1_create_continuation(
|
||||
__HYPERVISOR_set_trap_table, traps);
|
||||
}
|
||||
|
||||
if ( copy_from_user(&cur, traps, sizeof(cur)) ) return -EFAULT;
|
||||
@@ -816,6 +860,13 @@ long do_fpu_taskswitch(void)
|
||||
}
|
||||
|
||||
|
||||
#if defined(__i386__)
|
||||
#define DB_VALID_ADDR(_a) \
|
||||
((_a) <= (PAGE_OFFSET - 4))
|
||||
#elif defined(__x86_64__)
|
||||
#define DB_VALID_ADDR(_a) \
|
||||
((_a) >= HYPERVISOR_VIRT_END) || ((_a) <= (HYPERVISOR_VIRT_START-8))
|
||||
#endif
|
||||
long set_debugreg(struct exec_domain *p, int reg, unsigned long value)
|
||||
{
|
||||
int i;
|
||||
@@ -823,22 +874,22 @@ long set_debugreg(struct exec_domain *p, int reg, unsigned long value)
|
||||
switch ( reg )
|
||||
{
|
||||
case 0:
|
||||
if ( value > (PAGE_OFFSET-4) ) return -EPERM;
|
||||
if ( !DB_VALID_ADDR(value) ) return -EPERM;
|
||||
if ( p == current )
|
||||
__asm__ ( "mov %0, %%db0" : : "r" (value) );
|
||||
break;
|
||||
case 1:
|
||||
if ( value > (PAGE_OFFSET-4) ) return -EPERM;
|
||||
if ( !DB_VALID_ADDR(value) ) return -EPERM;
|
||||
if ( p == current )
|
||||
__asm__ ( "mov %0, %%db1" : : "r" (value) );
|
||||
break;
|
||||
case 2:
|
||||
if ( value > (PAGE_OFFSET-4) ) return -EPERM;
|
||||
if ( !DB_VALID_ADDR(value) ) return -EPERM;
|
||||
if ( p == current )
|
||||
__asm__ ( "mov %0, %%db2" : : "r" (value) );
|
||||
break;
|
||||
case 3:
|
||||
if ( value > (PAGE_OFFSET-4) ) return -EPERM;
|
||||
if ( !DB_VALID_ADDR(value) ) return -EPERM;
|
||||
if ( p == current )
|
||||
__asm__ ( "mov %0, %%db3" : : "r" (value) );
|
||||
break;
|
||||
|
||||
+14
-8
@@ -36,6 +36,8 @@
|
||||
#include <asm/vmx_vmcs.h>
|
||||
#include <public/io/ioreq.h>
|
||||
|
||||
#ifdef CONFIG_VMX
|
||||
|
||||
int vmcs_size;
|
||||
unsigned int opt_vmx_debug_level;
|
||||
|
||||
@@ -123,13 +125,13 @@ static int vmx_do_page_fault(unsigned long va, unsigned long error_code)
|
||||
/*
|
||||
* Set up guest page directory cache to make linear_pt_table[] work.
|
||||
*/
|
||||
__guest_get_pl2e(ed, va, &gpde);
|
||||
__guest_get_l2e(ed, va, &gpde);
|
||||
if (!(gpde & _PAGE_PRESENT))
|
||||
return 0;
|
||||
|
||||
index = (va >> L2_PAGETABLE_SHIFT);
|
||||
if (!l2_pgentry_val(ed->arch.guest_pl2e_cache[index])) {
|
||||
pfn = phys_to_machine_mapping[gpde >> PAGE_SHIFT];
|
||||
pfn = phys_to_machine_mapping(gpde >> PAGE_SHIFT);
|
||||
|
||||
VMX_DBG_LOG(DBG_LEVEL_VMMU, "vmx_do_page_fault: pagetable = %lx\n",
|
||||
pagetable_val(ed->arch.pagetable));
|
||||
@@ -301,10 +303,10 @@ inline unsigned long gva_to_gpa(unsigned long gva)
|
||||
unsigned long gpde, gpte, pfn, index;
|
||||
struct exec_domain *ed = current;
|
||||
|
||||
__guest_get_pl2e(ed, gva, &gpde);
|
||||
__guest_get_l2e(ed, gva, &gpde);
|
||||
index = (gva >> L2_PAGETABLE_SHIFT);
|
||||
|
||||
pfn = phys_to_machine_mapping[gpde >> PAGE_SHIFT];
|
||||
pfn = phys_to_machine_mapping(gpde >> PAGE_SHIFT);
|
||||
|
||||
ed->arch.guest_pl2e_cache[index] =
|
||||
mk_l2_pgentry((pfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
|
||||
@@ -451,8 +453,8 @@ static void mov_to_cr(int gp, int cr, struct xen_regs *regs)
|
||||
/*
|
||||
* The guest CR3 must be pointing to the guest physical.
|
||||
*/
|
||||
if (!(pfn = phys_to_machine_mapping[
|
||||
d->arch.arch_vmx.cpu_cr3 >> PAGE_SHIFT]))
|
||||
if (!(pfn = phys_to_machine_mapping(
|
||||
d->arch.arch_vmx.cpu_cr3 >> PAGE_SHIFT)))
|
||||
{
|
||||
VMX_DBG_LOG(DBG_LEVEL_VMMU, "Invalid CR3 value = %lx\n",
|
||||
d->arch.arch_vmx.cpu_cr3);
|
||||
@@ -504,7 +506,7 @@ static void mov_to_cr(int gp, int cr, struct xen_regs *regs)
|
||||
* removed some translation or changed page attributes.
|
||||
* We simply invalidate the shadow.
|
||||
*/
|
||||
pfn = phys_to_machine_mapping[value >> PAGE_SHIFT];
|
||||
pfn = phys_to_machine_mapping(value >> PAGE_SHIFT);
|
||||
if ((pfn << PAGE_SHIFT) != pagetable_val(d->arch.pagetable))
|
||||
__vmx_bug(regs);
|
||||
vmx_shadow_clear_state(d->domain);
|
||||
@@ -521,7 +523,7 @@ static void mov_to_cr(int gp, int cr, struct xen_regs *regs)
|
||||
"Invalid CR3 value=%lx\n", value);
|
||||
domain_crash(); /* need to take a clean path */
|
||||
}
|
||||
pfn = phys_to_machine_mapping[value >> PAGE_SHIFT];
|
||||
pfn = phys_to_machine_mapping(value >> PAGE_SHIFT);
|
||||
vmx_shadow_clear_state(d->domain);
|
||||
d->arch.pagetable = mk_pagetable(pfn << PAGE_SHIFT);
|
||||
shadow_mk_pagetable(d);
|
||||
@@ -927,6 +929,8 @@ asmlinkage void vmx_vmexit_handler(struct xen_regs regs)
|
||||
default:
|
||||
__vmx_bug(®s); /* should not happen */
|
||||
}
|
||||
|
||||
vmx_intr_assist(d);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -937,3 +941,5 @@ asmlinkage void load_cr2(void)
|
||||
local_irq_disable();
|
||||
asm volatile("movl %0,%%cr2": :"r" (d->arch.arch_vmx.cpu_cr2));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_VMX */
|
||||
@@ -32,6 +32,8 @@
|
||||
#include <public/io/ioreq.h>
|
||||
#include <asm/vmx_platform.h>
|
||||
|
||||
#ifdef CONFIG_VMX
|
||||
|
||||
extern long do_block();
|
||||
|
||||
#if defined (__i386__)
|
||||
@@ -386,3 +388,5 @@ void vmx_do_resume(struct exec_domain *d)
|
||||
if (!test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags))
|
||||
vmx_intr_assist(d);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_VMX */
|
||||
@@ -34,6 +34,8 @@
|
||||
#include <xen/sched.h>
|
||||
#include <asm/current.h>
|
||||
|
||||
#ifdef CONFIG_VMX
|
||||
|
||||
#define DECODE_success 1
|
||||
#define DECODE_failure 0
|
||||
|
||||
@@ -369,7 +371,7 @@ static int inst_copy_from_guest(char *buf, unsigned long guest_eip, int inst_len
|
||||
printk("inst_copy_from_guest- EXIT: read gpte faulted" );
|
||||
return 0;
|
||||
}
|
||||
mfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT];
|
||||
mfn = phys_to_machine_mapping(gpte >> PAGE_SHIFT);
|
||||
ma = (mfn << PAGE_SHIFT) | (guest_eip & (PAGE_SIZE - 1));
|
||||
inst_start = (unsigned char *)map_domain_mem(ma);
|
||||
|
||||
@@ -553,3 +555,4 @@ void handle_mmio(unsigned long va, unsigned long gpte, unsigned long gpa)
|
||||
domain_crash();
|
||||
}
|
||||
|
||||
#endif /* CONFIG_VMX */
|
||||
+8
-38
@@ -33,6 +33,8 @@
|
||||
#include <public/io/ioreq.h>
|
||||
#include <asm/domain_page.h>
|
||||
|
||||
#ifdef CONFIG_VMX
|
||||
|
||||
struct vmcs_struct *alloc_vmcs(void)
|
||||
{
|
||||
struct vmcs_struct *vmcs;
|
||||
@@ -118,7 +120,7 @@ int vmx_setup_platform(struct exec_domain *d, execution_context_t *context)
|
||||
addr = context->edi;
|
||||
offset = (addr & ~PAGE_MASK);
|
||||
addr = round_pgdown(addr);
|
||||
mpfn = phys_to_machine_mapping[addr >> PAGE_SHIFT];
|
||||
mpfn = phys_to_machine_mapping(addr >> PAGE_SHIFT);
|
||||
p = map_domain_mem(mpfn << PAGE_SHIFT);
|
||||
|
||||
e820p = (struct e820entry *) ((unsigned long) p + offset);
|
||||
@@ -131,52 +133,20 @@ int vmx_setup_platform(struct exec_domain *d, execution_context_t *context)
|
||||
}
|
||||
|
||||
if (gpfn == 0) {
|
||||
VMX_DBG_LOG(DBG_LEVEL_1, "No shared Page ?\n");
|
||||
printk("No shared Page ?\n");
|
||||
unmap_domain_mem(p);
|
||||
return -1;
|
||||
}
|
||||
unmap_domain_mem(p);
|
||||
|
||||
mpfn = phys_to_machine_mapping[gpfn];
|
||||
mpfn = phys_to_machine_mapping(gpfn);
|
||||
p = map_domain_mem(mpfn << PAGE_SHIFT);
|
||||
ASSERT(p != NULL);
|
||||
d->arch.arch_vmx.vmx_platform.shared_page_va = (unsigned long) p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add <guest pfn, machine pfn> mapping to per-domain mapping. Full
|
||||
* virtualization does not need per-domain mapping.
|
||||
*/
|
||||
static int add_mapping_perdomain(struct exec_domain *d, unsigned long gpfn,
|
||||
unsigned long mpfn)
|
||||
{
|
||||
struct pfn_info *page;
|
||||
unsigned long pfn = 0;
|
||||
|
||||
/*
|
||||
* We support up to 4GB memory for a guest at this point
|
||||
*/
|
||||
if (gpfn > ENTRIES_PER_L2_PAGETABLE * ENTRIES_PER_L1_PAGETABLE)
|
||||
return -1;
|
||||
|
||||
if (!(l1_pgentry_val(d->domain->arch.mm_perdomain_pt[
|
||||
gpfn >> (L2_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT)]) & _PAGE_PRESENT))
|
||||
{
|
||||
page = (struct pfn_info *) alloc_domheap_page(NULL);
|
||||
if (!page) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pfn = (unsigned long) (page - frame_table);
|
||||
d->domain->arch.mm_perdomain_pt[gpfn >> (L2_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT)] =
|
||||
mk_l1_pgentry((pfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
|
||||
}
|
||||
phys_to_machine_mapping[gpfn] = mpfn;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vmx_do_launch(struct exec_domain *ed)
|
||||
{
|
||||
/* Update CR3, GDT, LDT, TR */
|
||||
@@ -204,7 +174,6 @@ void vmx_do_launch(struct exec_domain *ed)
|
||||
d->arch.min_pfn = min(d->arch.min_pfn, pfn);
|
||||
d->arch.max_pfn = max(d->arch.max_pfn, pfn);
|
||||
list_ent = frame_table[pfn].list.next;
|
||||
add_mapping_perdomain(ed, i, pfn);
|
||||
}
|
||||
|
||||
spin_unlock(&d->page_alloc_lock);
|
||||
@@ -502,3 +471,4 @@ void vm_resume_fail(unsigned long eflags)
|
||||
BUG();
|
||||
}
|
||||
|
||||
#endif /* CONFIG_VMX */
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <xen/event.h>
|
||||
#include <xen/elf.h>
|
||||
#include <xen/kernel.h>
|
||||
#include <asm/shadow.h>
|
||||
|
||||
/* No ring-3 access in initial page tables. */
|
||||
#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
|
||||
@@ -261,7 +262,7 @@ int construct_dom0(struct domain *d,
|
||||
for ( count = 0; count < nr_pt_pages; count++ )
|
||||
{
|
||||
*l1tab = mk_l1_pgentry(l1_pgentry_val(*l1tab) & ~_PAGE_RW);
|
||||
page = &frame_table[l1_pgentry_to_pagenr(*l1tab)];
|
||||
page = &frame_table[l1_pgentry_to_pfn(*l1tab)];
|
||||
if ( count == 0 )
|
||||
{
|
||||
page->u.inuse.type_info &= ~PGT_type_mask;
|
||||
@@ -377,10 +378,13 @@ int construct_dom0(struct domain *d,
|
||||
|
||||
new_thread(ed, dsi.v_kernentry, vstack_end, vstartinfo_start);
|
||||
|
||||
#if 0 /* XXXXX DO NOT CHECK IN ENABLED !!! (but useful for testing so leave) */
|
||||
shadow_lock(&d->mm);
|
||||
shadow_mode_enable(d, SHM_test);
|
||||
shadow_unlock(&d->mm);
|
||||
#ifndef NDEBUG
|
||||
if (0) /* XXXXX DO NOT CHECK IN ENABLED !!! (but useful for testing so leave) */
|
||||
{
|
||||
shadow_lock(d);
|
||||
shadow_mode_enable(d, SHM_test);
|
||||
shadow_unlock(d);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -596,7 +596,7 @@ ENTRY(nmi)
|
||||
# Okay, its almost a normal NMI tick. We can only process it if:
|
||||
# A. We are the outermost Xen activation (in which case we have
|
||||
# the selectors safely saved on our stack)
|
||||
# B. DS-GS all contain sane Xen values.
|
||||
# B. DS and ES contain sane Xen values.
|
||||
# In all other cases we bail without touching DS-GS, as we have
|
||||
# interrupted an enclosing Xen activation in tricky prologue or
|
||||
# epilogue code.
|
||||
@@ -644,11 +644,11 @@ nmi_parity_err:
|
||||
orb $0x4,%al
|
||||
outb %al,$0x61
|
||||
cmpb $'i',%ss:SYMBOL_NAME(opt_nmi) # nmi=ignore
|
||||
je restore_all_xen
|
||||
je nmi_out
|
||||
bts $0,%ss:SYMBOL_NAME(nmi_softirq_reason)
|
||||
bts $NMI_SOFTIRQ,%ss:SYMBOL_NAME(irq_stat)
|
||||
cmpb $'d',%ss:SYMBOL_NAME(opt_nmi) # nmi=dom0
|
||||
je restore_all_xen
|
||||
je nmi_out
|
||||
movl $(__HYPERVISOR_DS),%edx # nmi=fatal
|
||||
movl %edx,%ds
|
||||
movl %edx,%es
|
||||
@@ -656,7 +656,15 @@ nmi_parity_err:
|
||||
push %edx
|
||||
call SYMBOL_NAME(mem_parity_error)
|
||||
addl $4,%esp
|
||||
jmp ret_from_intr
|
||||
nmi_out:movl %ss:XREGS_eflags(%esp),%eax
|
||||
movb %ss:XREGS_cs(%esp),%al
|
||||
testl $(3|X86_EFLAGS_VM),%eax
|
||||
jz restore_all_xen
|
||||
movl $(__HYPERVISOR_DS),%edx
|
||||
movl %edx,%ds
|
||||
movl %edx,%es
|
||||
GET_CURRENT(%ebx)
|
||||
jmp test_all_events
|
||||
|
||||
nmi_io_err:
|
||||
# Clear and disable the I/O-error line
|
||||
@@ -664,11 +672,11 @@ nmi_io_err:
|
||||
orb $0x8,%al
|
||||
outb %al,$0x61
|
||||
cmpb $'i',%ss:SYMBOL_NAME(opt_nmi) # nmi=ignore
|
||||
je restore_all_xen
|
||||
je nmi_out
|
||||
bts $1,%ss:SYMBOL_NAME(nmi_softirq_reason)
|
||||
bts $NMI_SOFTIRQ,%ss:SYMBOL_NAME(irq_stat)
|
||||
cmpb $'d',%ss:SYMBOL_NAME(opt_nmi) # nmi=dom0
|
||||
je restore_all_xen
|
||||
je nmi_out
|
||||
movl $(__HYPERVISOR_DS),%edx # nmi=fatal
|
||||
movl %edx,%ds
|
||||
movl %edx,%es
|
||||
@@ -676,7 +684,7 @@ nmi_io_err:
|
||||
push %edx
|
||||
call SYMBOL_NAME(io_check_error)
|
||||
addl $4,%esp
|
||||
jmp ret_from_intr
|
||||
jmp nmi_out
|
||||
|
||||
|
||||
ENTRY(setup_vm86_frame)
|
||||
|
||||
+6
-174
@@ -164,7 +164,7 @@ void subarch_init_memory(struct domain *dom_xen)
|
||||
}
|
||||
|
||||
/* M2P table is mappable read-only by privileged domains. */
|
||||
m2p_start_mfn = l2_pgentry_to_pagenr(
|
||||
m2p_start_mfn = l2_pgentry_to_pfn(
|
||||
idle_pg_table[l2_table_offset(RDWR_MPT_VIRT_START)]);
|
||||
for ( i = 0; i < 1024; i++ )
|
||||
{
|
||||
@@ -212,9 +212,10 @@ long do_stack_switch(unsigned long ss, unsigned long esp)
|
||||
|
||||
|
||||
/* Returns TRUE if given descriptor is valid for GDT or LDT. */
|
||||
int check_descriptor(unsigned long *d)
|
||||
int check_descriptor(struct desc_struct *d)
|
||||
{
|
||||
unsigned long base, limit, a = d[0], b = d[1];
|
||||
unsigned long base, limit;
|
||||
u32 a = d->a, b = d->b;
|
||||
|
||||
/* A not-present descriptor will always fault, so is safe. */
|
||||
if ( !(b & _SEGMENT_P) )
|
||||
@@ -298,8 +299,8 @@ int check_descriptor(unsigned long *d)
|
||||
if ( !(b & _SEGMENT_G) )
|
||||
goto bad; /* too dangerous; too hard to work out... */
|
||||
limit = (limit >> 12) - 1;
|
||||
d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff;
|
||||
d[1] &= ~0xf0000; d[1] |= limit & 0xf0000;
|
||||
d->a &= ~0x0ffff; d->a |= limit & 0x0ffff;
|
||||
d->b &= ~0xf0000; d->b |= limit & 0xf0000;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,175 +311,6 @@ int check_descriptor(unsigned long *d)
|
||||
}
|
||||
|
||||
|
||||
void destroy_gdt(struct exec_domain *ed)
|
||||
{
|
||||
int i;
|
||||
unsigned long pfn;
|
||||
|
||||
for ( i = 0; i < 16; i++ )
|
||||
{
|
||||
if ( (pfn = l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i])) != 0 )
|
||||
put_page_and_type(&frame_table[pfn]);
|
||||
ed->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
long set_gdt(struct exec_domain *ed,
|
||||
unsigned long *frames,
|
||||
unsigned int entries)
|
||||
{
|
||||
struct domain *d = ed->domain;
|
||||
/* NB. There are 512 8-byte entries per GDT page. */
|
||||
int i = 0, nr_pages = (entries + 511) / 512;
|
||||
struct desc_struct *vgdt;
|
||||
unsigned long pfn;
|
||||
|
||||
/* Check the first page in the new GDT. */
|
||||
if ( (pfn = frames[0]) >= max_page )
|
||||
goto fail;
|
||||
|
||||
/* The first page is special because Xen owns a range of entries in it. */
|
||||
if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
|
||||
{
|
||||
/* GDT checks failed: try zapping the Xen reserved entries. */
|
||||
if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
|
||||
goto fail;
|
||||
vgdt = map_domain_mem(pfn << PAGE_SHIFT);
|
||||
memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
|
||||
NR_RESERVED_GDT_ENTRIES*8);
|
||||
unmap_domain_mem(vgdt);
|
||||
put_page_and_type(&frame_table[pfn]);
|
||||
|
||||
/* Okay, we zapped the entries. Now try the GDT checks again. */
|
||||
if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check the remaining pages in the new GDT. */
|
||||
for ( i = 1; i < nr_pages; i++ )
|
||||
if ( ((pfn = frames[i]) >= max_page) ||
|
||||
!get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
|
||||
goto fail;
|
||||
|
||||
/* Copy reserved GDT entries to the new GDT. */
|
||||
vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
|
||||
memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY,
|
||||
gdt_table + FIRST_RESERVED_GDT_ENTRY,
|
||||
NR_RESERVED_GDT_ENTRIES*8);
|
||||
unmap_domain_mem(vgdt);
|
||||
|
||||
/* Tear down the old GDT. */
|
||||
destroy_gdt(ed);
|
||||
|
||||
/* Install the new GDT. */
|
||||
for ( i = 0; i < nr_pages; i++ )
|
||||
ed->arch.perdomain_ptes[i] =
|
||||
mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
|
||||
|
||||
SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
|
||||
SET_GDT_ENTRIES(ed, entries);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
while ( i-- > 0 )
|
||||
put_page_and_type(&frame_table[frames[i]]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
long do_set_gdt(unsigned long *frame_list, unsigned int entries)
|
||||
{
|
||||
int nr_pages = (entries + 511) / 512;
|
||||
unsigned long frames[16];
|
||||
long ret;
|
||||
|
||||
if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) )
|
||||
return -EINVAL;
|
||||
|
||||
if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
|
||||
return -EFAULT;
|
||||
|
||||
LOCK_BIGLOCK(current->domain);
|
||||
|
||||
if ( (ret = set_gdt(current, frames, entries)) == 0 )
|
||||
{
|
||||
local_flush_tlb();
|
||||
__asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
|
||||
}
|
||||
|
||||
UNLOCK_BIGLOCK(current->domain);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
long do_update_descriptor(
|
||||
unsigned long pa, unsigned long word1, unsigned long word2)
|
||||
{
|
||||
unsigned long *gdt_pent, pfn = pa >> PAGE_SHIFT, d[2];
|
||||
struct pfn_info *page;
|
||||
struct exec_domain *ed;
|
||||
long ret = -EINVAL;
|
||||
|
||||
d[0] = word1;
|
||||
d[1] = word2;
|
||||
|
||||
LOCK_BIGLOCK(current->domain);
|
||||
|
||||
if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(d) ) {
|
||||
UNLOCK_BIGLOCK(current->domain);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
page = &frame_table[pfn];
|
||||
if ( unlikely(!get_page(page, current->domain)) ) {
|
||||
UNLOCK_BIGLOCK(current->domain);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if the given frame is in use in an unsafe context. */
|
||||
switch ( page->u.inuse.type_info & PGT_type_mask )
|
||||
{
|
||||
case PGT_gdt_page:
|
||||
/* Disallow updates of Xen-reserved descriptors in the current GDT. */
|
||||
for_each_exec_domain(current->domain, ed) {
|
||||
if ( (l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[0]) == pfn) &&
|
||||
(((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
|
||||
(((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
|
||||
goto out;
|
||||
}
|
||||
if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
|
||||
goto out;
|
||||
break;
|
||||
case PGT_ldt_page:
|
||||
if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
|
||||
goto out;
|
||||
break;
|
||||
default:
|
||||
if ( unlikely(!get_page_type(page, PGT_writable_page)) )
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
|
||||
/* All is good so make the update. */
|
||||
gdt_pent = map_domain_mem(pa);
|
||||
memcpy(gdt_pent, d, 8);
|
||||
unmap_domain_mem(gdt_pent);
|
||||
|
||||
put_page_type(page);
|
||||
|
||||
ret = 0; /* success */
|
||||
|
||||
out:
|
||||
put_page(page);
|
||||
|
||||
UNLOCK_BIGLOCK(current->domain);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef MEMORY_GUARD
|
||||
|
||||
void *memguard_init(void *heap_start)
|
||||
|
||||
+25
-24
@@ -7,6 +7,7 @@
|
||||
#include <xen/console.h>
|
||||
#include <xen/mm.h>
|
||||
#include <xen/irq.h>
|
||||
#include <asm/flushtlb.h>
|
||||
|
||||
static int kstack_depth_to_print = 8*20;
|
||||
|
||||
@@ -114,6 +115,7 @@ void show_registers(struct xen_regs *regs)
|
||||
regs->esi, regs->edi, regs->ebp, esp);
|
||||
printk("ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n",
|
||||
ds, es, fs, gs, ss);
|
||||
printk("cr3: %08lx\n", read_cr3());
|
||||
|
||||
show_stack((unsigned long *)®s->esp);
|
||||
}
|
||||
@@ -175,32 +177,31 @@ asmlinkage void do_double_fault(void)
|
||||
__asm__ __volatile__ ( "hlt" );
|
||||
}
|
||||
|
||||
void __init doublefault_init(void)
|
||||
{
|
||||
/*
|
||||
* Make a separate task for double faults. This will get us debug output if
|
||||
* we blow the kernel stack.
|
||||
*/
|
||||
struct tss_struct *tss = &doublefault_tss;
|
||||
memset(tss, 0, sizeof(*tss));
|
||||
tss->ds = __HYPERVISOR_DS;
|
||||
tss->es = __HYPERVISOR_DS;
|
||||
tss->ss = __HYPERVISOR_DS;
|
||||
tss->esp = (unsigned long)
|
||||
&doublefault_stack[DOUBLEFAULT_STACK_SIZE];
|
||||
tss->__cr3 = __pa(idle_pg_table);
|
||||
tss->cs = __HYPERVISOR_CS;
|
||||
tss->eip = (unsigned long)do_double_fault;
|
||||
tss->eflags = 2;
|
||||
tss->bitmap = IOBMP_INVALID_OFFSET;
|
||||
_set_tssldt_desc(gdt_table+__DOUBLEFAULT_TSS_ENTRY,
|
||||
(unsigned long)tss, 235, 9);
|
||||
|
||||
set_task_gate(TRAP_double_fault, __DOUBLEFAULT_TSS_ENTRY<<3);
|
||||
}
|
||||
|
||||
void __init percpu_traps_init(void)
|
||||
{
|
||||
if ( smp_processor_id() == 0 )
|
||||
{
|
||||
/*
|
||||
* Make a separate task for double faults. This will get us debug
|
||||
* output if we blow the kernel stack.
|
||||
*/
|
||||
struct tss_struct *tss = &doublefault_tss;
|
||||
memset(tss, 0, sizeof(*tss));
|
||||
tss->ds = __HYPERVISOR_DS;
|
||||
tss->es = __HYPERVISOR_DS;
|
||||
tss->ss = __HYPERVISOR_DS;
|
||||
tss->esp = (unsigned long)
|
||||
&doublefault_stack[DOUBLEFAULT_STACK_SIZE];
|
||||
tss->__cr3 = __pa(idle_pg_table);
|
||||
tss->cs = __HYPERVISOR_CS;
|
||||
tss->eip = (unsigned long)do_double_fault;
|
||||
tss->eflags = 2;
|
||||
tss->bitmap = IOBMP_INVALID_OFFSET;
|
||||
_set_tssldt_desc(gdt_table+__DOUBLEFAULT_TSS_ENTRY,
|
||||
(unsigned long)tss, 235, 9);
|
||||
}
|
||||
|
||||
set_task_gate(TRAP_double_fault, __DOUBLEFAULT_TSS_ENTRY<<3);
|
||||
}
|
||||
|
||||
long set_fast_trap(struct exec_domain *p, int idx)
|
||||
|
||||
@@ -294,7 +294,7 @@ int construct_dom0(struct domain *d,
|
||||
for ( count = 0; count < nr_pt_pages; count++ )
|
||||
{
|
||||
*l1tab = mk_l1_pgentry(l1_pgentry_val(*l1tab) & ~_PAGE_RW);
|
||||
page = &frame_table[l1_pgentry_to_pagenr(*l1tab)];
|
||||
page = &frame_table[l1_pgentry_to_pfn(*l1tab)];
|
||||
|
||||
/* Read-only mapping + PGC_allocated + page-table page. */
|
||||
page->count_info = PGC_allocated | 3;
|
||||
|
||||
@@ -11,16 +11,25 @@
|
||||
#include <asm/apicdef.h>
|
||||
#include <public/xen.h>
|
||||
|
||||
|
||||
/*
|
||||
* %rax = hypercall vector
|
||||
* %rdi, %rsi, %rdx, %r10, %r8, %9 = hypercall arguments
|
||||
* %r11, %rcx = SYSCALL-saved %rflags and %rip
|
||||
* NB. We must move %r10 to %rcx for C function-calling ABI.
|
||||
*/
|
||||
ENTRY(hypercall)
|
||||
movl $0x0833,8(%rsp)
|
||||
sti
|
||||
movl $__GUEST_SS,8(%rsp)
|
||||
pushq %r11
|
||||
pushq $0x082b
|
||||
pushq $__GUEST_CS
|
||||
pushq %rcx
|
||||
pushq $0
|
||||
SAVE_ALL
|
||||
andq $(NR_hypercalls-1),%rax
|
||||
leaq SYMBOL_NAME(exception_table)(%rip),%rcx
|
||||
callq *(%rcx,%rax,8)
|
||||
movq %r10,%rcx
|
||||
andq $(NR_hypercalls-1),%rax
|
||||
leaq SYMBOL_NAME(hypercall_table)(%rip),%rbx
|
||||
callq *(%rbx,%rax,8)
|
||||
RESTORE_ALL
|
||||
addq $8,%rsp
|
||||
popq %rcx
|
||||
@@ -38,11 +47,12 @@ restore_all_xen:
|
||||
|
||||
error_code:
|
||||
SAVE_ALL
|
||||
sti
|
||||
movq %rsp,%rdi
|
||||
movl XREGS_entry_vector(%rsp),%eax
|
||||
leaq SYMBOL_NAME(exception_table)(%rip),%rdx
|
||||
callq *(%rdx,%rax,8)
|
||||
jmp restore_all_xen
|
||||
jmp restore_all_xen
|
||||
|
||||
ENTRY(divide_error)
|
||||
pushq $0
|
||||
@@ -133,7 +143,13 @@ ENTRY(double_fault)
|
||||
jmp error_code
|
||||
|
||||
ENTRY(nmi)
|
||||
iretq
|
||||
pushq $0
|
||||
SAVE_ALL
|
||||
inb $0x61,%al
|
||||
movl %eax,%esi # reason
|
||||
movq %rsp,%rdi # regs
|
||||
call SYMBOL_NAME(do_nmi)
|
||||
jmp restore_all_xen
|
||||
|
||||
.data
|
||||
|
||||
|
||||
+21
-235
@@ -199,7 +199,7 @@ void subarch_init_memory(struct domain *dom_xen)
|
||||
l2e = l3_pgentry_to_l2(l3e)[l2_table_offset(v)];
|
||||
if ( !(l2_pgentry_val(l2e) & _PAGE_PRESENT) )
|
||||
continue;
|
||||
m2p_start_mfn = l2_pgentry_to_pagenr(l2e);
|
||||
m2p_start_mfn = l2_pgentry_to_pfn(l2e);
|
||||
|
||||
for ( i = 0; i < ENTRIES_PER_L1_PAGETABLE; i++ )
|
||||
{
|
||||
@@ -240,99 +240,38 @@ long do_stack_switch(unsigned long ss, unsigned long esp)
|
||||
|
||||
|
||||
/* Returns TRUE if given descriptor is valid for GDT or LDT. */
|
||||
int check_descriptor(unsigned long *d)
|
||||
int check_descriptor(struct desc_struct *d)
|
||||
{
|
||||
unsigned long base, limit, a = d[0], b = d[1];
|
||||
u32 a = d->a, b = d->b;
|
||||
|
||||
/* A not-present descriptor will always fault, so is safe. */
|
||||
if ( !(b & _SEGMENT_P) )
|
||||
goto good;
|
||||
|
||||
/*
|
||||
* We don't allow a DPL of zero. There is no legitimate reason for
|
||||
* specifying DPL==0, and it gets rather dangerous if we also accept call
|
||||
* gates (consider a call gate pointing at another guestos descriptor with
|
||||
* DPL 0 -- this would get the OS ring-0 privileges).
|
||||
*/
|
||||
if ( (b & _SEGMENT_DPL) == 0 )
|
||||
/* The guest can only safely be executed in ring 3. */
|
||||
if ( (b & _SEGMENT_DPL) != 3 )
|
||||
goto bad;
|
||||
|
||||
if ( !(b & _SEGMENT_S) )
|
||||
{
|
||||
/*
|
||||
* System segment:
|
||||
* 1. Don't allow interrupt or trap gates as they belong in the IDT.
|
||||
* 2. Don't allow TSS descriptors or task gates as we don't
|
||||
* virtualise x86 tasks.
|
||||
* 3. Don't allow LDT descriptors because they're unnecessary and
|
||||
* I'm uneasy about allowing an LDT page to contain LDT
|
||||
* descriptors. In any case, Xen automatically creates the
|
||||
* required descriptor when reloading the LDT register.
|
||||
* 4. We allow call gates but they must not jump to a private segment.
|
||||
*/
|
||||
|
||||
/* Disallow everything but call gates. */
|
||||
if ( (b & _SEGMENT_TYPE) != 0xc00 )
|
||||
goto bad;
|
||||
|
||||
#if 0
|
||||
/* Can't allow far jump to a Xen-private segment. */
|
||||
if ( !VALID_CODESEL(a>>16) )
|
||||
goto bad;
|
||||
#endif
|
||||
|
||||
/* Reserved bits must be zero. */
|
||||
if ( (b & 0xe0) != 0 )
|
||||
goto bad;
|
||||
|
||||
/* No base/limit check is needed for a call gate. */
|
||||
/* Any code or data segment is okay. No base/limit checking. */
|
||||
if ( (b & _SEGMENT_S) )
|
||||
goto good;
|
||||
}
|
||||
|
||||
/* Check that base is at least a page away from Xen-private area. */
|
||||
base = (b&(0xff<<24)) | ((b&0xff)<<16) | (a>>16);
|
||||
if ( base >= (PAGE_OFFSET - PAGE_SIZE) )
|
||||
|
||||
/* Invalid type 0 is harmless. It is used for 2nd half of a call gate. */
|
||||
if ( (b & _SEGMENT_TYPE) == 0x000 )
|
||||
goto good;
|
||||
|
||||
/* Everything but a call gate is discarded here. */
|
||||
if ( (b & _SEGMENT_TYPE) != 0xc00 )
|
||||
goto bad;
|
||||
|
||||
/* Check and truncate the limit if necessary. */
|
||||
limit = (b&0xf0000) | (a&0xffff);
|
||||
limit++; /* We add one because limit is inclusive. */
|
||||
if ( (b & _SEGMENT_G) )
|
||||
limit <<= 12;
|
||||
|
||||
if ( (b & (_SEGMENT_CODE | _SEGMENT_EC)) == _SEGMENT_EC )
|
||||
{
|
||||
/*
|
||||
* Grows-down limit check.
|
||||
* NB. limit == 0xFFFFF provides no access (if G=1).
|
||||
* limit == 0x00000 provides 4GB-4kB access (if G=1).
|
||||
*/
|
||||
if ( (base + limit) > base )
|
||||
{
|
||||
limit = -(base & PAGE_MASK);
|
||||
goto truncate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Grows-up limit check.
|
||||
* NB. limit == 0xFFFFF provides 4GB access (if G=1).
|
||||
* limit == 0x00000 provides 4kB access (if G=1).
|
||||
*/
|
||||
if ( ((base + limit) <= base) ||
|
||||
((base + limit) > PAGE_OFFSET) )
|
||||
{
|
||||
limit = PAGE_OFFSET - base;
|
||||
truncate:
|
||||
if ( !(b & _SEGMENT_G) )
|
||||
goto bad; /* too dangerous; too hard to work out... */
|
||||
limit = (limit >> 12) - 1;
|
||||
d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff;
|
||||
d[1] &= ~0xf0000; d[1] |= limit & 0xf0000;
|
||||
}
|
||||
}
|
||||
/* Can't allow far jump to a Xen-private segment. */
|
||||
if ( !VALID_CODESEL(a>>16) )
|
||||
goto bad;
|
||||
|
||||
/* Reserved bits must be zero. */
|
||||
if ( (b & 0xe0) != 0 )
|
||||
goto bad;
|
||||
|
||||
good:
|
||||
return 1;
|
||||
bad:
|
||||
@@ -340,159 +279,6 @@ int check_descriptor(unsigned long *d)
|
||||
}
|
||||
|
||||
|
||||
void destroy_gdt(struct exec_domain *ed)
|
||||
{
|
||||
int i;
|
||||
unsigned long pfn;
|
||||
|
||||
for ( i = 0; i < 16; i++ )
|
||||
{
|
||||
if ( (pfn = l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i])) != 0 )
|
||||
put_page_and_type(&frame_table[pfn]);
|
||||
ed->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
long set_gdt(struct exec_domain *ed,
|
||||
unsigned long *frames,
|
||||
unsigned int entries)
|
||||
{
|
||||
struct domain *d = ed->domain;
|
||||
/* NB. There are 512 8-byte entries per GDT page. */
|
||||
int i = 0, nr_pages = (entries + 511) / 512;
|
||||
struct desc_struct *vgdt;
|
||||
unsigned long pfn;
|
||||
|
||||
/* Check the first page in the new GDT. */
|
||||
if ( (pfn = frames[0]) >= max_page )
|
||||
goto fail;
|
||||
|
||||
/* The first page is special because Xen owns a range of entries in it. */
|
||||
if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
|
||||
{
|
||||
/* GDT checks failed: try zapping the Xen reserved entries. */
|
||||
if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
|
||||
goto fail;
|
||||
vgdt = map_domain_mem(pfn << PAGE_SHIFT);
|
||||
memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
|
||||
NR_RESERVED_GDT_ENTRIES*8);
|
||||
unmap_domain_mem(vgdt);
|
||||
put_page_and_type(&frame_table[pfn]);
|
||||
|
||||
/* Okay, we zapped the entries. Now try the GDT checks again. */
|
||||
if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check the remaining pages in the new GDT. */
|
||||
for ( i = 1; i < nr_pages; i++ )
|
||||
if ( ((pfn = frames[i]) >= max_page) ||
|
||||
!get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
|
||||
goto fail;
|
||||
|
||||
/* Copy reserved GDT entries to the new GDT. */
|
||||
vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
|
||||
memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY,
|
||||
gdt_table + FIRST_RESERVED_GDT_ENTRY,
|
||||
NR_RESERVED_GDT_ENTRIES*8);
|
||||
unmap_domain_mem(vgdt);
|
||||
|
||||
/* Tear down the old GDT. */
|
||||
destroy_gdt(ed);
|
||||
|
||||
/* Install the new GDT. */
|
||||
for ( i = 0; i < nr_pages; i++ )
|
||||
ed->arch.perdomain_ptes[i] =
|
||||
mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
|
||||
|
||||
SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
|
||||
SET_GDT_ENTRIES(ed, entries);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
while ( i-- > 0 )
|
||||
put_page_and_type(&frame_table[frames[i]]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
long do_set_gdt(unsigned long *frame_list, unsigned int entries)
|
||||
{
|
||||
int nr_pages = (entries + 511) / 512;
|
||||
unsigned long frames[16];
|
||||
long ret;
|
||||
|
||||
if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) )
|
||||
return -EINVAL;
|
||||
|
||||
if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
|
||||
return -EFAULT;
|
||||
|
||||
if ( (ret = set_gdt(current, frames, entries)) == 0 )
|
||||
{
|
||||
local_flush_tlb();
|
||||
__asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
long do_update_descriptor(
|
||||
unsigned long pa, unsigned long word1, unsigned long word2)
|
||||
{
|
||||
unsigned long *gdt_pent, pfn = pa >> PAGE_SHIFT, d[2];
|
||||
struct pfn_info *page;
|
||||
long ret = -EINVAL;
|
||||
|
||||
d[0] = word1;
|
||||
d[1] = word2;
|
||||
|
||||
if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(d) )
|
||||
return -EINVAL;
|
||||
|
||||
page = &frame_table[pfn];
|
||||
if ( unlikely(!get_page(page, current->domain)) )
|
||||
return -EINVAL;
|
||||
|
||||
/* Check if the given frame is in use in an unsafe context. */
|
||||
switch ( page->u.inuse.type_info & PGT_type_mask )
|
||||
{
|
||||
case PGT_gdt_page:
|
||||
/* Disallow updates of Xen-reserved descriptors in the current GDT. */
|
||||
if ( (l1_pgentry_to_pagenr(current->arch.perdomain_ptes[0]) == pfn) &&
|
||||
(((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
|
||||
(((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
|
||||
goto out;
|
||||
if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
|
||||
goto out;
|
||||
break;
|
||||
case PGT_ldt_page:
|
||||
if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
|
||||
goto out;
|
||||
break;
|
||||
default:
|
||||
if ( unlikely(!get_page_type(page, PGT_writable_page)) )
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
|
||||
/* All is good so make the update. */
|
||||
gdt_pent = map_domain_mem(pa);
|
||||
memcpy(gdt_pent, d, 8);
|
||||
unmap_domain_mem(gdt_pent);
|
||||
|
||||
put_page_type(page);
|
||||
|
||||
ret = 0; /* success */
|
||||
|
||||
out:
|
||||
put_page(page);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef MEMORY_GUARD
|
||||
|
||||
#define ALLOC_PT(_level) \
|
||||
|
||||
+50
-32
@@ -129,10 +129,7 @@ void show_page_walk(unsigned long addr)
|
||||
printk(" L1 = %p\n", page);
|
||||
}
|
||||
|
||||
#define DOUBLEFAULT_STACK_SIZE 1024
|
||||
static unsigned char doublefault_stack[DOUBLEFAULT_STACK_SIZE];
|
||||
asmlinkage void double_fault(void);
|
||||
|
||||
asmlinkage void do_double_fault(struct xen_regs *regs)
|
||||
{
|
||||
/* Disable the NMI watchdog. It's useless now. */
|
||||
@@ -142,19 +139,9 @@ asmlinkage void do_double_fault(struct xen_regs *regs)
|
||||
|
||||
/* Find information saved during fault and dump it to the console. */
|
||||
printk("************************************\n");
|
||||
printk("EIP: %04lx:[<%p>] \nEFLAGS: %p\n",
|
||||
0xffff & regs->cs, regs->rip, regs->eflags);
|
||||
printk("rax: %p rbx: %p rcx: %p rdx: %p\n",
|
||||
regs->rax, regs->rbx, regs->rcx, regs->rdx);
|
||||
printk("rsi: %p rdi: %p rbp: %p rsp: %p\n",
|
||||
regs->rsi, regs->rdi, regs->rbp, regs->rsp);
|
||||
printk("r8: %p r9: %p r10: %p r11: %p\n",
|
||||
regs->r8, regs->r9, regs->r10, regs->r11);
|
||||
printk("r12: %p r13: %p r14: %p r15: %p\n",
|
||||
regs->r12, regs->r13, regs->r14, regs->r15);
|
||||
show_registers(regs);
|
||||
printk("************************************\n");
|
||||
printk("CPU%d DOUBLE FAULT -- system shutdown\n",
|
||||
logical_smp_processor_id());
|
||||
printk("CPU%d DOUBLE FAULT -- system shutdown\n", smp_processor_id());
|
||||
printk("System needs manual reset.\n");
|
||||
printk("************************************\n");
|
||||
|
||||
@@ -166,25 +153,29 @@ asmlinkage void do_double_fault(struct xen_regs *regs)
|
||||
__asm__ __volatile__ ( "hlt" );
|
||||
}
|
||||
|
||||
void __init doublefault_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Initialise IST1 for each CPU. Note the handler is non-reentrant. */
|
||||
for ( i = 0; i < NR_CPUS; i++ )
|
||||
init_tss[i].ist[0] = (unsigned long)
|
||||
&doublefault_stack[DOUBLEFAULT_STACK_SIZE];
|
||||
|
||||
/* Set interrupt gate for double faults, specifying IST1. */
|
||||
set_intr_gate(TRAP_double_fault, &double_fault);
|
||||
idt_table[TRAP_double_fault].a |= 1UL << 32; /* IST1 */
|
||||
}
|
||||
|
||||
asmlinkage void hypercall(void);
|
||||
void __init percpu_traps_init(void)
|
||||
{
|
||||
char *stack_top = (char *)get_stack_top();
|
||||
char *stack = (char *)((unsigned long)stack_top & ~(STACK_SIZE - 1));
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
/* Double-fault handler has its own per-CPU 1kB stack. */
|
||||
init_tss[cpu].ist[0] = (unsigned long)&stack[1024];
|
||||
set_intr_gate(TRAP_double_fault, &double_fault);
|
||||
idt_tables[cpu][TRAP_double_fault].a |= 1UL << 32; /* IST1 */
|
||||
|
||||
/* NMI handler has its own per-CPU 1kB stack. */
|
||||
init_tss[cpu].ist[1] = (unsigned long)&stack[2048];
|
||||
idt_tables[cpu][TRAP_nmi].a |= 2UL << 32; /* IST2 */
|
||||
|
||||
/*
|
||||
* Trampoline for SYSCALL entry from long mode.
|
||||
*/
|
||||
|
||||
/* Skip the NMI and DF stacks. */
|
||||
stack = &stack[2048];
|
||||
wrmsr(MSR_LSTAR, (unsigned long)stack, ((unsigned long)stack>>32));
|
||||
|
||||
/* movq %rsp, saversp(%rip) */
|
||||
stack[0] = 0x48;
|
||||
@@ -202,9 +193,36 @@ void __init percpu_traps_init(void)
|
||||
stack[14] = 0xe9;
|
||||
*(u32 *)&stack[15] = (char *)hypercall - &stack[19];
|
||||
|
||||
wrmsr(MSR_STAR, 0, (FLAT_RING3_CS64<<16) | __HYPERVISOR_CS);
|
||||
wrmsr(MSR_LSTAR, (unsigned long)stack, ((unsigned long)stack>>32));
|
||||
wrmsr(MSR_SYSCALL_MASK, 0xFFFFFFFFU, 0U);
|
||||
/*
|
||||
* Trampoline for SYSCALL entry from compatibility mode.
|
||||
*/
|
||||
|
||||
/* Skip the long-mode entry trampoline. */
|
||||
stack = &stack[19];
|
||||
wrmsr(MSR_CSTAR, (unsigned long)stack, ((unsigned long)stack>>32));
|
||||
|
||||
/* movq %rsp, saversp(%rip) */
|
||||
stack[0] = 0x48;
|
||||
stack[1] = 0x89;
|
||||
stack[2] = 0x25;
|
||||
*(u32 *)&stack[3] = (stack_top - &stack[7]) - 16;
|
||||
|
||||
/* leaq saversp(%rip), %rsp */
|
||||
stack[7] = 0x48;
|
||||
stack[8] = 0x8d;
|
||||
stack[9] = 0x25;
|
||||
*(u32 *)&stack[10] = (stack_top - &stack[14]) - 16;
|
||||
|
||||
/* jmp hypercall */
|
||||
stack[14] = 0xe9;
|
||||
*(u32 *)&stack[15] = (char *)hypercall - &stack[19];
|
||||
|
||||
/*
|
||||
* Common SYSCALL parameters.
|
||||
*/
|
||||
|
||||
wrmsr(MSR_STAR, 0, (FLAT_RING3_CS32<<16) | __HYPERVISOR_CS);
|
||||
wrmsr(MSR_SYSCALL_MASK, ~EF_IE, 0U); /* disable interrupts */
|
||||
}
|
||||
|
||||
void *decode_reg(struct xen_regs *regs, u8 b)
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
#define PREEMPT_CHECK(_op) \
|
||||
if ( hypercall_preempt_check() ) \
|
||||
return hypercall_create_continuation( \
|
||||
__HYPERVISOR_dom_mem_op, 5, \
|
||||
return hypercall5_create_continuation( \
|
||||
__HYPERVISOR_dom_mem_op, \
|
||||
(_op) | (i << START_EXTENT_SHIFT), \
|
||||
extent_list, nr_extents, extent_order, \
|
||||
(d == current->domain) ? DOMID_SELF : d->id);
|
||||
@@ -122,7 +122,7 @@ free_dom_mem(struct domain *d,
|
||||
long
|
||||
do_dom_mem_op(unsigned long op,
|
||||
unsigned long *extent_list,
|
||||
unsigned long nr_extents,
|
||||
unsigned int nr_extents,
|
||||
unsigned int extent_order,
|
||||
domid_t domid)
|
||||
{
|
||||
@@ -133,8 +133,7 @@ do_dom_mem_op(unsigned long op,
|
||||
start_extent = op >> START_EXTENT_SHIFT;
|
||||
op &= (1 << START_EXTENT_SHIFT) - 1;
|
||||
|
||||
if ( unlikely(start_extent > nr_extents) ||
|
||||
unlikely(nr_extents > ~0U) ) /* can pack into a uint? */
|
||||
if ( unlikely(start_extent > nr_extents) )
|
||||
return -EINVAL;
|
||||
|
||||
if ( likely(domid == DOMID_SELF) )
|
||||
@@ -150,13 +149,11 @@ do_dom_mem_op(unsigned long op,
|
||||
{
|
||||
case MEMOP_increase_reservation:
|
||||
rc = alloc_dom_mem(
|
||||
d, extent_list, start_extent,
|
||||
(unsigned int)nr_extents, extent_order);
|
||||
d, extent_list, start_extent, nr_extents, extent_order);
|
||||
break;
|
||||
case MEMOP_decrease_reservation:
|
||||
rc = free_dom_mem(
|
||||
d, extent_list, start_extent,
|
||||
(unsigned int)nr_extents, extent_order);
|
||||
d, extent_list, start_extent, nr_extents, extent_order);
|
||||
break;
|
||||
default:
|
||||
rc = -ENOSYS;
|
||||
|
||||
@@ -45,8 +45,6 @@ struct domain *do_createdomain(domid_t dom_id, unsigned int cpu)
|
||||
ed->processor = cpu;
|
||||
d->create_time = NOW();
|
||||
|
||||
memcpy(&ed->arch, &idle0_exec_domain.arch, sizeof(ed->arch));
|
||||
|
||||
spin_lock_init(&d->time_lock);
|
||||
|
||||
spin_lock_init(&d->big_lock);
|
||||
|
||||
+6
-8
@@ -13,10 +13,8 @@
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
#define FORCE_XENELF_IMAGE 1
|
||||
#define ELF_ADDR p_vaddr
|
||||
#elif defined(__ia64__)
|
||||
#define FORCE_XENELF_IMAGE 0
|
||||
#define ELF_ADDR p_paddr
|
||||
#endif
|
||||
|
||||
static inline int is_loadable_phdr(Elf_Phdr *phdr)
|
||||
@@ -100,10 +98,10 @@ int parseelfimage(char *elfbase,
|
||||
phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
|
||||
if ( !is_loadable_phdr(phdr) )
|
||||
continue;
|
||||
if ( phdr->ELF_ADDR < kernstart )
|
||||
kernstart = phdr->ELF_ADDR;
|
||||
if ( (phdr->ELF_ADDR + phdr->p_memsz) > kernend )
|
||||
kernend = phdr->ELF_ADDR + phdr->p_memsz;
|
||||
if ( phdr->p_paddr < kernstart )
|
||||
kernstart = phdr->p_paddr;
|
||||
if ( (phdr->p_paddr + phdr->p_memsz) > kernend )
|
||||
kernend = phdr->p_paddr + phdr->p_memsz;
|
||||
}
|
||||
|
||||
if ( (kernstart > kernend) ||
|
||||
@@ -144,10 +142,10 @@ int loadelfimage(char *elfbase)
|
||||
if ( !is_loadable_phdr(phdr) )
|
||||
continue;
|
||||
if ( phdr->p_filesz != 0 )
|
||||
memcpy((char *)phdr->ELF_ADDR, elfbase + phdr->p_offset,
|
||||
memcpy((char *)phdr->p_paddr, elfbase + phdr->p_offset,
|
||||
phdr->p_filesz);
|
||||
if ( phdr->p_memsz > phdr->p_filesz )
|
||||
memset((char *)phdr->ELF_ADDR + phdr->p_filesz, 0,
|
||||
memset((char *)phdr->p_paddr + phdr->p_filesz, 0,
|
||||
phdr->p_memsz - phdr->p_filesz);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ static struct {
|
||||
|
||||
static unsigned char keypress_key;
|
||||
|
||||
void keypress_softirq(void)
|
||||
static void keypress_softirq(void)
|
||||
{
|
||||
keyhandler_t *h;
|
||||
unsigned char key = keypress_key;
|
||||
@@ -94,7 +94,7 @@ static void halt_machine(unsigned char key, struct xen_regs *regs)
|
||||
machine_restart(NULL);
|
||||
}
|
||||
|
||||
void do_task_queues(unsigned char key)
|
||||
static void do_task_queues(unsigned char key)
|
||||
{
|
||||
struct domain *d;
|
||||
struct exec_domain *ed;
|
||||
|
||||
@@ -67,8 +67,8 @@ long do_multicall(multicall_entry_t *call_list, unsigned int nr_calls)
|
||||
if ( i < nr_calls )
|
||||
{
|
||||
mcs->flags = 0;
|
||||
return hypercall_create_continuation(
|
||||
__HYPERVISOR_multicall, 2, &call_list[i], nr_calls-i);
|
||||
return hypercall2_create_continuation(
|
||||
__HYPERVISOR_multicall, &call_list[i], nr_calls-i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -720,7 +720,7 @@ string_param("physdev_dom0_hide", opt_physdev_dom0_hide);
|
||||
|
||||
/* Test if boot params specify this device should NOT be visible to DOM0
|
||||
* (e.g. so that another domain can control it instead) */
|
||||
int pcidev_dom0_hidden(struct pci_dev *dev)
|
||||
static int pcidev_dom0_hidden(struct pci_dev *dev)
|
||||
{
|
||||
char cmp[10] = "(.......)";
|
||||
|
||||
|
||||
@@ -254,19 +254,6 @@ struct resource * __request_region(struct resource *parent, unsigned long start,
|
||||
return res;
|
||||
}
|
||||
|
||||
int __check_region(struct resource *parent, unsigned long start, unsigned long n)
|
||||
{
|
||||
struct resource * res;
|
||||
|
||||
res = __request_region(parent, start, n, "check-region");
|
||||
if (!res)
|
||||
return -EBUSY;
|
||||
|
||||
release_resource(res);
|
||||
xfree(res);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __release_region(struct resource *parent, unsigned long start, unsigned long n)
|
||||
{
|
||||
struct resource **p;
|
||||
|
||||
@@ -167,7 +167,7 @@ static inline u32 calc_evt(struct exec_domain *d, u32 avt)
|
||||
*
|
||||
* Returns non-zero on failure.
|
||||
*/
|
||||
int bvt_alloc_task(struct exec_domain *ed)
|
||||
static int bvt_alloc_task(struct exec_domain *ed)
|
||||
{
|
||||
struct domain *d = ed->domain;
|
||||
if ( (d->sched_priv == NULL) ) {
|
||||
@@ -184,7 +184,7 @@ int bvt_alloc_task(struct exec_domain *ed)
|
||||
/*
|
||||
* Add and remove a domain
|
||||
*/
|
||||
void bvt_add_task(struct exec_domain *d)
|
||||
static void bvt_add_task(struct exec_domain *d)
|
||||
{
|
||||
struct bvt_dom_info *inf = BVT_INFO(d->domain);
|
||||
struct bvt_edom_info *einf = EBVT_INFO(d);
|
||||
@@ -225,7 +225,7 @@ void bvt_add_task(struct exec_domain *d)
|
||||
}
|
||||
}
|
||||
|
||||
int bvt_init_idle_task(struct exec_domain *p)
|
||||
static int bvt_init_idle_task(struct exec_domain *p)
|
||||
{
|
||||
if ( bvt_alloc_task(p) < 0 )
|
||||
return -1;
|
||||
@@ -239,7 +239,7 @@ int bvt_init_idle_task(struct exec_domain *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bvt_wake(struct exec_domain *d)
|
||||
static void bvt_wake(struct exec_domain *d)
|
||||
{
|
||||
struct bvt_edom_info *einf = EBVT_INFO(d);
|
||||
struct exec_domain *curr;
|
||||
@@ -290,14 +290,14 @@ static void bvt_sleep(struct exec_domain *d)
|
||||
* bvt_free_task - free BVT private structures for a task
|
||||
* @d: task
|
||||
*/
|
||||
void bvt_free_task(struct domain *d)
|
||||
static void bvt_free_task(struct domain *d)
|
||||
{
|
||||
ASSERT(d->sched_priv != NULL);
|
||||
xfree(d->sched_priv);
|
||||
}
|
||||
|
||||
/* Control the scheduler. */
|
||||
int bvt_ctl(struct sched_ctl_cmd *cmd)
|
||||
static int bvt_ctl(struct sched_ctl_cmd *cmd)
|
||||
{
|
||||
struct bvt_ctl *params = &cmd->u.bvt;
|
||||
|
||||
@@ -310,7 +310,7 @@ int bvt_ctl(struct sched_ctl_cmd *cmd)
|
||||
}
|
||||
|
||||
/* Adjust scheduling parameter for a given domain. */
|
||||
int bvt_adjdom(
|
||||
static int bvt_adjdom(
|
||||
struct domain *d, struct sched_adjdom_cmd *cmd)
|
||||
{
|
||||
struct bvt_adjdom *params = &cmd->u.bvt;
|
||||
@@ -549,7 +549,7 @@ static void bvt_dump_cpu_state(int i)
|
||||
}
|
||||
|
||||
/* Initialise the data structures. */
|
||||
int bvt_init_scheduler()
|
||||
static int bvt_init_scheduler(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
include $(BASEDIR)/Rules.mk
|
||||
|
||||
OBJS := pci.o quirks.o compat.o names.o setup-res.o
|
||||
OBJS := pci.o quirks.o names.o setup-res.o
|
||||
|
||||
#obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o
|
||||
#obj-$(CONFIG_PROC_FS) += proc.o
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* $Id: compat.c,v 1.1 1998/02/16 10:35:50 mj Exp $
|
||||
*
|
||||
* PCI Bus Services -- Function For Backward Compatibility
|
||||
*
|
||||
* Copyright 1998--2000 Martin Mares <mj@ucw.cz>
|
||||
*/
|
||||
|
||||
#include <xen/types.h>
|
||||
//#include <xen/kernel.h>
|
||||
#include <xen/pci.h>
|
||||
|
||||
int
|
||||
pcibios_present(void)
|
||||
{
|
||||
return !list_empty(&pci_devices);
|
||||
}
|
||||
|
||||
int
|
||||
pcibios_find_class(unsigned int class, unsigned short index, unsigned char *bus, unsigned char *devfn)
|
||||
{
|
||||
const struct pci_dev *dev = NULL;
|
||||
int cnt = 0;
|
||||
|
||||
while ((dev = pci_find_class(class, dev)))
|
||||
if (index == cnt++) {
|
||||
*bus = dev->bus->number;
|
||||
*devfn = dev->devfn;
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pcibios_find_device(unsigned short vendor, unsigned short device, unsigned short index,
|
||||
unsigned char *bus, unsigned char *devfn)
|
||||
{
|
||||
const struct pci_dev *dev = NULL;
|
||||
int cnt = 0;
|
||||
|
||||
while ((dev = pci_find_device(vendor, device, dev)))
|
||||
if (index == cnt++) {
|
||||
*bus = dev->bus->number;
|
||||
*devfn = dev->devfn;
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
#define PCI_OP(rw,size,type) \
|
||||
int pcibios_##rw##_config_##size (unsigned char bus, unsigned char dev_fn, \
|
||||
unsigned char where, unsigned type val) \
|
||||
{ \
|
||||
struct pci_dev *dev = pci_find_slot(bus, dev_fn); \
|
||||
if (!dev) return PCIBIOS_DEVICE_NOT_FOUND; \
|
||||
return pci_##rw##_config_##size(dev, where, val); \
|
||||
}
|
||||
|
||||
PCI_OP(read, byte, char *)
|
||||
PCI_OP(read, word, short *)
|
||||
PCI_OP(read, dword, int *)
|
||||
PCI_OP(write, byte, char)
|
||||
PCI_OP(write, word, short)
|
||||
PCI_OP(write, dword, int)
|
||||
@@ -191,6 +191,10 @@ extern void __out_of_line_bug(int line) __attribute__((noreturn));
|
||||
#define __HYPERVISOR_DS32 0x0818
|
||||
#define __HYPERVISOR_DS __HYPERVISOR_DS64
|
||||
|
||||
#define __GUEST_CS 0x0833
|
||||
#define __GUEST_DS 0x0000
|
||||
#define __GUEST_SS 0x082b
|
||||
|
||||
/* For generic assembly code: use macros to define operation/operand sizes. */
|
||||
#define __OS "q" /* Operation Suffix */
|
||||
#define __OP "r" /* Operand Prefix */
|
||||
|
||||
@@ -96,6 +96,7 @@ struct arch_exec_domain
|
||||
pagetable_t pagetable;
|
||||
|
||||
pagetable_t monitor_table;
|
||||
pagetable_t phys_table; /* 1:1 pagetable */
|
||||
pagetable_t shadow_table;
|
||||
l2_pgentry_t *vpagetable; /* virtual address of pagetable */
|
||||
l2_pgentry_t *shadow_vtable; /* virtual address of shadow_table */
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <asm/desc.h>
|
||||
#include <asm/flushtlb.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <public/xen.h>
|
||||
|
||||
@@ -218,7 +219,7 @@ static inline int get_page_and_type(struct pfn_info *page,
|
||||
ASSERT(((_p)->count_info & PGC_count_mask) != 0); \
|
||||
ASSERT(page_get_owner(_p) == (_d))
|
||||
|
||||
int check_descriptor(unsigned long *d);
|
||||
int check_descriptor(struct desc_struct *d);
|
||||
|
||||
/*
|
||||
* Use currently-executing domain's pagetables on the specified CPUs.
|
||||
@@ -241,8 +242,20 @@ void synchronise_pagetables(unsigned long cpu_mask);
|
||||
#undef phys_to_machine_mapping
|
||||
|
||||
#define machine_to_phys_mapping ((unsigned long *)RDWR_MPT_VIRT_START)
|
||||
#define phys_to_machine_mapping ((unsigned long *)PERDOMAIN_VIRT_START)
|
||||
#define __phys_to_machine_mapping ((unsigned long *)PERDOMAIN_VIRT_START)
|
||||
/* Returns the machine physical */
|
||||
static inline unsigned long phys_to_machine_mapping(unsigned long pfn)
|
||||
{
|
||||
unsigned long mfn;
|
||||
l1_pgentry_t pte;
|
||||
|
||||
if (__get_user(l1_pgentry_val(pte), (__phys_to_machine_mapping + pfn))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mfn = l1_pgentry_to_phys(pte) >> PAGE_SHIFT;
|
||||
return mfn;
|
||||
}
|
||||
#define set_machinetophys(_mfn, _pfn) machine_to_phys_mapping[(_mfn)] = (_pfn)
|
||||
|
||||
#define DEFAULT_GDT_ENTRIES (LAST_RESERVED_GDT_ENTRY+1)
|
||||
|
||||
@@ -9,7 +9,23 @@
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define do_multicall_call(_call) BUG()
|
||||
#define do_multicall_call(_call) \
|
||||
do { \
|
||||
__asm__ __volatile__ ( \
|
||||
"movq "STR(MULTICALL_op)"(%0),%%rax; " \
|
||||
"andq $("STR(NR_hypercalls)"-1),%%rax; " \
|
||||
"leaq "STR(hypercall_table)"(%%rip),%%rdi; "\
|
||||
"leaq (%%rdi,%%rax,8),%%rax; " \
|
||||
"movq "STR(MULTICALL_arg0)"(%0),%%rdi; " \
|
||||
"movq "STR(MULTICALL_arg1)"(%0),%%rsi; " \
|
||||
"movq "STR(MULTICALL_arg2)"(%0),%%rdx; " \
|
||||
"movq "STR(MULTICALL_arg3)"(%0),%%rcx; " \
|
||||
"movq "STR(MULTICALL_arg4)"(%0),%%r8; " \
|
||||
"callq *(%%rax); " \
|
||||
"movq %%rax,"STR(MULTICALL_result)"(%0); " \
|
||||
: : "b" (_call) \
|
||||
: "rax", "rdi", "rsi", "rdx", "rcx", "r8" ); \
|
||||
} while ( 0 )
|
||||
|
||||
#else
|
||||
|
||||
|
||||
@@ -1,39 +1,14 @@
|
||||
/******************************************************************************
|
||||
* asm-x86/page.h
|
||||
*
|
||||
* Definitions relating to page tables.
|
||||
*/
|
||||
/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
|
||||
|
||||
#ifndef __X86_PAGE_H__
|
||||
#define __X86_PAGE_H__
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
#define L1_PAGETABLE_SHIFT 12
|
||||
#define L2_PAGETABLE_SHIFT 21
|
||||
#define L3_PAGETABLE_SHIFT 30
|
||||
#define L4_PAGETABLE_SHIFT 39
|
||||
|
||||
#define ENTRIES_PER_L1_PAGETABLE 512
|
||||
#define ENTRIES_PER_L2_PAGETABLE 512
|
||||
#define ENTRIES_PER_L3_PAGETABLE 512
|
||||
#define ENTRIES_PER_L4_PAGETABLE 512
|
||||
|
||||
#define __PAGE_OFFSET (0xFFFF830000000000)
|
||||
|
||||
#elif defined(__i386__)
|
||||
|
||||
#define L1_PAGETABLE_SHIFT 12
|
||||
#define L2_PAGETABLE_SHIFT 22
|
||||
|
||||
#define ENTRIES_PER_L1_PAGETABLE 1024
|
||||
#define ENTRIES_PER_L2_PAGETABLE 1024
|
||||
|
||||
#define __PAGE_OFFSET (0xFC400000)
|
||||
|
||||
#if defined(__i386__)
|
||||
#include <asm/x86_32/page.h>
|
||||
#elif defined(__x86_64__)
|
||||
#include <asm/x86_64/page.h>
|
||||
#endif
|
||||
|
||||
#define PAGE_SHIFT L1_PAGETABLE_SHIFT
|
||||
#ifndef __ASSEMBLY__
|
||||
#define PAGE_SIZE (1UL << PAGE_SHIFT)
|
||||
#else
|
||||
@@ -44,77 +19,9 @@
|
||||
#define clear_page(_p) memset((void *)(_p), 0, PAGE_SIZE)
|
||||
#define copy_page(_t,_f) memcpy((void *)(_t), (void *)(_f), PAGE_SIZE)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <xen/config.h>
|
||||
typedef struct { unsigned long l1_lo; } l1_pgentry_t;
|
||||
typedef struct { unsigned long l2_lo; } l2_pgentry_t;
|
||||
typedef struct { unsigned long l3_lo; } l3_pgentry_t;
|
||||
typedef struct { unsigned long l4_lo; } l4_pgentry_t;
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
/* Strip type from a table entry. */
|
||||
#define l1_pgentry_val(_x) ((_x).l1_lo)
|
||||
#define l2_pgentry_val(_x) ((_x).l2_lo)
|
||||
#define l3_pgentry_val(_x) ((_x).l3_lo)
|
||||
#define l4_pgentry_val(_x) ((_x).l4_lo)
|
||||
|
||||
/* Add type to a table entry. */
|
||||
#define mk_l1_pgentry(_x) ( (l1_pgentry_t) { (_x) } )
|
||||
#define mk_l2_pgentry(_x) ( (l2_pgentry_t) { (_x) } )
|
||||
#define mk_l3_pgentry(_x) ( (l3_pgentry_t) { (_x) } )
|
||||
#define mk_l4_pgentry(_x) ( (l4_pgentry_t) { (_x) } )
|
||||
|
||||
/* Turn a typed table entry into a page index. */
|
||||
#define l1_pgentry_to_pagenr(_x) (l1_pgentry_val(_x) >> PAGE_SHIFT)
|
||||
#define l2_pgentry_to_pagenr(_x) (l2_pgentry_val(_x) >> PAGE_SHIFT)
|
||||
#define l3_pgentry_to_pagenr(_x) (l3_pgentry_val(_x) >> PAGE_SHIFT)
|
||||
#define l4_pgentry_to_pagenr(_x) (l4_pgentry_val(_x) >> PAGE_SHIFT)
|
||||
|
||||
/* Turn a typed table entry into a physical address. */
|
||||
#define l1_pgentry_to_phys(_x) (l1_pgentry_val(_x) & PAGE_MASK)
|
||||
#define l2_pgentry_to_phys(_x) (l2_pgentry_val(_x) & PAGE_MASK)
|
||||
#define l3_pgentry_to_phys(_x) (l3_pgentry_val(_x) & PAGE_MASK)
|
||||
#define l4_pgentry_to_phys(_x) (l4_pgentry_val(_x) & PAGE_MASK)
|
||||
|
||||
/* Pagetable walking. */
|
||||
#define l2_pgentry_to_l1(_x) \
|
||||
((l1_pgentry_t *)__va(l2_pgentry_val(_x) & PAGE_MASK))
|
||||
#define l3_pgentry_to_l2(_x) \
|
||||
((l2_pgentry_t *)__va(l3_pgentry_val(_x) & PAGE_MASK))
|
||||
#define l4_pgentry_to_l3(_x) \
|
||||
((l3_pgentry_t *)__va(l4_pgentry_val(_x) & PAGE_MASK))
|
||||
|
||||
/* Given a virtual address, get an entry offset into a page table. */
|
||||
#define l1_table_offset(_a) \
|
||||
(((_a) >> L1_PAGETABLE_SHIFT) & (ENTRIES_PER_L1_PAGETABLE - 1))
|
||||
#if defined(__i386__)
|
||||
#define l2_table_offset(_a) \
|
||||
((_a) >> L2_PAGETABLE_SHIFT)
|
||||
#elif defined(__x86_64__)
|
||||
#define l2_table_offset(_a) \
|
||||
(((_a) >> L2_PAGETABLE_SHIFT) & (ENTRIES_PER_L2_PAGETABLE - 1))
|
||||
#define l3_table_offset(_a) \
|
||||
(((_a) >> L3_PAGETABLE_SHIFT) & (ENTRIES_PER_L3_PAGETABLE - 1))
|
||||
#define l4_table_offset(_a) \
|
||||
(((_a) >> L4_PAGETABLE_SHIFT) & (ENTRIES_PER_L4_PAGETABLE - 1))
|
||||
#endif
|
||||
|
||||
#if defined(__i386__)
|
||||
#define pagetable_t l2_pgentry_t
|
||||
#define pagetable_val(_x) ((_x).l2_lo)
|
||||
#define mk_pagetable(_x) ( (l2_pgentry_t) { (_x) } )
|
||||
#define ENTRIES_PER_PAGETABLE ENTRIES_PER_L2_PAGETABLE
|
||||
#elif defined(__x86_64__)
|
||||
#define pagetable_t l4_pgentry_t
|
||||
#define pagetable_val(_x) ((_x).l4_lo)
|
||||
#define mk_pagetable(_x) ( (l4_pgentry_t) { (_x) } )
|
||||
#define ENTRIES_PER_PAGETABLE ENTRIES_PER_L4_PAGETABLE
|
||||
#endif
|
||||
|
||||
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
|
||||
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
|
||||
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
|
||||
#define page_address(_p) (__va(((_p) - frame_table) << PAGE_SHIFT))
|
||||
#define pfn_to_page(_pfn) (frame_table + (_pfn))
|
||||
#define phys_to_page(kaddr) (frame_table + ((kaddr) >> PAGE_SHIFT))
|
||||
#define virt_to_page(kaddr) (frame_table + (__pa(kaddr) >> PAGE_SHIFT))
|
||||
|
||||
+118
-142
@@ -8,6 +8,10 @@
|
||||
#include <xen/perfc.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#ifdef CONFIG_VMX
|
||||
#include <asm/domain_page.h>
|
||||
#endif
|
||||
|
||||
/* Shadow PT flag bits in pfn_info */
|
||||
#define PSH_shadowed (1<<31) /* page has a shadow. PFN points to shadow */
|
||||
#define PSH_pfn_mask ((1<<21)-1)
|
||||
@@ -34,7 +38,7 @@ extern int shadow_fault(unsigned long va, long error_code);
|
||||
extern void shadow_l1_normal_pt_update(
|
||||
unsigned long pa, unsigned long gpte,
|
||||
unsigned long *prev_spfn_ptr, l1_pgentry_t **prev_spl1e_ptr);
|
||||
extern void shadow_l2_normal_pt_update(unsigned long pa, unsigned long gpte);
|
||||
extern void shadow_l2_normal_pt_update(unsigned long pa, unsigned long gpde);
|
||||
extern void unshadow_table(unsigned long gpfn, unsigned int type);
|
||||
extern int shadow_mode_enable(struct domain *p, unsigned int mode);
|
||||
|
||||
@@ -43,17 +47,15 @@ extern void vmx_shadow_clear_state(struct domain *);
|
||||
extern void vmx_shadow_invlpg(struct domain *, unsigned long);
|
||||
#endif
|
||||
|
||||
#define __get_machine_to_phys(_d, guest_gpfn, gpfn) \
|
||||
if ((_d)->arch.shadow_mode == SHM_full_32) \
|
||||
(guest_gpfn) = machine_to_phys_mapping[(gpfn)]; \
|
||||
else \
|
||||
(guest_gpfn) = (gpfn);
|
||||
#define __mfn_to_gpfn(_d, mfn) \
|
||||
( (shadow_mode(_d) == SHM_full_32) \
|
||||
? machine_to_phys_mapping[(mfn)] \
|
||||
: (mfn) )
|
||||
|
||||
#define __get_phys_to_machine(_d, host_gpfn, gpfn) \
|
||||
if ((_d)->arch.shadow_mode == SHM_full_32) \
|
||||
(host_gpfn) = phys_to_machine_mapping[(gpfn)]; \
|
||||
else \
|
||||
(host_gpfn) = (gpfn);
|
||||
#define __gpfn_to_mfn(_d, gpfn) \
|
||||
( (shadow_mode(_d) == SHM_full_32) \
|
||||
? phys_to_machine_mapping(gpfn) \
|
||||
: (gpfn) )
|
||||
|
||||
extern void __shadow_mode_disable(struct domain *d);
|
||||
static inline void shadow_mode_disable(struct domain *d)
|
||||
@@ -66,17 +68,18 @@ extern unsigned long shadow_l2_table(
|
||||
struct domain *d, unsigned long gpfn);
|
||||
|
||||
static inline void shadow_invalidate(struct exec_domain *ed) {
|
||||
if ( ed->domain->arch.shadow_mode != SHM_full_32 )
|
||||
if ( shadow_mode(ed->domain) != SHM_full_32 )
|
||||
BUG();
|
||||
memset(ed->arch.shadow_vtable, 0, PAGE_SIZE);
|
||||
}
|
||||
|
||||
#define SHADOW_DEBUG 1
|
||||
#define SHADOW_VERBOSE_DEBUG 0
|
||||
#define SHADOW_HASH_DEBUG 1
|
||||
|
||||
struct shadow_status {
|
||||
unsigned long pfn; /* Guest pfn. */
|
||||
unsigned long spfn_and_flags; /* Shadow pfn plus flags. */
|
||||
unsigned long smfn_and_flags; /* Shadow mfn plus flags. */
|
||||
struct shadow_status *next; /* Pull-to-front list. */
|
||||
};
|
||||
|
||||
@@ -84,62 +87,72 @@ struct shadow_status {
|
||||
#define shadow_ht_buckets 256
|
||||
|
||||
#ifdef VERBOSE
|
||||
#define SH_LOG(_f, _a...) \
|
||||
printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \
|
||||
current->domain->id , __LINE__ , ## _a )
|
||||
#define SH_LOG(_f, _a...) \
|
||||
printk("DOM%uP%u: (file=shadow.c, line=%d) " _f "\n", \
|
||||
current->domain->id , current->processor, __LINE__ , ## _a )
|
||||
#else
|
||||
#define SH_LOG(_f, _a...)
|
||||
#endif
|
||||
|
||||
#if SHADOW_DEBUG
|
||||
#define SH_VLOG(_f, _a...) \
|
||||
printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \
|
||||
current->domain->id , __LINE__ , ## _a )
|
||||
#define SH_VLOG(_f, _a...) \
|
||||
printk("DOM%uP%u: (file=shadow.c, line=%d) " _f "\n", \
|
||||
current->domain->id, current->processor, __LINE__ , ## _a )
|
||||
#else
|
||||
#define SH_VLOG(_f, _a...)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define SH_VVLOG(_f, _a...) \
|
||||
printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \
|
||||
current->domain->id , __LINE__ , ## _a )
|
||||
#if SHADOW_VERBOSE_DEBUG
|
||||
#define SH_VVLOG(_f, _a...) \
|
||||
printk("DOM%uP%u: (file=shadow.c, line=%d) " _f "\n", \
|
||||
current->domain->id, current->processor, __LINE__ , ## _a )
|
||||
#else
|
||||
#define SH_VVLOG(_f, _a...)
|
||||
#endif
|
||||
|
||||
static inline void __shadow_get_pl2e(
|
||||
// BUG: mafetter: this assumes ed == current, so why pass ed?
|
||||
static inline void __shadow_get_l2e(
|
||||
struct exec_domain *ed, unsigned long va, unsigned long *sl2e)
|
||||
{
|
||||
*sl2e = (ed->domain->arch.shadow_mode == SHM_full_32) ?
|
||||
l2_pgentry_val(ed->arch.shadow_vtable[l2_table_offset(va)]) :
|
||||
l2_pgentry_val(linear_l2_table[l2_table_offset(va)]);
|
||||
if ( shadow_mode(ed->domain) == SHM_full_32 ) {
|
||||
*sl2e = l2_pgentry_val(ed->arch.shadow_vtable[l2_table_offset(va)]);
|
||||
}
|
||||
else if ( shadow_mode(ed->domain) ) {
|
||||
*sl2e = l2_pgentry_val(shadow_linear_l2_table[l2_table_offset(va)]);
|
||||
}
|
||||
else
|
||||
*sl2e = l2_pgentry_val(linear_l2_table[l2_table_offset(va)]);
|
||||
}
|
||||
|
||||
static inline void __shadow_set_pl2e(
|
||||
static inline void __shadow_set_l2e(
|
||||
struct exec_domain *ed, unsigned long va, unsigned long value)
|
||||
{
|
||||
if ( ed->domain->arch.shadow_mode == SHM_full_32 )
|
||||
if ( shadow_mode(ed->domain) == SHM_full_32 ) {
|
||||
ed->arch.shadow_vtable[l2_table_offset(va)] = mk_l2_pgentry(value);
|
||||
}
|
||||
else if ( shadow_mode(ed->domain) ) {
|
||||
shadow_linear_l2_table[l2_table_offset(va)] = mk_l2_pgentry(value);
|
||||
}
|
||||
else
|
||||
linear_l2_table[l2_table_offset(va)] = mk_l2_pgentry(value);
|
||||
}
|
||||
|
||||
static inline void __guest_get_pl2e(
|
||||
static inline void __guest_get_l2e(
|
||||
struct exec_domain *ed, unsigned long va, unsigned long *l2e)
|
||||
{
|
||||
*l2e = (ed->domain->arch.shadow_mode == SHM_full_32) ?
|
||||
*l2e = ( shadow_mode(ed->domain) == SHM_full_32) ?
|
||||
l2_pgentry_val(ed->arch.vpagetable[l2_table_offset(va)]) :
|
||||
l2_pgentry_val(linear_l2_table[l2_table_offset(va)]);
|
||||
}
|
||||
|
||||
static inline void __guest_set_pl2e(
|
||||
static inline void __guest_set_l2e(
|
||||
struct exec_domain *ed, unsigned long va, unsigned long value)
|
||||
{
|
||||
if ( ed->domain->arch.shadow_mode == SHM_full_32 )
|
||||
if ( shadow_mode(ed->domain) == SHM_full_32 )
|
||||
{
|
||||
unsigned long pfn;
|
||||
|
||||
pfn = phys_to_machine_mapping[value >> PAGE_SHIFT];
|
||||
pfn = phys_to_machine_mapping(value >> PAGE_SHIFT);
|
||||
ed->arch.guest_pl2e_cache[l2_table_offset(va)] =
|
||||
mk_l2_pgentry((pfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
|
||||
|
||||
@@ -213,32 +226,18 @@ static inline void l1pte_write_fault(
|
||||
{
|
||||
unsigned long gpte = *gpte_p;
|
||||
unsigned long spte = *spte_p;
|
||||
unsigned long pfn = gpte >> PAGE_SHIFT;
|
||||
unsigned long mfn = __gpfn_to_mfn(d, pfn);
|
||||
|
||||
ASSERT(gpte & _PAGE_RW);
|
||||
gpte |= _PAGE_DIRTY | _PAGE_ACCESSED;
|
||||
|
||||
switch ( d->arch.shadow_mode )
|
||||
{
|
||||
case SHM_test:
|
||||
spte = gpte | _PAGE_RW;
|
||||
break;
|
||||
if ( shadow_mode(d) == SHM_logdirty )
|
||||
__mark_dirty(d, pfn);
|
||||
|
||||
case SHM_logdirty:
|
||||
spte = gpte | _PAGE_RW;
|
||||
__mark_dirty(d, gpte >> PAGE_SHIFT);
|
||||
spte = (mfn << PAGE_SHIFT) | (gpte & ~PAGE_MASK);
|
||||
|
||||
case SHM_full_32:
|
||||
{
|
||||
unsigned long host_pfn, host_gpte;
|
||||
|
||||
host_pfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT];
|
||||
host_gpte = (host_pfn << PAGE_SHIFT) | (gpte & ~PAGE_MASK);
|
||||
spte = host_gpte | _PAGE_RW;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
SH_VVLOG("updating spte=%lx gpte=%lx", spte, gpte);
|
||||
SH_VVLOG("l1pte_write_fault: updating spte=0x%08lx gpte=0x%08lx", spte, gpte);
|
||||
*gpte_p = gpte;
|
||||
*spte_p = spte;
|
||||
}
|
||||
@@ -248,31 +247,16 @@ static inline void l1pte_read_fault(
|
||||
{
|
||||
unsigned long gpte = *gpte_p;
|
||||
unsigned long spte = *spte_p;
|
||||
unsigned long pfn = gpte >> PAGE_SHIFT;
|
||||
unsigned long mfn = __gpfn_to_mfn(d, pfn);
|
||||
|
||||
gpte |= _PAGE_ACCESSED;
|
||||
spte = (mfn << PAGE_SHIFT) | (gpte & ~PAGE_MASK);
|
||||
|
||||
switch ( d->arch.shadow_mode )
|
||||
{
|
||||
case SHM_test:
|
||||
spte = (gpte & _PAGE_DIRTY) ? gpte : (gpte & ~_PAGE_RW);
|
||||
break;
|
||||
|
||||
case SHM_logdirty:
|
||||
spte = gpte & ~_PAGE_RW;
|
||||
break;
|
||||
|
||||
case SHM_full_32:
|
||||
{
|
||||
unsigned long host_pfn, host_gpte;
|
||||
|
||||
host_pfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT];
|
||||
host_gpte = (host_pfn << PAGE_SHIFT) | (gpte & ~PAGE_MASK);
|
||||
spte = (host_gpte & _PAGE_DIRTY) ? host_gpte : (host_gpte & ~_PAGE_RW);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
if ( (shadow_mode(d) == SHM_logdirty) || ! (gpte & _PAGE_DIRTY) )
|
||||
spte &= ~_PAGE_RW;
|
||||
|
||||
SH_VVLOG("l1pte_read_fault: updating spte=0x%08lx gpte=0x%08lx", spte, gpte);
|
||||
*gpte_p = gpte;
|
||||
*spte_p = spte;
|
||||
}
|
||||
@@ -283,8 +267,11 @@ static inline void l1pte_propagate_from_guest(
|
||||
unsigned long gpte = *gpte_p;
|
||||
unsigned long spte = *spte_p;
|
||||
unsigned long host_pfn, host_gpte;
|
||||
#if SHADOW_VERBOSE_DEBUG
|
||||
unsigned long old_spte = spte;
|
||||
#endif
|
||||
|
||||
switch ( d->arch.shadow_mode )
|
||||
switch ( shadow_mode(d) )
|
||||
{
|
||||
case SHM_test:
|
||||
spte = 0;
|
||||
@@ -309,7 +296,7 @@ static inline void l1pte_propagate_from_guest(
|
||||
return;
|
||||
}
|
||||
|
||||
host_pfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT];
|
||||
host_pfn = phys_to_machine_mapping(gpte >> PAGE_SHIFT);
|
||||
host_gpte = (host_pfn << PAGE_SHIFT) | (gpte & ~PAGE_MASK);
|
||||
|
||||
if ( (host_gpte & (_PAGE_PRESENT|_PAGE_ACCESSED) ) ==
|
||||
@@ -320,6 +307,11 @@ static inline void l1pte_propagate_from_guest(
|
||||
break;
|
||||
}
|
||||
|
||||
#if SHADOW_VERBOSE_DEBUG
|
||||
if ( old_spte || spte || gpte )
|
||||
SH_VVLOG("l1pte_propagate_from_guest: gpte=0x%08lx, old spte=0x%08lx, new spte=0x%08lx ", gpte, old_spte, spte);
|
||||
#endif
|
||||
|
||||
*gpte_p = gpte;
|
||||
*spte_p = spte;
|
||||
}
|
||||
@@ -328,24 +320,24 @@ static inline void l2pde_general(
|
||||
struct domain *d,
|
||||
unsigned long *gpde_p,
|
||||
unsigned long *spde_p,
|
||||
unsigned long sl1pfn)
|
||||
unsigned long sl1mfn)
|
||||
{
|
||||
unsigned long gpde = *gpde_p;
|
||||
unsigned long spde = *spde_p;
|
||||
|
||||
spde = 0;
|
||||
|
||||
if ( sl1pfn != 0 )
|
||||
if ( sl1mfn != 0 )
|
||||
{
|
||||
spde = (gpde & ~PAGE_MASK) | (sl1pfn << PAGE_SHIFT) |
|
||||
spde = (gpde & ~PAGE_MASK) | (sl1mfn << PAGE_SHIFT) |
|
||||
_PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY;
|
||||
gpde |= _PAGE_ACCESSED | _PAGE_DIRTY;
|
||||
|
||||
/* Detect linear p.t. mappings and write-protect them. */
|
||||
if ( (frame_table[sl1pfn].u.inuse.type_info & PGT_type_mask) ==
|
||||
if ( (frame_table[sl1mfn].u.inuse.type_info & PGT_type_mask) ==
|
||||
PGT_l2_page_table )
|
||||
{
|
||||
if ( d->arch.shadow_mode != SHM_full_32 )
|
||||
if ( shadow_mode(d) != SHM_full_32 )
|
||||
spde = gpde & ~_PAGE_RW;
|
||||
|
||||
}
|
||||
@@ -366,20 +358,20 @@ static void shadow_audit(struct domain *d, int print)
|
||||
for ( j = 0; j < shadow_ht_buckets; j++ )
|
||||
{
|
||||
a = &d->arch.shadow_ht[j];
|
||||
if ( a->pfn ) { live++; ASSERT(a->spfn_and_flags & PSH_pfn_mask); }
|
||||
if ( a->pfn ) { live++; ASSERT(a->smfn_and_flags & PSH_pfn_mask); }
|
||||
ASSERT(a->pfn < 0x00100000UL);
|
||||
a = a->next;
|
||||
while ( a && (live < 9999) )
|
||||
{
|
||||
live++;
|
||||
if ( (a->pfn == 0) || (a->spfn_and_flags == 0) )
|
||||
if ( (a->pfn == 0) || (a->smfn_and_flags == 0) )
|
||||
{
|
||||
printk("XXX live=%d pfn=%08lx sp=%08lx next=%p\n",
|
||||
live, a->pfn, a->spfn_and_flags, a->next);
|
||||
live, a->pfn, a->smfn_and_flags, a->next);
|
||||
BUG();
|
||||
}
|
||||
ASSERT(a->pfn < 0x00100000UL);
|
||||
ASSERT(a->spfn_and_flags & PSH_pfn_mask);
|
||||
ASSERT(a->smfn_and_flags & PSH_pfn_mask);
|
||||
a = a->next;
|
||||
}
|
||||
ASSERT(live < 9999);
|
||||
@@ -411,6 +403,12 @@ static inline struct shadow_status *hash_bucket(
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* N.B. This takes a guest pfn (i.e. a pfn in the guest's namespace,
|
||||
* which, depending on full shadow mode, may or may not equal
|
||||
* its mfn).
|
||||
* The shadow status it returns is a mfn.
|
||||
*/
|
||||
static inline unsigned long __shadow_status(
|
||||
struct domain *d, unsigned int gpfn)
|
||||
{
|
||||
@@ -419,7 +417,7 @@ static inline unsigned long __shadow_status(
|
||||
x = head = hash_bucket(d, gpfn);
|
||||
p = NULL;
|
||||
|
||||
SH_VVLOG("lookup gpfn=%08x bucket=%p", gpfn, x);
|
||||
//SH_VVLOG("lookup gpfn=%08x bucket=%p", gpfn, x);
|
||||
shadow_audit(d, 0);
|
||||
|
||||
do
|
||||
@@ -438,10 +436,12 @@ static inline unsigned long __shadow_status(
|
||||
|
||||
/* Swap 'x' contents with head contents. */
|
||||
SWAP(head->pfn, x->pfn);
|
||||
SWAP(head->spfn_and_flags, x->spfn_and_flags);
|
||||
SWAP(head->smfn_and_flags, x->smfn_and_flags);
|
||||
}
|
||||
|
||||
return head->spfn_and_flags;
|
||||
SH_VVLOG("lookup gpfn=%08lx => status=%08lx",
|
||||
gpfn, head->smfn_and_flags);
|
||||
return head->smfn_and_flags;
|
||||
}
|
||||
|
||||
p = x;
|
||||
@@ -449,6 +449,7 @@ static inline unsigned long __shadow_status(
|
||||
}
|
||||
while ( x != NULL );
|
||||
|
||||
SH_VVLOG("lookup gpfn=%08lx => status=0", gpfn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -462,7 +463,7 @@ static inline unsigned long get_shadow_status(
|
||||
{
|
||||
unsigned long res;
|
||||
|
||||
ASSERT(d->arch.shadow_mode);
|
||||
ASSERT(shadow_mode(d));
|
||||
|
||||
/*
|
||||
* If we get here we know that some sort of update has happened to the
|
||||
@@ -474,7 +475,7 @@ static inline unsigned long get_shadow_status(
|
||||
|
||||
shadow_lock(d);
|
||||
|
||||
if ( d->arch.shadow_mode == SHM_logdirty )
|
||||
if ( shadow_mode(d) == SHM_logdirty )
|
||||
__mark_dirty(d, gpfn);
|
||||
|
||||
if ( !(res = __shadow_status(d, gpfn)) )
|
||||
@@ -511,14 +512,14 @@ static inline void delete_shadow_status(
|
||||
{
|
||||
/* Overwrite head with contents of following node. */
|
||||
head->pfn = n->pfn;
|
||||
head->spfn_and_flags = n->spfn_and_flags;
|
||||
head->smfn_and_flags = n->smfn_and_flags;
|
||||
|
||||
/* Delete following node. */
|
||||
head->next = n->next;
|
||||
|
||||
/* Add deleted node to the free list. */
|
||||
n->pfn = 0;
|
||||
n->spfn_and_flags = 0;
|
||||
n->smfn_and_flags = 0;
|
||||
n->next = d->arch.shadow_ht_free;
|
||||
d->arch.shadow_ht_free = n;
|
||||
}
|
||||
@@ -526,7 +527,7 @@ static inline void delete_shadow_status(
|
||||
{
|
||||
/* This bucket is now empty. Initialise the head node. */
|
||||
head->pfn = 0;
|
||||
head->spfn_and_flags = 0;
|
||||
head->smfn_and_flags = 0;
|
||||
}
|
||||
|
||||
goto found;
|
||||
@@ -544,7 +545,7 @@ static inline void delete_shadow_status(
|
||||
|
||||
/* Add deleted node to the free list. */
|
||||
x->pfn = 0;
|
||||
x->spfn_and_flags = 0;
|
||||
x->smfn_and_flags = 0;
|
||||
x->next = d->arch.shadow_ht_free;
|
||||
d->arch.shadow_ht_free = x;
|
||||
|
||||
@@ -587,7 +588,7 @@ static inline void set_shadow_status(
|
||||
{
|
||||
if ( x->pfn == gpfn )
|
||||
{
|
||||
x->spfn_and_flags = s;
|
||||
x->smfn_and_flags = s;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -603,7 +604,7 @@ static inline void set_shadow_status(
|
||||
if ( head->pfn == 0 )
|
||||
{
|
||||
head->pfn = gpfn;
|
||||
head->spfn_and_flags = s;
|
||||
head->smfn_and_flags = s;
|
||||
ASSERT(head->next == NULL);
|
||||
goto done;
|
||||
}
|
||||
@@ -643,7 +644,7 @@ static inline void set_shadow_status(
|
||||
|
||||
/* Initialise the new node and insert directly after the head item. */
|
||||
x->pfn = gpfn;
|
||||
x->spfn_and_flags = s;
|
||||
x->smfn_and_flags = s;
|
||||
x->next = head->next;
|
||||
head->next = x;
|
||||
|
||||
@@ -652,10 +653,9 @@ static inline void set_shadow_status(
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VMX
|
||||
#include <asm/domain_page.h>
|
||||
|
||||
static inline void vmx_update_shadow_state(
|
||||
struct exec_domain *ed, unsigned long gpfn, unsigned long spfn)
|
||||
struct exec_domain *ed, unsigned long gpfn, unsigned long smfn)
|
||||
{
|
||||
|
||||
l2_pgentry_t *mpl2e = 0;
|
||||
@@ -672,70 +672,46 @@ static inline void vmx_update_shadow_state(
|
||||
map_domain_mem(pagetable_val(ed->arch.monitor_table));
|
||||
|
||||
mpl2e[l2_table_offset(SH_LINEAR_PT_VIRT_START)] =
|
||||
mk_l2_pgentry((spfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
|
||||
mk_l2_pgentry((smfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
|
||||
__flush_tlb_one(SH_LINEAR_PT_VIRT_START);
|
||||
|
||||
spl2e = (l2_pgentry_t *)map_domain_mem(spfn << PAGE_SHIFT);
|
||||
spl2e = (l2_pgentry_t *)map_domain_mem(smfn << PAGE_SHIFT);
|
||||
gpl2e = (l2_pgentry_t *)map_domain_mem(gpfn << PAGE_SHIFT);
|
||||
memset(spl2e, 0, ENTRIES_PER_L2_PAGETABLE * sizeof(l2_pgentry_t));
|
||||
|
||||
ed->arch.shadow_table = mk_pagetable(spfn<<PAGE_SHIFT);
|
||||
ed->arch.shadow_vtable = spl2e;
|
||||
ed->arch.vpagetable = gpl2e; /* expect the guest did clean this up */
|
||||
unmap_domain_mem(mpl2e);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_VMX */
|
||||
|
||||
static inline void __shadow_mk_pagetable(struct exec_domain *ed)
|
||||
{
|
||||
struct domain *d = ed->domain;
|
||||
unsigned long gpfn = pagetable_val(ed->arch.pagetable) >> PAGE_SHIFT;
|
||||
unsigned long spfn;
|
||||
SH_VLOG("0: __shadow_mk_pagetable(gpfn=%08lx\n", gpfn);
|
||||
unsigned long smfn = __shadow_status(d, gpfn) & PSH_pfn_mask;
|
||||
|
||||
if (d->arch.shadow_mode == SHM_full_32)
|
||||
{
|
||||
unsigned long guest_gpfn;
|
||||
guest_gpfn = machine_to_phys_mapping[gpfn];
|
||||
SH_VVLOG("0: __shadow_mk_pagetable(gpfn=%08lx, smfn=%08lx)", gpfn, smfn);
|
||||
|
||||
SH_VVLOG("__shadow_mk_pagetable(guest_gpfn=%08lx, gpfn=%08lx\n",
|
||||
guest_gpfn, gpfn);
|
||||
if ( unlikely(smfn == 0) )
|
||||
smfn = shadow_l2_table(d, gpfn);
|
||||
#ifdef CONFIG_VMX
|
||||
else
|
||||
if (d->arch.shadow_mode == SHM_full_32)
|
||||
vmx_update_shadow_state(ed, gpfn, smfn);
|
||||
#endif
|
||||
|
||||
spfn = __shadow_status(d, guest_gpfn) & PSH_pfn_mask;
|
||||
if ( unlikely(spfn == 0) ) {
|
||||
spfn = shadow_l2_table(d, gpfn);
|
||||
ed->arch.shadow_table = mk_pagetable(spfn<<PAGE_SHIFT);
|
||||
} else {
|
||||
vmx_update_shadow_state(ed, gpfn, spfn);
|
||||
}
|
||||
} else {
|
||||
spfn = __shadow_status(d, gpfn) & PSH_pfn_mask;
|
||||
|
||||
if ( unlikely(spfn == 0) ) {
|
||||
spfn = shadow_l2_table(d, gpfn);
|
||||
}
|
||||
ed->arch.shadow_table = mk_pagetable(spfn<<PAGE_SHIFT);
|
||||
}
|
||||
ed->arch.shadow_table = mk_pagetable(smfn<<PAGE_SHIFT);
|
||||
}
|
||||
#else
|
||||
static inline void __shadow_mk_pagetable(struct exec_domain *ed)
|
||||
{
|
||||
unsigned long gpfn = pagetable_val(ed->arch.pagetable) >> PAGE_SHIFT;
|
||||
unsigned long spfn = __shadow_status(ed->domain, gpfn);
|
||||
|
||||
if ( unlikely(spfn == 0) )
|
||||
spfn = shadow_l2_table(ed->domain, gpfn);
|
||||
|
||||
ed->arch.shadow_table = mk_pagetable(spfn << PAGE_SHIFT);
|
||||
}
|
||||
#endif /* CONFIG_VMX */
|
||||
|
||||
static inline void shadow_mk_pagetable(struct exec_domain *ed)
|
||||
{
|
||||
if ( unlikely(ed->domain->arch.shadow_mode) )
|
||||
if ( unlikely(shadow_mode(ed->domain)) )
|
||||
{
|
||||
SH_VVLOG("shadow_mk_pagetable( gptbase=%08lx, mode=%d )",
|
||||
pagetable_val(ed->arch.pagetable),
|
||||
ed->domain->arch.shadow_mode);
|
||||
shadow_mode(ed->domain));
|
||||
|
||||
shadow_lock(ed->domain);
|
||||
__shadow_mk_pagetable(ed);
|
||||
@@ -744,13 +720,13 @@ static inline void shadow_mk_pagetable(struct exec_domain *ed)
|
||||
SH_VVLOG("leaving shadow_mk_pagetable:\n"
|
||||
"( gptbase=%08lx, mode=%d ) sh=%08lx",
|
||||
pagetable_val(ed->arch.pagetable),
|
||||
ed->domain->arch.shadow_mode,
|
||||
shadow_mode(ed->domain),
|
||||
pagetable_val(ed->arch.shadow_table) );
|
||||
}
|
||||
}
|
||||
|
||||
#if SHADOW_DEBUG
|
||||
extern int check_pagetable(struct domain *d, pagetable_t pt, char *s);
|
||||
extern void check_pagetable(struct domain *d, pagetable_t pt, char *s);
|
||||
#else
|
||||
#define check_pagetable(d, pt, s) ((void)0)
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
|
||||
|
||||
#ifndef __X86_32_PAGE_H__
|
||||
#define __X86_32_PAGE_H__
|
||||
|
||||
#define L1_PAGETABLE_SHIFT 12
|
||||
#define L2_PAGETABLE_SHIFT 22
|
||||
#define PAGE_SHIFT L1_PAGETABLE_SHIFT
|
||||
|
||||
#define ENTRIES_PER_L1_PAGETABLE 1024
|
||||
#define ENTRIES_PER_L2_PAGETABLE 1024
|
||||
|
||||
#define __PAGE_OFFSET (0xFC400000)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <xen/config.h>
|
||||
typedef struct { unsigned long l1_lo; } l1_pgentry_t;
|
||||
typedef struct { unsigned long l2_lo; } l2_pgentry_t;
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
/* Strip type from a table entry. */
|
||||
#define l1_pgentry_val(_x) ((_x).l1_lo)
|
||||
#define l2_pgentry_val(_x) ((_x).l2_lo)
|
||||
|
||||
/* Add type to a table entry. */
|
||||
#define mk_l1_pgentry(_x) ( (l1_pgentry_t) { (_x) } )
|
||||
#define mk_l2_pgentry(_x) ( (l2_pgentry_t) { (_x) } )
|
||||
|
||||
/* Turn a typed table entry into a physical address. */
|
||||
#define l1_pgentry_to_phys(_x) (l1_pgentry_val(_x) & PAGE_MASK)
|
||||
#define l2_pgentry_to_phys(_x) (l2_pgentry_val(_x) & PAGE_MASK)
|
||||
|
||||
/* Turn a typed table entry into a page index. */
|
||||
#define l1_pgentry_to_pfn(_x) (l1_pgentry_val(_x) >> PAGE_SHIFT)
|
||||
#define l2_pgentry_to_pfn(_x) (l2_pgentry_val(_x) >> PAGE_SHIFT)
|
||||
|
||||
/* Pagetable walking. */
|
||||
#define l2_pgentry_to_l1(_x) \
|
||||
((l1_pgentry_t *)__va(l2_pgentry_to_phys(_x)))
|
||||
|
||||
/* Given a virtual address, get an entry offset into a page table. */
|
||||
#define l1_table_offset(_a) \
|
||||
(((_a) >> L1_PAGETABLE_SHIFT) & (ENTRIES_PER_L1_PAGETABLE - 1))
|
||||
#define l2_table_offset(_a) \
|
||||
((_a) >> L2_PAGETABLE_SHIFT)
|
||||
|
||||
/* Given a virtual address, get an entry offset into a linear page table. */
|
||||
#define l1_linear_offset(_a) ((_a) >> PAGE_SHIFT)
|
||||
|
||||
/* Root page-table definitions. */
|
||||
#define pagetable_t l2_pgentry_t
|
||||
#define pagetable_val(_x) ((_x).l2_lo)
|
||||
#define mk_pagetable(_x) ( (l2_pgentry_t) { (_x) } )
|
||||
#define ENTRIES_PER_PAGETABLE ENTRIES_PER_L2_PAGETABLE
|
||||
|
||||
#endif /* __X86_32_PAGE_H__ */
|
||||
@@ -39,4 +39,6 @@ struct xen_regs
|
||||
#define RING_2(_r) (((_r)->cs & 3) == 2)
|
||||
#define RING_3(_r) (((_r)->cs & 3) == 3)
|
||||
|
||||
#define GUESTOS_FAULT(_r) (!VM86_MODE(_r) && RING_1(_r))
|
||||
|
||||
#endif
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <xen/errno.h>
|
||||
#include <xen/prefetch.h>
|
||||
#include <xen/string.h>
|
||||
#include <xen/sched.h>
|
||||
|
||||
#define __user
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
|
||||
|
||||
#ifndef __X86_64_PAGE_H__
|
||||
#define __X86_64_PAGE_H__
|
||||
|
||||
#define L1_PAGETABLE_SHIFT 12
|
||||
#define L2_PAGETABLE_SHIFT 21
|
||||
#define L3_PAGETABLE_SHIFT 30
|
||||
#define L4_PAGETABLE_SHIFT 39
|
||||
#define PAGE_SHIFT L1_PAGETABLE_SHIFT
|
||||
|
||||
#define ENTRIES_PER_L1_PAGETABLE 512
|
||||
#define ENTRIES_PER_L2_PAGETABLE 512
|
||||
#define ENTRIES_PER_L3_PAGETABLE 512
|
||||
#define ENTRIES_PER_L4_PAGETABLE 512
|
||||
|
||||
#define __PAGE_OFFSET (0xFFFF830000000000)
|
||||
|
||||
/* These may increase in future (phys. bits in particular). */
|
||||
#define PADDR_BITS 40
|
||||
#define VADDR_BITS 48
|
||||
#define PADDR_MASK ((1UL << PADDR_BITS)-1)
|
||||
#define VADDR_MASK ((1UL << VADDR_BITS)-1)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <xen/config.h>
|
||||
typedef struct { unsigned long l1_lo; } l1_pgentry_t;
|
||||
typedef struct { unsigned long l2_lo; } l2_pgentry_t;
|
||||
typedef struct { unsigned long l3_lo; } l3_pgentry_t;
|
||||
typedef struct { unsigned long l4_lo; } l4_pgentry_t;
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
/* Strip type from a table entry. */
|
||||
#define l1_pgentry_val(_x) ((_x).l1_lo)
|
||||
#define l2_pgentry_val(_x) ((_x).l2_lo)
|
||||
#define l3_pgentry_val(_x) ((_x).l3_lo)
|
||||
#define l4_pgentry_val(_x) ((_x).l4_lo)
|
||||
|
||||
/* Add type to a table entry. */
|
||||
#define mk_l1_pgentry(_x) ( (l1_pgentry_t) { (_x) } )
|
||||
#define mk_l2_pgentry(_x) ( (l2_pgentry_t) { (_x) } )
|
||||
#define mk_l3_pgentry(_x) ( (l3_pgentry_t) { (_x) } )
|
||||
#define mk_l4_pgentry(_x) ( (l4_pgentry_t) { (_x) } )
|
||||
|
||||
/* Turn a typed table entry into a physical address. */
|
||||
#define l1_pgentry_to_phys(_x) (l1_pgentry_val(_x) & (PADDR_MASK & PAGE_MASK))
|
||||
#define l2_pgentry_to_phys(_x) (l2_pgentry_val(_x) & (PADDR_MASK & PAGE_MASK))
|
||||
#define l3_pgentry_to_phys(_x) (l3_pgentry_val(_x) & (PADDR_MASK & PAGE_MASK))
|
||||
#define l4_pgentry_to_phys(_x) (l4_pgentry_val(_x) & (PADDR_MASK & PAGE_MASK))
|
||||
|
||||
/* Turn a typed table entry into a page index. */
|
||||
#define l1_pgentry_to_pfn(_x) (l1_pgentry_val(_x) >> PAGE_SHIFT)
|
||||
#define l2_pgentry_to_pfn(_x) (l2_pgentry_val(_x) >> PAGE_SHIFT)
|
||||
#define l3_pgentry_to_pfn(_x) (l3_pgentry_val(_x) >> PAGE_SHIFT)
|
||||
#define l4_pgentry_to_pfn(_x) (l4_pgentry_val(_x) >> PAGE_SHIFT)
|
||||
|
||||
/* Pagetable walking. */
|
||||
#define l2_pgentry_to_l1(_x) \
|
||||
((l1_pgentry_t *)__va(l2_pgentry_to_phys(_x)))
|
||||
#define l3_pgentry_to_l2(_x) \
|
||||
((l2_pgentry_t *)__va(l3_pgentry_to_phys(_x)))
|
||||
#define l4_pgentry_to_l3(_x) \
|
||||
((l3_pgentry_t *)__va(l4_pgentry_to_phys(_x)))
|
||||
|
||||
/* Given a virtual address, get an entry offset into a page table. */
|
||||
#define l1_table_offset(_a) \
|
||||
(((_a) >> L1_PAGETABLE_SHIFT) & (ENTRIES_PER_L1_PAGETABLE - 1))
|
||||
#define l2_table_offset(_a) \
|
||||
(((_a) >> L2_PAGETABLE_SHIFT) & (ENTRIES_PER_L2_PAGETABLE - 1))
|
||||
#define l3_table_offset(_a) \
|
||||
(((_a) >> L3_PAGETABLE_SHIFT) & (ENTRIES_PER_L3_PAGETABLE - 1))
|
||||
#define l4_table_offset(_a) \
|
||||
(((_a) >> L4_PAGETABLE_SHIFT) & (ENTRIES_PER_L4_PAGETABLE - 1))
|
||||
|
||||
/* Given a virtual address, get an entry offset into a linear page table. */
|
||||
#define l1_linear_offset(_a) (((_a) & VADDR_MASK) >> PAGE_SHIFT)
|
||||
|
||||
/* Root page-table definitions. */
|
||||
#define pagetable_t l4_pgentry_t
|
||||
#define pagetable_val(_x) ((_x).l4_lo)
|
||||
#define mk_pagetable(_x) ( (l4_pgentry_t) { (_x) } )
|
||||
#define ENTRIES_PER_PAGETABLE ENTRIES_PER_L4_PAGETABLE
|
||||
|
||||
#endif /* __X86_64_PAGE_H__ */
|
||||
@@ -36,4 +36,6 @@ struct xen_regs
|
||||
#define RING_2(_r) (((_r)->cs & 3) == 2)
|
||||
#define RING_3(_r) (((_r)->cs & 3) == 3)
|
||||
|
||||
#define GUESTOS_FAULT(_r) (!VM86_MODE(_r) && RING_3(_r))
|
||||
|
||||
#endif
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <xen/config.h>
|
||||
#include <xen/compiler.h>
|
||||
#include <xen/errno.h>
|
||||
#include <xen/sched.h>
|
||||
#include <xen/prefetch.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
@@ -16,34 +15,19 @@
|
||||
#define VERIFY_READ 0
|
||||
#define VERIFY_WRITE 1
|
||||
|
||||
#define __addr_ok(addr) ((unsigned long)(addr) < HYPERVISOR_VIRT_START)
|
||||
|
||||
/*
|
||||
* Test whether a block of memory is a valid user space address.
|
||||
* Returns 0 if the range is valid, nonzero otherwise.
|
||||
*
|
||||
* This is equivalent to the following test:
|
||||
* ((u65)addr >= (u65)HYPERVISOR_VIRT_END) ?
|
||||
* (((u65)addr + (u65)size) >= ((u65)1 << 64)) :
|
||||
* (((u65)addr + (u65)size) >= ((u65)HYPERVISOR_VIRT_START))
|
||||
* Valid if in +ve half of 48-bit address space, or above Xen-reserved area.
|
||||
* This is also valid for range checks (addr, addr+size). As long as the
|
||||
* start address is outside the Xen-reserved area then we will access a
|
||||
* non-canonical address (and thus fault) before ever reaching VIRT_START.
|
||||
*/
|
||||
#define __range_not_ok(addr,size) ({ \
|
||||
unsigned long flag,sum; \
|
||||
if ((unsigned long)addr >= HYPERVISOR_VIRT_END) \
|
||||
asm("addq %3,%1 ; sbbq %0,%0" \
|
||||
:"=&r" (flag), "=r" (sum) \
|
||||
:"1" (addr),"g" ((long)(size))); \
|
||||
else \
|
||||
asm("addq %3,%1 ; sbbq %0,%0 ; cmpq %1,%4 ; sbbq $0,%0" \
|
||||
:"=&r" (flag), "=r" (sum) \
|
||||
:"1" (addr),"g" ((long)(size)),"r" (HYPERVISOR_VIRT_START)); \
|
||||
flag; })
|
||||
#define __addr_ok(addr) \
|
||||
(((unsigned long)(addr) < (1UL<<48)) || \
|
||||
((unsigned long)(addr) >= HYPERVISOR_VIRT_END))
|
||||
|
||||
#define access_ok(type, addr, size) (__range_not_ok(addr,size) == 0)
|
||||
#define access_ok(type, addr, size) (__addr_ok(addr))
|
||||
|
||||
#define array_access_ok(type,addr,count,size) \
|
||||
(likely(sizeof(count) <= 4) /* disallow 64-bit counts */ && \
|
||||
access_ok(type,addr,(unsigned long)count*(unsigned long)size))
|
||||
#define array_access_ok(type,addr,count,size) (__addr_ok(addr))
|
||||
|
||||
extern long __get_user_bad(void);
|
||||
extern void __put_user_bad(void);
|
||||
|
||||
@@ -43,11 +43,11 @@
|
||||
*/
|
||||
|
||||
#define FLAT_RING3_CS32 0x0823 /* GDT index 260 */
|
||||
#define FLAT_RING3_CS64 0x082b /* GDT index 261 */
|
||||
#define FLAT_RING3_DS32 0x0833 /* GDT index 262 */
|
||||
#define FLAT_RING3_CS64 0x0833 /* GDT index 261 */
|
||||
#define FLAT_RING3_DS32 0x082b /* GDT index 262 */
|
||||
#define FLAT_RING3_DS64 0x0000 /* NULL selector */
|
||||
#define FLAT_RING3_SS32 0x0833 /* GDT index 262 */
|
||||
#define FLAT_RING3_SS64 0x0833 /* GDT index 262 */
|
||||
#define FLAT_RING3_SS32 0x082b /* GDT index 262 */
|
||||
#define FLAT_RING3_SS64 0x082b /* GDT index 262 */
|
||||
|
||||
#define FLAT_GUESTOS_DS64 FLAT_RING3_DS64
|
||||
#define FLAT_GUESTOS_DS32 FLAT_RING3_DS32
|
||||
|
||||
@@ -23,7 +23,14 @@
|
||||
* XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
|
||||
*/
|
||||
|
||||
/* EAX = vector; EBX, ECX, EDX, ESI, EDI = args 1, 2, 3, 4, 5. */
|
||||
/*
|
||||
* x86_32: EAX = vector; EBX, ECX, EDX, ESI, EDI = args 1, 2, 3, 4, 5.
|
||||
* EAX = return value
|
||||
* (argument registers may be clobbered on return)
|
||||
* x86_64: RAX = vector; RDI, RSI, RDX, R10, R8, R9 = args 1, 2, 3, 4, 5, 6.
|
||||
* RAX = return value
|
||||
* (argument registers not clobbered on return; RCX, R11 are)
|
||||
*/
|
||||
#define __HYPERVISOR_set_trap_table 0
|
||||
#define __HYPERVISOR_mmu_update 1
|
||||
#define __HYPERVISOR_set_gdt 2
|
||||
|
||||
@@ -100,17 +100,13 @@ extern int allocate_resource(struct resource *root, struct resource *new,
|
||||
#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name))
|
||||
#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))
|
||||
|
||||
extern struct resource * __request_region(struct resource *, unsigned long start, unsigned long n, const char *name);
|
||||
|
||||
/* Compatibility cruft */
|
||||
#define check_region(start,n) __check_region(&ioport_resource, (start), (n))
|
||||
#define release_region(start,n) __release_region(&ioport_resource, (start), (n))
|
||||
#define check_mem_region(start,n) __check_region(&iomem_resource, (start), (n))
|
||||
#define release_mem_region(start,n) __release_region(&iomem_resource, (start), (n))
|
||||
|
||||
extern int __check_region(struct resource *, unsigned long, unsigned long);
|
||||
extern void __release_region(struct resource *, unsigned long, unsigned long);
|
||||
|
||||
extern struct resource * __request_region(struct resource *, unsigned long start, unsigned long n, const char *name);
|
||||
|
||||
#define get_ioport_list(buf) get_resource_list(&ioport_resource, buf, PAGE_SIZE)
|
||||
#define get_mem_list(buf) get_resource_list(&iomem_resource, buf, PAGE_SIZE)
|
||||
|
||||
|
||||
+25
-1
@@ -262,8 +262,32 @@ int idle_cpu(int cpu); /* Is CPU 'cpu' idle right now? */
|
||||
|
||||
void startup_cpu_idle_loop(void);
|
||||
|
||||
unsigned long hypercall_create_continuation(
|
||||
unsigned long __hypercall_create_continuation(
|
||||
unsigned int op, unsigned int nr_args, ...);
|
||||
#define hypercall0_create_continuation(_op) \
|
||||
__hypercall_create_continuation((_op), 0)
|
||||
#define hypercall1_create_continuation(_op, _a1) \
|
||||
__hypercall_create_continuation((_op), 1, \
|
||||
(unsigned long)(_a1))
|
||||
#define hypercall2_create_continuation(_op, _a1, _a2) \
|
||||
__hypercall_create_continuation((_op), 2, \
|
||||
(unsigned long)(_a1), (unsigned long)(_a2))
|
||||
#define hypercall3_create_continuation(_op, _a1, _a2, _a3) \
|
||||
__hypercall_create_continuation((_op), 3, \
|
||||
(unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3))
|
||||
#define hypercall4_create_continuation(_op, _a1, _a2, _a3, _a4) \
|
||||
__hypercall_create_continuation((_op), 4, \
|
||||
(unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3), \
|
||||
(unsigned long)(_a4))
|
||||
#define hypercall5_create_continuation(_op, _a1, _a2, _a3, _a4, _a5) \
|
||||
__hypercall_create_continuation((_op), 5, \
|
||||
(unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3), \
|
||||
(unsigned long)(_a4), (unsigned long)(_a5))
|
||||
#define hypercall6_create_continuation(_op, _a1, _a2, _a3, _a4, _a5, _a6) \
|
||||
__hypercall_create_continuation((_op), 6, \
|
||||
(unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3), \
|
||||
(unsigned long)(_a4), (unsigned long)(_a5), (unsigned long)(_a6))
|
||||
|
||||
#define hypercall_preempt_check() \
|
||||
(unlikely(softirq_pending(smp_processor_id())))
|
||||
|
||||
|
||||