mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
Merge latest xen-unstable into xen-ia64-unstable
This commit is contained in:
commit
72f6940bc6
74 files changed
+4332
-3290
No files matched your search
@@ -164,7 +164,7 @@ help:
|
||||
uninstall: DESTDIR=
|
||||
uninstall: D=$(DESTDIR)
|
||||
uninstall:
|
||||
[ -d $(D)/etc/xen ] && mv -f $(D)/etc/xen $(D)/etc/xen.old-`date +%s`
|
||||
[ -d $(D)/etc/xen ] && mv -f $(D)/etc/xen $(D)/etc/xen.old-`date +%s` || true
|
||||
rm -rf $(D)/etc/init.d/xend*
|
||||
rm -rf $(D)/etc/hotplug/xen-backend.agent
|
||||
rm -rf $(D)/var/run/xen* $(D)/var/lib/xen*
|
||||
|
||||
@@ -21,6 +21,9 @@ required if you wish to build from source.
|
||||
\item [$\dag$] The \path{iproute2} package.
|
||||
\item [$\dag$] The Linux bridge-utils\footnote{Available from {\tt
|
||||
http://bridge.sourceforge.net}} (e.g., \path{/sbin/brctl})
|
||||
\item [$\dag$] The Linux hotplug system\footnote{Available from {\tt
|
||||
http://linux-hotplug.sourceforge.net/}} (e.g., \path{/sbin/hotplug}
|
||||
and related scripts)
|
||||
\item [$\dag$] An installation of Twisted~v1.3 or
|
||||
above\footnote{Available from {\tt http://www.twistedmatrix.com}}.
|
||||
There may be a binary package available for your distribution;
|
||||
|
||||
@@ -1394,9 +1394,7 @@ static void handle_vcpu_hotplug_event(struct xenbus_watch *watch, const char *no
|
||||
return;
|
||||
|
||||
/* get the state value */
|
||||
xenbus_transaction_start("cpu");
|
||||
err = xenbus_scanf(dir, "availability", "%s", state);
|
||||
xenbus_transaction_end(0);
|
||||
|
||||
if (err != 1) {
|
||||
printk(KERN_ERR
|
||||
|
||||
@@ -324,7 +324,7 @@ static void shutdown_handler(struct xenbus_watch *watch, const char *node)
|
||||
int err;
|
||||
|
||||
again:
|
||||
err = xenbus_transaction_start("control");
|
||||
err = xenbus_transaction_start();
|
||||
if (err)
|
||||
return;
|
||||
str = (char *)xenbus_read("control", "shutdown", NULL);
|
||||
@@ -337,7 +337,7 @@ static void shutdown_handler(struct xenbus_watch *watch, const char *node)
|
||||
xenbus_write("control", "shutdown", "");
|
||||
|
||||
err = xenbus_transaction_end(0);
|
||||
if (err == -ETIMEDOUT) {
|
||||
if (err == -EAGAIN) {
|
||||
kfree(str);
|
||||
goto again;
|
||||
}
|
||||
@@ -366,7 +366,7 @@ static void sysrq_handler(struct xenbus_watch *watch, const char *node)
|
||||
int err;
|
||||
|
||||
again:
|
||||
err = xenbus_transaction_start("control");
|
||||
err = xenbus_transaction_start();
|
||||
if (err)
|
||||
return;
|
||||
if (!xenbus_scanf("control", "sysrq", "%c", &sysrq_key)) {
|
||||
@@ -379,7 +379,7 @@ static void sysrq_handler(struct xenbus_watch *watch, const char *node)
|
||||
xenbus_printf("control", "sysrq", "%c", '\0');
|
||||
|
||||
err = xenbus_transaction_end(0);
|
||||
if (err == -ETIMEDOUT)
|
||||
if (err == -EAGAIN)
|
||||
goto again;
|
||||
|
||||
if (sysrq_key != '\0') {
|
||||
|
||||
@@ -80,8 +80,9 @@ static void frontend_changed(struct xenbus_watch *watch, const char *node)
|
||||
return;
|
||||
}
|
||||
|
||||
again:
|
||||
/* Supply the information about the device the frontend needs */
|
||||
err = xenbus_transaction_start(be->dev->nodename);
|
||||
err = xenbus_transaction_start();
|
||||
if (err) {
|
||||
xenbus_dev_error(be->dev, err, "starting transaction");
|
||||
return;
|
||||
@@ -119,7 +120,15 @@ static void frontend_changed(struct xenbus_watch *watch, const char *node)
|
||||
goto abort;
|
||||
}
|
||||
|
||||
xenbus_transaction_end(0);
|
||||
err = xenbus_transaction_end(0);
|
||||
if (err == -EAGAIN)
|
||||
goto again;
|
||||
if (err) {
|
||||
xenbus_dev_error(be->dev, err, "ending transaction",
|
||||
ring_ref, evtchn);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
xenbus_dev_ok(be->dev);
|
||||
|
||||
return;
|
||||
|
||||
@@ -572,7 +572,8 @@ static int talk_to_backend(struct xenbus_device *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = xenbus_transaction_start(dev->nodename);
|
||||
again:
|
||||
err = xenbus_transaction_start();
|
||||
if (err) {
|
||||
xenbus_dev_error(dev, err, "starting transaction");
|
||||
goto destroy_blkring;
|
||||
@@ -603,6 +604,8 @@ static int talk_to_backend(struct xenbus_device *dev,
|
||||
|
||||
err = xenbus_transaction_end(0);
|
||||
if (err) {
|
||||
if (err == -EAGAIN)
|
||||
goto again;
|
||||
xenbus_dev_error(dev, err, "completing transaction");
|
||||
goto destroy_blkring;
|
||||
}
|
||||
|
||||
@@ -1122,7 +1122,8 @@ static int talk_to_backend(struct xenbus_device *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = xenbus_transaction_start(dev->nodename);
|
||||
again:
|
||||
err = xenbus_transaction_start();
|
||||
if (err) {
|
||||
xenbus_dev_error(dev, err, "starting transaction");
|
||||
goto destroy_ring;
|
||||
@@ -1160,6 +1161,8 @@ static int talk_to_backend(struct xenbus_device *dev,
|
||||
|
||||
err = xenbus_transaction_end(0);
|
||||
if (err) {
|
||||
if (err == -EAGAIN)
|
||||
goto again;
|
||||
xenbus_dev_error(dev, err, "completing transaction");
|
||||
goto destroy_ring;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,8 @@ static void frontend_changed(struct xenbus_watch *watch, const char *node)
|
||||
* Tell the front-end that we are ready to go -
|
||||
* unless something bad happens
|
||||
*/
|
||||
err = xenbus_transaction_start(be->dev->nodename);
|
||||
again:
|
||||
err = xenbus_transaction_start();
|
||||
if (err) {
|
||||
xenbus_dev_error(be->dev, err, "starting transaction");
|
||||
return;
|
||||
@@ -127,7 +128,14 @@ static void frontend_changed(struct xenbus_watch *watch, const char *node)
|
||||
goto abort;
|
||||
}
|
||||
|
||||
xenbus_transaction_end(0);
|
||||
err = xenbus_transaction_end(0);
|
||||
if (err == -EAGAIN)
|
||||
goto again;
|
||||
if (err) {
|
||||
xenbus_dev_error(be->dev, err, "end of transaction");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
xenbus_dev_ok(be->dev);
|
||||
return;
|
||||
abort:
|
||||
|
||||
@@ -331,7 +331,8 @@ static int talk_to_backend(struct xenbus_device *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = xenbus_transaction_start(dev->nodename);
|
||||
again:
|
||||
err = xenbus_transaction_start();
|
||||
if (err) {
|
||||
xenbus_dev_error(dev, err, "starting transaction");
|
||||
goto destroy_tpmring;
|
||||
@@ -363,6 +364,8 @@ static int talk_to_backend(struct xenbus_device *dev,
|
||||
}
|
||||
|
||||
err = xenbus_transaction_end(0);
|
||||
if (err == -EAGAIN)
|
||||
goto again;
|
||||
if (err) {
|
||||
xenbus_dev_error(dev, err, "completing transaction");
|
||||
goto destroy_tpmring;
|
||||
|
||||
@@ -287,12 +287,11 @@ EXPORT_SYMBOL(xenbus_rm);
|
||||
|
||||
/* Start a transaction: changes by others will not be seen during this
|
||||
* transaction, and changes will not be visible to others until end.
|
||||
* Transaction only applies to the given subtree.
|
||||
* You can only have one transaction at any time.
|
||||
*/
|
||||
int xenbus_transaction_start(const char *subtree)
|
||||
int xenbus_transaction_start(void)
|
||||
{
|
||||
return xs_error(xs_single(XS_TRANSACTION_START, subtree, NULL));
|
||||
return xs_error(xs_single(XS_TRANSACTION_START, "", NULL));
|
||||
}
|
||||
EXPORT_SYMBOL(xenbus_transaction_start);
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ int xenbus_write(const char *dir, const char *node, const char *string);
|
||||
int xenbus_mkdir(const char *dir, const char *node);
|
||||
int xenbus_exists(const char *dir, const char *node);
|
||||
int xenbus_rm(const char *dir, const char *node);
|
||||
int xenbus_transaction_start(const char *subtree);
|
||||
int xenbus_transaction_start(void);
|
||||
int xenbus_transaction_end(int abort);
|
||||
|
||||
/* Single read and scanf: returns -errno or num scanned if > 0. */
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
# CHECK-INSTALL
|
||||
|
||||
function error {
|
||||
echo
|
||||
echo ' *** Check for the hotplug scripts (hotplug) FAILED'
|
||||
exit 1
|
||||
}
|
||||
|
||||
which hotplug 1>/dev/null 2>&1 || error
|
||||
+1
-15
@@ -25,19 +25,13 @@ XEN_SCRIPTS += block-phy
|
||||
XEN_SCRIPTS += block-file
|
||||
XEN_SCRIPTS += block-enbd
|
||||
|
||||
# no 64-bit specifics in mem-map.sxp
|
||||
# so place in /usr/lib, not /usr/lib64
|
||||
XEN_BOOT_DIR = /usr/lib/xen/boot
|
||||
XEN_BOOT = mem-map.sxp
|
||||
|
||||
XEN_HOTPLUG_DIR = /etc/hotplug
|
||||
XEN_HOTPLUG_SCRIPTS = xen-backend.agent
|
||||
|
||||
all:
|
||||
build:
|
||||
|
||||
install: all install-initd install-configs install-scripts install-boot \
|
||||
install-hotplug
|
||||
install: all install-initd install-configs install-scripts install-hotplug
|
||||
|
||||
install-initd:
|
||||
[ -d $(DESTDIR)/etc/init.d ] || $(INSTALL_DIR) $(DESTDIR)/etc/init.d
|
||||
@@ -62,14 +56,6 @@ install-scripts:
|
||||
$(INSTALL_PROG) $$i $(DESTDIR)$(XEN_SCRIPT_DIR); \
|
||||
done
|
||||
|
||||
install-boot:
|
||||
[ -d $(DESTDIR)$(XEN_BOOT_DIR) ] || \
|
||||
$(INSTALL_DIR) $(DESTDIR)$(XEN_BOOT_DIR)
|
||||
for i in $(XEN_BOOT); \
|
||||
do [ -a $(DESTDIR)$(XEN_BOOT_DIR)/$$i ] || \
|
||||
$(INSTALL_PROG) $$i $(DESTDIR)$(XEN_BOOT_DIR); \
|
||||
done
|
||||
|
||||
install-hotplug:
|
||||
[ -d $(DESTDIR)$(XEN_HOTPLUG_DIR) ] || \
|
||||
$(INSTALL_DIR) $(DESTDIR)$(XEN_HOTPLUG_DIR)
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
(memmap
|
||||
(0000000000000000 000000000009f800 "AddressRangeMemory" WB)
|
||||
(000000000009f800 00000000000a0000 "AddressRangeReserved" UC)
|
||||
(00000000000a0000 00000000000bffff "AddressRangeIO" UC)
|
||||
(00000000000f0000 0000000000100000 "AddressRangeReserved" UC)
|
||||
(0000000000100000 0000000008000000 "AddressRangeMemory" WB)
|
||||
(0000000007fff000 0000000008000000 "AddressRangeShared" WB)
|
||||
(0000000008000000 0000000008003000 "AddressRangeNVS" UC)
|
||||
(0000000008003000 000000000800d000 "AddressRangeACPI" WB)
|
||||
(00000000fec00000 0000000100000000 "AddressRangeIO" UC))
|
||||
@@ -60,9 +60,6 @@ disk = [ 'file:/var/images/min-el3-i386.img,ioemu:hda,w' ]
|
||||
# New stuff
|
||||
device_model = '/usr/' + arch_libdir + '/xen/bin/qemu-dm'
|
||||
|
||||
# Advanced users only. Don't touch if you don't know what you're doing
|
||||
memmap = '/usr/lib/xen/boot/mem-map.sxp'
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Disk image for
|
||||
#cdrom=
|
||||
|
||||
@@ -44,7 +44,7 @@ all: vmxloader
|
||||
vmxloader: roms.h vmxloader.c acpi.h acpi_madt.c
|
||||
${CC} ${CFLAGS} ${DEFINES} -c vmxloader.c -c acpi_madt.c
|
||||
$(CC) -o vmxloader.tmp -m32 -nostdlib -Wl,-N -Wl,-Ttext -Wl,0x100000 vmxloader.o acpi_madt.o
|
||||
objcopy --change-addresses=0xC0000000 vmxloader.tmp vmxloader
|
||||
objcopy vmxloader.tmp vmxloader
|
||||
rm -f vmxloader.tmp
|
||||
|
||||
vmxassist.bin: vmxassist.ld ${OBJECTS}
|
||||
|
||||
@@ -34,28 +34,39 @@ int acpi_madt_update(unsigned char* acpi_start);
|
||||
/*
|
||||
* C runtime start off
|
||||
*/
|
||||
asm(" \n\
|
||||
.text \n\
|
||||
.globl _start \n\
|
||||
_start: \n\
|
||||
cli \n\
|
||||
movl $stack_top, %esp \n\
|
||||
movl %esp, %ebp \n\
|
||||
call main \n\
|
||||
jmp halt \n\
|
||||
\n\
|
||||
.globl halt \n\
|
||||
halt: \n\
|
||||
sti \n\
|
||||
jmp . \n\
|
||||
\n\
|
||||
.bss \n\
|
||||
.align 8 \n\
|
||||
.globl stack, stack_top \n\
|
||||
stack: \n\
|
||||
.skip 0x4000 \n\
|
||||
stack_top: \n\
|
||||
");
|
||||
asm(
|
||||
" .text \n"
|
||||
" .globl _start \n"
|
||||
"_start: \n"
|
||||
" cld \n"
|
||||
" cli \n"
|
||||
" lgdt gdt_desr \n"
|
||||
" movl $stack_top, %esp \n"
|
||||
" movl %esp, %ebp \n"
|
||||
" call main \n"
|
||||
" jmp halt \n"
|
||||
" \n"
|
||||
"gdt_desr: \n"
|
||||
" .word gdt_end - gdt - 1 \n"
|
||||
" .long gdt \n"
|
||||
" \n"
|
||||
" .align 8 \n"
|
||||
"gdt: \n"
|
||||
" .quad 0x0000000000000000 \n"
|
||||
" .quad 0x00CF92000000FFFF \n"
|
||||
" .quad 0x00CF9A000000FFFF \n"
|
||||
"gdt_end: \n"
|
||||
" \n"
|
||||
"halt: \n"
|
||||
" sti \n"
|
||||
" jmp . \n"
|
||||
" \n"
|
||||
" .bss \n"
|
||||
" .align 8 \n"
|
||||
"stack: \n"
|
||||
" .skip 0x4000 \n"
|
||||
"stack_top: \n"
|
||||
);
|
||||
|
||||
void *
|
||||
memcpy(void *dest, const void *src, unsigned n)
|
||||
@@ -95,7 +106,7 @@ cirrus_check(void)
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
main(void)
|
||||
{
|
||||
puts("VMXAssist Loader\n");
|
||||
puts("Loading ROMBIOS ...\n");
|
||||
|
||||
@@ -231,6 +231,8 @@ typedef struct CirrusVGAState {
|
||||
int cirrus_linear_io_addr;
|
||||
int cirrus_linear_bitblt_io_addr;
|
||||
int cirrus_mmio_io_addr;
|
||||
unsigned long cirrus_lfb_addr;
|
||||
unsigned long cirrus_lfb_end;
|
||||
uint32_t cirrus_addr_mask;
|
||||
uint32_t linear_mmio_mask;
|
||||
uint8_t cirrus_shadow_gr0;
|
||||
@@ -2447,6 +2449,10 @@ static void cirrus_update_memory_access(CirrusVGAState *s)
|
||||
{
|
||||
unsigned mode;
|
||||
|
||||
extern void unset_vram_mapping(unsigned long addr, unsigned long end);
|
||||
extern void set_vram_mapping(unsigned long addr, unsigned long end);
|
||||
extern int vga_accelerate;
|
||||
|
||||
if ((s->sr[0x17] & 0x44) == 0x44) {
|
||||
goto generic_io;
|
||||
} else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
|
||||
@@ -2454,17 +2460,21 @@ static void cirrus_update_memory_access(CirrusVGAState *s)
|
||||
} else {
|
||||
if ((s->gr[0x0B] & 0x14) == 0x14) {
|
||||
goto generic_io;
|
||||
} else if (s->gr[0x0B] & 0x02) {
|
||||
goto generic_io;
|
||||
}
|
||||
|
||||
mode = s->gr[0x05] & 0x7;
|
||||
if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
|
||||
} else if (s->gr[0x0B] & 0x02) {
|
||||
goto generic_io;
|
||||
}
|
||||
|
||||
mode = s->gr[0x05] & 0x7;
|
||||
if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
|
||||
if (vga_accelerate && s->cirrus_lfb_addr && s->cirrus_lfb_end)
|
||||
set_vram_mapping(s->cirrus_lfb_addr, s->cirrus_lfb_end);
|
||||
s->cirrus_linear_write[0] = cirrus_linear_mem_writeb;
|
||||
s->cirrus_linear_write[1] = cirrus_linear_mem_writew;
|
||||
s->cirrus_linear_write[2] = cirrus_linear_mem_writel;
|
||||
} else {
|
||||
generic_io:
|
||||
if (vga_accelerate && s->cirrus_lfb_addr && s->cirrus_lfb_end)
|
||||
unset_vram_mapping(s->cirrus_lfb_addr, s->cirrus_lfb_end);
|
||||
s->cirrus_linear_write[0] = cirrus_linear_writeb;
|
||||
s->cirrus_linear_write[1] = cirrus_linear_writew;
|
||||
s->cirrus_linear_write[2] = cirrus_linear_writel;
|
||||
@@ -3058,6 +3068,8 @@ static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
|
||||
/* XXX: add byte swapping apertures */
|
||||
cpu_register_physical_memory(addr, s->vram_size,
|
||||
s->cirrus_linear_io_addr);
|
||||
s->cirrus_lfb_addr = addr;
|
||||
s->cirrus_lfb_end = addr + VGA_RAM_SIZE;
|
||||
cpu_register_physical_memory(addr + 0x1000000, 0x400000,
|
||||
s->cirrus_linear_bitblt_io_addr);
|
||||
}
|
||||
|
||||
+4
-3
@@ -385,6 +385,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
unsigned long bios_offset, vga_bios_offset;
|
||||
int bios_size, isa_bios_size;
|
||||
PCIBus *pci_bus;
|
||||
extern void * shared_vram;
|
||||
|
||||
linux_boot = (kernel_filename != NULL);
|
||||
|
||||
@@ -511,14 +512,14 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
if (cirrus_vga_enabled) {
|
||||
if (pci_enabled) {
|
||||
pci_cirrus_vga_init(pci_bus,
|
||||
ds, phys_ram_base + ram_size, ram_size,
|
||||
ds, shared_vram, ram_size,
|
||||
vga_ram_size);
|
||||
} else {
|
||||
isa_cirrus_vga_init(ds, phys_ram_base + ram_size, ram_size,
|
||||
isa_cirrus_vga_init(ds, shared_vram, ram_size,
|
||||
vga_ram_size);
|
||||
}
|
||||
} else {
|
||||
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
|
||||
vga_initialize(pci_bus, ds, shared_vram, ram_size,
|
||||
vga_ram_size);
|
||||
}
|
||||
|
||||
|
||||
@@ -1568,6 +1568,8 @@ void vga_update_display(void)
|
||||
s->graphic_mode = graphic_mode;
|
||||
full_update = 1;
|
||||
}
|
||||
|
||||
full_update = 1;
|
||||
switch(graphic_mode) {
|
||||
case GMODE_TEXT:
|
||||
vga_draw_text(s, full_update);
|
||||
@@ -1848,6 +1850,7 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
|
||||
unsigned long vga_ram_offset, int vga_ram_size)
|
||||
{
|
||||
int i, j, v, b;
|
||||
extern void* shared_vram;
|
||||
|
||||
for(i = 0;i < 256; i++) {
|
||||
v = 0;
|
||||
@@ -1876,7 +1879,7 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
|
||||
|
||||
/* qemu's vga mem is not detached from phys_ram_base and can cause DM abort
|
||||
* when guest write vga mem, so allocate a new one */
|
||||
s->vram_ptr = qemu_mallocz(vga_ram_size);
|
||||
s->vram_ptr = shared_vram;
|
||||
|
||||
s->vram_offset = vga_ram_offset;
|
||||
s->vram_size = vga_ram_size;
|
||||
|
||||
@@ -54,6 +54,8 @@
|
||||
#include "exec-all.h"
|
||||
#include "vl.h"
|
||||
|
||||
void *shared_vram;
|
||||
|
||||
shared_iopage_t *shared_page = NULL;
|
||||
extern int reset_requested;
|
||||
|
||||
|
||||
+240
-7
@@ -134,6 +134,7 @@ int pci_enabled = 1;
|
||||
int prep_enabled = 0;
|
||||
int rtc_utc = 1;
|
||||
int cirrus_vga_enabled = 1;
|
||||
int vga_accelerate = 1;
|
||||
int graphic_width = 800;
|
||||
int graphic_height = 600;
|
||||
int graphic_depth = 15;
|
||||
@@ -141,6 +142,12 @@ int full_screen = 0;
|
||||
TextConsole *vga_console;
|
||||
CharDriverState *serial_hds[MAX_SERIAL_PORTS];
|
||||
int xc_handle;
|
||||
unsigned long *vgapage_array;
|
||||
unsigned long *freepage_array;
|
||||
unsigned long free_pages;
|
||||
void *vtop_table;
|
||||
unsigned long toptab;
|
||||
unsigned long vgaram_pages;
|
||||
|
||||
/***********************************************************/
|
||||
/* x86 ISA bus support */
|
||||
@@ -2162,6 +2169,7 @@ void help(void)
|
||||
"-isa simulate an ISA-only system (default is PCI system)\n"
|
||||
"-std-vga simulate a standard VGA card with VESA Bochs Extensions\n"
|
||||
" (default is CL-GD5446 PCI VGA)\n"
|
||||
"-vgaacc [0|1] 1 to accelerate CL-GD5446 speed, default is 1\n"
|
||||
#endif
|
||||
"-loadvm file start right away with a saved state (loadvm in monitor)\n"
|
||||
"\n"
|
||||
@@ -2251,6 +2259,7 @@ enum {
|
||||
QEMU_OPTION_serial,
|
||||
QEMU_OPTION_loadvm,
|
||||
QEMU_OPTION_full_screen,
|
||||
QEMU_OPTION_vgaacc,
|
||||
};
|
||||
|
||||
typedef struct QEMUOption {
|
||||
@@ -2327,6 +2336,7 @@ const QEMUOption qemu_options[] = {
|
||||
{ "pci", 0, QEMU_OPTION_pci },
|
||||
{ "nic-pcnet", 0, QEMU_OPTION_nic_pcnet },
|
||||
{ "cirrusvga", 0, QEMU_OPTION_cirrusvga },
|
||||
{ "vgaacc", HAS_ARG, QEMU_OPTION_vgaacc },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
@@ -2343,6 +2353,177 @@ static uint8_t *signal_stack;
|
||||
#define NET_IF_USER 1
|
||||
#define NET_IF_DUMMY 2
|
||||
|
||||
#include <xg_private.h>
|
||||
|
||||
#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
|
||||
#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
|
||||
|
||||
#ifdef __i386__
|
||||
#define _LEVEL_3_ 0
|
||||
#else
|
||||
#define _LEVEL_3_ 1
|
||||
#endif
|
||||
|
||||
#if _LEVEL_3_
|
||||
#define L3_PROT (_PAGE_PRESENT)
|
||||
#define L1_PAGETABLE_ENTRIES 512
|
||||
#else
|
||||
#define L1_PAGETABLE_ENTRIES 1024
|
||||
#endif
|
||||
|
||||
inline int
|
||||
get_vl2_table(unsigned long count, unsigned long start)
|
||||
{
|
||||
#if _LEVEL_3_
|
||||
return ((start + (count << PAGE_SHIFT)) >> L3_PAGETABLE_SHIFT) & 0x3;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
setup_mapping(int xc_handle, u32 dom, unsigned long toptab, unsigned long *mem_page_array, unsigned long *page_table_array, unsigned long v_start, unsigned long v_end)
|
||||
{
|
||||
l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
|
||||
l2_pgentry_t *vl2tab[4], *vl2e=NULL, *vl2_table = NULL;
|
||||
unsigned long l1tab;
|
||||
unsigned long ppt_alloc = 0;
|
||||
unsigned long count;
|
||||
int i = 0;
|
||||
#if _LEVEL_3_
|
||||
l3_pgentry_t *vl3tab = NULL;
|
||||
unsigned long l2tab;
|
||||
if ( (vl3tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
toptab >> PAGE_SHIFT)) == NULL )
|
||||
goto error_out;
|
||||
for (i = 0; i < 4 ; i++) {
|
||||
l2tab = vl3tab[i] & PAGE_MASK;
|
||||
vl2tab[i] = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
l2tab >> PAGE_SHIFT);
|
||||
if(vl2tab[i] == NULL)
|
||||
goto error_out;
|
||||
}
|
||||
munmap(vl3tab, PAGE_SIZE);
|
||||
vl3tab = NULL;
|
||||
#else
|
||||
if ( (vl2tab[0] = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
toptab >> PAGE_SHIFT)) == NULL )
|
||||
goto error_out;
|
||||
#endif
|
||||
|
||||
for ( count = 0; count < ((v_end-v_start)>>PAGE_SHIFT); count++ )
|
||||
{
|
||||
if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
|
||||
{
|
||||
vl2_table = vl2tab[get_vl2_table(count, v_start)];
|
||||
vl2e = &vl2_table[l2_table_offset(
|
||||
v_start + (count << PAGE_SHIFT))];
|
||||
|
||||
l1tab = page_table_array[ppt_alloc++] << PAGE_SHIFT;
|
||||
if ( vl1tab != NULL )
|
||||
munmap(vl1tab, PAGE_SIZE);
|
||||
|
||||
if ( (vl1tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
l1tab >> PAGE_SHIFT)) == NULL )
|
||||
{
|
||||
goto error_out;
|
||||
}
|
||||
memset(vl1tab, 0, PAGE_SIZE);
|
||||
vl1e = &vl1tab[l1_table_offset(v_start + (count<<PAGE_SHIFT))];
|
||||
*vl2e = l1tab | L2_PROT;
|
||||
}
|
||||
|
||||
*vl1e = (mem_page_array[count] << PAGE_SHIFT) | L1_PROT;
|
||||
vl1e++;
|
||||
}
|
||||
error_out:
|
||||
if(vl1tab) munmap(vl1tab, PAGE_SIZE);
|
||||
for(i = 0; i < 4; i++)
|
||||
if(vl2tab[i]) munmap(vl2tab[i], PAGE_SIZE);
|
||||
return ppt_alloc;
|
||||
}
|
||||
|
||||
void
|
||||
unsetup_mapping(int xc_handle, u32 dom, unsigned long toptab, unsigned long v_start, unsigned long v_end)
|
||||
{
|
||||
l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
|
||||
l2_pgentry_t *vl2tab[4], *vl2e=NULL, *vl2_table = NULL;
|
||||
unsigned long l1tab;
|
||||
unsigned long count;
|
||||
int i = 0;
|
||||
#if _LEVEL_3_
|
||||
l3_pgentry_t *vl3tab = NULL;
|
||||
unsigned long l2tab;
|
||||
if ( (vl3tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
toptab >> PAGE_SHIFT)) == NULL )
|
||||
goto error_out;
|
||||
for (i = 0; i < 4 ; i ++){
|
||||
l2tab = vl3tab[i] & PAGE_MASK;
|
||||
vl2tab[i] = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
l2tab >> PAGE_SHIFT);
|
||||
if(vl2tab[i] == NULL)
|
||||
goto error_out;
|
||||
}
|
||||
munmap(vl3tab, PAGE_SIZE);
|
||||
vl3tab = NULL;
|
||||
#else
|
||||
if ( (vl2tab[0] = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
toptab >> PAGE_SHIFT)) == NULL )
|
||||
goto error_out;
|
||||
#endif
|
||||
|
||||
for ( count = 0; count < ((v_end-v_start)>>PAGE_SHIFT); count++ ){
|
||||
if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
|
||||
{
|
||||
vl2_table = vl2tab[get_vl2_table(count, v_start)];
|
||||
vl2e = &vl2_table[l2_table_offset(v_start + (count << PAGE_SHIFT))];
|
||||
l1tab = *vl2e & PAGE_MASK;
|
||||
|
||||
if(l1tab == 0)
|
||||
continue;
|
||||
if ( vl1tab != NULL )
|
||||
munmap(vl1tab, PAGE_SIZE);
|
||||
|
||||
if ( (vl1tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
l1tab >> PAGE_SHIFT)) == NULL )
|
||||
{
|
||||
goto error_out;
|
||||
}
|
||||
vl1e = &vl1tab[l1_table_offset(v_start + (count<<PAGE_SHIFT))];
|
||||
*vl2e = 0;
|
||||
}
|
||||
|
||||
*vl1e = 0;
|
||||
vl1e++;
|
||||
}
|
||||
error_out:
|
||||
if(vl1tab) munmap(vl1tab, PAGE_SIZE);
|
||||
for(i = 0; i < 4; i++)
|
||||
if(vl2tab[i]) munmap(vl2tab[i], PAGE_SIZE);
|
||||
}
|
||||
|
||||
void set_vram_mapping(unsigned long addr, unsigned long end)
|
||||
{
|
||||
end = addr + VGA_RAM_SIZE;
|
||||
setup_mapping(xc_handle, domid, toptab,
|
||||
vgapage_array, freepage_array, addr, end);
|
||||
}
|
||||
|
||||
void unset_vram_mapping(unsigned long addr, unsigned long end)
|
||||
{
|
||||
end = addr + VGA_RAM_SIZE;
|
||||
/* FIXME Flush the shadow page */
|
||||
unsetup_mapping(xc_handle, domid, toptab, addr, end);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifdef CONFIG_GDBSTUB
|
||||
@@ -2366,8 +2547,9 @@ int main(int argc, char **argv)
|
||||
char serial_devices[MAX_SERIAL_PORTS][128];
|
||||
int serial_device_index;
|
||||
const char *loadvm = NULL;
|
||||
unsigned long nr_pages, *page_array;
|
||||
unsigned long nr_pages, extra_pages, ram_pages, *page_array;
|
||||
extern void *shared_page;
|
||||
extern void *shared_vram;
|
||||
/* change the qemu-dm to daemon, just like bochs dm */
|
||||
// daemon(0, 0);
|
||||
|
||||
@@ -2674,6 +2856,17 @@ int main(int argc, char **argv)
|
||||
case QEMU_OPTION_cirrusvga:
|
||||
cirrus_vga_enabled = 1;
|
||||
break;
|
||||
case QEMU_OPTION_vgaacc:
|
||||
{
|
||||
const char *p;
|
||||
p = optarg;
|
||||
vga_accelerate = strtol(p, (char **)&p, 0);
|
||||
if (*p != '\0') {
|
||||
fprintf(stderr, "qemu: invalid vgaacc option\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEMU_OPTION_std_vga:
|
||||
cirrus_vga_enabled = 0;
|
||||
break;
|
||||
@@ -2803,12 +2996,25 @@ int main(int argc, char **argv)
|
||||
/* init the memory */
|
||||
phys_ram_size = ram_size + vga_ram_size + bios_size;
|
||||
|
||||
#define PAGE_SHIFT 12
|
||||
#define PAGE_SIZE (1 << PAGE_SHIFT)
|
||||
ram_pages = ram_size/PAGE_SIZE;
|
||||
vgaram_pages = (vga_ram_size -1)/PAGE_SIZE + 1;
|
||||
free_pages = vgaram_pages / L1_PAGETABLE_ENTRIES;
|
||||
extra_pages = vgaram_pages + free_pages;
|
||||
|
||||
nr_pages = ram_size/PAGE_SIZE;
|
||||
xc_handle = xc_interface_open();
|
||||
|
||||
|
||||
xc_dominfo_t info;
|
||||
xc_domain_getinfo(xc_handle, domid, 1, &info);
|
||||
|
||||
nr_pages = info.nr_pages + extra_pages;
|
||||
|
||||
if ( xc_domain_setmaxmem(xc_handle, domid,
|
||||
(nr_pages) * PAGE_SIZE/1024 ) != 0)
|
||||
{
|
||||
perror("set maxmem");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if ( (page_array = (unsigned long *)
|
||||
malloc(nr_pages * sizeof(unsigned long))) == NULL)
|
||||
{
|
||||
@@ -2816,6 +3022,12 @@ int main(int argc, char **argv)
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (xc_domain_memory_increase_reservation(xc_handle, domid,
|
||||
extra_pages , 0, 0, NULL) != 0) {
|
||||
perror("increase reservation");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if ( xc_get_pfn_list(xc_handle, domid, page_array, nr_pages) != nr_pages )
|
||||
{
|
||||
perror("xc_get_pfn_list");
|
||||
@@ -2825,15 +3037,36 @@ int main(int argc, char **argv)
|
||||
if ((phys_ram_base = xc_map_foreign_batch(xc_handle, domid,
|
||||
PROT_READ|PROT_WRITE,
|
||||
page_array,
|
||||
nr_pages - 1)) == 0) {
|
||||
ram_pages - 1)) == 0) {
|
||||
perror("xc_map_foreign_batch");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
page_array[nr_pages - 1]);
|
||||
page_array[ram_pages - 1]);
|
||||
|
||||
vgapage_array = &page_array[nr_pages - vgaram_pages];
|
||||
|
||||
if ((shared_vram = xc_map_foreign_batch(xc_handle, domid,
|
||||
PROT_READ|PROT_WRITE,
|
||||
vgapage_array,
|
||||
vgaram_pages)) == 0) {
|
||||
perror("xc_map_foreign_batch vgaram ");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
memset(shared_vram, 0, vgaram_pages * PAGE_SIZE);
|
||||
toptab = page_array[ram_pages] << PAGE_SHIFT;
|
||||
|
||||
vtop_table = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
page_array[ram_pages]);
|
||||
|
||||
freepage_array = &page_array[nr_pages - extra_pages];
|
||||
|
||||
|
||||
fprintf(logfile, "shared page at pfn:%lx, mfn: %lx\n", (nr_pages-1),
|
||||
(page_array[nr_pages - 1]));
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
#ifndef __LINUX_BOOT_PARAMS_H__
|
||||
#define __LINUX_BOOT_PARAMS_H__
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
#define E820MAX 32
|
||||
|
||||
struct mem_map {
|
||||
int nr_map;
|
||||
struct entry {
|
||||
u64 addr; /* start of memory segment */
|
||||
u64 size; /* size of memory segment */
|
||||
u32 type; /* type of memory segment */
|
||||
#define E820_RAM 1
|
||||
#define E820_RESERVED 2
|
||||
#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */
|
||||
#define E820_NVS 4
|
||||
#define E820_IO 16
|
||||
#define E820_SHARED 17
|
||||
#define E820_XENSTORE 18
|
||||
|
||||
u32 caching_attr; /* used by hypervisor */
|
||||
#define MEMMAP_UC 0
|
||||
#define MEMMAP_WC 1
|
||||
#define MEMMAP_WT 4
|
||||
#define MEMMAP_WP 5
|
||||
#define MEMMAP_WB 6
|
||||
|
||||
}map[E820MAX];
|
||||
};
|
||||
|
||||
struct e820entry {
|
||||
u64 addr; /* start of memory segment */
|
||||
u64 size; /* size of memory segment */
|
||||
u32 type; /* type of memory segment */
|
||||
}__attribute__((packed));
|
||||
|
||||
struct e820map {
|
||||
u32 nr_map;
|
||||
struct e820entry map[E820MAX];
|
||||
}__attribute__((packed));
|
||||
|
||||
struct drive_info_struct { __u8 dummy[32]; };
|
||||
|
||||
struct sys_desc_table {
|
||||
__u16 length;
|
||||
__u8 table[318];
|
||||
};
|
||||
|
||||
struct screen_info {
|
||||
unsigned char orig_x; /* 0x00 */
|
||||
unsigned char orig_y; /* 0x01 */
|
||||
unsigned short dontuse1; /* 0x02 -- EXT_MEM_K sits here */
|
||||
unsigned short orig_video_page; /* 0x04 */
|
||||
unsigned char orig_video_mode; /* 0x06 */
|
||||
unsigned char orig_video_cols; /* 0x07 */
|
||||
unsigned short unused2; /* 0x08 */
|
||||
unsigned short orig_video_ega_bx; /* 0x0a */
|
||||
unsigned short unused3; /* 0x0c */
|
||||
unsigned char orig_video_lines; /* 0x0e */
|
||||
unsigned char orig_video_isVGA; /* 0x0f */
|
||||
unsigned short orig_video_points; /* 0x10 */
|
||||
|
||||
/* VESA graphic mode -- linear frame buffer */
|
||||
unsigned short lfb_width; /* 0x12 */
|
||||
unsigned short lfb_height; /* 0x14 */
|
||||
unsigned short lfb_depth; /* 0x16 */
|
||||
unsigned int lfb_base; /* 0x18 */
|
||||
unsigned int lfb_size; /* 0x1c */
|
||||
unsigned short dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */
|
||||
unsigned short lfb_linelength; /* 0x24 */
|
||||
unsigned char red_size; /* 0x26 */
|
||||
unsigned char red_pos; /* 0x27 */
|
||||
unsigned char green_size; /* 0x28 */
|
||||
unsigned char green_pos; /* 0x29 */
|
||||
unsigned char blue_size; /* 0x2a */
|
||||
unsigned char blue_pos; /* 0x2b */
|
||||
unsigned char rsvd_size; /* 0x2c */
|
||||
unsigned char rsvd_pos; /* 0x2d */
|
||||
unsigned short vesapm_seg; /* 0x2e */
|
||||
unsigned short vesapm_off; /* 0x30 */
|
||||
unsigned short pages; /* 0x32 */
|
||||
/* 0x34 -- 0x3f reserved for future expansion */
|
||||
};
|
||||
|
||||
struct screen_info_overlap {
|
||||
__u8 reserved1[2]; /* 0x00 */
|
||||
__u16 ext_mem_k; /* 0x02 */
|
||||
__u8 reserved2[0x20 - 0x04]; /* 0x04 */
|
||||
__u16 cl_magic; /* 0x20 */
|
||||
#define CL_MAGIC_VALUE 0xA33F
|
||||
__u16 cl_offset; /* 0x22 */
|
||||
__u8 reserved3[0x40 - 0x24]; /* 0x24 */
|
||||
};
|
||||
|
||||
|
||||
struct apm_bios_info {
|
||||
__u16 version;
|
||||
__u16 cseg;
|
||||
__u32 offset;
|
||||
__u16 cseg_16;
|
||||
__u16 dseg;
|
||||
__u16 flags;
|
||||
__u16 cseg_len;
|
||||
__u16 cseg_16_len;
|
||||
__u16 dseg_len;
|
||||
};
|
||||
|
||||
struct linux_boot_params {
|
||||
union { /* 0x00 */
|
||||
struct screen_info info;
|
||||
struct screen_info_overlap overlap;
|
||||
} screen;
|
||||
|
||||
struct apm_bios_info apm_bios_info; /* 0x40 */
|
||||
__u8 reserved4[0x80 - 0x54]; /* 0x54 */
|
||||
struct drive_info_struct drive_info; /* 0x80 */
|
||||
struct sys_desc_table sys_desc_table; /* 0xa0 */
|
||||
__u32 alt_mem_k; /* 0x1e0 */
|
||||
__u8 reserved5[4]; /* 0x1e4 */
|
||||
__u8 e820_map_nr; /* 0x1e8 */
|
||||
__u8 reserved6[8]; /* 0x1e9 */
|
||||
__u8 setup_sects; /* 0x1f1 */
|
||||
__u16 mount_root_rdonly; /* 0x1f2 */
|
||||
__u16 syssize; /* 0x1f4 */
|
||||
__u16 swapdev; /* 0x1f6 */
|
||||
__u16 ramdisk_flags; /* 0x1f8 */
|
||||
#define RAMDISK_IMAGE_START_MASK 0x07FF
|
||||
#define RAMDISK_PROMPT_FLAG 0x8000
|
||||
#define RAMDISK_LOAD_FLAG 0x4000
|
||||
__u16 vid_mode; /* 0x1fa */
|
||||
__u16 root_dev; /* 0x1fc */
|
||||
__u8 reserved9[1]; /* 0x1fe */
|
||||
__u8 aux_device_info; /* 0x1ff */
|
||||
/* 2.00+ */
|
||||
__u8 reserved10[2]; /* 0x200 */
|
||||
__u8 header_magic[4]; /* 0x202 */
|
||||
__u16 protocol_version; /* 0x206 */
|
||||
__u8 reserved11[8]; /* 0x208 */
|
||||
__u8 loader_type; /* 0x210 */
|
||||
#define LOADER_TYPE_LOADLIN 1
|
||||
#define LOADER_TYPE_BOOTSECT_LOADER 2
|
||||
#define LOADER_TYPE_SYSLINUX 3
|
||||
#define LOADER_TYPE_ETHERBOOT 4
|
||||
#define LOADER_TYPE_UNKNOWN 0xFF
|
||||
__u8 loader_flags; /* 0x211 */
|
||||
__u8 reserved12[2]; /* 0x212 */
|
||||
__u32 code32_start; /* 0x214 */
|
||||
__u32 initrd_start; /* 0x218 */
|
||||
__u32 initrd_size; /* 0x21c */
|
||||
__u8 reserved13[4]; /* 0x220 */
|
||||
/* 2.01+ */
|
||||
__u16 heap_end_ptr; /* 0x224 */
|
||||
__u8 reserved14[2]; /* 0x226 */
|
||||
/* 2.02+ */
|
||||
__u32 cmd_line_ptr; /* 0x228 */
|
||||
/* 2.03+ */
|
||||
__u32 ramdisk_max; /* 0x22c */
|
||||
__u8 reserved15[0x2d0 - 0x230]; /* 0x230 */
|
||||
struct e820entry e820_map[E820MAX]; /* 0x2d0 */
|
||||
__u64 shared_info; /* 0x550 */
|
||||
__u8 padding[0x800 - 0x558]; /* 0x558 */
|
||||
__u8 cmd_line[0x800]; /* 0x800 */
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif /* __LINUX_BOOT_PARAMS_H__ */
|
||||
+163
-308
@@ -10,7 +10,8 @@
|
||||
#include <unistd.h>
|
||||
#include <zlib.h>
|
||||
#include <xen/io/ioreq.h>
|
||||
#include "linux_boot_params.h"
|
||||
|
||||
#define VMX_LOADER_ENTR_ADDR 0x00100000
|
||||
|
||||
#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
|
||||
#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
|
||||
@@ -18,13 +19,29 @@
|
||||
#define L3_PROT (_PAGE_PRESENT)
|
||||
#endif
|
||||
|
||||
#define E820MAX 128
|
||||
|
||||
#define E820_RAM 1
|
||||
#define E820_RESERVED 2
|
||||
#define E820_ACPI 3
|
||||
#define E820_NVS 4
|
||||
#define E820_IO 16
|
||||
#define E820_SHARED_PAGE 17
|
||||
#define E820_XENSTORE 18
|
||||
|
||||
#define E820_MAP_PAGE 0x00090000
|
||||
#define E820_MAP_NR_OFFSET 0x000001E8
|
||||
#define E820_MAP_OFFSET 0x000002D0
|
||||
|
||||
struct e820entry {
|
||||
u64 addr;
|
||||
u64 size;
|
||||
u32 type;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
|
||||
#define round_pgdown(_p) ((_p)&PAGE_MASK)
|
||||
|
||||
#define LINUX_BOOT_PARAMS_ADDR 0x00090000
|
||||
#define LINUX_KERNEL_ENTR_ADDR 0x00100000
|
||||
#define LINUX_PAGE_OFFSET 0xC0000000
|
||||
|
||||
static int
|
||||
parseelfimage(
|
||||
char *elfbase, unsigned long elfsize, struct domain_setup_info *dsi);
|
||||
@@ -33,78 +50,70 @@ loadelfimage(
|
||||
char *elfbase, int xch, u32 dom, unsigned long *parray,
|
||||
struct domain_setup_info *dsi);
|
||||
|
||||
static void build_e820map(struct mem_map *mem_mapp, unsigned long mem_size)
|
||||
static unsigned char build_e820map(void *e820_page, unsigned long mem_size)
|
||||
{
|
||||
int nr_map = 0;
|
||||
struct e820entry *e820entry =
|
||||
(struct e820entry *)(((unsigned char *)e820_page) + E820_MAP_OFFSET);
|
||||
unsigned char nr_map = 0;
|
||||
|
||||
/* XXX: Doesn't work for > 4GB yet */
|
||||
mem_mapp->map[nr_map].addr = 0x0;
|
||||
mem_mapp->map[nr_map].size = 0x9F800;
|
||||
mem_mapp->map[nr_map].type = E820_RAM;
|
||||
mem_mapp->map[nr_map].caching_attr = MEMMAP_WB;
|
||||
e820entry[nr_map].addr = 0x0;
|
||||
e820entry[nr_map].size = 0x9F800;
|
||||
e820entry[nr_map].type = E820_RAM;
|
||||
nr_map++;
|
||||
|
||||
mem_mapp->map[nr_map].addr = 0x9F800;
|
||||
mem_mapp->map[nr_map].size = 0x800;
|
||||
mem_mapp->map[nr_map].type = E820_RESERVED;
|
||||
mem_mapp->map[nr_map].caching_attr = MEMMAP_UC;
|
||||
e820entry[nr_map].addr = 0x9F800;
|
||||
e820entry[nr_map].size = 0x800;
|
||||
e820entry[nr_map].type = E820_RESERVED;
|
||||
nr_map++;
|
||||
|
||||
mem_mapp->map[nr_map].addr = 0xA0000;
|
||||
mem_mapp->map[nr_map].size = 0x20000;
|
||||
mem_mapp->map[nr_map].type = E820_IO;
|
||||
mem_mapp->map[nr_map].caching_attr = MEMMAP_UC;
|
||||
e820entry[nr_map].addr = 0xA0000;
|
||||
e820entry[nr_map].size = 0x20000;
|
||||
e820entry[nr_map].type = E820_IO;
|
||||
nr_map++;
|
||||
|
||||
mem_mapp->map[nr_map].addr = 0xF0000;
|
||||
mem_mapp->map[nr_map].size = 0x10000;
|
||||
mem_mapp->map[nr_map].type = E820_RESERVED;
|
||||
mem_mapp->map[nr_map].caching_attr = MEMMAP_UC;
|
||||
e820entry[nr_map].addr = 0xF0000;
|
||||
e820entry[nr_map].size = 0x10000;
|
||||
e820entry[nr_map].type = E820_RESERVED;
|
||||
nr_map++;
|
||||
|
||||
#define STATIC_PAGES 2 /* for ioreq_t and store_mfn */
|
||||
/* Most of the ram goes here */
|
||||
mem_mapp->map[nr_map].addr = 0x100000;
|
||||
mem_mapp->map[nr_map].size = mem_size - 0x100000 - STATIC_PAGES*PAGE_SIZE;
|
||||
mem_mapp->map[nr_map].type = E820_RAM;
|
||||
mem_mapp->map[nr_map].caching_attr = MEMMAP_WB;
|
||||
e820entry[nr_map].addr = 0x100000;
|
||||
e820entry[nr_map].size = mem_size - 0x100000 - STATIC_PAGES*PAGE_SIZE;
|
||||
e820entry[nr_map].type = E820_RAM;
|
||||
nr_map++;
|
||||
|
||||
/* Statically allocated special pages */
|
||||
|
||||
/* Shared ioreq_t page */
|
||||
mem_mapp->map[nr_map].addr = mem_size - PAGE_SIZE;
|
||||
mem_mapp->map[nr_map].size = PAGE_SIZE;
|
||||
mem_mapp->map[nr_map].type = E820_SHARED;
|
||||
mem_mapp->map[nr_map].caching_attr = MEMMAP_WB;
|
||||
e820entry[nr_map].addr = mem_size - PAGE_SIZE;
|
||||
e820entry[nr_map].size = PAGE_SIZE;
|
||||
e820entry[nr_map].type = E820_SHARED_PAGE;
|
||||
nr_map++;
|
||||
|
||||
/* For xenstore */
|
||||
mem_mapp->map[nr_map].addr = mem_size - 2*PAGE_SIZE;
|
||||
mem_mapp->map[nr_map].size = PAGE_SIZE;
|
||||
mem_mapp->map[nr_map].type = E820_XENSTORE;
|
||||
mem_mapp->map[nr_map].caching_attr = MEMMAP_WB;
|
||||
e820entry[nr_map].addr = mem_size - 2*PAGE_SIZE;
|
||||
e820entry[nr_map].size = PAGE_SIZE;
|
||||
e820entry[nr_map].type = E820_XENSTORE;
|
||||
nr_map++;
|
||||
|
||||
mem_mapp->map[nr_map].addr = mem_size;
|
||||
mem_mapp->map[nr_map].size = 0x3 * PAGE_SIZE;
|
||||
mem_mapp->map[nr_map].type = E820_NVS;
|
||||
mem_mapp->map[nr_map].caching_attr = MEMMAP_UC;
|
||||
e820entry[nr_map].addr = mem_size;
|
||||
e820entry[nr_map].size = 0x3 * PAGE_SIZE;
|
||||
e820entry[nr_map].type = E820_NVS;
|
||||
nr_map++;
|
||||
|
||||
mem_mapp->map[nr_map].addr = mem_size + 0x3 * PAGE_SIZE;
|
||||
mem_mapp->map[nr_map].size = 0xA * PAGE_SIZE;
|
||||
mem_mapp->map[nr_map].type = E820_ACPI;
|
||||
mem_mapp->map[nr_map].caching_attr = MEMMAP_WB;
|
||||
e820entry[nr_map].addr = mem_size + 0x3 * PAGE_SIZE;
|
||||
e820entry[nr_map].size = 0xA * PAGE_SIZE;
|
||||
e820entry[nr_map].type = E820_ACPI;
|
||||
nr_map++;
|
||||
|
||||
mem_mapp->map[nr_map].addr = 0xFEC00000;
|
||||
mem_mapp->map[nr_map].size = 0x1400000;
|
||||
mem_mapp->map[nr_map].type = E820_IO;
|
||||
mem_mapp->map[nr_map].caching_attr = MEMMAP_UC;
|
||||
e820entry[nr_map].addr = 0xFEC00000;
|
||||
e820entry[nr_map].size = 0x1400000;
|
||||
e820entry[nr_map].type = E820_IO;
|
||||
nr_map++;
|
||||
|
||||
mem_mapp->nr_map = nr_map;
|
||||
return (*(((unsigned char *)e820_page) + E820_MAP_NR_OFFSET) = nr_map);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -112,19 +121,19 @@ static void build_e820map(struct mem_map *mem_mapp, unsigned long mem_size)
|
||||
* vmxloader will use it to config ACPI MADT table
|
||||
*/
|
||||
#define VCPU_MAGIC 0x76637075 /* "vcpu" */
|
||||
static int
|
||||
set_nr_vcpus(int xc_handle, u32 dom, unsigned long *pfn_list,
|
||||
static int
|
||||
set_nr_vcpus(int xc_handle, u32 dom, unsigned long *pfn_list,
|
||||
struct domain_setup_info *dsi, unsigned long vcpus)
|
||||
{
|
||||
char *va_map;
|
||||
unsigned long *va_vcpus;
|
||||
|
||||
|
||||
va_map = xc_map_foreign_range(
|
||||
xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
|
||||
pfn_list[(0x9F000 - dsi->v_start) >> PAGE_SHIFT]);
|
||||
pfn_list[(0x9F000 - dsi->v_start) >> PAGE_SHIFT]);
|
||||
if ( va_map == NULL )
|
||||
return -1;
|
||||
|
||||
|
||||
va_vcpus = (unsigned long *)(va_map + 0x800);
|
||||
*va_vcpus++ = VCPU_MAGIC;
|
||||
*va_vcpus++ = vcpus;
|
||||
@@ -164,24 +173,23 @@ static int zap_mmio_range(int xc_handle, u32 dom,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zap_mmio_ranges(int xc_handle, u32 dom,
|
||||
unsigned long l2tab,
|
||||
struct mem_map *mem_mapp)
|
||||
static int zap_mmio_ranges(int xc_handle, u32 dom, unsigned long l2tab,
|
||||
unsigned char e820_map_nr, unsigned char *e820map)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
struct e820entry *e820entry = (struct e820entry *)e820map;
|
||||
|
||||
l2_pgentry_32_t *vl2tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
l2tab >> PAGE_SHIFT);
|
||||
if ( vl2tab == 0 )
|
||||
return -1;
|
||||
|
||||
for ( i = 0; i < mem_mapp->nr_map; i++ )
|
||||
for ( i = 0; i < e820_map_nr; i++ )
|
||||
{
|
||||
if ( (mem_mapp->map[i].type == E820_IO) &&
|
||||
(mem_mapp->map[i].caching_attr == MEMMAP_UC) &&
|
||||
if ( (e820entry[i].type == E820_IO) &&
|
||||
(zap_mmio_range(xc_handle, dom, vl2tab,
|
||||
mem_mapp->map[i].addr,
|
||||
mem_mapp->map[i].size) == -1) )
|
||||
e820entry[i].addr, e820entry[i].size) == -1))
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -200,7 +208,7 @@ static int zap_mmio_range(int xc_handle, u32 dom,
|
||||
unsigned long vl3e;
|
||||
l1_pgentry_t *vl1tab;
|
||||
l2_pgentry_t *vl2tab;
|
||||
|
||||
|
||||
mmio_addr = mmio_range_start & PAGE_MASK;
|
||||
for ( ; mmio_addr < mmio_range_end; mmio_addr += PAGE_SIZE )
|
||||
{
|
||||
@@ -239,22 +247,22 @@ static int zap_mmio_range(int xc_handle, u32 dom,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zap_mmio_ranges(int xc_handle, u32 dom,
|
||||
unsigned long l3tab,
|
||||
struct mem_map *mem_mapp)
|
||||
static int zap_mmio_ranges(int xc_handle, u32 dom, unsigned long l3tab,
|
||||
unsigned char e820_map_nr, unsigned char *e820map)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
struct e820entry *e820entry = (struct e820entry *)e820map;
|
||||
|
||||
l3_pgentry_t *vl3tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
l3tab >> PAGE_SHIFT);
|
||||
if (vl3tab == 0)
|
||||
return -1;
|
||||
for (i = 0; i < mem_mapp->nr_map; i++) {
|
||||
if ((mem_mapp->map[i].type == E820_IO)
|
||||
&& (mem_mapp->map[i].caching_attr == MEMMAP_UC))
|
||||
if (zap_mmio_range(xc_handle, dom, vl3tab,
|
||||
mem_mapp->map[i].addr, mem_mapp->map[i].size) == -1)
|
||||
return -1;
|
||||
for ( i = 0; i < e820_map_nr; i++ ) {
|
||||
if ( (e820entry[i].type == E820_IO) &&
|
||||
(zap_mmio_range(xc_handle, dom, vl3tab,
|
||||
e820entry[i].addr, e820entry[i].size) == -1) )
|
||||
return -1;
|
||||
}
|
||||
munmap(vl3tab, PAGE_SIZE);
|
||||
return 0;
|
||||
@@ -265,18 +273,14 @@ static int zap_mmio_ranges(int xc_handle, u32 dom,
|
||||
static int setup_guest(int xc_handle,
|
||||
u32 dom, int memsize,
|
||||
char *image, unsigned long image_size,
|
||||
gzFile initrd_gfd, unsigned long initrd_len,
|
||||
unsigned long nr_pages,
|
||||
vcpu_guest_context_t *ctxt,
|
||||
const char *cmdline,
|
||||
unsigned long shared_info_frame,
|
||||
unsigned int control_evtchn,
|
||||
unsigned long flags,
|
||||
unsigned int vcpus,
|
||||
unsigned int store_evtchn,
|
||||
unsigned long *store_mfn,
|
||||
struct mem_map *mem_mapp
|
||||
)
|
||||
unsigned long *store_mfn)
|
||||
{
|
||||
l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
|
||||
l2_pgentry_t *vl2tab=NULL, *vl2e=NULL;
|
||||
@@ -289,8 +293,8 @@ static int setup_guest(int xc_handle,
|
||||
unsigned long l1tab;
|
||||
unsigned long count, i;
|
||||
shared_info_t *shared_info;
|
||||
struct linux_boot_params * boot_paramsp;
|
||||
__u16 * boot_gdtp;
|
||||
void *e820_page;
|
||||
unsigned char e820_map_nr;
|
||||
xc_mmu_t *mmu = NULL;
|
||||
int rc;
|
||||
|
||||
@@ -298,12 +302,6 @@ static int setup_guest(int xc_handle,
|
||||
unsigned long ppt_alloc;
|
||||
|
||||
struct domain_setup_info dsi;
|
||||
unsigned long vinitrd_start;
|
||||
unsigned long vinitrd_end;
|
||||
unsigned long vboot_params_start;
|
||||
unsigned long vboot_params_end;
|
||||
unsigned long vboot_gdt_start;
|
||||
unsigned long vboot_gdt_end;
|
||||
unsigned long vpt_start;
|
||||
unsigned long vpt_end;
|
||||
unsigned long v_end;
|
||||
@@ -322,27 +320,8 @@ static int setup_guest(int xc_handle,
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Why do we need this? The number of page-table frames depends on the
|
||||
* size of the bootstrap address space. But the size of the address space
|
||||
* depends on the number of page-table frames (since each one is mapped
|
||||
* read-only). We have a pair of simultaneous equations in two unknowns,
|
||||
* which we solve by exhaustive search.
|
||||
*/
|
||||
vboot_params_start = LINUX_BOOT_PARAMS_ADDR;
|
||||
vboot_params_end = vboot_params_start + PAGE_SIZE;
|
||||
vboot_gdt_start = vboot_params_end;
|
||||
vboot_gdt_end = vboot_gdt_start + PAGE_SIZE;
|
||||
|
||||
/* memsize is in megabytes */
|
||||
v_end = memsize << 20;
|
||||
/* leaving the top 4k untouched for IO requests page use */
|
||||
vinitrd_end = v_end - PAGE_SIZE;
|
||||
vinitrd_start = vinitrd_end - initrd_len;
|
||||
vinitrd_start = vinitrd_start & (~(PAGE_SIZE - 1));
|
||||
|
||||
if(initrd_len == 0)
|
||||
vinitrd_start = vinitrd_end = 0;
|
||||
|
||||
#ifdef __i386__
|
||||
nr_pt_pages = 1 + ((memsize + 3) >> 2);
|
||||
@@ -353,24 +332,17 @@ static int setup_guest(int xc_handle,
|
||||
vpt_end = vpt_start + (nr_pt_pages * PAGE_SIZE);
|
||||
|
||||
printf("VIRTUAL MEMORY ARRANGEMENT:\n"
|
||||
" Boot_params: %08lx->%08lx\n"
|
||||
" boot_gdt: %08lx->%08lx\n"
|
||||
" Loaded kernel: %08lx->%08lx\n"
|
||||
" Init. ramdisk: %08lx->%08lx\n"
|
||||
" Loaded VMX loader: %08lx->%08lx\n"
|
||||
" Page tables: %08lx->%08lx\n"
|
||||
" TOTAL: %08lx->%08lx\n",
|
||||
vboot_params_start, vboot_params_end,
|
||||
vboot_gdt_start, vboot_gdt_end,
|
||||
dsi.v_kernstart, dsi.v_kernend,
|
||||
vinitrd_start, vinitrd_end,
|
||||
dsi.v_kernstart, dsi.v_kernend,
|
||||
vpt_start, vpt_end,
|
||||
dsi.v_start, v_end);
|
||||
printf(" ENTRY ADDRESS: %08lx\n", dsi.v_kernentry);
|
||||
printf(" INITRD LENGTH: %08lx\n", initrd_len);
|
||||
|
||||
if ( (v_end - dsi.v_start) > (nr_pages * PAGE_SIZE) )
|
||||
{
|
||||
printf("Initial guest OS requires too much space\n"
|
||||
ERROR("Initial guest OS requires too much space\n"
|
||||
"(%luMB is greater than %luMB limit)\n",
|
||||
(v_end-dsi.v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
|
||||
goto error_out;
|
||||
@@ -390,23 +362,6 @@ static int setup_guest(int xc_handle,
|
||||
|
||||
loadelfimage(image, xc_handle, dom, page_array, &dsi);
|
||||
|
||||
/* Load the initial ramdisk image. */
|
||||
if ( initrd_len != 0 )
|
||||
{
|
||||
for ( i = (vinitrd_start - dsi.v_start);
|
||||
i < (vinitrd_end - dsi.v_start); i += PAGE_SIZE )
|
||||
{
|
||||
char page[PAGE_SIZE];
|
||||
if ( gzread(initrd_gfd, page, PAGE_SIZE) == -1 )
|
||||
{
|
||||
PERROR("Error reading initrd image, could not");
|
||||
goto error_out;
|
||||
}
|
||||
xc_copy_to_domain_page(xc_handle, dom,
|
||||
page_array[i>>PAGE_SHIFT], page);
|
||||
}
|
||||
}
|
||||
|
||||
if ( (mmu = xc_init_mmu_updates(xc_handle, dom)) == NULL )
|
||||
goto error_out;
|
||||
|
||||
@@ -428,15 +383,14 @@ static int setup_guest(int xc_handle,
|
||||
l2tab = page_array[ppt_alloc++] << PAGE_SHIFT;
|
||||
ctxt->ctrlreg[3] = l2tab;
|
||||
|
||||
/* Initialise the page tables. */
|
||||
if ( (vl2tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
if ( (vl2tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
l2tab >> PAGE_SHIFT)) == NULL )
|
||||
goto error_out;
|
||||
memset(vl2tab, 0, PAGE_SIZE);
|
||||
vl2e = &vl2tab[l2_table_offset(dsi.v_start)];
|
||||
for ( count = 0; count < ((v_end-dsi.v_start)>>PAGE_SHIFT); count++ )
|
||||
{
|
||||
{
|
||||
if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
|
||||
{
|
||||
l1tab = page_array[ppt_alloc++] << PAGE_SHIFT;
|
||||
@@ -460,23 +414,35 @@ static int setup_guest(int xc_handle,
|
||||
munmap(vl1tab, PAGE_SIZE);
|
||||
munmap(vl2tab, PAGE_SIZE);
|
||||
#else
|
||||
/* here l3tab means pdpt, only 4 entry is used */
|
||||
l3tab = page_array[ppt_alloc++] << PAGE_SHIFT;
|
||||
ctxt->ctrlreg[3] = l3tab;
|
||||
|
||||
/* Initialise the page tables. */
|
||||
if ( (vl3tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
if ( (vl3tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
l3tab >> PAGE_SHIFT)) == NULL )
|
||||
goto error_out;
|
||||
memset(vl3tab, 0, PAGE_SIZE);
|
||||
|
||||
/* Fill in every PDPT entry. */
|
||||
for ( i = 0; i < L3_PAGETABLE_ENTRIES_PAE; i++ )
|
||||
{
|
||||
l2tab = page_array[ppt_alloc++] << PAGE_SHIFT;
|
||||
if ( (vl2tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
l2tab >> PAGE_SHIFT)) == NULL )
|
||||
goto error_out;
|
||||
memset(vl2tab, 0, PAGE_SIZE);
|
||||
munmap(vl2tab, PAGE_SIZE);
|
||||
vl3tab[i] = l2tab | L3_PROT;
|
||||
}
|
||||
|
||||
vl3e = &vl3tab[l3_table_offset(dsi.v_start)];
|
||||
|
||||
for ( count = 0; count < ((v_end-dsi.v_start)>>PAGE_SHIFT); count++ )
|
||||
{
|
||||
if (!(count % (1 << (L3_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT)))){
|
||||
l2tab = page_array[ppt_alloc++] << PAGE_SHIFT;
|
||||
if (!(count & (1 << (L3_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT)))){
|
||||
l2tab = vl3tab[count >> (L3_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT)]
|
||||
& PAGE_MASK;
|
||||
|
||||
if (vl2tab != NULL)
|
||||
munmap(vl2tab, PAGE_SIZE);
|
||||
@@ -486,8 +452,6 @@ static int setup_guest(int xc_handle,
|
||||
l2tab >> PAGE_SHIFT)) == NULL )
|
||||
goto error_out;
|
||||
|
||||
memset(vl2tab, 0, PAGE_SIZE);
|
||||
*vl3e++ = l2tab | L3_PROT;
|
||||
vl2e = &vl2tab[l2_table_offset(dsi.v_start + (count << PAGE_SHIFT))];
|
||||
}
|
||||
if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
|
||||
@@ -519,103 +483,31 @@ static int setup_guest(int xc_handle,
|
||||
for ( count = 0; count < nr_pages; count++ )
|
||||
{
|
||||
if ( xc_add_mmu_update(xc_handle, mmu,
|
||||
(page_array[count] << PAGE_SHIFT) |
|
||||
(page_array[count] << PAGE_SHIFT) |
|
||||
MMU_MACHPHYS_UPDATE, count) )
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
set_nr_vcpus(xc_handle, dom, page_array, &dsi, vcpus);
|
||||
|
||||
if ((boot_paramsp = xc_map_foreign_range(
|
||||
xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
|
||||
page_array[(vboot_params_start-dsi.v_start)>>PAGE_SHIFT])) == 0)
|
||||
goto error_out;
|
||||
|
||||
memset(boot_paramsp, 0, sizeof(*boot_paramsp));
|
||||
|
||||
strncpy((char *)boot_paramsp->cmd_line, cmdline, 0x800);
|
||||
boot_paramsp->cmd_line[0x800-1] = '\0';
|
||||
boot_paramsp->cmd_line_ptr = ((unsigned long) vboot_params_start) + offsetof(struct linux_boot_params, cmd_line);
|
||||
|
||||
boot_paramsp->setup_sects = 0;
|
||||
boot_paramsp->mount_root_rdonly = 1;
|
||||
boot_paramsp->swapdev = 0x0;
|
||||
boot_paramsp->ramdisk_flags = 0x0;
|
||||
boot_paramsp->root_dev = 0x0; /* We must tell kernel root dev by kernel command line. */
|
||||
|
||||
/* we don't have a ps/2 mouse now.
|
||||
* 0xAA means a aux mouse is there.
|
||||
* See detect_auxiliary_port() in pc_keyb.c.
|
||||
*/
|
||||
boot_paramsp->aux_device_info = 0x0;
|
||||
|
||||
boot_paramsp->header_magic[0] = 0x48; /* "H" */
|
||||
boot_paramsp->header_magic[1] = 0x64; /* "d" */
|
||||
boot_paramsp->header_magic[2] = 0x72; /* "r" */
|
||||
boot_paramsp->header_magic[3] = 0x53; /* "S" */
|
||||
|
||||
boot_paramsp->protocol_version = 0x0203; /* 2.03 */
|
||||
boot_paramsp->loader_type = 0x71; /* GRUB */
|
||||
boot_paramsp->loader_flags = 0x1; /* loaded high */
|
||||
boot_paramsp->code32_start = LINUX_KERNEL_ENTR_ADDR; /* 1MB */
|
||||
boot_paramsp->initrd_start = vinitrd_start;
|
||||
boot_paramsp->initrd_size = initrd_len;
|
||||
|
||||
i = ((memsize - 1) << 10) - 4;
|
||||
boot_paramsp->alt_mem_k = i; /* alt_mem_k */
|
||||
boot_paramsp->screen.overlap.ext_mem_k = i & 0xFFFF; /* ext_mem_k */
|
||||
|
||||
/*
|
||||
* Stuff SCREAN_INFO
|
||||
*/
|
||||
boot_paramsp->screen.info.orig_x = 0;
|
||||
boot_paramsp->screen.info.orig_y = 0;
|
||||
boot_paramsp->screen.info.orig_video_page = 8;
|
||||
boot_paramsp->screen.info.orig_video_mode = 3;
|
||||
boot_paramsp->screen.info.orig_video_cols = 80;
|
||||
boot_paramsp->screen.info.orig_video_ega_bx = 0;
|
||||
boot_paramsp->screen.info.orig_video_lines = 25;
|
||||
boot_paramsp->screen.info.orig_video_isVGA = 1;
|
||||
boot_paramsp->screen.info.orig_video_points = 0x0010;
|
||||
|
||||
/* seems we may NOT stuff boot_paramsp->apm_bios_info */
|
||||
/* seems we may NOT stuff boot_paramsp->drive_info */
|
||||
/* seems we may NOT stuff boot_paramsp->sys_desc_table */
|
||||
*((unsigned short *) &boot_paramsp->drive_info.dummy[0]) = 800;
|
||||
boot_paramsp->drive_info.dummy[2] = 4;
|
||||
boot_paramsp->drive_info.dummy[14] = 32;
|
||||
|
||||
/* memsize is in megabytes */
|
||||
/* If you need to create a special e820map, comment this line
|
||||
and use mem-map.sxp */
|
||||
build_e820map(mem_mapp, memsize << 20);
|
||||
*store_mfn = page_array[(v_end-2) >> PAGE_SHIFT];
|
||||
#if defined (__i386__)
|
||||
if (zap_mmio_ranges(xc_handle, dom, l2tab, mem_mapp) == -1)
|
||||
#else
|
||||
if (zap_mmio_ranges(xc_handle, dom, l3tab, mem_mapp) == -1)
|
||||
#endif
|
||||
goto error_out;
|
||||
boot_paramsp->e820_map_nr = mem_mapp->nr_map;
|
||||
for (i=0; i<mem_mapp->nr_map; i++) {
|
||||
boot_paramsp->e820_map[i].addr = mem_mapp->map[i].addr;
|
||||
boot_paramsp->e820_map[i].size = mem_mapp->map[i].size;
|
||||
boot_paramsp->e820_map[i].type = mem_mapp->map[i].type;
|
||||
if (mem_mapp->map[i].type == E820_SHARED)
|
||||
shared_page_frame = (mem_mapp->map[i].addr >> PAGE_SHIFT);
|
||||
}
|
||||
munmap(boot_paramsp, PAGE_SIZE);
|
||||
shared_page_frame = (v_end - PAGE_SIZE) >> PAGE_SHIFT;
|
||||
|
||||
if ((boot_gdtp = xc_map_foreign_range(
|
||||
if ((e820_page = xc_map_foreign_range(
|
||||
xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
|
||||
page_array[(vboot_gdt_start-dsi.v_start)>>PAGE_SHIFT])) == 0)
|
||||
page_array[E820_MAP_PAGE >> PAGE_SHIFT])) == 0)
|
||||
goto error_out;
|
||||
memset(boot_gdtp, 0, PAGE_SIZE);
|
||||
boot_gdtp[12*4 + 0] = boot_gdtp[13*4 + 0] = 0xffff; /* limit */
|
||||
boot_gdtp[12*4 + 1] = boot_gdtp[13*4 + 1] = 0x0000; /* base */
|
||||
boot_gdtp[12*4 + 2] = 0x9a00; boot_gdtp[13*4 + 2] = 0x9200; /* perms */
|
||||
boot_gdtp[12*4 + 3] = boot_gdtp[13*4 + 3] = 0x00cf; /* granu + top of limit */
|
||||
munmap(boot_gdtp, PAGE_SIZE);
|
||||
memset(e820_page, 0, PAGE_SIZE);
|
||||
e820_map_nr = build_e820map(e820_page, v_end);
|
||||
#if defined (__i386__)
|
||||
if (zap_mmio_ranges(xc_handle, dom, l2tab, e820_map_nr,
|
||||
((unsigned char *)e820_page) + E820_MAP_OFFSET) == -1)
|
||||
#else
|
||||
if (zap_mmio_ranges(xc_handle, dom, l3tab, e820_map_nr,
|
||||
((unsigned char *)e820_page) + E820_MAP_OFFSET) == -1)
|
||||
#endif
|
||||
goto error_out;
|
||||
munmap(e820_page, PAGE_SIZE);
|
||||
|
||||
/* shared_info page starts its life empty. */
|
||||
if ((shared_info = xc_map_foreign_range(
|
||||
@@ -651,20 +543,21 @@ static int setup_guest(int xc_handle,
|
||||
/*
|
||||
* Initial register values:
|
||||
*/
|
||||
ctxt->user_regs.ds = 0x68;
|
||||
ctxt->user_regs.es = 0x0;
|
||||
ctxt->user_regs.fs = 0x0;
|
||||
ctxt->user_regs.gs = 0x0;
|
||||
ctxt->user_regs.ss = 0x68;
|
||||
ctxt->user_regs.cs = 0x60;
|
||||
ctxt->user_regs.ds = 0;
|
||||
ctxt->user_regs.es = 0;
|
||||
ctxt->user_regs.fs = 0;
|
||||
ctxt->user_regs.gs = 0;
|
||||
ctxt->user_regs.ss = 0;
|
||||
ctxt->user_regs.cs = 0;
|
||||
ctxt->user_regs.eip = dsi.v_kernentry;
|
||||
ctxt->user_regs.edx = vboot_gdt_start;
|
||||
ctxt->user_regs.eax = 0x800;
|
||||
ctxt->user_regs.esp = vboot_gdt_end;
|
||||
ctxt->user_regs.edx = 0;
|
||||
ctxt->user_regs.eax = 0;
|
||||
ctxt->user_regs.esp = 0;
|
||||
ctxt->user_regs.ebx = 0; /* startup_32 expects this to be 0 to signal boot cpu */
|
||||
ctxt->user_regs.ecx = mem_mapp->nr_map;
|
||||
ctxt->user_regs.esi = vboot_params_start;
|
||||
ctxt->user_regs.edi = vboot_params_start + 0x2d0;
|
||||
ctxt->user_regs.ecx = 0;
|
||||
ctxt->user_regs.esi = 0;
|
||||
ctxt->user_regs.edi = 0;
|
||||
ctxt->user_regs.ebp = 0;
|
||||
|
||||
ctxt->user_regs.eflags = 0;
|
||||
|
||||
@@ -684,9 +577,9 @@ static int vmx_identify(void)
|
||||
int eax, ecx;
|
||||
|
||||
#ifdef __i386__
|
||||
__asm__ __volatile__ ("pushl %%ebx; cpuid; popl %%ebx"
|
||||
: "=a" (eax), "=c" (ecx)
|
||||
: "0" (1)
|
||||
__asm__ __volatile__ ("pushl %%ebx; cpuid; popl %%ebx"
|
||||
: "=a" (eax), "=c" (ecx)
|
||||
: "0" (1)
|
||||
: "dx");
|
||||
#elif defined __x86_64__
|
||||
__asm__ __volatile__ ("pushq %%rbx; cpuid; popq %%rbx"
|
||||
@@ -705,9 +598,6 @@ int xc_vmx_build(int xc_handle,
|
||||
u32 domid,
|
||||
int memsize,
|
||||
const char *image_name,
|
||||
struct mem_map *mem_mapp,
|
||||
const char *ramdisk_name,
|
||||
const char *cmdline,
|
||||
unsigned int control_evtchn,
|
||||
unsigned long flags,
|
||||
unsigned int vcpus,
|
||||
@@ -715,20 +605,18 @@ int xc_vmx_build(int xc_handle,
|
||||
unsigned long *store_mfn)
|
||||
{
|
||||
dom0_op_t launch_op, op;
|
||||
int initrd_fd = -1;
|
||||
gzFile initrd_gfd = NULL;
|
||||
int rc, i;
|
||||
vcpu_guest_context_t st_ctxt, *ctxt = &st_ctxt;
|
||||
unsigned long nr_pages;
|
||||
char *image = NULL;
|
||||
unsigned long image_size, initrd_size=0;
|
||||
unsigned long image_size;
|
||||
|
||||
if ( vmx_identify() < 0 )
|
||||
{
|
||||
PERROR("CPU doesn't support VMX Extensions");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
|
||||
if ( (nr_pages = xc_get_tot_pages(xc_handle, domid)) < 0 )
|
||||
{
|
||||
PERROR("Could not find total pages for domain");
|
||||
@@ -738,32 +626,15 @@ int xc_vmx_build(int xc_handle,
|
||||
if ( (image = xc_read_kernel_image(image_name, &image_size)) == NULL )
|
||||
goto error_out;
|
||||
|
||||
if ( (ramdisk_name != NULL) && (strlen(ramdisk_name) != 0) )
|
||||
{
|
||||
if ( (initrd_fd = open(ramdisk_name, O_RDONLY)) < 0 )
|
||||
{
|
||||
PERROR("Could not open the initial ramdisk image");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
initrd_size = xc_get_filesz(initrd_fd);
|
||||
|
||||
if ( (initrd_gfd = gzdopen(initrd_fd, "rb")) == NULL )
|
||||
{
|
||||
PERROR("Could not allocate decompression state for initrd");
|
||||
goto error_out;
|
||||
}
|
||||
}
|
||||
|
||||
if ( mlock(&st_ctxt, sizeof(st_ctxt) ) )
|
||||
{
|
||||
{
|
||||
PERROR("xc_vmx_build: ctxt mlock failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
op.cmd = DOM0_GETDOMAININFO;
|
||||
op.u.getdomaininfo.domain = (domid_t)domid;
|
||||
if ( (xc_dom0_op(xc_handle, &op) < 0) ||
|
||||
if ( (xc_dom0_op(xc_handle, &op) < 0) ||
|
||||
((u16)op.u.getdomaininfo.domain != domid) )
|
||||
{
|
||||
PERROR("Could not get info on domain");
|
||||
@@ -783,21 +654,14 @@ int xc_vmx_build(int xc_handle,
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if ( setup_guest(xc_handle, domid, memsize, image, image_size,
|
||||
initrd_gfd, initrd_size, nr_pages,
|
||||
ctxt, cmdline,
|
||||
op.u.getdomaininfo.shared_info_frame,
|
||||
control_evtchn, flags, vcpus, store_evtchn, store_mfn,
|
||||
mem_mapp) < 0 )
|
||||
if ( setup_guest(xc_handle, domid, memsize, image, image_size, nr_pages,
|
||||
ctxt, op.u.getdomaininfo.shared_info_frame, control_evtchn,
|
||||
flags, vcpus, store_evtchn, store_mfn) < 0)
|
||||
{
|
||||
ERROR("Error constructing guest OS");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if ( initrd_fd >= 0 )
|
||||
close(initrd_fd);
|
||||
if ( initrd_gfd )
|
||||
gzclose(initrd_gfd);
|
||||
free(image);
|
||||
|
||||
ctxt->flags = VGCF_VMX_GUEST;
|
||||
@@ -813,15 +677,10 @@ int xc_vmx_build(int xc_handle,
|
||||
|
||||
/* No LDT. */
|
||||
ctxt->ldt_ents = 0;
|
||||
|
||||
|
||||
/* Use the default Xen-provided GDT. */
|
||||
ctxt->gdt_ents = 0;
|
||||
|
||||
/* Ring 1 stack is the initial stack. */
|
||||
/*
|
||||
ctxt->kernel_ss = FLAT_KERNEL_DS;
|
||||
ctxt->kernel_sp = vstartinfo_start;
|
||||
*/
|
||||
/* No debugging. */
|
||||
memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
|
||||
|
||||
@@ -845,14 +704,10 @@ int xc_vmx_build(int xc_handle,
|
||||
|
||||
launch_op.cmd = DOM0_SETDOMAININFO;
|
||||
rc = xc_dom0_op(xc_handle, &launch_op);
|
||||
|
||||
|
||||
return rc;
|
||||
|
||||
error_out:
|
||||
if ( initrd_gfd != NULL )
|
||||
gzclose(initrd_gfd);
|
||||
else if ( initrd_fd >= 0 )
|
||||
close(initrd_fd);
|
||||
free(image);
|
||||
|
||||
return -1;
|
||||
@@ -864,7 +719,7 @@ static inline int is_loadable_phdr(Elf32_Phdr *phdr)
|
||||
((phdr->p_flags & (PF_W|PF_X)) != 0));
|
||||
}
|
||||
|
||||
static int parseelfimage(char *elfbase,
|
||||
static int parseelfimage(char *elfbase,
|
||||
unsigned long elfsize,
|
||||
struct domain_setup_info *dsi)
|
||||
{
|
||||
@@ -899,11 +754,11 @@ static int parseelfimage(char *elfbase,
|
||||
ERROR("ELF image has no section-header strings table (shstrtab).");
|
||||
return -EINVAL;
|
||||
}
|
||||
shdr = (Elf32_Shdr *)(elfbase + ehdr->e_shoff +
|
||||
shdr = (Elf32_Shdr *)(elfbase + ehdr->e_shoff +
|
||||
(ehdr->e_shstrndx*ehdr->e_shentsize));
|
||||
shstrtab = elfbase + shdr->sh_offset;
|
||||
|
||||
for ( h = 0; h < ehdr->e_phnum; h++ )
|
||||
|
||||
for ( h = 0; h < ehdr->e_phnum; h++ )
|
||||
{
|
||||
phdr = (Elf32_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
|
||||
if ( !is_loadable_phdr(phdr) )
|
||||
@@ -914,8 +769,8 @@ static int parseelfimage(char *elfbase,
|
||||
kernend = phdr->p_paddr + phdr->p_memsz;
|
||||
}
|
||||
|
||||
if ( (kernstart > kernend) ||
|
||||
(ehdr->e_entry < kernstart) ||
|
||||
if ( (kernstart > kernend) ||
|
||||
(ehdr->e_entry < kernstart) ||
|
||||
(ehdr->e_entry > kernend) )
|
||||
{
|
||||
ERROR("Malformed ELF image.");
|
||||
@@ -924,9 +779,9 @@ static int parseelfimage(char *elfbase,
|
||||
|
||||
dsi->v_start = 0x00000000;
|
||||
|
||||
dsi->v_kernstart = kernstart - LINUX_PAGE_OFFSET;
|
||||
dsi->v_kernend = kernend - LINUX_PAGE_OFFSET;
|
||||
dsi->v_kernentry = LINUX_KERNEL_ENTR_ADDR;
|
||||
dsi->v_kernstart = kernstart;
|
||||
dsi->v_kernend = kernend;
|
||||
dsi->v_kernentry = VMX_LOADER_ENTR_ADDR;
|
||||
|
||||
dsi->v_end = dsi->v_kernend;
|
||||
|
||||
@@ -945,18 +800,18 @@ loadelfimage(
|
||||
char *va;
|
||||
unsigned long pa, done, chunksz;
|
||||
|
||||
for ( h = 0; h < ehdr->e_phnum; h++ )
|
||||
for ( h = 0; h < ehdr->e_phnum; h++ )
|
||||
{
|
||||
phdr = (Elf32_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
|
||||
if ( !is_loadable_phdr(phdr) )
|
||||
continue;
|
||||
|
||||
|
||||
for ( done = 0; done < phdr->p_filesz; done += chunksz )
|
||||
{
|
||||
pa = (phdr->p_paddr + done) - dsi->v_start - LINUX_PAGE_OFFSET;
|
||||
pa = (phdr->p_paddr + done) - dsi->v_start;
|
||||
if ((va = xc_map_foreign_range(
|
||||
xch, dom, PAGE_SIZE, PROT_WRITE,
|
||||
parray[pa>>PAGE_SHIFT])) == 0)
|
||||
parray[pa >> PAGE_SHIFT])) == 0)
|
||||
return -1;
|
||||
chunksz = phdr->p_filesz - done;
|
||||
if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
|
||||
@@ -968,10 +823,10 @@ loadelfimage(
|
||||
|
||||
for ( ; done < phdr->p_memsz; done += chunksz )
|
||||
{
|
||||
pa = (phdr->p_paddr + done) - dsi->v_start - LINUX_PAGE_OFFSET;
|
||||
pa = (phdr->p_paddr + done) - dsi->v_start;
|
||||
if ((va = xc_map_foreign_range(
|
||||
xch, dom, PAGE_SIZE, PROT_WRITE,
|
||||
parray[pa>>PAGE_SHIFT])) == 0)
|
||||
parray[pa >> PAGE_SHIFT])) == 0)
|
||||
return -1;
|
||||
chunksz = phdr->p_memsz - done;
|
||||
if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
|
||||
|
||||
@@ -57,9 +57,6 @@ int xc_vmx_build(int xc_handle,
|
||||
uint32_t domid,
|
||||
int memsize,
|
||||
const char *image_name,
|
||||
struct mem_map *memmap,
|
||||
const char *ramdisk_name,
|
||||
const char *cmdline,
|
||||
unsigned int control_evtchn,
|
||||
unsigned long flags,
|
||||
unsigned int vcpus,
|
||||
|
||||
+18
-15
@@ -28,25 +28,27 @@ unsigned long csum_page (void * page);
|
||||
#define _PAGE_PSE 0x080
|
||||
#define _PAGE_GLOBAL 0x100
|
||||
|
||||
#if defined(__i386__)
|
||||
#define L1_PAGETABLE_SHIFT 12
|
||||
#define L2_PAGETABLE_SHIFT 22
|
||||
#define L1_PAGETABLE_SHIFT_PAE 12
|
||||
#define L2_PAGETABLE_SHIFT_PAE 21
|
||||
#define L3_PAGETABLE_SHIFT_PAE 30
|
||||
|
||||
#if defined(__i386__)
|
||||
#define L1_PAGETABLE_SHIFT 12
|
||||
#define L2_PAGETABLE_SHIFT 22
|
||||
#elif defined(__x86_64__)
|
||||
#define L1_PAGETABLE_SHIFT 12
|
||||
#define L2_PAGETABLE_SHIFT 21
|
||||
#define L3_PAGETABLE_SHIFT 30
|
||||
#define L4_PAGETABLE_SHIFT 39
|
||||
#define L1_PAGETABLE_SHIFT 12
|
||||
#define L2_PAGETABLE_SHIFT 21
|
||||
#define L3_PAGETABLE_SHIFT 30
|
||||
#define L4_PAGETABLE_SHIFT 39
|
||||
#endif
|
||||
|
||||
#if defined(__i386__)
|
||||
#define ENTRIES_PER_L1_PAGETABLE 1024
|
||||
#define ENTRIES_PER_L2_PAGETABLE 1024
|
||||
#define L1_PAGETABLE_ENTRIES_PAE 512
|
||||
#define L2_PAGETABLE_ENTRIES_PAE 512
|
||||
#define L3_PAGETABLE_ENTRIES_PAE 4
|
||||
|
||||
#if defined(__i386__)
|
||||
#define L1_PAGETABLE_ENTRIES 1024
|
||||
#define L2_PAGETABLE_ENTRIES 1024
|
||||
#elif defined(__x86_64__)
|
||||
#define L1_PAGETABLE_ENTRIES 512
|
||||
#define L2_PAGETABLE_ENTRIES 512
|
||||
@@ -70,17 +72,18 @@ typedef unsigned long l3_pgentry_t;
|
||||
typedef unsigned long l4_pgentry_t;
|
||||
#endif
|
||||
|
||||
#if defined(__i386__)
|
||||
#define l1_table_offset(_a) \
|
||||
(((_a) >> L1_PAGETABLE_SHIFT) & (ENTRIES_PER_L1_PAGETABLE - 1))
|
||||
#define l2_table_offset(_a) \
|
||||
((_a) >> L2_PAGETABLE_SHIFT)
|
||||
#define l1_table_offset_pae(_a) \
|
||||
(((_a) >> L1_PAGETABLE_SHIFT_PAE) & (L1_PAGETABLE_ENTRIES_PAE - 1))
|
||||
#define l2_table_offset_pae(_a) \
|
||||
(((_a) >> L2_PAGETABLE_SHIFT_PAE) & (L2_PAGETABLE_ENTRIES_PAE - 1))
|
||||
#define l3_table_offset_pae(_a) \
|
||||
(((_a) >> L3_PAGETABLE_SHIFT_PAE) & (L3_PAGETABLE_ENTRIES_PAE - 1))
|
||||
|
||||
#if defined(__i386__)
|
||||
#define l1_table_offset(_a) \
|
||||
(((_a) >> L1_PAGETABLE_SHIFT) & (L1_PAGETABLE_ENTRIES - 1))
|
||||
#define l2_table_offset(_a) \
|
||||
((_a) >> L2_PAGETABLE_SHIFT)
|
||||
#elif defined(__x86_64__)
|
||||
#define l1_table_offset(_a) \
|
||||
(((_a) >> L1_PAGETABLE_SHIFT) & (L1_PAGETABLE_ENTRIES - 1))
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "xc_private.h"
|
||||
#include "linux_boot_params.h"
|
||||
|
||||
/* Needed for Python versions earlier than 2.3. */
|
||||
#ifndef PyMODINIT_FUNC
|
||||
@@ -310,80 +309,24 @@ static PyObject *pyxc_vmx_build(PyObject *self,
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom;
|
||||
char *image, *ramdisk = NULL, *cmdline = "";
|
||||
PyObject *memmap;
|
||||
char *image;
|
||||
int control_evtchn, store_evtchn;
|
||||
int flags = 0, vcpus = 1;
|
||||
int numItems, i;
|
||||
int memsize;
|
||||
struct mem_map mem_map;
|
||||
unsigned long store_mfn = 0;
|
||||
|
||||
static char *kwd_list[] = { "dom", "control_evtchn", "store_evtchn",
|
||||
"memsize", "image", "memmap",
|
||||
"ramdisk", "cmdline", "flags",
|
||||
"vcpus", NULL };
|
||||
"memsize", "image", "flags", "vcpus", NULL };
|
||||
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiisO!|ssii", kwd_list,
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiisii", kwd_list,
|
||||
&dom, &control_evtchn, &store_evtchn,
|
||||
&memsize,
|
||||
&image, &PyList_Type, &memmap,
|
||||
&ramdisk, &cmdline, &flags, &vcpus) )
|
||||
&memsize, &image, &flags, &vcpus) )
|
||||
return NULL;
|
||||
|
||||
memset(&mem_map, 0, sizeof(mem_map));
|
||||
/* Parse memmap */
|
||||
|
||||
/* get the number of lines passed to us */
|
||||
numItems = PyList_Size(memmap) - 1; /* removing the line
|
||||
containing "memmap" */
|
||||
mem_map.nr_map = numItems;
|
||||
|
||||
/* should raise an error here. */
|
||||
if (numItems < 0) return NULL; /* Not a list */
|
||||
|
||||
/* iterate over items of the list, grabbing ranges and parsing them */
|
||||
for (i = 1; i <= numItems; i++) { // skip over "memmap"
|
||||
PyObject *item, *f1, *f2, *f3, *f4;
|
||||
int numFields;
|
||||
unsigned long lf1, lf2, lf3, lf4;
|
||||
char *sf1, *sf2;
|
||||
|
||||
/* grab the string object from the next element of the list */
|
||||
item = PyList_GetItem(memmap, i); /* Can't fail */
|
||||
|
||||
/* get the number of lines passed to us */
|
||||
numFields = PyList_Size(item);
|
||||
|
||||
if (numFields != 4)
|
||||
return NULL;
|
||||
|
||||
f1 = PyList_GetItem(item, 0);
|
||||
f2 = PyList_GetItem(item, 1);
|
||||
f3 = PyList_GetItem(item, 2);
|
||||
f4 = PyList_GetItem(item, 3);
|
||||
|
||||
/* Convert objects to strings/longs */
|
||||
sf1 = PyString_AsString(f1);
|
||||
sf2 = PyString_AsString(f2);
|
||||
lf3 = PyLong_AsLong(f3);
|
||||
lf4 = PyLong_AsLong(f4);
|
||||
if ( sscanf(sf1, "%lx", &lf1) != 1 )
|
||||
return NULL;
|
||||
if ( sscanf(sf2, "%lx", &lf2) != 1 )
|
||||
return NULL;
|
||||
|
||||
mem_map.map[i-1].addr = lf1;
|
||||
mem_map.map[i-1].size = lf2 - lf1;
|
||||
mem_map.map[i-1].type = lf3;
|
||||
mem_map.map[i-1].caching_attr = lf4;
|
||||
}
|
||||
|
||||
if ( xc_vmx_build(xc->xc_handle, dom, memsize, image, &mem_map,
|
||||
ramdisk, cmdline, control_evtchn, flags,
|
||||
vcpus, store_evtchn, &store_mfn) != 0 )
|
||||
if ( xc_vmx_build(xc->xc_handle, dom, memsize, image, control_evtchn,
|
||||
flags, vcpus, store_evtchn, &store_mfn) != 0 )
|
||||
return PyErr_SetFromErrno(xc_error);
|
||||
|
||||
|
||||
return Py_BuildValue("{s:i}", "store_mfn", store_mfn);
|
||||
}
|
||||
|
||||
|
||||
@@ -582,9 +582,8 @@ static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
}
|
||||
|
||||
#define xspy_transaction_start_doc "\n" \
|
||||
"Start a transaction on a path.\n" \
|
||||
"Start a transaction.\n" \
|
||||
"Only one transaction can be active at a time.\n" \
|
||||
" path [string]: xenstore path.\n" \
|
||||
"\n" \
|
||||
"Returns None on success.\n" \
|
||||
"Raises RuntimeError on error.\n" \
|
||||
@@ -593,8 +592,8 @@ static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
static PyObject *xspy_transaction_start(PyObject *self, PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static char *kwd_spec[] = { "path", NULL };
|
||||
static char *arg_spec = "s|";
|
||||
static char *kwd_spec[] = { NULL };
|
||||
static char *arg_spec = "";
|
||||
char *path = NULL;
|
||||
|
||||
struct xs_handle *xh = xshandle(self);
|
||||
@@ -606,7 +605,7 @@ static PyObject *xspy_transaction_start(PyObject *self, PyObject *args,
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
|
||||
goto exit;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_transaction_start(xh, path);
|
||||
xsval = xs_transaction_start(xh);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (!xsval) {
|
||||
PyErr_SetFromErrno(PyExc_RuntimeError);
|
||||
@@ -623,7 +622,7 @@ static PyObject *xspy_transaction_start(PyObject *self, PyObject *args,
|
||||
"Attempts to commit the transaction unless abort is true.\n" \
|
||||
" abort [int]: abort flag (default 0).\n" \
|
||||
"\n" \
|
||||
"Returns None on success.\n" \
|
||||
"Returns True on success, False if you need to try again.\n" \
|
||||
"Raises RuntimeError on error.\n" \
|
||||
"\n"
|
||||
|
||||
@@ -646,11 +645,16 @@ static PyObject *xspy_transaction_end(PyObject *self, PyObject *args,
|
||||
xsval = xs_transaction_end(xh, abort);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (!xsval) {
|
||||
if (errno == EAGAIN) {
|
||||
Py_INCREF(Py_False);
|
||||
val = Py_False;
|
||||
goto exit;
|
||||
}
|
||||
PyErr_SetFromErrno(PyExc_RuntimeError);
|
||||
goto exit;
|
||||
}
|
||||
Py_INCREF(Py_None);
|
||||
val = Py_None;
|
||||
Py_INCREF(Py_True);
|
||||
val = Py_True;
|
||||
exit:
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
mem_caching_attr = {
|
||||
'UC' : 0,
|
||||
'WC' : 1,
|
||||
'WT' : 4,
|
||||
'WP' : 5,
|
||||
'WB' : 6,
|
||||
};
|
||||
|
||||
e820_mem_type = {
|
||||
'AddressRangeMemory' : 1,
|
||||
'AddressRangeReserved' : 2,
|
||||
'AddressRangeACPI' : 3,
|
||||
'AddressRangeNVS' : 4,
|
||||
'AddressRangeIO' : 16,
|
||||
'AddressRangeShared' : 17,
|
||||
};
|
||||
|
||||
MT_COL = 2
|
||||
MA_COL = 3
|
||||
|
||||
def strmap(row):
|
||||
if (type(row) != type([])):
|
||||
return row
|
||||
row[MT_COL] = e820_mem_type[row[MT_COL]]
|
||||
row[MA_COL] = mem_caching_attr[row[MA_COL]]
|
||||
return row
|
||||
|
||||
def memmap_parse(memmap):
|
||||
return map(strmap, memmap)
|
||||
|
||||
if __name__ == '__main__':
|
||||
memmap = [ 'memmap',
|
||||
[ '1', '2', 'AddressRangeMemory', 'UC'],
|
||||
[ '1', '2', 'AddressRangeReserved', 'UC'],
|
||||
[ '1', '2', 'AddressRangeACPI', 'WB'],
|
||||
[ '1', '2', 'AddressRangeNVS', 'WB'],
|
||||
[ '1', '2', 'AddressRangeIO', 'WB'],
|
||||
[ '1', '2', 'AddressRangeShared', 'WB']]
|
||||
print memmap_parse(memmap);
|
||||
|
||||
|
||||
@@ -1,451 +0,0 @@
|
||||
"""Temporary files.
|
||||
|
||||
This module provides generic, low- and high-level interfaces for
|
||||
creating temporary files and directories. The interfaces listed
|
||||
as "safe" just below can be used without fear of race conditions.
|
||||
Those listed as "unsafe" cannot, and are provided for backward
|
||||
compatibility only.
|
||||
|
||||
This module also provides some data items to the user:
|
||||
|
||||
TMP_MAX - maximum number of names that will be tried before
|
||||
giving up.
|
||||
template - the default prefix for all temporary names.
|
||||
You may change this to control the default prefix.
|
||||
tempdir - If this is set to a string before the first use of
|
||||
any routine from this module, it will be considered as
|
||||
another candidate location to store temporary files.
|
||||
"""
|
||||
|
||||
__all__ = [
|
||||
"NamedTemporaryFile", "TemporaryFile", # high level safe interfaces
|
||||
"mkstemp", "mkdtemp", # low level safe interfaces
|
||||
"mktemp", # deprecated unsafe interface
|
||||
"TMP_MAX", "gettempprefix", # constants
|
||||
"tempdir", "gettempdir"
|
||||
]
|
||||
|
||||
|
||||
# Imports.
|
||||
|
||||
import os as _os
|
||||
import errno as _errno
|
||||
from random import Random as _Random
|
||||
|
||||
if _os.name == 'mac':
|
||||
import Carbon.Folder as _Folder
|
||||
import Carbon.Folders as _Folders
|
||||
|
||||
try:
|
||||
import fcntl as _fcntl
|
||||
# If PYTHONCASEOK is set on Windows, stinking FCNTL.py gets
|
||||
# imported, and we don't get an ImportError then. Provoke
|
||||
# an AttributeError instead in that case.
|
||||
_fcntl.fcntl
|
||||
except (ImportError, AttributeError):
|
||||
def _set_cloexec(fd):
|
||||
pass
|
||||
else:
|
||||
def _set_cloexec(fd):
|
||||
flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0)
|
||||
if flags >= 0:
|
||||
# flags read successfully, modify
|
||||
flags |= _fcntl.FD_CLOEXEC
|
||||
_fcntl.fcntl(fd, _fcntl.F_SETFD, flags)
|
||||
|
||||
|
||||
try:
|
||||
import thread as _thread
|
||||
except ImportError:
|
||||
import dummy_thread as _thread
|
||||
_allocate_lock = _thread.allocate_lock
|
||||
|
||||
_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL
|
||||
if hasattr(_os, 'O_NOINHERIT'):
|
||||
_text_openflags |= _os.O_NOINHERIT
|
||||
if hasattr(_os, 'O_NOFOLLOW'):
|
||||
_text_openflags |= _os.O_NOFOLLOW
|
||||
|
||||
_bin_openflags = _text_openflags
|
||||
if hasattr(_os, 'O_BINARY'):
|
||||
_bin_openflags |= _os.O_BINARY
|
||||
|
||||
if hasattr(_os, 'TMP_MAX'):
|
||||
TMP_MAX = _os.TMP_MAX
|
||||
else:
|
||||
TMP_MAX = 10000
|
||||
|
||||
template = "tmp"
|
||||
|
||||
tempdir = None
|
||||
|
||||
# Internal routines.
|
||||
|
||||
_once_lock = _allocate_lock()
|
||||
|
||||
class _RandomNameSequence:
|
||||
"""An instance of _RandomNameSequence generates an endless
|
||||
sequence of unpredictable strings which can safely be incorporated
|
||||
into file names. Each string is six characters long. Multiple
|
||||
threads can safely use the same instance at the same time.
|
||||
|
||||
_RandomNameSequence is an iterator."""
|
||||
|
||||
characters = ("abcdefghijklmnopqrstuvwxyz" +
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
|
||||
"0123456789-_")
|
||||
|
||||
def __init__(self):
|
||||
self.mutex = _allocate_lock()
|
||||
self.rng = _Random()
|
||||
self.normcase = _os.path.normcase
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
m = self.mutex
|
||||
c = self.characters
|
||||
choose = self.rng.choice
|
||||
|
||||
m.acquire()
|
||||
try:
|
||||
letters = [choose(c) for dummy in "123456"]
|
||||
finally:
|
||||
m.release()
|
||||
|
||||
return self.normcase(''.join(letters))
|
||||
|
||||
def _candidate_tempdir_list():
|
||||
"""Generate a list of candidate temporary directories which
|
||||
_get_default_tempdir will try."""
|
||||
|
||||
dirlist = []
|
||||
|
||||
# First, try the environment.
|
||||
for envname in 'TMPDIR', 'TEMP', 'TMP':
|
||||
dirname = _os.getenv(envname)
|
||||
if dirname: dirlist.append(dirname)
|
||||
|
||||
# Failing that, try OS-specific locations.
|
||||
if _os.name == 'mac':
|
||||
try:
|
||||
fsr = _Folder.FSFindFolder(_Folders.kOnSystemDisk,
|
||||
_Folders.kTemporaryFolderType, 1)
|
||||
dirname = fsr.as_pathname()
|
||||
dirlist.append(dirname)
|
||||
except _Folder.error:
|
||||
pass
|
||||
elif _os.name == 'riscos':
|
||||
dirname = _os.getenv('Wimp$ScrapDir')
|
||||
if dirname: dirlist.append(dirname)
|
||||
elif _os.name == 'nt':
|
||||
dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ])
|
||||
else:
|
||||
dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ])
|
||||
|
||||
# As a last resort, the current directory.
|
||||
try:
|
||||
dirlist.append(_os.getcwd())
|
||||
except (AttributeError, _os.error):
|
||||
dirlist.append(_os.curdir)
|
||||
|
||||
return dirlist
|
||||
|
||||
def _get_default_tempdir():
|
||||
"""Calculate the default directory to use for temporary files.
|
||||
This routine should be called exactly once.
|
||||
|
||||
We determine whether or not a candidate temp dir is usable by
|
||||
trying to create and write to a file in that directory. If this
|
||||
is successful, the test file is deleted. To prevent denial of
|
||||
service, the name of the test file must be randomized."""
|
||||
|
||||
namer = _RandomNameSequence()
|
||||
dirlist = _candidate_tempdir_list()
|
||||
flags = _text_openflags
|
||||
|
||||
for dir in dirlist:
|
||||
if dir != _os.curdir:
|
||||
dir = _os.path.normcase(_os.path.abspath(dir))
|
||||
# Try only a few names per directory.
|
||||
for seq in xrange(100):
|
||||
name = namer.next()
|
||||
filename = _os.path.join(dir, name)
|
||||
try:
|
||||
fd = _os.open(filename, flags, 0600)
|
||||
fp = _os.fdopen(fd, 'w')
|
||||
fp.write('blat')
|
||||
fp.close()
|
||||
_os.unlink(filename)
|
||||
del fp, fd
|
||||
return dir
|
||||
except (OSError, IOError), e:
|
||||
if e[0] != _errno.EEXIST:
|
||||
break # no point trying more names in this directory
|
||||
pass
|
||||
raise IOError, (_errno.ENOENT,
|
||||
("No usable temporary directory found in %s" % dirlist))
|
||||
|
||||
_name_sequence = None
|
||||
|
||||
def _get_candidate_names():
|
||||
"""Common setup sequence for all user-callable interfaces."""
|
||||
|
||||
global _name_sequence
|
||||
if _name_sequence is None:
|
||||
_once_lock.acquire()
|
||||
try:
|
||||
if _name_sequence is None:
|
||||
_name_sequence = _RandomNameSequence()
|
||||
finally:
|
||||
_once_lock.release()
|
||||
return _name_sequence
|
||||
|
||||
|
||||
def _mkstemp_inner(dir, pre, suf, flags):
|
||||
"""Code common to mkstemp, TemporaryFile, and NamedTemporaryFile."""
|
||||
|
||||
names = _get_candidate_names()
|
||||
|
||||
for seq in xrange(TMP_MAX):
|
||||
name = names.next()
|
||||
file = _os.path.join(dir, pre + name + suf)
|
||||
try:
|
||||
fd = _os.open(file, flags, 0600)
|
||||
_set_cloexec(fd)
|
||||
return (fd, file)
|
||||
except OSError, e:
|
||||
if e.errno == _errno.EEXIST:
|
||||
continue # try again
|
||||
raise
|
||||
|
||||
raise IOError, (_errno.EEXIST, "No usable temporary file name found")
|
||||
|
||||
|
||||
# User visible interfaces.
|
||||
|
||||
def gettempprefix():
|
||||
"""Accessor for tempdir.template."""
|
||||
return template
|
||||
|
||||
tempdir = None
|
||||
|
||||
def gettempdir():
|
||||
"""Accessor for tempdir.tempdir."""
|
||||
global tempdir
|
||||
if tempdir is None:
|
||||
_once_lock.acquire()
|
||||
try:
|
||||
if tempdir is None:
|
||||
tempdir = _get_default_tempdir()
|
||||
finally:
|
||||
_once_lock.release()
|
||||
return tempdir
|
||||
|
||||
def mkstemp(suffix="", prefix=template, dir=None, text=False):
|
||||
"""mkstemp([suffix, [prefix, [dir, [text]]]])
|
||||
User-callable function to create and return a unique temporary
|
||||
file. The return value is a pair (fd, name) where fd is the
|
||||
file descriptor returned by os.open, and name is the filename.
|
||||
|
||||
If 'suffix' is specified, the file name will end with that suffix,
|
||||
otherwise there will be no suffix.
|
||||
|
||||
If 'prefix' is specified, the file name will begin with that prefix,
|
||||
otherwise a default prefix is used.
|
||||
|
||||
If 'dir' is specified, the file will be created in that directory,
|
||||
otherwise a default directory is used.
|
||||
|
||||
If 'text' is specified and true, the file is opened in text
|
||||
mode. Else (the default) the file is opened in binary mode. On
|
||||
some operating systems, this makes no difference.
|
||||
|
||||
The file is readable and writable only by the creating user ID.
|
||||
If the operating system uses permission bits to indicate whether a
|
||||
file is executable, the file is executable by no one. The file
|
||||
descriptor is not inherited by children of this process.
|
||||
|
||||
Caller is responsible for deleting the file when done with it.
|
||||
"""
|
||||
|
||||
if dir is None:
|
||||
dir = gettempdir()
|
||||
|
||||
if text:
|
||||
flags = _text_openflags
|
||||
else:
|
||||
flags = _bin_openflags
|
||||
|
||||
return _mkstemp_inner(dir, prefix, suffix, flags)
|
||||
|
||||
|
||||
def mkdtemp(suffix="", prefix=template, dir=None):
|
||||
"""mkdtemp([suffix, [prefix, [dir]]])
|
||||
User-callable function to create and return a unique temporary
|
||||
directory. The return value is the pathname of the directory.
|
||||
|
||||
Arguments are as for mkstemp, except that the 'text' argument is
|
||||
not accepted.
|
||||
|
||||
The directory is readable, writable, and searchable only by the
|
||||
creating user.
|
||||
|
||||
Caller is responsible for deleting the directory when done with it.
|
||||
"""
|
||||
|
||||
if dir is None:
|
||||
dir = gettempdir()
|
||||
|
||||
names = _get_candidate_names()
|
||||
|
||||
for seq in xrange(TMP_MAX):
|
||||
name = names.next()
|
||||
file = _os.path.join(dir, prefix + name + suffix)
|
||||
try:
|
||||
_os.mkdir(file, 0700)
|
||||
return file
|
||||
except OSError, e:
|
||||
if e.errno == _errno.EEXIST:
|
||||
continue # try again
|
||||
raise
|
||||
|
||||
raise IOError, (_errno.EEXIST, "No usable temporary directory name found")
|
||||
|
||||
def mktemp(suffix="", prefix=template, dir=None):
|
||||
"""mktemp([suffix, [prefix, [dir]]])
|
||||
User-callable function to return a unique temporary file name. The
|
||||
file is not created.
|
||||
|
||||
Arguments are as for mkstemp, except that the 'text' argument is
|
||||
not accepted.
|
||||
|
||||
This function is unsafe and should not be used. The file name
|
||||
refers to a file that did not exist at some point, but by the time
|
||||
you get around to creating it, someone else may have beaten you to
|
||||
the punch.
|
||||
"""
|
||||
|
||||
## from warnings import warn as _warn
|
||||
## _warn("mktemp is a potential security risk to your program",
|
||||
## RuntimeWarning, stacklevel=2)
|
||||
|
||||
if dir is None:
|
||||
dir = gettempdir()
|
||||
|
||||
names = _get_candidate_names()
|
||||
for seq in xrange(TMP_MAX):
|
||||
name = names.next()
|
||||
file = _os.path.join(dir, prefix + name + suffix)
|
||||
if not _os.path.exists(file):
|
||||
return file
|
||||
|
||||
raise IOError, (_errno.EEXIST, "No usable temporary filename found")
|
||||
|
||||
class _TemporaryFileWrapper:
|
||||
"""Temporary file wrapper
|
||||
|
||||
This class provides a wrapper around files opened for
|
||||
temporary use. In particular, it seeks to automatically
|
||||
remove the file when it is no longer needed.
|
||||
"""
|
||||
|
||||
def __init__(self, file, name):
|
||||
self.file = file
|
||||
self.name = name
|
||||
self.close_called = False
|
||||
|
||||
def __getattr__(self, name):
|
||||
file = self.__dict__['file']
|
||||
a = getattr(file, name)
|
||||
if type(a) != type(0):
|
||||
setattr(self, name, a)
|
||||
return a
|
||||
|
||||
# NT provides delete-on-close as a primitive, so we don't need
|
||||
# the wrapper to do anything special. We still use it so that
|
||||
# file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile.
|
||||
if _os.name != 'nt':
|
||||
|
||||
# Cache the unlinker so we don't get spurious errors at
|
||||
# shutdown when the module-level "os" is None'd out. Note
|
||||
# that this must be referenced as self.unlink, because the
|
||||
# name TemporaryFileWrapper may also get None'd out before
|
||||
# __del__ is called.
|
||||
unlink = _os.unlink
|
||||
|
||||
def close(self):
|
||||
if not self.close_called:
|
||||
self.close_called = True
|
||||
self.file.close()
|
||||
self.unlink(self.name)
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="",
|
||||
prefix=template, dir=None):
|
||||
"""Create and return a temporary file.
|
||||
Arguments:
|
||||
'prefix', 'suffix', 'dir' -- as for mkstemp.
|
||||
'mode' -- the mode argument to os.fdopen (default "w+b").
|
||||
'bufsize' -- the buffer size argument to os.fdopen (default -1).
|
||||
The file is created as mkstemp() would do it.
|
||||
|
||||
Returns a file object; the name of the file is accessible as
|
||||
file.name. The file will be automatically deleted when it is
|
||||
closed.
|
||||
"""
|
||||
|
||||
if dir is None:
|
||||
dir = gettempdir()
|
||||
|
||||
if 'b' in mode:
|
||||
flags = _bin_openflags
|
||||
else:
|
||||
flags = _text_openflags
|
||||
|
||||
# Setting O_TEMPORARY in the flags causes the OS to delete
|
||||
# the file when it is closed. This is only supported by Windows.
|
||||
if _os.name == 'nt':
|
||||
flags |= _os.O_TEMPORARY
|
||||
|
||||
(fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)
|
||||
file = _os.fdopen(fd, mode, bufsize)
|
||||
return _TemporaryFileWrapper(file, name)
|
||||
|
||||
if _os.name != 'posix' or _os.sys.platform == 'cygwin':
|
||||
# On non-POSIX and Cygwin systems, assume that we cannot unlink a file
|
||||
# while it is open.
|
||||
TemporaryFile = NamedTemporaryFile
|
||||
|
||||
else:
|
||||
def TemporaryFile(mode='w+b', bufsize=-1, suffix="",
|
||||
prefix=template, dir=None):
|
||||
"""Create and return a temporary file.
|
||||
Arguments:
|
||||
'prefix', 'suffix', 'directory' -- as for mkstemp.
|
||||
'mode' -- the mode argument to os.fdopen (default "w+b").
|
||||
'bufsize' -- the buffer size argument to os.fdopen (default -1).
|
||||
The file is created as mkstemp() would do it.
|
||||
|
||||
Returns a file object. The file has no name, and will cease to
|
||||
exist when it is closed.
|
||||
"""
|
||||
|
||||
if dir is None:
|
||||
dir = gettempdir()
|
||||
|
||||
if 'b' in mode:
|
||||
flags = _bin_openflags
|
||||
else:
|
||||
flags = _text_openflags
|
||||
|
||||
(fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)
|
||||
try:
|
||||
_os.unlink(name)
|
||||
return _os.fdopen(fd, mode, bufsize)
|
||||
except:
|
||||
_os.close(fd)
|
||||
raise
|
||||
@@ -1,43 +0,0 @@
|
||||
"""Xend interface to block control scripts.
|
||||
"""
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import string
|
||||
import xen.util.process
|
||||
|
||||
from xen.xend import XendRoot
|
||||
|
||||
xroot = XendRoot.instance()
|
||||
|
||||
"""Where network control scripts live."""
|
||||
SCRIPT_DIR = xroot.block_script_dir
|
||||
|
||||
def block(op, type, dets, script=None):
|
||||
"""Call a block control script.
|
||||
Xend calls this with op 'bind' when it is about to export a block device
|
||||
(other than a raw partition). The script is called with unbind when a
|
||||
device is no longer in use and should be removed.
|
||||
|
||||
@param op: operation (start, stop, status)
|
||||
@param type: type of block device (determines the script used)
|
||||
@param dets: arguments to the control script
|
||||
@param script: block script name
|
||||
"""
|
||||
|
||||
if op not in ['bind', 'unbind']:
|
||||
raise ValueError('Invalid operation:' + op)
|
||||
|
||||
# Special case phy devices - they don't require any (un)binding
|
||||
# Parallax also doesn't need script-based binding.
|
||||
if (type == 'phy') or (type == 'parallax'):
|
||||
return dets
|
||||
|
||||
if script is None:
|
||||
script = xroot.get_block_script(type)
|
||||
script = os.path.join(SCRIPT_DIR, script)
|
||||
args = [op] + string.split(dets, ':')
|
||||
args = ' '.join(args)
|
||||
ret = xen.util.process.runscript(script + ' ' + args)
|
||||
if len(ret):
|
||||
return ret.splitlines()[0]
|
||||
@@ -252,7 +252,7 @@ class PrettyPrinter:
|
||||
self.block = self.block.parent
|
||||
|
||||
def prettyprint(self, out=sys.stdout):
|
||||
self.top.prettyprint(Line(out, self.width))
|
||||
self.top.prettyprint(Line(out, self.width), self.width)
|
||||
|
||||
class SXPPrettyPrinter(PrettyPrinter):
|
||||
"""An SXP prettyprinter.
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
#============================================================================
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2.1 of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#============================================================================
|
||||
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
|
||||
#============================================================================
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import errno
|
||||
import dircache
|
||||
import time
|
||||
|
||||
import sxp
|
||||
import XendRoot
|
||||
xroot = XendRoot.instance()
|
||||
|
||||
class XendDB:
|
||||
"""Persistence for Xend. Stores data in files and directories.
|
||||
"""
|
||||
|
||||
def __init__(self, path=None):
|
||||
self.dbpath = xroot.get_dbroot()
|
||||
if path:
|
||||
self.dbpath = os.path.join(self.dbpath, path)
|
||||
pass
|
||||
|
||||
def listdir(self, dpath):
|
||||
try:
|
||||
return dircache.listdir(dpath)
|
||||
except:
|
||||
return []
|
||||
|
||||
def filepath(self, path):
|
||||
return os.path.join(self.dbpath, path)
|
||||
|
||||
def fetch(self, path):
|
||||
fpath = self.filepath(path)
|
||||
return self.fetchfile(fpath)
|
||||
|
||||
def fetchfile(self, fpath):
|
||||
pin = sxp.Parser()
|
||||
fin = file(fpath, "rb")
|
||||
try:
|
||||
while 1:
|
||||
try:
|
||||
buf = fin.read(1024)
|
||||
except IOError, ex:
|
||||
if ex.errno == errno.EINTR:
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
pin.input(buf)
|
||||
if buf == '':
|
||||
pin.input_eof()
|
||||
break
|
||||
finally:
|
||||
fin.close()
|
||||
return pin.get_val()
|
||||
|
||||
def save(self, path, sxpr):
|
||||
fpath = self.filepath(path)
|
||||
return self.savefile(fpath, sxpr)
|
||||
|
||||
def savefile(self, fpath, sxpr):
|
||||
backup = False
|
||||
fdir = os.path.dirname(fpath)
|
||||
if not os.path.isdir(fdir):
|
||||
os.makedirs(fdir)
|
||||
if os.path.exists(fpath):
|
||||
backup = True
|
||||
real_fpath = fpath
|
||||
fpath += ".new."
|
||||
|
||||
fout = file(fpath, "wb+")
|
||||
try:
|
||||
try:
|
||||
t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
|
||||
fout.write("# %s %s\n" % (fpath, t))
|
||||
sxp.show(sxpr, out=fout)
|
||||
finally:
|
||||
fout.close()
|
||||
except:
|
||||
if backup:
|
||||
try:
|
||||
os.unlink(fpath)
|
||||
except:
|
||||
pass
|
||||
raise
|
||||
if backup:
|
||||
os.rename(fpath, real_fpath)
|
||||
|
||||
def fetchall(self, path):
|
||||
dpath = self.filepath(path)
|
||||
d = {}
|
||||
for k in self.listdir(dpath):
|
||||
try:
|
||||
v = self.fetchfile(os.path.join(dpath, k))
|
||||
d[k] = v
|
||||
except:
|
||||
pass
|
||||
return d
|
||||
|
||||
def saveall(self, path, d):
|
||||
for (k, v) in d.items():
|
||||
self.save(os.path.join(path, k), v)
|
||||
|
||||
def delete(self, path):
|
||||
dpath = self.filepath(path)
|
||||
os.unlink(dpath)
|
||||
|
||||
def ls(self, path):
|
||||
dpath = self.filepath(path)
|
||||
return self.listdir(dpath)
|
||||
|
||||
|
||||
|
||||
@@ -433,12 +433,11 @@ class XendDomain:
|
||||
self.domain_shutdowns()
|
||||
return val
|
||||
|
||||
|
||||
def domain_sysrq(self, id, key):
|
||||
"""Send a SysRq to a domain
|
||||
"""
|
||||
dominfo = self.domain_lookup(id)
|
||||
val = dominfo.send_sysrq(key)
|
||||
return val
|
||||
"""Send a SysRq to the specified domain."""
|
||||
return self.callInfo(id, XendDomainInfo.send_sysrq, key)
|
||||
|
||||
|
||||
def domain_shutdowns(self):
|
||||
"""Process pending domain shutdowns.
|
||||
@@ -630,73 +629,45 @@ class XendDomain:
|
||||
except Exception, ex:
|
||||
raise XendError(str(ex))
|
||||
|
||||
def domain_device_create(self, id, devconfig):
|
||||
"""Create a new device for a domain.
|
||||
|
||||
@param id: domain id
|
||||
@param devconfig: device configuration
|
||||
def domain_device_create(self, domid, devconfig):
|
||||
"""Create a new device for the specified domain.
|
||||
"""
|
||||
dominfo = self.domain_lookup(id)
|
||||
val = dominfo.device_create(devconfig)
|
||||
dominfo.exportToDB()
|
||||
return val
|
||||
return self.callInfo(domid, XendDomainInfo.device_create, devconfig)
|
||||
|
||||
def domain_device_configure(self, id, devconfig, devid):
|
||||
"""Configure an existing device for a domain.
|
||||
|
||||
@param id: domain id
|
||||
@param devconfig: device configuration
|
||||
@param devid: device id
|
||||
def domain_device_configure(self, domid, devconfig, devid):
|
||||
"""Configure an existing device in the specified domain.
|
||||
@return: updated device configuration
|
||||
"""
|
||||
dominfo = self.domain_lookup(id)
|
||||
val = dominfo.device_configure(devconfig, devid)
|
||||
dominfo.exportToDB()
|
||||
return val
|
||||
return self.callInfo(domid, XendDomainInfo.device_configure,
|
||||
devconfig, devid)
|
||||
|
||||
|
||||
def domain_device_refresh(self, id, type, devid):
|
||||
"""Refresh a device.
|
||||
|
||||
@param id: domain id
|
||||
@param devid: device id
|
||||
@param type: device type
|
||||
"""
|
||||
dominfo = self.domain_lookup(id)
|
||||
val = dominfo.device_refresh(type, devid)
|
||||
dominfo.exportToDB()
|
||||
return val
|
||||
|
||||
def domain_device_destroy(self, id, type, devid):
|
||||
"""Destroy a device.
|
||||
|
||||
@param id: domain id
|
||||
@param devid: device id
|
||||
@param type: device type
|
||||
"""
|
||||
dominfo = self.domain_lookup(id)
|
||||
return dominfo.destroyDevice(type, devid)
|
||||
def domain_device_refresh(self, domid, devtype, devid):
|
||||
"""Refresh a device."""
|
||||
return self.callInfo(domid, XendDomainInfo.device_refresh, devtype,
|
||||
devid)
|
||||
|
||||
|
||||
def domain_devtype_ls(self, id, type):
|
||||
"""Get list of device sxprs for a domain.
|
||||
def domain_device_destroy(self, domid, devtype, devid):
|
||||
"""Destroy a device."""
|
||||
return self.callInfo(domid, XendDomainInfo.destroyDevice, devtype,
|
||||
devid)
|
||||
|
||||
@param id: domain
|
||||
@param type: device type
|
||||
@return: device sxprs
|
||||
"""
|
||||
dominfo = self.domain_lookup(id)
|
||||
return dominfo.getDeviceSxprs(type)
|
||||
|
||||
def domain_devtype_get(self, id, type, devid):
|
||||
def domain_devtype_ls(self, domid, devtype):
|
||||
"""Get list of device sxprs for the specified domain."""
|
||||
return self.callInfo(domid, XendDomainInfo.getDeviceSxprs, devtype)
|
||||
|
||||
|
||||
def domain_devtype_get(self, domid, devtype, devid):
|
||||
"""Get a device from a domain.
|
||||
|
||||
@param id: domain
|
||||
@param type: device type
|
||||
@param devid: device id
|
||||
@return: device object (or None)
|
||||
"""
|
||||
dominfo = self.domain_lookup(id)
|
||||
return dominfo.getDevice(type, devid)
|
||||
return self.callInfo(domid, XendDomainInfo.getDevice, devtype, devid)
|
||||
|
||||
|
||||
def domain_vif_limit_set(self, id, vif, credit, period):
|
||||
"""Limit the vif's transmission rate
|
||||
@@ -723,7 +694,7 @@ class XendDomain:
|
||||
"""Set the memory limit for a domain.
|
||||
|
||||
@param id: domain
|
||||
@param mem: memory limit (in MB)
|
||||
@param mem: memory limit (in MiB)
|
||||
@return: 0 on success, -1 on error
|
||||
"""
|
||||
dominfo = self.domain_lookup(id)
|
||||
@@ -734,42 +705,37 @@ class XendDomain:
|
||||
except Exception, ex:
|
||||
raise XendError(str(ex))
|
||||
|
||||
def domain_mem_target_set(self, id, mem):
|
||||
def domain_mem_target_set(self, domid, mem):
|
||||
"""Set the memory target for a domain.
|
||||
|
||||
@param id: domain
|
||||
@param mem: memory target (in MB)
|
||||
@return: 0 on success, -1 on error
|
||||
@param mem: memory target (in MiB)
|
||||
"""
|
||||
dominfo = self.domain_lookup(id)
|
||||
return dominfo.setMemoryTarget(mem << 10)
|
||||
self.callInfo(domid, XendDomainInfo.setMemoryTarget, mem << 10)
|
||||
|
||||
def domain_vcpu_hotplug(self, id, vcpu, state):
|
||||
"""Enable or disable VCPU vcpu in DOM id
|
||||
|
||||
@param id: domain
|
||||
def domain_vcpu_hotplug(self, domid, vcpu, state):
|
||||
"""Enable or disable specified VCPU in specified domain
|
||||
|
||||
@param vcpu: target VCPU in domain
|
||||
@param state: which state VCPU will become
|
||||
@return: 0 on success, -1 on error
|
||||
"""
|
||||
self.callInfo(domid, XendDomainInfo.vcpu_hotplug, vcpu, state)
|
||||
|
||||
dominfo = self.domain_lookup(id)
|
||||
return dominfo.vcpu_hotplug(vcpu, state)
|
||||
|
||||
def domain_dumpcore(self, id):
|
||||
"""Save a core dump for a crashed domain.
|
||||
def domain_dumpcore(self, domid):
|
||||
"""Save a core dump for a crashed domain."""
|
||||
self.callInfo(domid, XendDomainInfo.dumpCore)
|
||||
|
||||
|
||||
## private:
|
||||
|
||||
def callInfo(self, domid, fn, *args, **kwargs):
|
||||
self.refresh()
|
||||
dominfo = self.domains.get(domid)
|
||||
if dominfo:
|
||||
return fn(dominfo, *args, **kwargs)
|
||||
|
||||
|
||||
@param id: domain
|
||||
"""
|
||||
dominfo = self.domain_lookup(id)
|
||||
corefile = "/var/xen/dump/%s.%s.core" % (dominfo.getName(),
|
||||
dominfo.getDomid())
|
||||
try:
|
||||
xc.domain_dumpcore(dom=dominfo.getDomid(), corefile=corefile)
|
||||
except Exception, ex:
|
||||
log.warning("Dumpcore failed, id=%s name=%s: %s",
|
||||
dominfo.getDomid(), dominfo.getName(), ex)
|
||||
|
||||
def instance():
|
||||
"""Singleton constructor. Use this instead of the class constructor.
|
||||
"""
|
||||
|
||||
@@ -34,6 +34,7 @@ from xen.util.blkif import blkdev_uname_to_file
|
||||
|
||||
from xen.xend.server.channel import EventChannel
|
||||
|
||||
from xen.xend import image
|
||||
from xen.xend import sxp
|
||||
from xen.xend.XendBootloader import bootloader
|
||||
from xen.xend.XendLogging import log
|
||||
@@ -319,6 +320,7 @@ class XendDomainInfo:
|
||||
|
||||
try:
|
||||
defaultInfo('name', lambda: "Domain-%d" % self.domid)
|
||||
defaultInfo('ssidref', lambda: 0)
|
||||
defaultInfo('restart_mode', lambda: RESTART_ONREBOOT)
|
||||
defaultInfo('cpu_weight', lambda: 1.0)
|
||||
defaultInfo('bootloader', lambda: None)
|
||||
@@ -511,6 +513,19 @@ class XendDomainInfo:
|
||||
self.info['backend'], 0)
|
||||
|
||||
|
||||
def dumpCore(self):
|
||||
"""Create a core dump for this domain. Nothrow guarantee."""
|
||||
|
||||
try:
|
||||
corefile = "/var/xen/dump/%s.%s.core" % (self.info['name'],
|
||||
self.domid)
|
||||
xc.domain_dumpcore(dom = self.domid, corefile = corefile)
|
||||
|
||||
except Exception, exn:
|
||||
log.error("XendDomainInfo.dumpCore failed: id = %s name = %s: %s",
|
||||
self.domid, self.info['name'], str(exn))
|
||||
|
||||
|
||||
def closeStoreChannel(self):
|
||||
"""Close the store channel, if any. Nothrow guarantee."""
|
||||
|
||||
@@ -614,7 +629,7 @@ class XendDomainInfo:
|
||||
sxpr.append(['maxmem', self.info['maxmem_KiB'] / 1024])
|
||||
|
||||
if self.infoIsSet('device'):
|
||||
for (n, c) in self.info['device']:
|
||||
for (_, c) in self.info['device']:
|
||||
sxpr.append(['device', c])
|
||||
|
||||
def stateChar(name):
|
||||
@@ -706,13 +721,6 @@ class XendDomainInfo:
|
||||
"""
|
||||
# todo - add support for scheduling params?
|
||||
try:
|
||||
if 'image' not in self.info:
|
||||
raise VmError('Missing image in configuration')
|
||||
|
||||
self.image = ImageHandler.create(self,
|
||||
self.info['image'],
|
||||
self.info['device'])
|
||||
|
||||
self.initDomain()
|
||||
|
||||
# Create domain devices.
|
||||
@@ -737,6 +745,14 @@ class XendDomainInfo:
|
||||
|
||||
self.domid = xc.domain_create(dom = self.domid or 0,
|
||||
ssidref = self.info['ssidref'])
|
||||
|
||||
if 'image' not in self.info:
|
||||
raise VmError('Missing image in configuration')
|
||||
|
||||
self.image = image.create(self,
|
||||
self.info['image'],
|
||||
self.info['device'])
|
||||
|
||||
if self.domid <= 0:
|
||||
raise VmError('Creating domain failed: name=%s' %
|
||||
self.info['name'])
|
||||
@@ -839,20 +855,20 @@ class XendDomainInfo:
|
||||
"""Release all vm devices.
|
||||
"""
|
||||
|
||||
t = xstransact("%s/device" % self.path)
|
||||
|
||||
for n in controllerClasses.keys():
|
||||
for d in t.list(n):
|
||||
try:
|
||||
t.remove(d)
|
||||
except ex:
|
||||
# Log and swallow any exceptions in removal -- there's
|
||||
# nothing more we can do.
|
||||
log.exception(
|
||||
"Device release failed: %s; %s; %s; %s" %
|
||||
(self.info['name'], n, d, str(ex)))
|
||||
t.commit()
|
||||
|
||||
while True:
|
||||
t = xstransact("%s/device" % self.path)
|
||||
for n in controllerClasses.keys():
|
||||
for d in t.list(n):
|
||||
try:
|
||||
t.remove(d)
|
||||
except ex:
|
||||
# Log and swallow any exceptions in removal --
|
||||
# there's nothing more we can do.
|
||||
log.exception(
|
||||
"Device release failed: %s; %s; %s; %s" %
|
||||
(self.info['name'], n, d, str(ex)))
|
||||
if t.commit():
|
||||
break
|
||||
|
||||
def eventChannel(self, path=None):
|
||||
"""Create an event channel to the domain.
|
||||
@@ -1084,19 +1100,6 @@ class XendDomainInfo:
|
||||
return name in self.info and self.info[name] is not None
|
||||
|
||||
|
||||
#============================================================================
|
||||
# Register image handlers.
|
||||
|
||||
from image import \
|
||||
addImageHandlerClass, \
|
||||
ImageHandler, \
|
||||
LinuxImageHandler, \
|
||||
VmxImageHandler
|
||||
|
||||
addImageHandlerClass(LinuxImageHandler)
|
||||
addImageHandlerClass(VmxImageHandler)
|
||||
|
||||
|
||||
#============================================================================
|
||||
# Register device controllers and their device config types.
|
||||
|
||||
|
||||
@@ -33,6 +33,15 @@ xc = xen.lowlevel.xc.new()
|
||||
|
||||
MAX_GUEST_CMDLINE = 1024
|
||||
|
||||
|
||||
def create(vm, imageConfig, deviceConfig):
|
||||
"""Create an image handler for a vm.
|
||||
|
||||
@return ImageHandler instance
|
||||
"""
|
||||
return findImageHandlerClass(imageConfig)(vm, imageConfig, deviceConfig)
|
||||
|
||||
|
||||
class ImageHandler:
|
||||
"""Abstract base class for image handlers.
|
||||
|
||||
@@ -48,81 +57,39 @@ class ImageHandler:
|
||||
|
||||
The method destroy() is called when the domain is destroyed.
|
||||
The default is to do nothing.
|
||||
|
||||
"""
|
||||
|
||||
#======================================================================
|
||||
# Class vars and methods.
|
||||
|
||||
"""Table of image handler classes for virtual machine images.
|
||||
Indexed by image type.
|
||||
"""
|
||||
imageHandlerClasses = {}
|
||||
|
||||
def addImageHandlerClass(cls, h):
|
||||
"""Add a handler class for an image type
|
||||
@param h: handler: ImageHandler subclass
|
||||
"""
|
||||
cls.imageHandlerClasses[h.ostype] = h
|
||||
|
||||
addImageHandlerClass = classmethod(addImageHandlerClass)
|
||||
|
||||
def findImageHandlerClass(cls, image):
|
||||
"""Find the image handler class for an image config.
|
||||
|
||||
@param image config
|
||||
@return ImageHandler subclass or None
|
||||
"""
|
||||
ty = sxp.name(image)
|
||||
if ty is None:
|
||||
raise VmError('missing image type')
|
||||
imageClass = cls.imageHandlerClasses.get(ty)
|
||||
if imageClass is None:
|
||||
raise VmError('unknown image type: ' + ty)
|
||||
return imageClass
|
||||
|
||||
findImageHandlerClass = classmethod(findImageHandlerClass)
|
||||
|
||||
def create(cls, vm, imageConfig, deviceConfig):
|
||||
"""Create an image handler for a vm.
|
||||
|
||||
@return ImageHandler instance
|
||||
"""
|
||||
imageClass = cls.findImageHandlerClass(imageConfig)
|
||||
return imageClass(vm, imageConfig, deviceConfig)
|
||||
|
||||
create = classmethod(create)
|
||||
|
||||
#======================================================================
|
||||
# Instance vars and methods.
|
||||
|
||||
ostype = None
|
||||
|
||||
kernel = None
|
||||
ramdisk = None
|
||||
cmdline = None
|
||||
|
||||
flags = 0
|
||||
|
||||
def __init__(self, vm, imageConfig, deviceConfig):
|
||||
self.vm = vm
|
||||
|
||||
self.kernel = None
|
||||
self.ramdisk = None
|
||||
self.cmdline = None
|
||||
self.flags = 0
|
||||
|
||||
self.configure(imageConfig, deviceConfig)
|
||||
|
||||
def configure(self, imageConfig, _):
|
||||
"""Config actions common to all unix-like domains."""
|
||||
|
||||
self.kernel = sxp.child_value(imageConfig, "kernel")
|
||||
def get_cfg(name, default = None):
|
||||
return sxp.child_value(imageConfig, name, default)
|
||||
|
||||
self.kernel = get_cfg("kernel")
|
||||
self.cmdline = ""
|
||||
ip = sxp.child_value(imageConfig, "ip", None)
|
||||
ip = get_cfg("ip")
|
||||
if ip:
|
||||
self.cmdline += " ip=" + ip
|
||||
root = sxp.child_value(imageConfig, "root")
|
||||
root = get_cfg("root")
|
||||
if root:
|
||||
self.cmdline += " root=" + root
|
||||
args = sxp.child_value(imageConfig, "args")
|
||||
args = get_cfg("args")
|
||||
if args:
|
||||
self.cmdline += " " + args
|
||||
self.ramdisk = sxp.child_value(imageConfig, "ramdisk", '')
|
||||
self.ramdisk = get_cfg("ramdisk", '')
|
||||
|
||||
self.vm.storeVm(("image/ostype", self.ostype),
|
||||
("image/kernel", self.kernel),
|
||||
@@ -130,7 +97,7 @@ class ImageHandler:
|
||||
("image/ramdisk", self.ramdisk))
|
||||
|
||||
|
||||
def handleBootloading():
|
||||
def handleBootloading(self):
|
||||
self.unlink(self.kernel)
|
||||
self.unlink(self.ramdisk)
|
||||
|
||||
@@ -194,7 +161,6 @@ class ImageHandler:
|
||||
if d.has_key('console_mfn'):
|
||||
self.vm.setConsoleRef(d.get('console_mfn'))
|
||||
|
||||
addImageHandlerClass = ImageHandler.addImageHandlerClass
|
||||
|
||||
class LinuxImageHandler(ImageHandler):
|
||||
|
||||
@@ -238,22 +204,19 @@ class VmxImageHandler(ImageHandler):
|
||||
|
||||
def configure(self, imageConfig, deviceConfig):
|
||||
ImageHandler.configure(self, imageConfig, deviceConfig)
|
||||
|
||||
self.memmap = sxp.child_value(imageConfig, 'memmap')
|
||||
|
||||
self.dmargs = self.parseDeviceModelArgs(imageConfig, deviceConfig)
|
||||
self.device_model = sxp.child_value(imageConfig, 'device_model')
|
||||
if not self.device_model:
|
||||
raise VmError("vmx: missing device model")
|
||||
self.display = sxp.child_value(imageConfig, 'display')
|
||||
|
||||
self.vm.storeVm(("image/memmap", self.memmap),
|
||||
("image/dmargs", " ".join(self.dmargs)),
|
||||
self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)),
|
||||
("image/device-model", self.device_model),
|
||||
("image/display", self.display))
|
||||
|
||||
self.device_channel = None
|
||||
self.pid = 0
|
||||
self.memmap_value = []
|
||||
|
||||
self.dmargs += self.configVNC(imageConfig)
|
||||
|
||||
@@ -261,7 +224,6 @@ class VmxImageHandler(ImageHandler):
|
||||
def createImage(self):
|
||||
"""Create a VM for the VMX environment.
|
||||
"""
|
||||
self.parseMemmap()
|
||||
self.createDomain()
|
||||
|
||||
def buildDomain(self):
|
||||
@@ -278,9 +240,6 @@ class VmxImageHandler(ImageHandler):
|
||||
log.debug("control_evtchn = %d", self.device_channel.port2)
|
||||
log.debug("store_evtchn = %d", store_evtchn)
|
||||
log.debug("memsize = %d", self.vm.getMemoryTarget() / 1024)
|
||||
log.debug("memmap = %s", self.memmap_value)
|
||||
log.debug("cmdline = %s", self.cmdline)
|
||||
log.debug("ramdisk = %s", self.ramdisk)
|
||||
log.debug("flags = %d", self.flags)
|
||||
log.debug("vcpus = %d", self.vm.getVCpuCount())
|
||||
|
||||
@@ -289,9 +248,6 @@ class VmxImageHandler(ImageHandler):
|
||||
control_evtchn = self.device_channel.port2,
|
||||
store_evtchn = store_evtchn,
|
||||
memsize = self.vm.getMemoryTarget() / 1024,
|
||||
memmap = self.memmap_value,
|
||||
cmdline = self.cmdline,
|
||||
ramdisk = self.ramdisk,
|
||||
flags = self.flags,
|
||||
vcpus = self.vm.getVCpuCount())
|
||||
if isinstance(ret, dict):
|
||||
@@ -299,18 +255,11 @@ class VmxImageHandler(ImageHandler):
|
||||
return 0
|
||||
return ret
|
||||
|
||||
def parseMemmap(self):
|
||||
if self.memmap is None:
|
||||
return
|
||||
memmap = sxp.parse(open(self.memmap))[0]
|
||||
from xen.util.memmap import memmap_parse
|
||||
self.memmap_value = memmap_parse(memmap)
|
||||
|
||||
# Return a list of cmd line args to the device models based on the
|
||||
# xm config file
|
||||
def parseDeviceModelArgs(self, imageConfig, deviceConfig):
|
||||
dmargs = [ 'cdrom', 'boot', 'fda', 'fdb',
|
||||
'localtime', 'serial', 'stdvga', 'isa', 'vcpus' ]
|
||||
'localtime', 'serial', 'stdvga', 'isa', 'vcpus' ]
|
||||
ret = []
|
||||
for a in dmargs:
|
||||
v = sxp.child_value(imageConfig, a)
|
||||
@@ -439,3 +388,28 @@ class VmxImageHandler(ImageHandler):
|
||||
return 16 * 1024
|
||||
else:
|
||||
return (1 + ((mem_mb + 3) >> 2)) * 4
|
||||
|
||||
|
||||
"""Table of image handler classes for virtual machine images. Indexed by
|
||||
image type.
|
||||
"""
|
||||
imageHandlerClasses = {}
|
||||
|
||||
|
||||
for h in LinuxImageHandler, VmxImageHandler:
|
||||
imageHandlerClasses[h.ostype] = h
|
||||
|
||||
|
||||
def findImageHandlerClass(image):
|
||||
"""Find the image handler class for an image config.
|
||||
|
||||
@param image config
|
||||
@return ImageHandler subclass or None
|
||||
"""
|
||||
ty = sxp.name(image)
|
||||
if ty is None:
|
||||
raise VmError('missing image type')
|
||||
imageClass = imageHandlerClasses.get(ty)
|
||||
if imageClass is None:
|
||||
raise VmError('unknown image type: ' + ty)
|
||||
return imageClass
|
||||
@@ -126,20 +126,21 @@ class DevController:
|
||||
compulsory to use it; subclasses may prefer to allocate IDs based upon
|
||||
the device configuration instead.
|
||||
"""
|
||||
path = self.frontendMiscPath()
|
||||
t = xstransact(path)
|
||||
try:
|
||||
result = t.read("nextDeviceID")
|
||||
if result:
|
||||
result = int(result)
|
||||
else:
|
||||
result = 1
|
||||
t.write("nextDeviceID", str(result + 1))
|
||||
t.commit()
|
||||
return result
|
||||
except:
|
||||
t.abort()
|
||||
raise
|
||||
while True:
|
||||
path = self.frontendMiscPath()
|
||||
t = xstransact(path)
|
||||
try:
|
||||
result = t.read("nextDeviceID")
|
||||
if result:
|
||||
result = int(result)
|
||||
else:
|
||||
result = 1
|
||||
t.write("nextDeviceID", str(result + 1))
|
||||
if t.commit():
|
||||
return result
|
||||
except:
|
||||
t.abort()
|
||||
raise
|
||||
|
||||
|
||||
## private:
|
||||
|
||||
@@ -280,8 +280,8 @@ class XenStore:
|
||||
(', while writing %s : %s' % (str(path),
|
||||
str(data))))
|
||||
|
||||
def begin(self, path):
|
||||
self.getxs().transaction_start(path)
|
||||
def begin(self):
|
||||
self.getxs().transaction_start()
|
||||
|
||||
def commit(self, abandon=False):
|
||||
self.getxs().transaction_end(abort=abandon)
|
||||
|
||||
@@ -14,16 +14,8 @@ class xstransact:
|
||||
def __init__(self, path):
|
||||
self.in_transaction = False
|
||||
self.path = path.rstrip("/")
|
||||
while True:
|
||||
try:
|
||||
xshandle().transaction_start(path)
|
||||
self.in_transaction = True
|
||||
return
|
||||
except RuntimeError, ex:
|
||||
if ex.args[0] == errno.ENOENT and path != "/":
|
||||
path = "/".join(path.split("/")[0:-1]) or "/"
|
||||
else:
|
||||
raise
|
||||
xshandle().transaction_start()
|
||||
self.in_transaction = True
|
||||
|
||||
def __del__(self):
|
||||
if self.in_transaction:
|
||||
@@ -175,14 +167,8 @@ class xstransact:
|
||||
t = cls(path)
|
||||
try:
|
||||
v = t.read(*args)
|
||||
t.commit()
|
||||
return v
|
||||
except RuntimeError, ex:
|
||||
t.abort()
|
||||
if ex.args[0] == errno.ETIMEDOUT:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
return v
|
||||
except:
|
||||
t.abort()
|
||||
raise
|
||||
@@ -194,14 +180,8 @@ class xstransact:
|
||||
t = cls(path)
|
||||
try:
|
||||
t.write(*args, **opts)
|
||||
t.commit()
|
||||
return
|
||||
except RuntimeError, ex:
|
||||
t.abort()
|
||||
if ex.args[0] == errno.ETIMEDOUT:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
if t.commit():
|
||||
return
|
||||
except:
|
||||
t.abort()
|
||||
raise
|
||||
@@ -217,14 +197,8 @@ class xstransact:
|
||||
t = cls(path)
|
||||
try:
|
||||
t.remove(*args)
|
||||
t.commit()
|
||||
return
|
||||
except RuntimeError, ex:
|
||||
t.abort()
|
||||
if ex.args[0] == errno.ETIMEDOUT:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
if t.commit():
|
||||
return
|
||||
except:
|
||||
t.abort()
|
||||
raise
|
||||
@@ -236,14 +210,8 @@ class xstransact:
|
||||
t = cls(path)
|
||||
try:
|
||||
v = t.list(*args)
|
||||
t.commit()
|
||||
return v
|
||||
except RuntimeError, ex:
|
||||
t.abort()
|
||||
if ex.args[0] == errno.ETIMEDOUT:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
if t.commit():
|
||||
return v
|
||||
except:
|
||||
t.abort()
|
||||
raise
|
||||
@@ -255,14 +223,8 @@ class xstransact:
|
||||
t = cls(path)
|
||||
try:
|
||||
v = t.gather(*args)
|
||||
t.commit()
|
||||
return v
|
||||
except RuntimeError, ex:
|
||||
t.abort()
|
||||
if ex.args[0] == errno.ETIMEDOUT:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
if t.commit():
|
||||
return v
|
||||
except:
|
||||
t.abort()
|
||||
raise
|
||||
@@ -274,14 +236,8 @@ class xstransact:
|
||||
t = cls(path)
|
||||
try:
|
||||
v = t.store(*args)
|
||||
t.commit()
|
||||
return v
|
||||
except RuntimeError, ex:
|
||||
t.abort()
|
||||
if ex.args[0] == errno.ETIMEDOUT:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
if t.commit():
|
||||
return v
|
||||
except:
|
||||
t.abort()
|
||||
raise
|
||||
|
||||
+21
-55
@@ -1,5 +1,6 @@
|
||||
# (C) Copyright IBM Corp. 2005
|
||||
# Copyright (C) 2004 Mike Wray
|
||||
# Copyright (c) 2005 XenSource Ltd
|
||||
#
|
||||
# Authors:
|
||||
# Sean Dague <sean at dague dot net>
|
||||
@@ -169,12 +170,6 @@ def handle_xend_error(cmd, dom, ex):
|
||||
#
|
||||
#########################################################################
|
||||
|
||||
def xm_create(args):
|
||||
from xen.xm import create
|
||||
# ugly hack because the opt parser apparently wants
|
||||
# the subcommand name just to throw it away!
|
||||
create.main(["bogus"] + args)
|
||||
|
||||
def xm_save(args):
|
||||
arg_check(args,2,"save")
|
||||
|
||||
@@ -196,13 +191,6 @@ def xm_restore(args):
|
||||
if id is not None:
|
||||
server.xend_domain_unpause(domid)
|
||||
|
||||
def xm_migrate(args):
|
||||
# TODO: arg_check
|
||||
from xen.xm import migrate
|
||||
# ugly hack because the opt parser apparently wants
|
||||
# the subcommand name just to throw it away!
|
||||
migrate.main(["bogus"] + args)
|
||||
|
||||
def xm_list(args):
|
||||
use_long = 0
|
||||
show_vcpus = 0
|
||||
@@ -290,14 +278,6 @@ def xm_show_vcpus(domsinfo):
|
||||
def xm_vcpu_list(args):
|
||||
xm_list(["-v"] + args)
|
||||
|
||||
def xm_destroy(args):
|
||||
arg_check(args,1,"destroy")
|
||||
|
||||
from xen.xm import destroy
|
||||
# ugly hack because the opt parser apparently wants
|
||||
# the subcommand name just to throw it away!
|
||||
destroy.main(["bogus"] + args)
|
||||
|
||||
def xm_reboot(args):
|
||||
arg_check(args,1,"reboot")
|
||||
from xen.xm import shutdown
|
||||
@@ -305,20 +285,6 @@ def xm_reboot(args):
|
||||
# the subcommand name just to throw it away!
|
||||
shutdown.main(["bogus", "-R"] + args)
|
||||
|
||||
def xm_shutdown(args):
|
||||
arg_check(args,1,"shutdown")
|
||||
|
||||
from xen.xm import shutdown
|
||||
# ugly hack because the opt parser apparently wants
|
||||
# the subcommand name just to throw it away!
|
||||
shutdown.main(["bogus"] + args)
|
||||
|
||||
def xm_sysrq(args):
|
||||
from xen.xm import sysrq
|
||||
# ugly hack because the opt parser apparently wants
|
||||
# the subcommand name just to throw it away!
|
||||
sysrq.main(["bogus"] + args)
|
||||
|
||||
def xm_pause(args):
|
||||
arg_check(args, 1, "pause")
|
||||
dom = args[0]
|
||||
@@ -333,6 +299,11 @@ def xm_unpause(args):
|
||||
from xen.xend.XendClient import server
|
||||
server.xend_domain_unpause(dom)
|
||||
|
||||
def xm_subcommand(command, args):
|
||||
cmd = __import__(command, globals(), locals(), 'xen.xm')
|
||||
cmd.main(["bogus"] + args)
|
||||
|
||||
|
||||
#############################################################
|
||||
|
||||
def cpu_make_map(cpulist):
|
||||
@@ -506,14 +477,6 @@ def xm_network_list(args):
|
||||
sxp.show(x)
|
||||
print
|
||||
|
||||
def xm_network_attach(args):
|
||||
|
||||
print "Not implemented"
|
||||
|
||||
def xm_network_detach(args):
|
||||
|
||||
print "Not implemented"
|
||||
|
||||
def xm_block_list(args):
|
||||
arg_check(args,1,"block-list")
|
||||
dom = args[0]
|
||||
@@ -609,11 +572,8 @@ commands = {
|
||||
# domain commands
|
||||
"domid": xm_domid,
|
||||
"domname": xm_domname,
|
||||
"create": xm_create,
|
||||
"destroy": xm_destroy,
|
||||
"restore": xm_restore,
|
||||
"save": xm_save,
|
||||
"shutdown": xm_shutdown,
|
||||
"reboot": xm_reboot,
|
||||
"list": xm_list,
|
||||
# memory commands
|
||||
@@ -625,10 +585,7 @@ commands = {
|
||||
"vcpu-enable": xm_vcpu_enable,
|
||||
"vcpu-disable": xm_vcpu_disable,
|
||||
"vcpu-list": xm_vcpu_list,
|
||||
# migration
|
||||
"migrate": xm_migrate,
|
||||
# special
|
||||
"sysrq": xm_sysrq,
|
||||
"pause": xm_pause,
|
||||
"unpause": xm_unpause,
|
||||
# host commands
|
||||
@@ -647,14 +604,24 @@ commands = {
|
||||
# network
|
||||
"network-limit": xm_network_limit,
|
||||
"network-list": xm_network_list,
|
||||
"network-attach": xm_network_attach,
|
||||
"network-detach": xm_network_detach,
|
||||
# vnet
|
||||
"vnet-list": xm_vnet_list,
|
||||
"vnet-create": xm_vnet_create,
|
||||
"vnet-delete": xm_vnet_delete,
|
||||
}
|
||||
|
||||
## The commands supported by a separate argument parser in xend.xm.
|
||||
subcommands = [
|
||||
'create',
|
||||
'destroy',
|
||||
'migrate',
|
||||
'sysrq',
|
||||
'shutdown'
|
||||
]
|
||||
|
||||
for c in subcommands:
|
||||
commands[c] = eval('lambda args: xm_subcommand("%s", args)' % c)
|
||||
|
||||
aliases = {
|
||||
"balloon": "mem-set",
|
||||
"vif-list": "network-list",
|
||||
@@ -669,6 +636,7 @@ help = {
|
||||
"--long": longhelp
|
||||
}
|
||||
|
||||
|
||||
def xm_lookup_cmd(cmd):
|
||||
if commands.has_key(cmd):
|
||||
return commands[cmd]
|
||||
@@ -688,9 +656,7 @@ def deprecated(old,new):
|
||||
err('Option %s is the new replacement, see "xm help %s" for more info' % (new, new))
|
||||
|
||||
def usage(cmd=None):
|
||||
if cmd == "full":
|
||||
print fullhelp
|
||||
elif help.has_key(cmd):
|
||||
if help.has_key(cmd):
|
||||
print help[cmd]
|
||||
else:
|
||||
print shorthelp
|
||||
@@ -701,7 +667,7 @@ def main(argv=sys.argv):
|
||||
usage()
|
||||
|
||||
if re.compile('-*help').match(argv[1]):
|
||||
if len(argv) > 2 and help.has_key(argv[2]):
|
||||
if len(argv) > 2:
|
||||
usage(argv[2])
|
||||
else:
|
||||
usage()
|
||||
|
||||
+12
-4
@@ -28,11 +28,11 @@ CLIENTS := xenstore-exists xenstore-list xenstore-read xenstore-rm
|
||||
CLIENTS += xenstore-write
|
||||
CLIENTS_OBJS := $(patsubst xenstore-%,xenstore_%.o,$(CLIENTS))
|
||||
|
||||
all: libxenstore.so xenstored $(CLIENTS)
|
||||
all: libxenstore.so xenstored $(CLIENTS) xs_tdb_dump
|
||||
|
||||
testcode: xs_test xenstored_test xs_random xs_dom0_test
|
||||
|
||||
xenstored: xenstored_core.o xenstored_watch.o xenstored_domain.o xenstored_transaction.o xs_lib.o talloc.o utils.o
|
||||
xenstored: xenstored_core.o xenstored_watch.o xenstored_domain.o xenstored_transaction.o xs_lib.o talloc.o utils.o tdb.o
|
||||
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxenctrl -o $@
|
||||
|
||||
$(CLIENTS): libxenstore.so
|
||||
@@ -42,7 +42,10 @@ $(CLIENTS): xenstore-%: xenstore_%.o
|
||||
$(CLIENTS_OBJS): xenstore_%.o: xenstore_client.c
|
||||
$(COMPILE.c) -DCLIENT_$(*F) -o $@ $<
|
||||
|
||||
xenstored_test: xenstored_core_test.o xenstored_watch_test.o xenstored_domain_test.o xenstored_transaction_test.o xs_lib.o talloc_test.o fake_libxc.o utils.o
|
||||
xenstored_test: xenstored_core_test.o xenstored_watch_test.o xenstored_domain_test.o xenstored_transaction_test.o xs_lib.o talloc_test.o fake_libxc.o utils.o tdb.o
|
||||
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
|
||||
|
||||
xs_tdb_dump: xs_tdb_dump.o utils.o tdb.o talloc.o
|
||||
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
|
||||
|
||||
xs_test: xs_test.o xs_lib.o utils.o
|
||||
@@ -50,6 +53,11 @@ xs_random: xs_random.o xs_test_lib.o xs_lib.o talloc.o utils.o
|
||||
xs_stress: xs_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o
|
||||
xs_crashme: xs_crashme.o xs_lib.o talloc.o utils.o
|
||||
|
||||
speedtest: speedtest.o xs.o xs_lib.o utils.o talloc.o
|
||||
|
||||
check-speed: speedtest xenstored_test $(TESTDIR)
|
||||
$(TESTENV) time ./speedtest 100
|
||||
|
||||
xs_test.o xs_stress.o xenstored_core_test.o xenstored_watch_test.o xenstored_transaction_test.o xenstored_domain_test.o xs_random.o xs_test_lib.o talloc_test.o fake_libxc.o xs_crashme.o: CFLAGS=$(BASECFLAGS) $(TESTFLAGS)
|
||||
|
||||
xenstored_%_test.o: xenstored_%.c
|
||||
@@ -98,7 +106,7 @@ RANDSEED=$(shell date +%s)
|
||||
randomcheck: xs_random xenstored_test $(TESTDIR)
|
||||
$(TESTENV) ./xs_random --simple --fast /tmp/xs_random 200000 $(RANDSEED) && echo
|
||||
$(TESTENV) ./xs_random --fast /tmp/xs_random 100000 $(RANDSEED) && echo
|
||||
$(TESTENV) ./xs_random --fail /tmp/xs_random 10000 $(RANDSEED)
|
||||
# $(TESTENV) ./xs_random --fail /tmp/xs_random 10000 $(RANDSEED)
|
||||
|
||||
crashme: xs_crashme xenstored_test $(TESTDIR)
|
||||
rm -rf $(TESTDIR)/store $(TESTDIR)/transactions /tmp/xs_crashme.vglog* /tmp/trace
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
Xen Store Daemon Speed test
|
||||
Copyright (C) 2005 Rusty Russell IBM Corporation
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "utils.h"
|
||||
#include "xs.h"
|
||||
#include "list.h"
|
||||
#include "talloc.h"
|
||||
|
||||
static void do_command(const char *cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = system(cmd);
|
||||
if (ret == -1 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0)
|
||||
barf_perror("Failed '%s': %i", cmd, ret);
|
||||
}
|
||||
|
||||
static int start_daemon(void)
|
||||
{
|
||||
int fds[2], pid;
|
||||
|
||||
do_command(talloc_asprintf(NULL, "rm -rf testsuite/tmp/*"));
|
||||
|
||||
/* Start daemon. */
|
||||
pipe(fds);
|
||||
if ((pid = fork())) {
|
||||
/* Child writes PID when its ready: we wait for that. */
|
||||
char buffer[20];
|
||||
close(fds[1]);
|
||||
if (read(fds[0], buffer, sizeof(buffer)) < 0)
|
||||
barf("Failed to summon daemon");
|
||||
close(fds[0]);
|
||||
} else {
|
||||
dup2(fds[1], STDOUT_FILENO);
|
||||
close(fds[0]);
|
||||
#if 0
|
||||
execlp("valgrind", "valgrind", "-q", "--suppressions=testsuite/vg-suppressions", "xenstored_test", "--output-pid",
|
||||
"--no-fork", "--trace-file=/tmp/trace", NULL);
|
||||
#else
|
||||
execlp("./xenstored_test", "xenstored_test", "--output-pid", "--no-fork", NULL);
|
||||
// execlp("strace", "strace", "-o", "/tmp/out", "./xenstored_test", "--output-pid", "--no-fork", NULL);
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
static void kill_daemon(int pid)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
kill(pid, SIGTERM);
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
#define NUM_ENTRIES 50
|
||||
|
||||
/* We create the given number of trees, each with NUM_ENTRIES, using
|
||||
* transactions. */
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, j, pid, print;
|
||||
struct xs_handle *h;
|
||||
|
||||
if (argc != 2)
|
||||
barf("Usage: speedtest <numdomains>");
|
||||
|
||||
pid = start_daemon();
|
||||
h = xs_daemon_open();
|
||||
print = atoi(argv[1]) / 76;
|
||||
if (!print)
|
||||
print = 1;
|
||||
for (i = 0; i < atoi(argv[1]); i ++) {
|
||||
char name[64];
|
||||
|
||||
if (i % print == 0)
|
||||
write(1, ".", 1);
|
||||
if (!xs_transaction_start(h, "/")) {
|
||||
kill_daemon(pid);
|
||||
barf_perror("Starting transaction");
|
||||
}
|
||||
sprintf(name, "/%i", i);
|
||||
if (!xs_mkdir(h, name)) {
|
||||
kill_daemon(pid);
|
||||
barf_perror("Making directory %s", name);
|
||||
}
|
||||
|
||||
for (j = 0; j < NUM_ENTRIES; j++) {
|
||||
sprintf(name, "/%i/%i", i, j);
|
||||
if (!xs_write(h, name, name, strlen(name))) {
|
||||
kill_daemon(pid);
|
||||
barf_perror("Making directory %s", name);
|
||||
}
|
||||
}
|
||||
if (!xs_transaction_end(h, false)) {
|
||||
kill_daemon(pid);
|
||||
barf_perror("Ending transaction");
|
||||
}
|
||||
}
|
||||
write(1, "\n", 1);
|
||||
|
||||
kill_daemon(pid);
|
||||
wait(NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,157 @@
|
||||
#ifndef __TDB_H__
|
||||
#define __TDB_H__
|
||||
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
trivial database library
|
||||
|
||||
Copyright (C) Andrew Tridgell 1999-2004
|
||||
|
||||
** NOTE! The following LGPL license applies to the tdb
|
||||
** library. This does NOT imply that all of Samba is released
|
||||
** under the LGPL
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* flags to tdb_store() */
|
||||
#define TDB_REPLACE 1
|
||||
#define TDB_INSERT 2
|
||||
#define TDB_MODIFY 3
|
||||
|
||||
/* flags for tdb_open() */
|
||||
#define TDB_DEFAULT 0 /* just a readability place holder */
|
||||
#define TDB_CLEAR_IF_FIRST 1
|
||||
#define TDB_INTERNAL 2 /* don't store on disk */
|
||||
#define TDB_NOLOCK 4 /* don't do any locking */
|
||||
#define TDB_NOMMAP 8 /* don't use mmap */
|
||||
#define TDB_CONVERT 16 /* convert endian (internal use) */
|
||||
#define TDB_BIGENDIAN 32 /* header is big-endian (internal use) */
|
||||
|
||||
#define TDB_ERRCODE(code, ret) ((tdb->ecode = (code)), ret)
|
||||
|
||||
/* error codes */
|
||||
enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK,
|
||||
TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT,
|
||||
TDB_ERR_NOEXIST};
|
||||
|
||||
#ifndef u32
|
||||
#define u32 unsigned
|
||||
#endif
|
||||
|
||||
typedef struct TDB_DATA {
|
||||
char *dptr;
|
||||
size_t dsize;
|
||||
} TDB_DATA;
|
||||
|
||||
typedef u32 tdb_len;
|
||||
typedef u32 tdb_off;
|
||||
|
||||
/* this is stored at the front of every database */
|
||||
struct tdb_header {
|
||||
char magic_food[32]; /* for /etc/magic */
|
||||
u32 version; /* version of the code */
|
||||
u32 hash_size; /* number of hash entries */
|
||||
tdb_off rwlocks;
|
||||
tdb_off reserved[31];
|
||||
};
|
||||
|
||||
struct tdb_lock_type {
|
||||
u32 count;
|
||||
u32 ltype;
|
||||
};
|
||||
|
||||
struct tdb_traverse_lock {
|
||||
struct tdb_traverse_lock *next;
|
||||
u32 off;
|
||||
u32 hash;
|
||||
};
|
||||
|
||||
#ifndef PRINTF_ATTRIBUTE
|
||||
#define PRINTF_ATTRIBUTE(a,b)
|
||||
#endif
|
||||
|
||||
/* this is the context structure that is returned from a db open */
|
||||
typedef struct tdb_context {
|
||||
char *name; /* the name of the database */
|
||||
void *map_ptr; /* where it is currently mapped */
|
||||
int fd; /* open file descriptor for the database */
|
||||
tdb_len map_size; /* how much space has been mapped */
|
||||
int read_only; /* opened read-only */
|
||||
struct tdb_lock_type *locked; /* array of chain locks */
|
||||
enum TDB_ERROR ecode; /* error code for last tdb error */
|
||||
struct tdb_header header; /* a cached copy of the header */
|
||||
u32 flags; /* the flags passed to tdb_open */
|
||||
struct tdb_traverse_lock travlocks; /* current traversal locks */
|
||||
struct tdb_context *next; /* all tdbs to avoid multiple opens */
|
||||
dev_t device; /* uniquely identifies this tdb */
|
||||
ino_t inode; /* uniquely identifies this tdb */
|
||||
void (*log_fn)(struct tdb_context *tdb, int level, const char *, ...) PRINTF_ATTRIBUTE(3,4); /* logging function */
|
||||
u32 (*hash_fn)(TDB_DATA *key);
|
||||
int open_flags; /* flags used in the open - needed by reopen */
|
||||
} TDB_CONTEXT;
|
||||
|
||||
typedef int (*tdb_traverse_func)(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *);
|
||||
typedef void (*tdb_log_func)(TDB_CONTEXT *, int , const char *, ...);
|
||||
typedef u32 (*tdb_hash_func)(TDB_DATA *key);
|
||||
|
||||
TDB_CONTEXT *tdb_open(const char *name, int hash_size, int tdb_flags,
|
||||
int open_flags, mode_t mode);
|
||||
TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
|
||||
int open_flags, mode_t mode,
|
||||
tdb_log_func log_fn,
|
||||
tdb_hash_func hash_fn);
|
||||
|
||||
int tdb_reopen(TDB_CONTEXT *tdb);
|
||||
int tdb_reopen_all(void);
|
||||
void tdb_logging_function(TDB_CONTEXT *tdb, tdb_log_func);
|
||||
enum TDB_ERROR tdb_error(TDB_CONTEXT *tdb);
|
||||
const char *tdb_errorstr(TDB_CONTEXT *tdb);
|
||||
TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||
int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||
int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
|
||||
int tdb_append(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA new_dbuf);
|
||||
int tdb_close(TDB_CONTEXT *tdb);
|
||||
TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb);
|
||||
TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||
int tdb_traverse(TDB_CONTEXT *tdb, tdb_traverse_func fn, void *);
|
||||
int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||
int tdb_lockall(TDB_CONTEXT *tdb);
|
||||
void tdb_unlockall(TDB_CONTEXT *tdb);
|
||||
|
||||
/* Low level locking functions: use with care */
|
||||
int tdb_chainlock(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||
int tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||
int tdb_chainlock_read(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||
int tdb_chainunlock_read(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||
TDB_CONTEXT *tdb_copy(TDB_CONTEXT *tdb, const char *outfile);
|
||||
|
||||
/* Debug functions. Not used in production. */
|
||||
void tdb_dump_all(TDB_CONTEXT *tdb);
|
||||
int tdb_printfreelist(TDB_CONTEXT *tdb);
|
||||
|
||||
extern TDB_DATA tdb_null;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* tdb.h */
|
||||
@@ -6,6 +6,8 @@ rm /dir/test
|
||||
# Create file and remove it
|
||||
write /test contents
|
||||
rm /test
|
||||
expect tool
|
||||
dir /
|
||||
|
||||
# Create directory and remove it.
|
||||
mkdir /dir
|
||||
@@ -15,3 +17,4 @@ rm /dir
|
||||
mkdir /dir
|
||||
write /dir/test contents
|
||||
rm /dir
|
||||
|
||||
@@ -1,21 +1,43 @@
|
||||
# Test transaction timeouts. Take a second each.
|
||||
# Test transaction clashes.
|
||||
|
||||
mkdir /test
|
||||
write /test/entry1 contents
|
||||
|
||||
# Transactions can take as long as the want...
|
||||
start /test
|
||||
sleep 1100
|
||||
rm /test/entry1
|
||||
commit
|
||||
dir /test
|
||||
|
||||
# ... as long as noone is waiting.
|
||||
1 start /test
|
||||
notimeout
|
||||
2 mkdir /test/dir
|
||||
1 mkdir /test/dir
|
||||
expect 1:dir
|
||||
1 dir /test
|
||||
expect 1: commit failed: Connection timed out
|
||||
# Start transaction, do read-only op, transaction succeeds
|
||||
1 start
|
||||
1 write /test/entry1 contents2
|
||||
expect contents
|
||||
read /test/entry1
|
||||
1 commit
|
||||
expect contents2
|
||||
read /test/entry1
|
||||
|
||||
# Start transaction, abort other transaction, transaction succeeds.
|
||||
1 start
|
||||
1 write /test/entry1 contents3
|
||||
start
|
||||
write /test/entry1 contents
|
||||
abort
|
||||
1 commit
|
||||
expect contents3
|
||||
read /test/entry1
|
||||
|
||||
# Start transaction, do write op, transaction fails
|
||||
1 start
|
||||
1 write /test/entry1 contents4
|
||||
write /test/entry1 contents
|
||||
expect 1: commit failed: Resource temporarily unavailable
|
||||
1 commit
|
||||
expect contents
|
||||
read /test/entry1
|
||||
|
||||
# Start transaction, do other transaction, transaction fails
|
||||
1 start
|
||||
1 write /test/entry1 contents4
|
||||
start
|
||||
write /test/entry1 contents5
|
||||
commit
|
||||
expect 1: commit failed: Resource temporarily unavailable
|
||||
1 commit
|
||||
expect contents5
|
||||
read /test/entry1
|
||||
@@ -3,7 +3,7 @@
|
||||
mkdir /test
|
||||
|
||||
# Simple transaction: create a file inside transaction.
|
||||
1 start /test
|
||||
1 start
|
||||
1 write /test/entry1 contents
|
||||
2 dir /test
|
||||
expect 1:entry1
|
||||
@@ -15,7 +15,7 @@ expect 2:contents
|
||||
rm /test/entry1
|
||||
|
||||
# Create a file and abort transaction.
|
||||
1 start /test
|
||||
1 start
|
||||
1 write /test/entry1 contents
|
||||
2 dir /test
|
||||
expect 1:entry1
|
||||
@@ -25,7 +25,7 @@ expect 1:entry1
|
||||
|
||||
write /test/entry1 contents
|
||||
# Delete in transaction, commit
|
||||
1 start /test
|
||||
1 start
|
||||
1 rm /test/entry1
|
||||
expect 2:entry1
|
||||
2 dir /test
|
||||
@@ -35,7 +35,7 @@ expect 2:entry1
|
||||
|
||||
# Delete in transaction, abort.
|
||||
write /test/entry1 contents
|
||||
1 start /test
|
||||
1 start
|
||||
1 rm /test/entry1
|
||||
expect 2:entry1
|
||||
2 dir /test
|
||||
@@ -47,7 +47,7 @@ expect 2:entry1
|
||||
# Events inside transactions don't trigger watches until (successful) commit.
|
||||
mkdir /test/dir
|
||||
1 watch /test token
|
||||
2 start /test
|
||||
2 start
|
||||
2 mkdir /test/dir/sub
|
||||
expect 1: waitwatch failed: Connection timed out
|
||||
1 waitwatch
|
||||
@@ -55,7 +55,7 @@ expect 1: waitwatch failed: Connection timed out
|
||||
1 close
|
||||
|
||||
1 watch /test token
|
||||
2 start /test
|
||||
2 start
|
||||
2 mkdir /test/dir/sub
|
||||
2 abort
|
||||
expect 1: waitwatch failed: Connection timed out
|
||||
@@ -63,7 +63,7 @@ expect 1: waitwatch failed: Connection timed out
|
||||
1 close
|
||||
|
||||
1 watch /test token
|
||||
2 start /test
|
||||
2 start
|
||||
2 mkdir /test/dir/sub
|
||||
2 commit
|
||||
expect 1:/test/dir/sub:token
|
||||
@@ -73,7 +73,7 @@ expect 1:/test/dir/sub:token
|
||||
|
||||
# Rm inside transaction works like rm outside: children get notified.
|
||||
1 watch /test/dir/sub token
|
||||
2 start /test
|
||||
2 start
|
||||
2 rm /test/dir
|
||||
2 commit
|
||||
expect 1:/test/dir/sub:token
|
||||
@@ -83,7 +83,7 @@ expect 1:/test/dir/sub:token
|
||||
|
||||
# Multiple events from single transaction don't trigger assert
|
||||
1 watch /test token
|
||||
2 start /test
|
||||
2 start
|
||||
2 write /test/1 contents
|
||||
2 write /test/2 contents
|
||||
2 commit
|
||||
|
||||
@@ -13,23 +13,23 @@ expect 0 READ
|
||||
getperm /test
|
||||
watch /test token
|
||||
unwatch /test token
|
||||
start /
|
||||
start
|
||||
commit
|
||||
start /
|
||||
start
|
||||
abort
|
||||
|
||||
# These don't work
|
||||
expect write failed: Read-only file system
|
||||
expect write failed: Permission denied
|
||||
write /test2 contents
|
||||
expect write failed: Read-only file system
|
||||
expect write failed: Permission denied
|
||||
write /test contents
|
||||
expect setperm failed: Read-only file system
|
||||
expect setperm failed: Permission denied
|
||||
setperm /test 100 NONE
|
||||
expect setperm failed: Read-only file system
|
||||
expect setperm failed: Permission denied
|
||||
setperm /test 100 NONE
|
||||
expect shutdown failed: Read-only file system
|
||||
expect shutdown failed: Permission denied
|
||||
shutdown
|
||||
expect introduce failed: Read-only file system
|
||||
expect introduce failed: Permission denied
|
||||
introduce 1 100 7 /home
|
||||
|
||||
# Check that watches work like normal.
|
||||
|
||||
@@ -33,14 +33,6 @@ unwatch /dir/file token
|
||||
expect *No such file or directory
|
||||
unwatch /dir/file token
|
||||
expect *Permission denied
|
||||
start /dir/file
|
||||
expect *No such file or directory
|
||||
abort
|
||||
expect *Permission denied
|
||||
start /dir/file
|
||||
expect *No such file or directory
|
||||
commit
|
||||
expect *Permission denied
|
||||
introduce 2 100 7 /dir/file
|
||||
|
||||
# Now it exists
|
||||
@@ -73,12 +65,4 @@ unwatch /dir/file token
|
||||
expect *No such file or directory
|
||||
unwatch /dir/file token
|
||||
expect *Permission denied
|
||||
start /dir/file
|
||||
expect *No such file or directory
|
||||
abort
|
||||
expect *Permission denied
|
||||
start /dir/file
|
||||
expect *No such file or directory
|
||||
commit
|
||||
expect *Permission denied
|
||||
introduce 2 100 7 /dir/file
|
||||
@@ -1,13 +1,14 @@
|
||||
# Test case where blocked connection gets sent watch.
|
||||
|
||||
mkdir /test
|
||||
watch /test token
|
||||
1 start /test
|
||||
# This will block on above
|
||||
noackwrite /test/entry contents
|
||||
1 write /test/entry2 contents
|
||||
1 commit
|
||||
readack
|
||||
expect /test/entry2:token
|
||||
waitwatch
|
||||
ackwatch token
|
||||
# FIXME: We no longer block connections
|
||||
# mkdir /test
|
||||
# watch /test token
|
||||
# 1 start
|
||||
# # This will block on above
|
||||
# noackwrite /test/entry contents
|
||||
# 1 write /test/entry2 contents
|
||||
# 1 commit
|
||||
# readack
|
||||
# expect /test/entry2:token
|
||||
# waitwatch
|
||||
# ackwatch token
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <xs.h>
|
||||
#include <errno.h>
|
||||
|
||||
static void
|
||||
usage(const char *progname)
|
||||
@@ -82,8 +83,8 @@ main(int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* XXX maybe find longest common prefix */
|
||||
success = xs_transaction_start(xsh, "/");
|
||||
again:
|
||||
success = xs_transaction_start(xsh);
|
||||
if (!success)
|
||||
errx(1, "couldn't start transaction");
|
||||
|
||||
@@ -145,8 +146,10 @@ main(int argc, char **argv)
|
||||
|
||||
out:
|
||||
success = xs_transaction_end(xsh, ret ? true : false);
|
||||
if (!success)
|
||||
if (!success) {
|
||||
if (ret == 0 && errno == EAGAIN)
|
||||
goto again;
|
||||
errx(1, "couldn't end transaction");
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -75,7 +75,7 @@ static struct xsd_errors xsd_errors[] __attribute__((unused)) = {
|
||||
XSD_ERROR(ENOSYS),
|
||||
XSD_ERROR(EROFS),
|
||||
XSD_ERROR(EBUSY),
|
||||
XSD_ERROR(ETIMEDOUT),
|
||||
XSD_ERROR(EAGAIN),
|
||||
XSD_ERROR(EISCONN),
|
||||
};
|
||||
struct xsd_sockmsg
|
||||
|
||||
+423
-625
File diff suppressed because it is too large.
Load diff
@@ -28,6 +28,7 @@
|
||||
#include "xs_lib.h"
|
||||
#include "xenstored.h"
|
||||
#include "list.h"
|
||||
#include "tdb.h"
|
||||
|
||||
struct buffered_data
|
||||
{
|
||||
@@ -49,8 +50,6 @@ typedef int connreadfn_t(struct connection *, void *, unsigned int);
|
||||
|
||||
enum state
|
||||
{
|
||||
/* Blocked by transaction. */
|
||||
BLOCKED,
|
||||
/* Doing action, not listening */
|
||||
BUSY,
|
||||
/* Completed */
|
||||
@@ -70,9 +69,6 @@ struct connection
|
||||
/* Blocked on transaction? Busy? */
|
||||
enum state state;
|
||||
|
||||
/* Node we are waiting for (if state == BLOCKED) */
|
||||
char *blocked_by;
|
||||
|
||||
/* Is this a read-only connection? */
|
||||
bool can_write;
|
||||
|
||||
@@ -103,9 +99,27 @@ struct connection
|
||||
};
|
||||
extern struct list_head connections;
|
||||
|
||||
/* Return length of string (including nul) at this offset. */
|
||||
unsigned int get_string(const struct buffered_data *data,
|
||||
unsigned int offset);
|
||||
struct node {
|
||||
const char *name;
|
||||
|
||||
/* Database I came from */
|
||||
TDB_CONTEXT *tdb;
|
||||
|
||||
/* Parent (optional) */
|
||||
struct node *parent;
|
||||
|
||||
/* Permissions. */
|
||||
unsigned int num_perms;
|
||||
struct xs_permissions *perms;
|
||||
|
||||
/* Contents. */
|
||||
unsigned int datalen;
|
||||
void *data;
|
||||
|
||||
/* Children, each nul-terminated. */
|
||||
unsigned int childlen;
|
||||
char *children;
|
||||
};
|
||||
|
||||
/* Break input into vectors, return the number, fill in up to num of them. */
|
||||
unsigned int get_strings(struct buffered_data *data,
|
||||
@@ -114,9 +128,6 @@ unsigned int get_strings(struct buffered_data *data,
|
||||
/* Is child node a child or equal to parent node? */
|
||||
bool is_child(const char *child, const char *parent);
|
||||
|
||||
/* Create a new buffer with lifetime of context. */
|
||||
struct buffered_data *new_buffer(void *ctx);
|
||||
|
||||
void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
|
||||
const void *data, unsigned int len);
|
||||
|
||||
@@ -129,15 +140,22 @@ void send_error(struct connection *conn, int error);
|
||||
/* Canonicalize this path if possible. */
|
||||
char *canonicalize(struct connection *conn, const char *node);
|
||||
|
||||
/* Check permissions on this node. */
|
||||
bool check_node_perms(struct connection *conn, const char *node,
|
||||
enum xs_perm_type perm);
|
||||
|
||||
/* Check if node is an event node. */
|
||||
bool check_event_node(const char *node);
|
||||
|
||||
/* Path to this node outside transaction. */
|
||||
char *node_dir_outside_transaction(const char *node);
|
||||
/* Get this node, checking we have permissions. */
|
||||
struct node *get_node(struct connection *conn,
|
||||
const char *name,
|
||||
enum xs_perm_type perm);
|
||||
|
||||
/* Get TDB context for this connection */
|
||||
TDB_CONTEXT *tdb_context(struct connection *conn);
|
||||
|
||||
/* Destructor for tdbs: required for transaction code */
|
||||
int destroy_tdb(void *_tdb);
|
||||
|
||||
/* Replace the tdb: required for transaction code */
|
||||
bool replace_tdb(const char *newname, TDB_CONTEXT *newtdb);
|
||||
|
||||
/* Fail due to excessive corruption, capitalist pigdogs! */
|
||||
void __attribute__((noreturn)) corrupt(struct connection *conn,
|
||||
@@ -145,23 +163,9 @@ void __attribute__((noreturn)) corrupt(struct connection *conn,
|
||||
|
||||
struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
|
||||
|
||||
void handle_input(struct connection *conn);
|
||||
void handle_output(struct connection *conn);
|
||||
|
||||
/* Is this a valid node name? */
|
||||
bool is_valid_nodename(const char *node);
|
||||
|
||||
/* Return a pointer to an open dir, self-closig and attached to pathname. */
|
||||
DIR **talloc_opendir(const char *pathname);
|
||||
|
||||
/* Return a pointer to an fd, self-closing and attached to this pathname. */
|
||||
int *talloc_open(const char *pathname, int flags, int mode);
|
||||
|
||||
/* Convenient talloc-style destructor for paths. */
|
||||
int destroy_path(void *path);
|
||||
|
||||
/* Read entire contents of a talloced fd. */
|
||||
void *read_all(int *fd, unsigned int *size);
|
||||
|
||||
/* Tracing infrastructure. */
|
||||
void trace_create(const void *data, const char *type);
|
||||
|
||||
@@ -309,16 +309,11 @@ void do_introduce(struct connection *conn, struct buffered_data *in)
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn->id != 0) {
|
||||
if (conn->id != 0 || !conn->can_write) {
|
||||
send_error(conn, EACCES);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn->can_write) {
|
||||
send_error(conn, EROFS);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Sanity check args. */
|
||||
if ((atoi(vec[2]) <= 0) || !is_valid_nodename(vec[3])) {
|
||||
send_error(conn, EINVAL);
|
||||
@@ -386,7 +381,7 @@ void do_release(struct connection *conn, const char *domid_str)
|
||||
|
||||
talloc_free(domain->conn);
|
||||
|
||||
fire_watches(NULL, "@releaseDomain", false);
|
||||
fire_watches(conn, "@releaseDomain", false);
|
||||
|
||||
send_ack(conn, XS_RELEASE);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "talloc.h"
|
||||
#include "list.h"
|
||||
#include "xenstored_transaction.h"
|
||||
@@ -51,74 +52,26 @@ struct transaction
|
||||
/* Global list of transactions. */
|
||||
struct list_head list;
|
||||
|
||||
/* Generation when transaction started. */
|
||||
unsigned int generation;
|
||||
|
||||
/* My owner (conn->transaction == me). */
|
||||
struct connection *conn;
|
||||
|
||||
/* Subtree this transaction covers */
|
||||
char *node;
|
||||
|
||||
/* Base for this transaction. */
|
||||
char *divert;
|
||||
/* TDB to work on, and filename */
|
||||
TDB_CONTEXT *tdb;
|
||||
char *tdb_name;
|
||||
|
||||
/* List of changed nodes. */
|
||||
struct list_head changes;
|
||||
|
||||
/* Someone's waiting: time limit. */
|
||||
struct timeval timeout;
|
||||
|
||||
/* We've timed out. */
|
||||
bool destined_to_fail;
|
||||
};
|
||||
static LIST_HEAD(transactions);
|
||||
static unsigned int generation;
|
||||
|
||||
bool within_transaction(struct transaction *trans, const char *node)
|
||||
/* Return tdb context to use for this connection. */
|
||||
TDB_CONTEXT *tdb_transaction_context(struct transaction *trans)
|
||||
{
|
||||
if (!trans)
|
||||
return true;
|
||||
return is_child(node, trans->node);
|
||||
}
|
||||
|
||||
/* You are on notice: this transaction is blocking someone. */
|
||||
static void start_transaction_timeout(struct transaction *trans)
|
||||
{
|
||||
if (timerisset(&trans->timeout))
|
||||
return;
|
||||
|
||||
/* One second timeout. */
|
||||
gettimeofday(&trans->timeout, NULL);
|
||||
trans->timeout.tv_sec += 1;
|
||||
}
|
||||
|
||||
struct transaction *transaction_covering_node(const char *node)
|
||||
{
|
||||
struct transaction *i;
|
||||
|
||||
list_for_each_entry(i, &transactions, list) {
|
||||
if (i->destined_to_fail)
|
||||
continue;
|
||||
if (is_child(i->node, node) || is_child(node, i->node))
|
||||
return i;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool transaction_block(struct connection *conn, const char *node)
|
||||
{
|
||||
struct transaction *trans;
|
||||
|
||||
/* Transactions don't overlap, so we can't be blocked by
|
||||
* others if we're in one. */
|
||||
if (conn->transaction)
|
||||
return false;
|
||||
|
||||
trans = transaction_covering_node(node);
|
||||
if (trans) {
|
||||
start_transaction_timeout(trans);
|
||||
conn->state = BLOCKED;
|
||||
conn->blocked_by = talloc_strdup(conn, node);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return trans->tdb;
|
||||
}
|
||||
|
||||
/* Callers get a change node (which can fail) and only commit after they've
|
||||
@@ -127,8 +80,11 @@ void add_change_node(struct transaction *trans, const char *node, bool recurse)
|
||||
{
|
||||
struct changed_node *i;
|
||||
|
||||
if (!trans)
|
||||
if (!trans) {
|
||||
/* They're changing the global database. */
|
||||
generation++;
|
||||
return;
|
||||
}
|
||||
|
||||
list_for_each_entry(i, &trans->changes, list)
|
||||
if (streq(i->node, node))
|
||||
@@ -140,167 +96,47 @@ void add_change_node(struct transaction *trans, const char *node, bool recurse)
|
||||
list_add_tail(&i->list, &trans->changes);
|
||||
}
|
||||
|
||||
char *node_dir_inside_transaction(struct transaction *trans, const char *node)
|
||||
{
|
||||
return talloc_asprintf(node, "%s/%s", trans->divert,
|
||||
node + strlen(trans->node));
|
||||
}
|
||||
|
||||
void shortest_transaction_timeout(struct timeval *tv)
|
||||
{
|
||||
struct transaction *i;
|
||||
|
||||
list_for_each_entry(i, &transactions, list) {
|
||||
if (!timerisset(&i->timeout))
|
||||
continue;
|
||||
|
||||
if (!timerisset(tv) || timercmp(&i->timeout, tv, <))
|
||||
*tv = i->timeout;
|
||||
}
|
||||
}
|
||||
|
||||
void check_transaction_timeout(void)
|
||||
{
|
||||
struct transaction *i;
|
||||
struct timeval now;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
list_for_each_entry(i, &transactions, list) {
|
||||
if (!timerisset(&i->timeout))
|
||||
continue;
|
||||
|
||||
if (timercmp(&i->timeout, &now, <))
|
||||
i->destined_to_fail = true;
|
||||
}
|
||||
}
|
||||
|
||||
static int destroy_transaction(void *_transaction)
|
||||
{
|
||||
struct transaction *trans = _transaction;
|
||||
|
||||
list_del(&trans->list);
|
||||
trace_destroy(trans, "transaction");
|
||||
return destroy_path(trans->divert);
|
||||
if (trans->tdb)
|
||||
tdb_close(trans->tdb);
|
||||
unlink(trans->tdb_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool copy_file(const char *src, const char *dst)
|
||||
void do_transaction_start(struct connection *conn, struct buffered_data *in)
|
||||
{
|
||||
int *infd, *outfd;
|
||||
void *data;
|
||||
unsigned int size;
|
||||
|
||||
infd = talloc_open(src, O_RDONLY, 0);
|
||||
if (!infd)
|
||||
return false;
|
||||
outfd = talloc_open(dst, O_WRONLY|O_CREAT|O_EXCL, 0640);
|
||||
if (!outfd)
|
||||
return false;
|
||||
data = read_all(infd, &size);
|
||||
if (!data)
|
||||
return false;
|
||||
return xs_write_all(*outfd, data, size);
|
||||
}
|
||||
|
||||
static bool copy_dir(const char *src, const char *dst)
|
||||
{
|
||||
DIR **dir;
|
||||
struct dirent *dirent;
|
||||
|
||||
if (mkdir(dst, 0750) != 0)
|
||||
return false;
|
||||
|
||||
dir = talloc_opendir(src);
|
||||
if (!dir)
|
||||
return false;
|
||||
|
||||
while ((dirent = readdir(*dir)) != NULL) {
|
||||
struct stat st;
|
||||
char *newsrc, *newdst;
|
||||
|
||||
if (streq(dirent->d_name, ".") || streq(dirent->d_name, ".."))
|
||||
continue;
|
||||
|
||||
newsrc = talloc_asprintf(src, "%s/%s", src, dirent->d_name);
|
||||
newdst = talloc_asprintf(src, "%s/%s", dst, dirent->d_name);
|
||||
if (stat(newsrc, &st) != 0)
|
||||
return false;
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
if (!copy_dir(newsrc, newdst))
|
||||
return false;
|
||||
} else {
|
||||
if (!copy_file(newsrc, newdst))
|
||||
return false;
|
||||
}
|
||||
/* Free now so we don't run out of file descriptors */
|
||||
talloc_free(newsrc);
|
||||
talloc_free(newdst);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void do_transaction_start(struct connection *conn, const char *node)
|
||||
{
|
||||
struct transaction *transaction;
|
||||
char *dir;
|
||||
struct transaction *trans;
|
||||
|
||||
if (conn->transaction) {
|
||||
send_error(conn, EBUSY);
|
||||
return;
|
||||
}
|
||||
|
||||
node = canonicalize(conn, node);
|
||||
if (!check_node_perms(conn, node, XS_PERM_READ)) {
|
||||
/* Attach transaction to input for autofree until it's complete */
|
||||
trans = talloc(in, struct transaction);
|
||||
INIT_LIST_HEAD(&trans->changes);
|
||||
trans->conn = conn;
|
||||
trans->generation = generation;
|
||||
trans->tdb_name = talloc_asprintf(trans, "%s.%p",
|
||||
xs_daemon_tdb(), trans);
|
||||
trans->tdb = tdb_copy(tdb_context(conn), trans->tdb_name);
|
||||
if (!trans->tdb) {
|
||||
send_error(conn, errno);
|
||||
return;
|
||||
}
|
||||
/* Make it close if we go away. */
|
||||
talloc_steal(trans, trans->tdb);
|
||||
|
||||
if (transaction_block(conn, node))
|
||||
return;
|
||||
|
||||
dir = node_dir_outside_transaction(node);
|
||||
|
||||
/* Attach transaction to node for autofree until it's complete */
|
||||
transaction = talloc(node, struct transaction);
|
||||
transaction->node = talloc_strdup(transaction, node);
|
||||
transaction->divert = talloc_asprintf(transaction, "%s/%p",
|
||||
xs_daemon_transactions(),
|
||||
transaction);
|
||||
INIT_LIST_HEAD(&transaction->changes);
|
||||
transaction->conn = conn;
|
||||
timerclear(&transaction->timeout);
|
||||
transaction->destined_to_fail = false;
|
||||
list_add_tail(&transaction->list, &transactions);
|
||||
talloc_set_destructor(transaction, destroy_transaction);
|
||||
trace_create(transaction, "transaction");
|
||||
|
||||
if (!copy_dir(dir, transaction->divert)) {
|
||||
send_error(conn, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
talloc_steal(conn, transaction);
|
||||
conn->transaction = transaction;
|
||||
send_ack(transaction->conn, XS_TRANSACTION_START);
|
||||
}
|
||||
|
||||
static bool commit_transaction(struct transaction *trans)
|
||||
{
|
||||
char *tmp, *dir;
|
||||
|
||||
/* Move: orig -> .old, repl -> orig. Cleanup deletes .old. */
|
||||
dir = node_dir_outside_transaction(trans->node);
|
||||
tmp = talloc_asprintf(trans, "%s.old", dir);
|
||||
|
||||
if (rename(dir, tmp) != 0)
|
||||
return false;
|
||||
if (rename(trans->divert, dir) != 0)
|
||||
corrupt(trans->conn, "Failed rename %s to %s",
|
||||
trans->divert, dir);
|
||||
|
||||
trans->divert = tmp;
|
||||
return true;
|
||||
/* Now we own it. */
|
||||
conn->transaction = talloc_steal(conn, trans);
|
||||
list_add_tail(&trans->list, &transactions);
|
||||
talloc_set_destructor(trans, destroy_transaction);
|
||||
send_ack(conn, XS_TRANSACTION_START);
|
||||
}
|
||||
|
||||
void do_transaction_end(struct connection *conn, const char *arg)
|
||||
@@ -318,25 +154,29 @@ void do_transaction_end(struct connection *conn, const char *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set to NULL so fire_watches sends events. */
|
||||
/* Set to NULL so fire_watches sends events, tdb_context works. */
|
||||
trans = conn->transaction;
|
||||
conn->transaction = NULL;
|
||||
/* Attach transaction to arg for auto-cleanup */
|
||||
talloc_steal(arg, trans);
|
||||
|
||||
if (streq(arg, "T")) {
|
||||
if (trans->destined_to_fail) {
|
||||
send_error(conn, ETIMEDOUT);
|
||||
/* FIXME: Merge, rather failing on any change. */
|
||||
if (trans->generation != generation) {
|
||||
send_error(conn, EAGAIN);
|
||||
return;
|
||||
}
|
||||
if (!commit_transaction(trans)) {
|
||||
if (!replace_tdb(trans->tdb_name, trans->tdb)) {
|
||||
send_error(conn, errno);
|
||||
return;
|
||||
}
|
||||
/* Don't close this: we won! */
|
||||
trans->tdb = NULL;
|
||||
|
||||
/* Fire off the watches for everything that changed. */
|
||||
list_for_each_entry(i, &trans->changes, list)
|
||||
fire_watches(conn, i->node, i->recurse);
|
||||
generation++;
|
||||
}
|
||||
send_ack(conn, XS_TRANSACTION_END);
|
||||
}
|
||||
|
||||
@@ -22,29 +22,14 @@
|
||||
|
||||
struct transaction;
|
||||
|
||||
void do_transaction_start(struct connection *conn, const char *node);
|
||||
void do_transaction_start(struct connection *conn, struct buffered_data *node);
|
||||
void do_transaction_end(struct connection *conn, const char *arg);
|
||||
|
||||
/* Is node covered by this transaction? */
|
||||
bool within_transaction(struct transaction *trans, const char *node);
|
||||
|
||||
/* If a write op on this node blocked by another connections' transaction,
|
||||
* mark conn, setup transaction timeout and return true.
|
||||
*/
|
||||
bool transaction_block(struct connection *conn, const char *node);
|
||||
|
||||
/* Return transaction which covers this node. */
|
||||
struct transaction *transaction_covering_node(const char *node);
|
||||
|
||||
/* Return directory of node within transaction t. */
|
||||
char *node_dir_inside_transaction(struct transaction *t, const char *node);
|
||||
bool transaction_block(struct connection *conn);
|
||||
|
||||
/* This node was changed: can fail and longjmp. */
|
||||
void add_change_node(struct transaction *trans, const char *node, bool recurse);
|
||||
|
||||
/* Get shortest timeout: leave tv unset if none. */
|
||||
void shortest_transaction_timeout(struct timeval *tv);
|
||||
|
||||
/* Have any transactions timed out yet? */
|
||||
void check_transaction_timeout(void);
|
||||
/* Return tdb context to use for this connection. */
|
||||
TDB_CONTEXT *tdb_transaction_context(struct transaction *trans);
|
||||
#endif /* _XENSTORED_TRANSACTION_H */
|
||||
@@ -96,36 +96,38 @@ static int destroy_watch_event(void *_event)
|
||||
}
|
||||
|
||||
static void add_event(struct connection *conn,
|
||||
struct watch *watch, const char *node)
|
||||
struct watch *watch,
|
||||
const char *name)
|
||||
{
|
||||
struct watch_event *event;
|
||||
|
||||
/* Check read permission: no permission, no watch event.
|
||||
* If it doesn't exist, we need permission to read parent.
|
||||
*/
|
||||
if (!check_node_perms(conn, node, XS_PERM_READ|XS_PERM_ENOENT_OK) &&
|
||||
!check_event_node(node)) {
|
||||
return;
|
||||
if (!check_event_node(name)) {
|
||||
/* Can this conn load node, or see that it doesn't exist? */
|
||||
struct node *node;
|
||||
|
||||
node = get_node(conn, name, XS_PERM_READ);
|
||||
if (!node && errno != ENOENT)
|
||||
return;
|
||||
}
|
||||
|
||||
if (watch->relative_path) {
|
||||
node += strlen(watch->relative_path);
|
||||
if (*node == '/') /* Could be "" */
|
||||
node++;
|
||||
name += strlen(watch->relative_path);
|
||||
if (*name == '/') /* Could be "" */
|
||||
name++;
|
||||
}
|
||||
|
||||
event = talloc(watch, struct watch_event);
|
||||
event->len = strlen(node) + 1 + strlen(watch->token) + 1;
|
||||
event->len = strlen(name) + 1 + strlen(watch->token) + 1;
|
||||
event->data = talloc_array(event, char, event->len);
|
||||
strcpy(event->data, node);
|
||||
strcpy(event->data + strlen(node) + 1, watch->token);
|
||||
strcpy(event->data, name);
|
||||
strcpy(event->data + strlen(name) + 1, watch->token);
|
||||
talloc_set_destructor(event, destroy_watch_event);
|
||||
list_add_tail(&event->list, &watch->events);
|
||||
trace_create(event, "watch_event");
|
||||
}
|
||||
|
||||
/* FIXME: we fail to fire on out of memory. Should drop connections. */
|
||||
void fire_watches(struct connection *conn, const char *node, bool recurse)
|
||||
void fire_watches(struct connection *conn, const char *name, bool recurse)
|
||||
{
|
||||
struct connection *i;
|
||||
struct watch *watch;
|
||||
@@ -137,9 +139,9 @@ void fire_watches(struct connection *conn, const char *node, bool recurse)
|
||||
/* Create an event for each watch. */
|
||||
list_for_each_entry(i, &connections, list) {
|
||||
list_for_each_entry(watch, &i->watches, list) {
|
||||
if (is_child(node, watch->node))
|
||||
add_event(i, watch, node);
|
||||
else if (recurse && is_child(watch->node, node))
|
||||
if (is_child(name, watch->node))
|
||||
add_event(i, watch, name);
|
||||
else if (recurse && is_child(watch->node, name))
|
||||
add_event(i, watch, watch->node);
|
||||
else
|
||||
continue;
|
||||
@@ -156,49 +158,6 @@ static int destroy_watch(void *_watch)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void shortest_watch_ack_timeout(struct timeval *tv)
|
||||
{
|
||||
(void)tv;
|
||||
#if 0 /* FIXME */
|
||||
struct watch *watch;
|
||||
|
||||
list_for_each_entry(watch, &watches, list) {
|
||||
struct watch_event *i;
|
||||
list_for_each_entry(i, &watch->events, list) {
|
||||
if (!timerisset(&i->timeout))
|
||||
continue;
|
||||
if (!timerisset(tv) || timercmp(&i->timeout, tv, <))
|
||||
*tv = i->timeout;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void check_watch_ack_timeout(void)
|
||||
{
|
||||
#if 0
|
||||
struct watch *watch;
|
||||
struct timeval now;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
list_for_each_entry(watch, &watches, list) {
|
||||
struct watch_event *i, *tmp;
|
||||
list_for_each_entry_safe(i, tmp, &watch->events, list) {
|
||||
if (!timerisset(&i->timeout))
|
||||
continue;
|
||||
if (timercmp(&i->timeout, &now, <)) {
|
||||
xprintf("Warning: timeout on watch event %s"
|
||||
" token %s\n",
|
||||
i->node, watch->token);
|
||||
trace_watch_timeout(watch->conn, i->node,
|
||||
watch->token);
|
||||
timerclear(&i->timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void do_watch(struct connection *conn, struct buffered_data *in)
|
||||
{
|
||||
struct watch *watch;
|
||||
|
||||
@@ -32,15 +32,9 @@ bool is_watch_event(struct connection *conn, struct buffered_data *out);
|
||||
/* Look through our watches: if any of them have an event, queue it. */
|
||||
void queue_next_event(struct connection *conn);
|
||||
|
||||
/* Fire all watches: recurse means all the children are effected (ie. rm).
|
||||
/* Fire all watches: recurse means all the children are affected (ie. rm).
|
||||
*/
|
||||
void fire_watches(struct connection *conn, const char *node, bool recurse);
|
||||
|
||||
/* Find shortest timeout: if any, reduce tv (may already be set). */
|
||||
void shortest_watch_ack_timeout(struct timeval *tv);
|
||||
|
||||
/* Check for watches which may have timed out. */
|
||||
void check_watch_ack_timeout(void);
|
||||
void fire_watches(struct connection *conn, const char *name, bool recurse);
|
||||
|
||||
void dump_watches(struct connection *conn);
|
||||
|
||||
|
||||
+2
-3
@@ -497,13 +497,12 @@ bool xs_unwatch(struct xs_handle *h, const char *path, const char *token)
|
||||
|
||||
/* Start a transaction: changes by others will not be seen during this
|
||||
* transaction, and changes will not be visible to others until end.
|
||||
* Transaction only applies to the given subtree.
|
||||
* You can only have one transaction at any time.
|
||||
* Returns false on failure.
|
||||
*/
|
||||
bool xs_transaction_start(struct xs_handle *h, const char *subtree)
|
||||
bool xs_transaction_start(struct xs_handle *h)
|
||||
{
|
||||
return xs_bool(xs_single(h, XS_TRANSACTION_START, subtree, NULL));
|
||||
return xs_bool(xs_single(h, XS_TRANSACTION_START, "", NULL));
|
||||
}
|
||||
|
||||
/* End a transaction.
|
||||
|
||||
+3
-4
@@ -109,16 +109,15 @@ bool xs_unwatch(struct xs_handle *h, const char *path, const char *token);
|
||||
|
||||
/* Start a transaction: changes by others will not be seen during this
|
||||
* transaction, and changes will not be visible to others until end.
|
||||
* Transaction only applies to the given subtree.
|
||||
* You can only have one transaction at any time.
|
||||
* Returns false on failure.
|
||||
*/
|
||||
bool xs_transaction_start(struct xs_handle *h, const char *subtree);
|
||||
bool xs_transaction_start(struct xs_handle *h);
|
||||
|
||||
/* End a transaction.
|
||||
* If abandon is true, transaction is discarded instead of committed.
|
||||
* Returns false on failure, which indicates an error: transactions will
|
||||
* not fail spuriously.
|
||||
* Returns false on failure: if errno == EAGAIN, you have to restart
|
||||
* transaction.
|
||||
*/
|
||||
bool xs_transaction_end(struct xs_handle *h, bool abort);
|
||||
|
||||
|
||||
+7
-18
@@ -50,6 +50,13 @@ static const char *xs_daemon_path(void)
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *xs_daemon_tdb(void)
|
||||
{
|
||||
static char buf[PATH_MAX];
|
||||
sprintf(buf, "%s/tdb", xs_daemon_rootdir());
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *xs_daemon_socket(void)
|
||||
{
|
||||
return xs_daemon_path();
|
||||
@@ -66,24 +73,6 @@ const char *xs_daemon_socket_ro(void)
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *xs_daemon_store(void)
|
||||
{
|
||||
static char buf[PATH_MAX];
|
||||
if (snprintf(buf, PATH_MAX, "%s/store",
|
||||
xs_daemon_rootdir()) >= PATH_MAX)
|
||||
return NULL;
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *xs_daemon_transactions(void)
|
||||
{
|
||||
static char buf[PATH_MAX];
|
||||
if (snprintf(buf, PATH_MAX, "%s/transactions",
|
||||
xs_daemon_rootdir()) >= PATH_MAX)
|
||||
return NULL;
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *xs_domain_dev(void)
|
||||
{
|
||||
char *s = getenv("XENSTORED_PATH");
|
||||
|
||||
@@ -36,7 +36,7 @@ enum xs_perm_type {
|
||||
|
||||
struct xs_permissions
|
||||
{
|
||||
domid_t id;
|
||||
unsigned int id;
|
||||
enum xs_perm_type perms;
|
||||
};
|
||||
|
||||
@@ -46,9 +46,8 @@ struct xs_permissions
|
||||
/* Path for various daemon things: env vars can override. */
|
||||
const char *xs_daemon_socket(void);
|
||||
const char *xs_daemon_socket_ro(void);
|
||||
const char *xs_daemon_store(void);
|
||||
const char *xs_daemon_transactions(void);
|
||||
const char *xs_domain_dev(void);
|
||||
const char *xs_daemon_tdb(void);
|
||||
|
||||
/* Simple write function: loops for you. */
|
||||
bool xs_write_all(int fd, const void *data, unsigned int len);
|
||||
|
||||
+33
-85
@@ -41,7 +41,7 @@ struct ops
|
||||
struct xs_permissions *perms,
|
||||
unsigned int num);
|
||||
|
||||
bool (*transaction_start)(void *h, const char *subtree);
|
||||
bool (*transaction_start)(void *h);
|
||||
bool (*transaction_end)(void *h, bool abort);
|
||||
|
||||
/* Create and destroy a new handle. */
|
||||
@@ -53,7 +53,6 @@ struct file_ops_info
|
||||
{
|
||||
const char *base;
|
||||
char *transact_base;
|
||||
char *transact;
|
||||
};
|
||||
|
||||
static void convert_to_dir(const char *dirname)
|
||||
@@ -96,31 +95,6 @@ static char *path_to_name(struct file_ops_info *info, const char *path)
|
||||
return filename;
|
||||
}
|
||||
|
||||
/* Is child a subnode of parent, or equal? */
|
||||
static bool is_child(const char *child, const char *parent)
|
||||
{
|
||||
unsigned int len = strlen(parent);
|
||||
|
||||
/* / should really be "" for this algorithm to work, but that's a
|
||||
* usability nightmare. */
|
||||
if (streq(parent, "/"))
|
||||
return true;
|
||||
|
||||
if (strncmp(child, parent, len) != 0)
|
||||
return false;
|
||||
|
||||
return child[len] == '/' || child[len] == '\0';
|
||||
}
|
||||
|
||||
static bool write_ok(struct file_ops_info *info, const char *path)
|
||||
{
|
||||
if (info->transact && !is_child(path, info->transact)) {
|
||||
errno = EROFS;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static char **file_directory(struct file_ops_info *info,
|
||||
const char *path, unsigned int *num)
|
||||
{
|
||||
@@ -184,8 +158,10 @@ static void *file_read(struct file_ops_info *info,
|
||||
|
||||
ret = grab_file(filename, &size);
|
||||
/* Directory exists, .DATA doesn't. */
|
||||
if (!ret && errno == ENOENT && strends(filename, ".DATA"))
|
||||
errno = EISDIR;
|
||||
if (!ret && errno == ENOENT && strends(filename, ".DATA")) {
|
||||
ret = strdup("");
|
||||
size = 0;
|
||||
}
|
||||
*len = size;
|
||||
return ret;
|
||||
}
|
||||
@@ -270,9 +246,6 @@ static bool file_set_perms(struct file_ops_info *info,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!write_ok(info, path))
|
||||
return false;
|
||||
|
||||
/* Check non-perm file exists/ */
|
||||
if (lstat(filename, &st) != 0)
|
||||
return false;
|
||||
@@ -338,9 +311,6 @@ static bool file_write(struct file_ops_info *info,
|
||||
char *filename = filename_to_data(path_to_name(info, path));
|
||||
int fd;
|
||||
|
||||
if (!write_ok(info, path))
|
||||
return false;
|
||||
|
||||
make_dirs(parent_filename(filename));
|
||||
fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0600);
|
||||
if (fd < 0)
|
||||
@@ -358,9 +328,6 @@ static bool file_mkdir(struct file_ops_info *info, const char *path)
|
||||
{
|
||||
char *dirname = path_to_name(info, path);
|
||||
|
||||
if (!write_ok(info, path))
|
||||
return false;
|
||||
|
||||
make_dirs(parent_filename(dirname));
|
||||
if (mkdir(dirname, 0700) != 0)
|
||||
return (errno == EEXIST);
|
||||
@@ -374,20 +341,12 @@ static bool file_rm(struct file_ops_info *info, const char *path)
|
||||
char *filename = path_to_name(info, path);
|
||||
struct stat st;
|
||||
|
||||
if (info->transact && streq(info->transact, path)) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lstat(filename, &st) != 0) {
|
||||
if (lstat(parent_filename(filename), &st) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!write_ok(info, path))
|
||||
return false;
|
||||
|
||||
if (streq(path, "/")) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
@@ -398,28 +357,20 @@ static bool file_rm(struct file_ops_info *info, const char *path)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool file_transaction_start(struct file_ops_info *info,
|
||||
const char *subtree)
|
||||
static bool file_transaction_start(struct file_ops_info *info)
|
||||
{
|
||||
char *cmd;
|
||||
char *filename = path_to_name(info, subtree);
|
||||
struct stat st;
|
||||
|
||||
if (info->transact) {
|
||||
if (info->transact_base) {
|
||||
errno = EBUSY;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lstat(filename, &st) != 0)
|
||||
return false;
|
||||
|
||||
cmd = talloc_asprintf(NULL, "cp -r %s %s.transact",
|
||||
info->base, info->base);
|
||||
info->transact_base = talloc_asprintf(NULL, "%s.transact", info->base);
|
||||
cmd = talloc_asprintf(NULL, "cp -r %s %s",
|
||||
info->base, info->transact_base);
|
||||
do_command(cmd);
|
||||
talloc_free(cmd);
|
||||
|
||||
info->transact_base = talloc_asprintf(NULL, "%s.transact", info->base);
|
||||
info->transact = talloc_strdup(NULL, subtree);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -427,7 +378,7 @@ static bool file_transaction_end(struct file_ops_info *info, bool abort)
|
||||
{
|
||||
char *old, *cmd;
|
||||
|
||||
if (!info->transact) {
|
||||
if (!info->transact_base) {
|
||||
errno = ENOENT;
|
||||
return false;
|
||||
}
|
||||
@@ -448,9 +399,7 @@ static bool file_transaction_end(struct file_ops_info *info, bool abort)
|
||||
|
||||
success:
|
||||
talloc_free(cmd);
|
||||
talloc_free(info->transact);
|
||||
talloc_free(info->transact_base);
|
||||
info->transact = NULL;
|
||||
info->transact_base = NULL;
|
||||
return true;
|
||||
}
|
||||
@@ -461,7 +410,6 @@ static struct file_ops_info *file_handle(const char *dir)
|
||||
|
||||
info->base = dir;
|
||||
info->transact_base = NULL;
|
||||
info->transact = NULL;
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -898,11 +846,10 @@ static char *do_next_op(struct ops *ops, void *h, int state, bool verbose)
|
||||
case 7: {
|
||||
if (verbose)
|
||||
printf("START %s\n", name);
|
||||
ret = bool_to_errstring(ops->transaction_start(h, name));
|
||||
ret = bool_to_errstring(ops->transaction_start(h));
|
||||
if (streq(ret, "OK")) {
|
||||
talloc_free(ret);
|
||||
ret = talloc_asprintf(NULL, "OK:START-TRANSACT:%s",
|
||||
name);
|
||||
ret = talloc_asprintf(NULL, "OK:START-TRANSACT");
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -978,6 +925,8 @@ static void setup_file_ops(const char *dir)
|
||||
barf_perror("Creating directory %s/tool", dir);
|
||||
if (!file_set_perms(h, talloc_strdup(h, "/"), &perm, 1))
|
||||
barf_perror("Setting root perms in %s", dir);
|
||||
if (!file_set_perms(h, talloc_strdup(h, "/tool"), &perm, 1))
|
||||
barf_perror("Setting root perms in %s/tool", dir);
|
||||
file_close(h);
|
||||
}
|
||||
|
||||
@@ -1071,7 +1020,7 @@ static unsigned int try_simple(const bool *trymap,
|
||||
goto out;
|
||||
|
||||
if (!data->fast) {
|
||||
if (strstarts(ret, "OK:START-TRANSACT:")) {
|
||||
if (streq(ret, "OK:START-TRANSACT")) {
|
||||
void *pre = data->ops->handle(data->dir);
|
||||
|
||||
snapshot = dump(data->ops, pre);
|
||||
@@ -1303,7 +1252,7 @@ static unsigned int try_diff(const bool *trymap,
|
||||
void *_data)
|
||||
{
|
||||
void *fileh, *xsh;
|
||||
char *transact = NULL;
|
||||
bool transact = false;
|
||||
struct ops *fail;
|
||||
struct diff_data *data = _data;
|
||||
unsigned int i, print;
|
||||
@@ -1348,13 +1297,9 @@ static unsigned int try_diff(const bool *trymap,
|
||||
goto out;
|
||||
|
||||
if (strstarts(file, "OK:START-TRANSACT:"))
|
||||
transact = talloc_strdup(NULL,
|
||||
file +
|
||||
strlen("OK:START-TRANSACT:"));
|
||||
else if (streq(file, "OK:STOP-TRANSACT")) {
|
||||
talloc_free(transact);
|
||||
transact = NULL;
|
||||
}
|
||||
transact = true;
|
||||
else if (streq(file, "OK:STOP-TRANSACT"))
|
||||
transact = false;
|
||||
|
||||
talloc_free(file);
|
||||
talloc_free(xs);
|
||||
@@ -1379,7 +1324,7 @@ static unsigned int try_diff(const bool *trymap,
|
||||
|
||||
fail = NULL;
|
||||
if (!ops_equal(&xs_ops, xsh_pre, &file_ops, fileh_pre,
|
||||
transact, &fail)) {
|
||||
"/", &fail)) {
|
||||
if (fail)
|
||||
barf("%s failed during transact\n",
|
||||
fail->name);
|
||||
@@ -1456,9 +1401,6 @@ static unsigned int try_fail(const bool *trymap,
|
||||
fileh = file_handle(data->dir);
|
||||
xsh = xs_handle(data->dir);
|
||||
|
||||
sprintf(seed, "%i", data->seed);
|
||||
free(xs_debug_command(xsh, "failtest", seed, strlen(seed)+1));
|
||||
|
||||
print = number / 76;
|
||||
if (!print)
|
||||
print = 1;
|
||||
@@ -1491,8 +1433,12 @@ static unsigned int try_fail(const bool *trymap,
|
||||
if (trymap && !trymap[i])
|
||||
continue;
|
||||
|
||||
/* Turn on failure. */
|
||||
sprintf(seed, "%i", data->seed + i);
|
||||
free(xs_debug_command(xsh, "failtest",seed,strlen(seed)+1));
|
||||
|
||||
if (verbose)
|
||||
printf("(%i) ", i);
|
||||
printf("(%i) seed %s ", i, seed);
|
||||
ret = do_next_op(&xs_ops, xsh, i + data->seed, verbose);
|
||||
if (streq(ret, "FAILED:Connection reset by peer")
|
||||
|| streq(ret, "FAILED:Bad file descriptor")
|
||||
@@ -1549,8 +1495,6 @@ static unsigned int try_fail(const bool *trymap,
|
||||
fail = NULL;
|
||||
if (!ops_equal(&xs_ops, tmpxsh, &file_ops, tmpfileh, "/",
|
||||
&fail)) {
|
||||
xs_close(tmpxsh);
|
||||
file_close(tmpfileh);
|
||||
if (fail) {
|
||||
if (verbose)
|
||||
printf("%s failed\n", fail->name);
|
||||
@@ -1561,10 +1505,16 @@ static unsigned int try_fail(const bool *trymap,
|
||||
failed = 0;
|
||||
if (verbose)
|
||||
printf("(Looks like it succeeded)\n");
|
||||
xs_close(tmpxsh);
|
||||
file_close(tmpfileh);
|
||||
goto try_applying;
|
||||
}
|
||||
if (verbose)
|
||||
printf("Two backends not equal\n");
|
||||
printf("Trees differ:\nXS:%s\nFILE:%s\n",
|
||||
dump(&xs_ops, tmpxsh),
|
||||
dump(&file_ops, tmpfileh));
|
||||
xs_close(tmpxsh);
|
||||
file_close(tmpfileh);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1572,8 +1522,6 @@ static unsigned int try_fail(const bool *trymap,
|
||||
if (!xsh)
|
||||
file_transaction_end(fileh, true);
|
||||
|
||||
/* Turn failures back on. */
|
||||
free(xs_debug_command(tmpxsh, "failtest", NULL, 0));
|
||||
xs_close(tmpxsh);
|
||||
file_close(tmpfileh);
|
||||
}
|
||||
|
||||
+23
-23
@@ -8,6 +8,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define NUM_HANDLES 2
|
||||
#define DIR_FANOUT 3
|
||||
@@ -36,24 +37,18 @@ static void work(unsigned int cycles, unsigned int childnum)
|
||||
|
||||
srandom(childnum);
|
||||
for (i = 0; i < cycles; i++) {
|
||||
unsigned int lockdepth, j, len;
|
||||
char file[100] = "", lockdir[100];
|
||||
unsigned int j, len;
|
||||
char file[100] = "";
|
||||
char *contents, tmp[100];
|
||||
struct xs_handle *h = handles[random() % NUM_HANDLES];
|
||||
|
||||
lockdepth = random() % DIR_DEPTH;
|
||||
for (j = 0; j < DIR_DEPTH; j++) {
|
||||
if (j == lockdepth)
|
||||
strcpy(lockdir, file);
|
||||
for (j = 0; j < DIR_DEPTH; j++)
|
||||
sprintf(file + strlen(file), "/%li",
|
||||
random()%DIR_FANOUT);
|
||||
}
|
||||
if (streq(lockdir, ""))
|
||||
strcpy(lockdir, "/");
|
||||
|
||||
if (!xs_transaction_start(h, lockdir))
|
||||
barf_perror("%i: starting transaction %i on %s",
|
||||
childnum, i, lockdir);
|
||||
if (!xs_transaction_start(h))
|
||||
barf_perror("%i: starting transaction %i",
|
||||
childnum, i);
|
||||
|
||||
sprintf(file + strlen(file), "/count");
|
||||
contents = xs_read(h, file, &len);
|
||||
@@ -68,18 +63,23 @@ static void work(unsigned int cycles, unsigned int childnum)
|
||||
/* Abandon 1 in 10 */
|
||||
if (random() % 10 == 0) {
|
||||
if (!xs_transaction_end(h, true))
|
||||
barf_perror("%i: can't abort transact %s",
|
||||
childnum, lockdir);
|
||||
barf_perror("%i: can't abort transact",
|
||||
childnum);
|
||||
i--;
|
||||
} else {
|
||||
if (!xs_transaction_end(h, false))
|
||||
barf_perror("%i: can't commit transact %s",
|
||||
childnum, lockdir);
|
||||
|
||||
/* Offset when we print . so kids don't all
|
||||
* print at once. */
|
||||
if ((i + print/(childnum+1)) % print == 0)
|
||||
write(STDOUT_FILENO, &id, 1);
|
||||
if (!xs_transaction_end(h, false)) {
|
||||
if (errno == EAGAIN) {
|
||||
write(STDOUT_FILENO, "!", 1);
|
||||
i--;
|
||||
} else
|
||||
barf_perror("%i: can't commit trans",
|
||||
childnum);
|
||||
} else {
|
||||
/* Offset when we print . so kids don't all
|
||||
* print at once. */
|
||||
if ((i + print/(childnum+1)) % print == 0)
|
||||
write(STDOUT_FILENO, &id, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,7 +201,7 @@ int main(int argc, char *argv[])
|
||||
printf("\nCounting results...\n");
|
||||
i = tally_counts();
|
||||
if (i != (unsigned)atoi(argv[1]))
|
||||
barf("Total counts %i not %s", i, atoi(argv[1]));
|
||||
barf("Total counts %i not %s", i, argv[1]);
|
||||
printf("Success!\n");
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/* Simple program to dump out all records of TDB */
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "xs_lib.h"
|
||||
#include "tdb.h"
|
||||
#include "talloc.h"
|
||||
#include "utils.h"
|
||||
|
||||
struct record_hdr {
|
||||
u32 num_perms;
|
||||
u32 datalen;
|
||||
u32 childlen;
|
||||
struct xs_permissions perms[0];
|
||||
};
|
||||
|
||||
static u32 total_size(struct record_hdr *hdr)
|
||||
{
|
||||
return sizeof(*hdr) + hdr->num_perms * sizeof(struct xs_permissions)
|
||||
+ hdr->datalen + hdr->childlen;
|
||||
}
|
||||
|
||||
static char perm_to_char(enum xs_perm_type perm)
|
||||
{
|
||||
return perm == XS_PERM_READ ? 'r' :
|
||||
perm == XS_PERM_WRITE ? 'w' :
|
||||
perm == XS_PERM_NONE ? '-' :
|
||||
perm == (XS_PERM_READ|XS_PERM_WRITE) ? 'b' :
|
||||
'?';
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
TDB_DATA key;
|
||||
TDB_CONTEXT *tdb;
|
||||
|
||||
if (argc != 2)
|
||||
barf("Usage: xs_tdb_dump <tdbfile>");
|
||||
|
||||
tdb = tdb_open(talloc_strdup(NULL, argv[1]), 0, 0, O_RDONLY, 0);
|
||||
if (!tdb)
|
||||
barf_perror("Could not open %s", argv[1]);
|
||||
|
||||
key = tdb_firstkey(tdb);
|
||||
while (key.dptr) {
|
||||
TDB_DATA data;
|
||||
struct record_hdr *hdr;
|
||||
|
||||
data = tdb_fetch(tdb, key);
|
||||
hdr = (void *)data.dptr;
|
||||
if (data.dsize < sizeof(*hdr))
|
||||
fprintf(stderr, "%.*s: BAD truncated\n",
|
||||
key.dsize, key.dptr);
|
||||
else if (data.dsize != total_size(hdr))
|
||||
fprintf(stderr, "%.*s: BAD length %i for %i/%i/%i (%i)\n",
|
||||
key.dsize, key.dptr, data.dsize,
|
||||
hdr->num_perms, hdr->datalen,
|
||||
hdr->childlen, total_size(hdr));
|
||||
else {
|
||||
unsigned int i;
|
||||
char *p;
|
||||
|
||||
printf("%.*s: ", key.dsize, key.dptr);
|
||||
for (i = 0; i < hdr->num_perms; i++)
|
||||
printf("%s%c%i",
|
||||
i == 0 ? "" : ",",
|
||||
perm_to_char(hdr->perms[i].perms),
|
||||
hdr->perms[i].id);
|
||||
p = (void *)&hdr->perms[hdr->num_perms];
|
||||
printf(" %.*s\n", hdr->datalen, p);
|
||||
p += hdr->datalen;
|
||||
for (i = 0; i < hdr->childlen; i += strlen(p+i)+1)
|
||||
printf("\t-> %s\n", p+i);
|
||||
}
|
||||
key = tdb_nextkey(tdb, key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -562,9 +562,9 @@ static void do_unwatch(unsigned int handle, const char *node, const char *token)
|
||||
failed(handle);
|
||||
}
|
||||
|
||||
static void do_start(unsigned int handle, const char *node)
|
||||
static void do_start(unsigned int handle)
|
||||
{
|
||||
if (!xs_transaction_start(handles[handle], node))
|
||||
if (!xs_transaction_start(handles[handle]))
|
||||
failed(handle);
|
||||
}
|
||||
|
||||
@@ -791,7 +791,7 @@ static void do_command(unsigned int default_handle, char *line)
|
||||
xs_daemon_close(handles[handle]);
|
||||
handles[handle] = NULL;
|
||||
} else if (streq(command, "start"))
|
||||
do_start(handle, arg(line, 1));
|
||||
do_start(handle);
|
||||
else if (streq(command, "commit"))
|
||||
do_end(handle, false);
|
||||
else if (streq(command, "abort"))
|
||||
|
||||
+5
-9
@@ -2273,8 +2273,7 @@ int do_mmu_update(
|
||||
|
||||
|
||||
int update_grant_pte_mapping(
|
||||
unsigned long pte_addr, l1_pgentry_t _nl1e,
|
||||
struct domain *d, struct vcpu *v)
|
||||
unsigned long pte_addr, l1_pgentry_t _nl1e, struct vcpu *v)
|
||||
{
|
||||
int rc = GNTST_okay;
|
||||
void *va;
|
||||
@@ -2282,6 +2281,7 @@ int update_grant_pte_mapping(
|
||||
struct pfn_info *page;
|
||||
u32 type_info;
|
||||
l1_pgentry_t ol1e;
|
||||
struct domain *d = v->domain;
|
||||
|
||||
ASSERT(spin_is_locked(&d->big_lock));
|
||||
ASSERT(!shadow_mode_refcounts(d));
|
||||
@@ -2319,8 +2319,6 @@ int update_grant_pte_mapping(
|
||||
|
||||
put_page_from_l1e(ol1e, d);
|
||||
|
||||
rc = (l1e_get_flags(ol1e) & _PAGE_PRESENT) ? GNTST_flush_all : GNTST_okay;
|
||||
|
||||
if ( unlikely(shadow_mode_enabled(d)) )
|
||||
{
|
||||
struct domain_mmap_cache sh_mapcache;
|
||||
@@ -2415,10 +2413,10 @@ int clear_grant_pte_mapping(
|
||||
|
||||
|
||||
int update_grant_va_mapping(
|
||||
unsigned long va, l1_pgentry_t _nl1e, struct domain *d, struct vcpu *v)
|
||||
unsigned long va, l1_pgentry_t _nl1e, struct vcpu *v)
|
||||
{
|
||||
int rc = GNTST_okay;
|
||||
l1_pgentry_t *pl1e, ol1e;
|
||||
struct domain *d = v->domain;
|
||||
|
||||
ASSERT(spin_is_locked(&d->big_lock));
|
||||
ASSERT(!shadow_mode_refcounts(d));
|
||||
@@ -2439,12 +2437,10 @@ int update_grant_va_mapping(
|
||||
|
||||
put_page_from_l1e(ol1e, d);
|
||||
|
||||
rc = (l1e_get_flags(ol1e) & _PAGE_PRESENT) ? GNTST_flush_one : GNTST_okay;
|
||||
|
||||
if ( unlikely(shadow_mode_enabled(d)) )
|
||||
shadow_do_update_va_mapping(va, _nl1e, v);
|
||||
|
||||
return rc;
|
||||
return GNTST_okay;
|
||||
}
|
||||
|
||||
int clear_grant_va_mapping(unsigned long addr, unsigned long frame)
|
||||
|
||||
+118
-112
@@ -37,19 +37,19 @@
|
||||
#endif
|
||||
#ifdef CONFIG_VMX
|
||||
|
||||
struct vmcs_struct *alloc_vmcs(void)
|
||||
struct vmcs_struct *alloc_vmcs(void)
|
||||
{
|
||||
struct vmcs_struct *vmcs;
|
||||
u32 vmx_msr_low, vmx_msr_high;
|
||||
|
||||
rdmsr(MSR_IA32_VMX_BASIC_MSR, vmx_msr_low, vmx_msr_high);
|
||||
vmcs_size = vmx_msr_high & 0x1fff;
|
||||
vmcs = alloc_xenheap_pages(get_order_from_bytes(vmcs_size));
|
||||
vmcs = alloc_xenheap_pages(get_order_from_bytes(vmcs_size));
|
||||
memset((char *)vmcs, 0, vmcs_size); /* don't remove this */
|
||||
|
||||
vmcs->vmcs_revision_id = vmx_msr_low;
|
||||
return vmcs;
|
||||
}
|
||||
}
|
||||
|
||||
void free_vmcs(struct vmcs_struct *vmcs)
|
||||
{
|
||||
@@ -65,7 +65,7 @@ static inline int construct_vmcs_controls(struct arch_vmx_struct *arch_vmx)
|
||||
void *io_bitmap_a;
|
||||
void *io_bitmap_b;
|
||||
|
||||
error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL,
|
||||
error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL,
|
||||
MONITOR_PIN_BASED_EXEC_CONTROLS);
|
||||
|
||||
error |= __vmwrite(VM_EXIT_CONTROLS, MONITOR_VM_EXIT_CONTROLS);
|
||||
@@ -73,8 +73,8 @@ static inline int construct_vmcs_controls(struct arch_vmx_struct *arch_vmx)
|
||||
error |= __vmwrite(VM_ENTRY_CONTROLS, MONITOR_VM_ENTRY_CONTROLS);
|
||||
|
||||
/* need to use 0x1000 instead of PAGE_SIZE */
|
||||
io_bitmap_a = (void*) alloc_xenheap_pages(get_order_from_bytes(0x1000));
|
||||
io_bitmap_b = (void*) alloc_xenheap_pages(get_order_from_bytes(0x1000));
|
||||
io_bitmap_a = (void*) alloc_xenheap_pages(get_order_from_bytes(0x1000));
|
||||
io_bitmap_b = (void*) alloc_xenheap_pages(get_order_from_bytes(0x1000));
|
||||
memset(io_bitmap_a, 0xff, 0x1000);
|
||||
/* don't bother debug port access */
|
||||
clear_bit(PC_DEBUG_PORT, io_bitmap_a);
|
||||
@@ -89,8 +89,10 @@ static inline int construct_vmcs_controls(struct arch_vmx_struct *arch_vmx)
|
||||
return error;
|
||||
}
|
||||
|
||||
#define GUEST_SEGMENT_LIMIT 0xffffffff
|
||||
#define HOST_SEGMENT_LIMIT 0xffffffff
|
||||
#define GUEST_LAUNCH_DS 0x08
|
||||
#define GUEST_LAUNCH_CS 0x10
|
||||
#define GUEST_SEGMENT_LIMIT 0xffffffff
|
||||
#define HOST_SEGMENT_LIMIT 0xffffffff
|
||||
|
||||
struct host_execution_env {
|
||||
/* selectors */
|
||||
@@ -110,72 +112,76 @@ struct host_execution_env {
|
||||
unsigned long tr_base;
|
||||
unsigned long ds_base;
|
||||
unsigned long cs_base;
|
||||
#ifdef __x86_64__
|
||||
unsigned long fs_base;
|
||||
unsigned long gs_base;
|
||||
#endif
|
||||
#ifdef __x86_64__
|
||||
unsigned long fs_base;
|
||||
unsigned long gs_base;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define round_pgdown(_p) ((_p)&PAGE_MASK) /* coped from domain.c */
|
||||
|
||||
int vmx_setup_platform(struct vcpu *d, struct cpu_user_regs *regs)
|
||||
static void vmx_setup_platform(struct vcpu *v, struct cpu_user_regs *regs)
|
||||
{
|
||||
int i;
|
||||
unsigned int n;
|
||||
unsigned long *p, mpfn, offset, addr;
|
||||
struct e820entry *e820p;
|
||||
unsigned char e820_map_nr;
|
||||
struct e820entry *e820entry;
|
||||
unsigned char *p;
|
||||
unsigned long mpfn;
|
||||
unsigned long gpfn = 0;
|
||||
|
||||
local_flush_tlb_pge();
|
||||
regs->ebx = 0; /* Linux expects ebx to be 0 for boot proc */
|
||||
|
||||
n = regs->ecx;
|
||||
if (n > 32) {
|
||||
VMX_DBG_LOG(DBG_LEVEL_1, "Too many e820 entries: %d", n);
|
||||
return -1;
|
||||
mpfn = get_mfn_from_pfn(E820_MAP_PAGE >> PAGE_SHIFT);
|
||||
if (mpfn == INVALID_MFN) {
|
||||
printk("Can not find E820 memory map page for VMX domain.\n");
|
||||
domain_crash();
|
||||
}
|
||||
|
||||
addr = regs->edi;
|
||||
offset = (addr & ~PAGE_MASK);
|
||||
addr = round_pgdown(addr);
|
||||
|
||||
mpfn = get_mfn_from_pfn(addr >> PAGE_SHIFT);
|
||||
p = map_domain_page(mpfn);
|
||||
if (p == NULL) {
|
||||
printk("Can not map E820 memory map page for VMX domain.\n");
|
||||
domain_crash();
|
||||
}
|
||||
|
||||
e820p = (struct e820entry *) ((unsigned long) p + offset);
|
||||
e820_map_nr = *(p + E820_MAP_NR_OFFSET);
|
||||
e820entry = (struct e820entry *)(p + E820_MAP_OFFSET);
|
||||
|
||||
#ifndef NDEBUG
|
||||
print_e820_memory_map(e820p, n);
|
||||
#endif
|
||||
|
||||
for ( i = 0; i < n; i++ )
|
||||
for ( i = 0; i < e820_map_nr; i++ )
|
||||
{
|
||||
if ( e820p[i].type == E820_SHARED_PAGE )
|
||||
if (e820entry[i].type == E820_SHARED_PAGE)
|
||||
{
|
||||
gpfn = (e820p[i].addr >> PAGE_SHIFT);
|
||||
gpfn = (e820entry[i].addr >> PAGE_SHIFT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( gpfn == 0 )
|
||||
{
|
||||
unmap_domain_page(p);
|
||||
return -1;
|
||||
}
|
||||
if ( gpfn == 0 ) {
|
||||
printk("Can not get io request shared page"
|
||||
" from E820 memory map for VMX domain.\n");
|
||||
unmap_domain_page(p);
|
||||
domain_crash();
|
||||
}
|
||||
unmap_domain_page(p);
|
||||
|
||||
unmap_domain_page(p);
|
||||
if (v->vcpu_id)
|
||||
return;
|
||||
|
||||
/* Initialise shared page */
|
||||
mpfn = get_mfn_from_pfn(gpfn);
|
||||
if (mpfn == INVALID_MFN) {
|
||||
printk("Can not find io request shared page for VMX domain.\n");
|
||||
domain_crash();
|
||||
}
|
||||
|
||||
p = map_domain_page(mpfn);
|
||||
d->domain->arch.vmx_platform.shared_page_va = (unsigned long)p;
|
||||
if (p == NULL) {
|
||||
printk("Can not map io request shared page for VMX domain.\n");
|
||||
domain_crash();
|
||||
}
|
||||
v->domain->arch.vmx_platform.shared_page_va = (unsigned long)p;
|
||||
|
||||
VMX_DBG_LOG(DBG_LEVEL_1, "eport: %x\n", iopacket_port(d->domain));
|
||||
VMX_DBG_LOG(DBG_LEVEL_1, "eport: %x\n", iopacket_port(v->domain));
|
||||
|
||||
clear_bit(iopacket_port(d->domain),
|
||||
&d->domain->shared_info->evtchn_mask[0]);
|
||||
|
||||
return 0;
|
||||
clear_bit(iopacket_port(v->domain),
|
||||
&v->domain->shared_info->evtchn_mask[0]);
|
||||
}
|
||||
|
||||
void vmx_set_host_env(struct vcpu *v)
|
||||
@@ -203,7 +209,7 @@ void vmx_set_host_env(struct vcpu *v)
|
||||
error |= __vmwrite(HOST_TR_BASE, host_env.tr_base);
|
||||
}
|
||||
|
||||
void vmx_do_launch(struct vcpu *v)
|
||||
void vmx_do_launch(struct vcpu *v)
|
||||
{
|
||||
/* Update CR3, GDT, LDT, TR */
|
||||
unsigned int error = 0;
|
||||
@@ -217,7 +223,7 @@ void vmx_do_launch(struct vcpu *v)
|
||||
error |= __vmwrite(GUEST_CR0, cr0);
|
||||
cr0 &= ~X86_CR0_PG;
|
||||
error |= __vmwrite(CR0_READ_SHADOW, cr0);
|
||||
error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
|
||||
error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
|
||||
MONITOR_CPU_BASED_EXEC_CONTROLS);
|
||||
|
||||
__asm__ __volatile__ ("mov %%cr4,%0" : "=r" (cr4) : );
|
||||
@@ -247,7 +253,7 @@ void vmx_do_launch(struct vcpu *v)
|
||||
error |= __vmwrite(GUEST_LDTR_SELECTOR, 0);
|
||||
error |= __vmwrite(GUEST_LDTR_BASE, 0);
|
||||
error |= __vmwrite(GUEST_LDTR_LIMIT, 0);
|
||||
|
||||
|
||||
error |= __vmwrite(GUEST_TR_BASE, 0);
|
||||
error |= __vmwrite(GUEST_TR_LIMIT, 0xff);
|
||||
|
||||
@@ -261,10 +267,8 @@ void vmx_do_launch(struct vcpu *v)
|
||||
/*
|
||||
* Initially set the same environement as host.
|
||||
*/
|
||||
static inline int
|
||||
construct_init_vmcs_guest(struct cpu_user_regs *regs,
|
||||
struct vcpu_guest_context *ctxt,
|
||||
struct host_execution_env *host_env)
|
||||
static inline int
|
||||
construct_init_vmcs_guest(struct cpu_user_regs *regs)
|
||||
{
|
||||
int error = 0;
|
||||
union vmcs_arbytes arbytes;
|
||||
@@ -292,31 +296,37 @@ construct_init_vmcs_guest(struct cpu_user_regs *regs,
|
||||
error |= __vmwrite(CR3_TARGET_COUNT, 0);
|
||||
|
||||
/* Guest Selectors */
|
||||
error |= __vmwrite(GUEST_CS_SELECTOR, regs->cs);
|
||||
error |= __vmwrite(GUEST_ES_SELECTOR, regs->es);
|
||||
error |= __vmwrite(GUEST_SS_SELECTOR, regs->ss);
|
||||
error |= __vmwrite(GUEST_DS_SELECTOR, regs->ds);
|
||||
error |= __vmwrite(GUEST_FS_SELECTOR, regs->fs);
|
||||
error |= __vmwrite(GUEST_GS_SELECTOR, regs->gs);
|
||||
error |= __vmwrite(GUEST_ES_SELECTOR, GUEST_LAUNCH_DS);
|
||||
error |= __vmwrite(GUEST_SS_SELECTOR, GUEST_LAUNCH_DS);
|
||||
error |= __vmwrite(GUEST_DS_SELECTOR, GUEST_LAUNCH_DS);
|
||||
error |= __vmwrite(GUEST_FS_SELECTOR, GUEST_LAUNCH_DS);
|
||||
error |= __vmwrite(GUEST_GS_SELECTOR, GUEST_LAUNCH_DS);
|
||||
error |= __vmwrite(GUEST_CS_SELECTOR, GUEST_LAUNCH_CS);
|
||||
|
||||
/* Guest segment bases */
|
||||
error |= __vmwrite(GUEST_ES_BASE, 0);
|
||||
error |= __vmwrite(GUEST_SS_BASE, 0);
|
||||
error |= __vmwrite(GUEST_DS_BASE, 0);
|
||||
error |= __vmwrite(GUEST_FS_BASE, 0);
|
||||
error |= __vmwrite(GUEST_GS_BASE, 0);
|
||||
error |= __vmwrite(GUEST_CS_BASE, 0);
|
||||
|
||||
/* Guest segment Limits */
|
||||
error |= __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT);
|
||||
error |= __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT);
|
||||
error |= __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT);
|
||||
error |= __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT);
|
||||
error |= __vmwrite(GUEST_FS_LIMIT, GUEST_SEGMENT_LIMIT);
|
||||
error |= __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT);
|
||||
error |= __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT);
|
||||
|
||||
error |= __vmwrite(GUEST_IDTR_LIMIT, host_env->idtr_limit);
|
||||
|
||||
/* AR bytes */
|
||||
/* Guest segment AR bytes */
|
||||
arbytes.bytes = 0;
|
||||
arbytes.fields.seg_type = 0x3; /* type = 3 */
|
||||
arbytes.fields.s = 1; /* code or data, i.e. not system */
|
||||
arbytes.fields.dpl = 0; /* DPL = 3 */
|
||||
arbytes.fields.p = 1; /* segment present */
|
||||
arbytes.fields.default_ops_size = 1; /* 32-bit */
|
||||
arbytes.fields.g = 1;
|
||||
arbytes.fields.g = 1;
|
||||
arbytes.fields.null_bit = 0; /* not null */
|
||||
|
||||
error |= __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes);
|
||||
@@ -328,35 +338,31 @@ construct_init_vmcs_guest(struct cpu_user_regs *regs,
|
||||
arbytes.fields.seg_type = 0xb; /* type = 0xb */
|
||||
error |= __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes);
|
||||
|
||||
error |= __vmwrite(GUEST_GDTR_BASE, regs->edx);
|
||||
regs->edx = 0;
|
||||
error |= __vmwrite(GUEST_GDTR_LIMIT, regs->eax);
|
||||
regs->eax = 0;
|
||||
/* Guest GDT */
|
||||
error |= __vmwrite(GUEST_GDTR_BASE, 0);
|
||||
error |= __vmwrite(GUEST_GDTR_LIMIT, 0);
|
||||
|
||||
/* Guest IDT */
|
||||
error |= __vmwrite(GUEST_IDTR_BASE, 0);
|
||||
error |= __vmwrite(GUEST_IDTR_LIMIT, 0);
|
||||
|
||||
/* Guest LDT & TSS */
|
||||
arbytes.fields.s = 0; /* not code or data segement */
|
||||
arbytes.fields.seg_type = 0x2; /* LTD */
|
||||
arbytes.fields.default_ops_size = 0; /* 16-bit */
|
||||
arbytes.fields.g = 0;
|
||||
arbytes.fields.g = 0;
|
||||
error |= __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes);
|
||||
|
||||
arbytes.fields.seg_type = 0xb; /* 32-bit TSS (busy) */
|
||||
error |= __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes);
|
||||
/* CR3 is set in vmx_final_setup_guest */
|
||||
|
||||
error |= __vmwrite(GUEST_ES_BASE, host_env->ds_base);
|
||||
error |= __vmwrite(GUEST_CS_BASE, host_env->cs_base);
|
||||
error |= __vmwrite(GUEST_SS_BASE, host_env->ds_base);
|
||||
error |= __vmwrite(GUEST_DS_BASE, host_env->ds_base);
|
||||
error |= __vmwrite(GUEST_FS_BASE, host_env->ds_base);
|
||||
error |= __vmwrite(GUEST_GS_BASE, host_env->ds_base);
|
||||
error |= __vmwrite(GUEST_IDTR_BASE, host_env->idtr_base);
|
||||
|
||||
error |= __vmwrite(GUEST_RSP, regs->esp);
|
||||
error |= __vmwrite(GUEST_RSP, 0);
|
||||
error |= __vmwrite(GUEST_RIP, regs->eip);
|
||||
|
||||
/* Guest EFLAGS */
|
||||
eflags = regs->eflags & ~VMCS_EFLAGS_RESERVED_0; /* clear 0s */
|
||||
eflags |= VMCS_EFLAGS_RESERVED_1; /* set 1s */
|
||||
|
||||
error |= __vmwrite(GUEST_RFLAGS, eflags);
|
||||
|
||||
error |= __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
|
||||
@@ -381,14 +387,14 @@ static inline int construct_vmcs_host(struct host_execution_env *host_env)
|
||||
#if defined (__i386__)
|
||||
error |= __vmwrite(HOST_FS_SELECTOR, host_env->ds_selector);
|
||||
error |= __vmwrite(HOST_GS_SELECTOR, host_env->ds_selector);
|
||||
error |= __vmwrite(HOST_FS_BASE, host_env->ds_base);
|
||||
error |= __vmwrite(HOST_GS_BASE, host_env->ds_base);
|
||||
error |= __vmwrite(HOST_FS_BASE, host_env->ds_base);
|
||||
error |= __vmwrite(HOST_GS_BASE, host_env->ds_base);
|
||||
|
||||
#else
|
||||
rdmsrl(MSR_FS_BASE, host_env->fs_base);
|
||||
rdmsrl(MSR_GS_BASE, host_env->gs_base);
|
||||
error |= __vmwrite(HOST_FS_BASE, host_env->fs_base);
|
||||
error |= __vmwrite(HOST_GS_BASE, host_env->gs_base);
|
||||
rdmsrl(MSR_FS_BASE, host_env->fs_base);
|
||||
rdmsrl(MSR_GS_BASE, host_env->gs_base);
|
||||
error |= __vmwrite(HOST_FS_BASE, host_env->fs_base);
|
||||
error |= __vmwrite(HOST_GS_BASE, host_env->gs_base);
|
||||
|
||||
#endif
|
||||
host_env->cs_selector = __HYPERVISOR_CS;
|
||||
@@ -401,16 +407,16 @@ static inline int construct_vmcs_host(struct host_execution_env *host_env)
|
||||
error |= __vmwrite(HOST_CR0, crn); /* same CR0 */
|
||||
|
||||
/* CR3 is set in vmx_final_setup_hostos */
|
||||
__asm__ __volatile__ ("mov %%cr4,%0" : "=r" (crn) : );
|
||||
__asm__ __volatile__ ("mov %%cr4,%0" : "=r" (crn) : );
|
||||
error |= __vmwrite(HOST_CR4, crn);
|
||||
|
||||
error |= __vmwrite(HOST_RIP, (unsigned long) vmx_asm_vmexit_handler);
|
||||
#ifdef __x86_64__
|
||||
/* TBD: support cr8 for 64-bit guest */
|
||||
__vmwrite(VIRTUAL_APIC_PAGE_ADDR, 0);
|
||||
__vmwrite(TPR_THRESHOLD, 0);
|
||||
__vmwrite(SECONDARY_VM_EXEC_CONTROL, 0);
|
||||
#endif
|
||||
#ifdef __x86_64__
|
||||
/* TBD: support cr8 for 64-bit guest */
|
||||
__vmwrite(VIRTUAL_APIC_PAGE_ADDR, 0);
|
||||
__vmwrite(TPR_THRESHOLD, 0);
|
||||
__vmwrite(SECONDARY_VM_EXEC_CONTROL, 0);
|
||||
#endif
|
||||
|
||||
return error;
|
||||
}
|
||||
@@ -440,37 +446,37 @@ int construct_vmcs(struct arch_vmx_struct *arch_vmx,
|
||||
|
||||
if ((error = __vmpclear (vmcs_phys_ptr))) {
|
||||
printk("construct_vmcs: VMCLEAR failed\n");
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((error = load_vmcs(arch_vmx, vmcs_phys_ptr))) {
|
||||
printk("construct_vmcs: load_vmcs failed: VMCS = %lx\n",
|
||||
(unsigned long) vmcs_phys_ptr);
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((error = construct_vmcs_controls(arch_vmx))) {
|
||||
printk("construct_vmcs: construct_vmcs_controls failed\n");
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
/* host selectors */
|
||||
if ((error = construct_vmcs_host(&host_env))) {
|
||||
printk("construct_vmcs: construct_vmcs_host failed\n");
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
/* guest selectors */
|
||||
if ((error = construct_init_vmcs_guest(regs, ctxt, &host_env))) {
|
||||
if ((error = construct_init_vmcs_guest(regs))) {
|
||||
printk("construct_vmcs: construct_vmcs_guest failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((error |= __vmwrite(EXCEPTION_BITMAP,
|
||||
if ((error |= __vmwrite(EXCEPTION_BITMAP,
|
||||
MONITOR_DEFAULT_EXCEPTION_BITMAP))) {
|
||||
printk("construct_vmcs: setting Exception bitmap failed\n");
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (regs->eflags & EF_TF)
|
||||
__vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
|
||||
else
|
||||
else
|
||||
__vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
|
||||
|
||||
return 0;
|
||||
@@ -491,7 +497,7 @@ int modify_vmcs(struct arch_vmx_struct *arch_vmx,
|
||||
if ((error = load_vmcs(arch_vmx, vmcs_phys_ptr))) {
|
||||
printk("modify_vmcs: load_vmcs failed: VMCS = %lx\n",
|
||||
(unsigned long) vmcs_phys_ptr);
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
load_cpu_user_regs(regs);
|
||||
|
||||
@@ -500,23 +506,23 @@ int modify_vmcs(struct arch_vmx_struct *arch_vmx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
|
||||
int load_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((error = __vmptrld(phys_ptr))) {
|
||||
clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
||||
clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
||||
return error;
|
||||
}
|
||||
set_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
||||
set_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int store_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
|
||||
int store_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
|
||||
{
|
||||
/* take the current VMCS */
|
||||
__vmptrst(phys_ptr);
|
||||
clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
||||
clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -536,7 +542,7 @@ void vm_resume_fail(unsigned long eflags)
|
||||
__vmx_bug(guest_cpu_user_regs());
|
||||
}
|
||||
|
||||
void arch_vmx_do_resume(struct vcpu *v)
|
||||
void arch_vmx_do_resume(struct vcpu *v)
|
||||
{
|
||||
u64 vmcs_phys_ptr = (u64) virt_to_phys(v->arch.arch_vmx.vmcs);
|
||||
|
||||
@@ -545,7 +551,7 @@ void arch_vmx_do_resume(struct vcpu *v)
|
||||
reset_stack_and_jump(vmx_asm_do_resume);
|
||||
}
|
||||
|
||||
void arch_vmx_do_launch(struct vcpu *v)
|
||||
void arch_vmx_do_launch(struct vcpu *v)
|
||||
{
|
||||
u64 vmcs_phys_ptr = (u64) virt_to_phys(v->arch.arch_vmx.vmcs);
|
||||
|
||||
|
||||
+240
-359
@@ -24,10 +24,6 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define GRANT_DEBUG 0
|
||||
#define GRANT_DEBUG_VERBOSE 0
|
||||
|
||||
#include <xen/config.h>
|
||||
#include <xen/lib.h>
|
||||
#include <xen/sched.h>
|
||||
#include <xen/shadow.h>
|
||||
@@ -68,262 +64,6 @@ put_maptrack_handle(
|
||||
t->map_count--;
|
||||
}
|
||||
|
||||
static int
|
||||
__gnttab_activate_grant_ref(
|
||||
struct domain *mapping_d, /* IN */
|
||||
struct vcpu *mapping_ed,
|
||||
struct domain *granting_d,
|
||||
grant_ref_t ref,
|
||||
u16 dev_hst_ro_flags,
|
||||
u64 addr,
|
||||
unsigned long *pframe ) /* OUT */
|
||||
{
|
||||
domid_t sdom;
|
||||
u16 sflags;
|
||||
active_grant_entry_t *act;
|
||||
grant_entry_t *sha;
|
||||
s16 rc = 1;
|
||||
unsigned long frame = 0;
|
||||
int retries = 0;
|
||||
|
||||
/*
|
||||
* Objectives of this function:
|
||||
* . Make the record ( granting_d, ref ) active, if not already.
|
||||
* . Update shared grant entry of owner, indicating frame is mapped.
|
||||
* . Increment the owner act->pin reference counts.
|
||||
* . get_page on shared frame if new mapping.
|
||||
* . get_page_type if this is first RW mapping of frame.
|
||||
* . Add PTE to virtual address space of mapping_d, if necessary.
|
||||
* Returns:
|
||||
* . -ve: error
|
||||
* . 1: ok
|
||||
* . 0: ok and TLB invalidate of host_addr needed.
|
||||
*
|
||||
* On success, *pframe contains mfn.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We bound the number of times we retry CMPXCHG on memory locations that
|
||||
* we share with a guest OS. The reason is that the guest can modify that
|
||||
* location at a higher rate than we can read-modify-CMPXCHG, so the guest
|
||||
* could cause us to livelock. There are a few cases where it is valid for
|
||||
* the guest to race our updates (e.g., to change the GTF_readonly flag),
|
||||
* so we allow a few retries before failing.
|
||||
*/
|
||||
|
||||
act = &granting_d->grant_table->active[ref];
|
||||
sha = &granting_d->grant_table->shared[ref];
|
||||
|
||||
spin_lock(&granting_d->grant_table->lock);
|
||||
|
||||
if ( act->pin == 0 )
|
||||
{
|
||||
/* CASE 1: Activating a previously inactive entry. */
|
||||
|
||||
sflags = sha->flags;
|
||||
sdom = sha->domid;
|
||||
|
||||
/* This loop attempts to set the access (reading/writing) flags
|
||||
* in the grant table entry. It tries a cmpxchg on the field
|
||||
* up to five times, and then fails under the assumption that
|
||||
* the guest is misbehaving. */
|
||||
for ( ; ; )
|
||||
{
|
||||
u32 scombo, prev_scombo, new_scombo;
|
||||
|
||||
if ( unlikely((sflags & GTF_type_mask) != GTF_permit_access) ||
|
||||
unlikely(sdom != mapping_d->domain_id) )
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Bad flags (%x) or dom (%d). (NB. expected dom %d)\n",
|
||||
sflags, sdom, mapping_d->domain_id);
|
||||
|
||||
/* Merge two 16-bit values into a 32-bit combined update. */
|
||||
/* NB. Endianness! */
|
||||
prev_scombo = scombo = ((u32)sdom << 16) | (u32)sflags;
|
||||
|
||||
new_scombo = scombo | GTF_reading;
|
||||
if ( !(dev_hst_ro_flags & GNTMAP_readonly) )
|
||||
{
|
||||
new_scombo |= GTF_writing;
|
||||
if ( unlikely(sflags & GTF_readonly) )
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Attempt to write-pin a r/o grant entry.\n");
|
||||
}
|
||||
|
||||
/* NB. prev_scombo is updated in place to seen value. */
|
||||
if ( unlikely(cmpxchg_user((u32 *)&sha->flags,
|
||||
prev_scombo,
|
||||
new_scombo)) )
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Fault while modifying shared flags and domid.\n");
|
||||
|
||||
/* Did the combined update work (did we see what we expected?). */
|
||||
if ( likely(prev_scombo == scombo) )
|
||||
break;
|
||||
|
||||
if ( retries++ == 4 )
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Shared grant entry is unstable.\n");
|
||||
|
||||
/* Didn't see what we expected. Split out the seen flags & dom. */
|
||||
/* NB. Endianness! */
|
||||
sflags = (u16)prev_scombo;
|
||||
sdom = (u16)(prev_scombo >> 16);
|
||||
}
|
||||
|
||||
/* rmb(); */ /* not on x86 */
|
||||
|
||||
frame = __gpfn_to_mfn_foreign(granting_d, sha->frame);
|
||||
|
||||
if ( unlikely(!pfn_valid(frame)) ||
|
||||
unlikely(!((dev_hst_ro_flags & GNTMAP_readonly) ?
|
||||
get_page(&frame_table[frame], granting_d) :
|
||||
get_page_and_type(&frame_table[frame], granting_d,
|
||||
PGT_writable_page))) )
|
||||
{
|
||||
clear_bit(_GTF_writing, &sha->flags);
|
||||
clear_bit(_GTF_reading, &sha->flags);
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Could not pin the granted frame (%lx)!\n", frame);
|
||||
}
|
||||
|
||||
if ( dev_hst_ro_flags & GNTMAP_device_map )
|
||||
act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
|
||||
GNTPIN_devr_inc : GNTPIN_devw_inc;
|
||||
if ( dev_hst_ro_flags & GNTMAP_host_map )
|
||||
act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
|
||||
GNTPIN_hstr_inc : GNTPIN_hstw_inc;
|
||||
act->domid = sdom;
|
||||
act->frame = frame;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* CASE 2: Active modications to an already active entry. */
|
||||
|
||||
/*
|
||||
* A cheesy check for possible pin-count overflow.
|
||||
* A more accurate check cannot be done with a single comparison.
|
||||
*/
|
||||
if ( (act->pin & 0x80808080U) != 0 )
|
||||
PIN_FAIL(unlock_out, ENOSPC,
|
||||
"Risk of counter overflow %08x\n", act->pin);
|
||||
|
||||
frame = act->frame;
|
||||
|
||||
if ( !(dev_hst_ro_flags & GNTMAP_readonly) &&
|
||||
!((sflags = sha->flags) & GTF_writing) )
|
||||
{
|
||||
for ( ; ; )
|
||||
{
|
||||
u16 prev_sflags;
|
||||
|
||||
if ( unlikely(sflags & GTF_readonly) )
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Attempt to write-pin a r/o grant entry.\n");
|
||||
|
||||
prev_sflags = sflags;
|
||||
|
||||
/* NB. prev_sflags is updated in place to seen value. */
|
||||
if ( unlikely(cmpxchg_user(&sha->flags, prev_sflags,
|
||||
prev_sflags | GTF_writing)) )
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Fault while modifying shared flags.\n");
|
||||
|
||||
if ( likely(prev_sflags == sflags) )
|
||||
break;
|
||||
|
||||
if ( retries++ == 4 )
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Shared grant entry is unstable.\n");
|
||||
|
||||
sflags = prev_sflags;
|
||||
}
|
||||
|
||||
if ( unlikely(!get_page_type(&frame_table[frame],
|
||||
PGT_writable_page)) )
|
||||
{
|
||||
clear_bit(_GTF_writing, &sha->flags);
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Attempt to write-pin a unwritable page.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if ( dev_hst_ro_flags & GNTMAP_device_map )
|
||||
act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
|
||||
GNTPIN_devr_inc : GNTPIN_devw_inc;
|
||||
|
||||
if ( dev_hst_ro_flags & GNTMAP_host_map )
|
||||
act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
|
||||
GNTPIN_hstr_inc : GNTPIN_hstw_inc;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point:
|
||||
* act->pin updated to reference count mappings.
|
||||
* sha->flags updated to indicate to granting domain mapping done.
|
||||
* frame contains the mfn.
|
||||
*/
|
||||
|
||||
spin_unlock(&granting_d->grant_table->lock);
|
||||
|
||||
if ( (addr != 0) && (dev_hst_ro_flags & GNTMAP_host_map) )
|
||||
{
|
||||
/* Write update into the pagetable. */
|
||||
l1_pgentry_t pte;
|
||||
pte = l1e_from_pfn(frame, GRANT_PTE_FLAGS);
|
||||
|
||||
if ( (dev_hst_ro_flags & GNTMAP_application_map) )
|
||||
l1e_add_flags(pte,_PAGE_USER);
|
||||
if ( !(dev_hst_ro_flags & GNTMAP_readonly) )
|
||||
l1e_add_flags(pte,_PAGE_RW);
|
||||
|
||||
if ( dev_hst_ro_flags & GNTMAP_contains_pte )
|
||||
rc = update_grant_pte_mapping(addr, pte, mapping_d, mapping_ed);
|
||||
else
|
||||
rc = update_grant_va_mapping(addr, pte, mapping_d, mapping_ed);
|
||||
|
||||
/* IMPORTANT: rc indicates the degree of TLB flush that is required.
|
||||
* GNTST_flush_one (1) or GNTST_flush_all (2). This is done in the
|
||||
* outer gnttab_map_grant_ref. */
|
||||
if ( rc < 0 )
|
||||
{
|
||||
/* Failure: undo and abort. */
|
||||
|
||||
spin_lock(&granting_d->grant_table->lock);
|
||||
|
||||
if ( dev_hst_ro_flags & GNTMAP_readonly )
|
||||
{
|
||||
act->pin -= GNTPIN_hstr_inc;
|
||||
}
|
||||
else
|
||||
{
|
||||
act->pin -= GNTPIN_hstw_inc;
|
||||
if ( (act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) == 0 )
|
||||
{
|
||||
clear_bit(_GTF_writing, &sha->flags);
|
||||
put_page_type(&frame_table[frame]);
|
||||
}
|
||||
}
|
||||
|
||||
if ( act->pin == 0 )
|
||||
{
|
||||
clear_bit(_GTF_reading, &sha->flags);
|
||||
put_page(&frame_table[frame]);
|
||||
}
|
||||
|
||||
spin_unlock(&granting_d->grant_table->lock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*pframe = frame;
|
||||
return rc;
|
||||
|
||||
unlock_out:
|
||||
spin_unlock(&granting_d->grant_table->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 0 if TLB flush / invalidate required by caller.
|
||||
* va will indicate the address to be invalidated.
|
||||
@@ -333,8 +73,7 @@ __gnttab_activate_grant_ref(
|
||||
*/
|
||||
static int
|
||||
__gnttab_map_grant_ref(
|
||||
gnttab_map_grant_ref_t *uop,
|
||||
unsigned long *va)
|
||||
gnttab_map_grant_ref_t *uop)
|
||||
{
|
||||
domid_t dom;
|
||||
grant_ref_t ref;
|
||||
@@ -344,7 +83,23 @@ __gnttab_map_grant_ref(
|
||||
int handle;
|
||||
u64 addr;
|
||||
unsigned long frame = 0;
|
||||
int rc;
|
||||
int rc = GNTST_okay;
|
||||
active_grant_entry_t *act;
|
||||
|
||||
/* Entry details from @rd's shared grant table. */
|
||||
grant_entry_t *sha;
|
||||
domid_t sdom;
|
||||
u16 sflags;
|
||||
|
||||
/*
|
||||
* We bound the number of times we retry CMPXCHG on memory locations that
|
||||
* we share with a guest OS. The reason is that the guest can modify that
|
||||
* location at a higher rate than we can read-modify-CMPXCHG, so the guest
|
||||
* could cause us to livelock. There are a few cases where it is valid for
|
||||
* the guest to race our updates (e.g., to change the GTF_readonly flag),
|
||||
* so we allow a few retries before failing.
|
||||
*/
|
||||
int retries = 0;
|
||||
|
||||
led = current;
|
||||
ld = led->domain;
|
||||
@@ -359,17 +114,6 @@ __gnttab_map_grant_ref(
|
||||
return -EFAULT; /* don't set status */
|
||||
}
|
||||
|
||||
if ( (dev_hst_ro_flags & GNTMAP_host_map) &&
|
||||
( (addr == 0) ||
|
||||
(!(dev_hst_ro_flags & GNTMAP_contains_pte) &&
|
||||
unlikely(!__addr_ok(addr))) ) )
|
||||
{
|
||||
DPRINTK("Bad virtual address (%"PRIx64") or flags (%"PRIx16").\n",
|
||||
addr, dev_hst_ro_flags);
|
||||
(void)__put_user(GNTST_bad_virt_addr, &uop->handle);
|
||||
return GNTST_bad_gntref;
|
||||
}
|
||||
|
||||
if ( unlikely(ref >= NR_GRANT_ENTRIES) ||
|
||||
unlikely((dev_hst_ro_flags &
|
||||
(GNTMAP_device_map|GNTMAP_host_map)) == 0) )
|
||||
@@ -379,7 +123,8 @@ __gnttab_map_grant_ref(
|
||||
return GNTST_bad_gntref;
|
||||
}
|
||||
|
||||
if (acm_pre_grant_map_ref(dom)) {
|
||||
if ( acm_pre_grant_map_ref(dom) )
|
||||
{
|
||||
(void)__put_user(GNTST_permission_denied, &uop->handle);
|
||||
return GNTST_permission_denied;
|
||||
}
|
||||
@@ -432,65 +177,242 @@ __gnttab_map_grant_ref(
|
||||
handle = get_maptrack_handle(ld->grant_table);
|
||||
}
|
||||
|
||||
#if GRANT_DEBUG_VERBOSE
|
||||
DPRINTK("Mapping grant ref (%hu) for domain (%hu) with flags (%x)\n",
|
||||
ref, dom, dev_hst_ro_flags);
|
||||
#endif
|
||||
act = &rd->grant_table->active[ref];
|
||||
sha = &rd->grant_table->shared[ref];
|
||||
|
||||
if ( (rc = __gnttab_activate_grant_ref(ld, led, rd, ref, dev_hst_ro_flags,
|
||||
addr, &frame)) >= 0 )
|
||||
spin_lock(&rd->grant_table->lock);
|
||||
|
||||
if ( act->pin == 0 )
|
||||
{
|
||||
/* CASE 1: Activating a previously inactive entry. */
|
||||
|
||||
sflags = sha->flags;
|
||||
sdom = sha->domid;
|
||||
|
||||
/* This loop attempts to set the access (reading/writing) flags
|
||||
* in the grant table entry. It tries a cmpxchg on the field
|
||||
* up to five times, and then fails under the assumption that
|
||||
* the guest is misbehaving. */
|
||||
for ( ; ; )
|
||||
{
|
||||
u32 scombo, prev_scombo, new_scombo;
|
||||
|
||||
if ( unlikely((sflags & GTF_type_mask) != GTF_permit_access) ||
|
||||
unlikely(sdom != led->domain->domain_id) )
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Bad flags (%x) or dom (%d). (NB. expected dom %d)\n",
|
||||
sflags, sdom, led->domain->domain_id);
|
||||
|
||||
/* Merge two 16-bit values into a 32-bit combined update. */
|
||||
/* NB. Endianness! */
|
||||
prev_scombo = scombo = ((u32)sdom << 16) | (u32)sflags;
|
||||
|
||||
new_scombo = scombo | GTF_reading;
|
||||
if ( !(dev_hst_ro_flags & GNTMAP_readonly) )
|
||||
{
|
||||
new_scombo |= GTF_writing;
|
||||
if ( unlikely(sflags & GTF_readonly) )
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Attempt to write-pin a r/o grant entry.\n");
|
||||
}
|
||||
|
||||
/* NB. prev_scombo is updated in place to seen value. */
|
||||
if ( unlikely(cmpxchg_user((u32 *)&sha->flags,
|
||||
prev_scombo,
|
||||
new_scombo)) )
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Fault while modifying shared flags and domid.\n");
|
||||
|
||||
/* Did the combined update work (did we see what we expected?). */
|
||||
if ( likely(prev_scombo == scombo) )
|
||||
break;
|
||||
|
||||
if ( retries++ == 4 )
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Shared grant entry is unstable.\n");
|
||||
|
||||
/* Didn't see what we expected. Split out the seen flags & dom. */
|
||||
/* NB. Endianness! */
|
||||
sflags = (u16)prev_scombo;
|
||||
sdom = (u16)(prev_scombo >> 16);
|
||||
}
|
||||
|
||||
/* rmb(); */ /* not on x86 */
|
||||
|
||||
frame = __gpfn_to_mfn_foreign(rd, sha->frame);
|
||||
|
||||
if ( unlikely(!pfn_valid(frame)) ||
|
||||
unlikely(!((dev_hst_ro_flags & GNTMAP_readonly) ?
|
||||
get_page(&frame_table[frame], rd) :
|
||||
get_page_and_type(&frame_table[frame], rd,
|
||||
PGT_writable_page))) )
|
||||
{
|
||||
clear_bit(_GTF_writing, &sha->flags);
|
||||
clear_bit(_GTF_reading, &sha->flags);
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Could not pin the granted frame (%lx)!\n", frame);
|
||||
}
|
||||
|
||||
if ( dev_hst_ro_flags & GNTMAP_device_map )
|
||||
act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
|
||||
GNTPIN_devr_inc : GNTPIN_devw_inc;
|
||||
if ( dev_hst_ro_flags & GNTMAP_host_map )
|
||||
act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
|
||||
GNTPIN_hstr_inc : GNTPIN_hstw_inc;
|
||||
act->domid = sdom;
|
||||
act->frame = frame;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* CASE 2: Active modications to an already active entry. */
|
||||
|
||||
/*
|
||||
* Only make the maptrack live _after_ writing the pte, in case we
|
||||
* overwrite the same frame number, causing a maptrack walk to find it
|
||||
* A cheesy check for possible pin-count overflow.
|
||||
* A more accurate check cannot be done with a single comparison.
|
||||
*/
|
||||
ld->grant_table->maptrack[handle].domid = dom;
|
||||
if ( (act->pin & 0x80808080U) != 0 )
|
||||
PIN_FAIL(unlock_out, ENOSPC,
|
||||
"Risk of counter overflow %08x\n", act->pin);
|
||||
|
||||
ld->grant_table->maptrack[handle].ref_and_flags
|
||||
= (ref << MAPTRACK_REF_SHIFT) |
|
||||
(dev_hst_ro_flags & MAPTRACK_GNTMAP_MASK);
|
||||
sflags = sha->flags;
|
||||
frame = act->frame;
|
||||
|
||||
(void)__put_user((u64)frame << PAGE_SHIFT, &uop->dev_bus_addr);
|
||||
if ( !(dev_hst_ro_flags & GNTMAP_readonly) &&
|
||||
!(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) )
|
||||
{
|
||||
for ( ; ; )
|
||||
{
|
||||
u16 prev_sflags;
|
||||
|
||||
if ( unlikely(sflags & GTF_readonly) )
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Attempt to write-pin a r/o grant entry.\n");
|
||||
|
||||
if ( ( dev_hst_ro_flags & GNTMAP_host_map ) &&
|
||||
!( dev_hst_ro_flags & GNTMAP_contains_pte) )
|
||||
*va = addr;
|
||||
prev_sflags = sflags;
|
||||
|
||||
(void)__put_user(handle, &uop->handle);
|
||||
/* NB. prev_sflags is updated in place to seen value. */
|
||||
if ( unlikely(cmpxchg_user(&sha->flags, prev_sflags,
|
||||
prev_sflags | GTF_writing)) )
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Fault while modifying shared flags.\n");
|
||||
|
||||
if ( likely(prev_sflags == sflags) )
|
||||
break;
|
||||
|
||||
if ( retries++ == 4 )
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Shared grant entry is unstable.\n");
|
||||
|
||||
sflags = prev_sflags;
|
||||
}
|
||||
|
||||
if ( unlikely(!get_page_type(&frame_table[frame],
|
||||
PGT_writable_page)) )
|
||||
{
|
||||
clear_bit(_GTF_writing, &sha->flags);
|
||||
PIN_FAIL(unlock_out, GNTST_general_error,
|
||||
"Attempt to write-pin a unwritable page.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if ( dev_hst_ro_flags & GNTMAP_device_map )
|
||||
act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
|
||||
GNTPIN_devr_inc : GNTPIN_devw_inc;
|
||||
|
||||
if ( dev_hst_ro_flags & GNTMAP_host_map )
|
||||
act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
|
||||
GNTPIN_hstr_inc : GNTPIN_hstw_inc;
|
||||
}
|
||||
else
|
||||
|
||||
/*
|
||||
* At this point:
|
||||
* act->pin updated to reference count mappings.
|
||||
* sha->flags updated to indicate to granting domain mapping done.
|
||||
* frame contains the mfn.
|
||||
*/
|
||||
|
||||
spin_unlock(&rd->grant_table->lock);
|
||||
|
||||
if ( dev_hst_ro_flags & GNTMAP_host_map )
|
||||
{
|
||||
(void)__put_user(rc, &uop->handle);
|
||||
put_maptrack_handle(ld->grant_table, handle);
|
||||
/* Write update into the pagetable. */
|
||||
l1_pgentry_t pte;
|
||||
pte = l1e_from_pfn(frame, GRANT_PTE_FLAGS);
|
||||
|
||||
if ( (dev_hst_ro_flags & GNTMAP_application_map) )
|
||||
l1e_add_flags(pte,_PAGE_USER);
|
||||
if ( !(dev_hst_ro_flags & GNTMAP_readonly) )
|
||||
l1e_add_flags(pte,_PAGE_RW);
|
||||
|
||||
if ( dev_hst_ro_flags & GNTMAP_contains_pte )
|
||||
rc = update_grant_pte_mapping(addr, pte, led);
|
||||
else
|
||||
rc = update_grant_va_mapping(addr, pte, led);
|
||||
|
||||
if ( rc < 0 )
|
||||
{
|
||||
/* Failure: undo and abort. */
|
||||
|
||||
spin_lock(&rd->grant_table->lock);
|
||||
|
||||
if ( dev_hst_ro_flags & GNTMAP_readonly )
|
||||
{
|
||||
act->pin -= GNTPIN_hstr_inc;
|
||||
}
|
||||
else
|
||||
{
|
||||
act->pin -= GNTPIN_hstw_inc;
|
||||
if ( (act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) == 0 )
|
||||
{
|
||||
clear_bit(_GTF_writing, &sha->flags);
|
||||
put_page_type(&frame_table[frame]);
|
||||
}
|
||||
}
|
||||
|
||||
if ( act->pin == 0 )
|
||||
{
|
||||
clear_bit(_GTF_reading, &sha->flags);
|
||||
put_page(&frame_table[frame]);
|
||||
}
|
||||
|
||||
spin_unlock(&rd->grant_table->lock);
|
||||
}
|
||||
}
|
||||
|
||||
ld->grant_table->maptrack[handle].domid = dom;
|
||||
ld->grant_table->maptrack[handle].ref_and_flags =
|
||||
(ref << MAPTRACK_REF_SHIFT) |
|
||||
(dev_hst_ro_flags & MAPTRACK_GNTMAP_MASK);
|
||||
|
||||
(void)__put_user((u64)frame << PAGE_SHIFT, &uop->dev_bus_addr);
|
||||
(void)__put_user(handle, &uop->handle);
|
||||
|
||||
put_domain(rd);
|
||||
return rc;
|
||||
|
||||
|
||||
unlock_out:
|
||||
spin_unlock(&rd->grant_table->lock);
|
||||
(void)__put_user(rc, &uop->handle);
|
||||
put_maptrack_handle(ld->grant_table, handle);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long
|
||||
gnttab_map_grant_ref(
|
||||
gnttab_map_grant_ref_t *uop, unsigned int count)
|
||||
{
|
||||
int i, rc, flush = 0;
|
||||
unsigned long va = 0;
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < count; i++ )
|
||||
if ( (rc =__gnttab_map_grant_ref(&uop[i], &va)) >= 0 )
|
||||
flush += rc;
|
||||
|
||||
if ( flush == 1 )
|
||||
flush_tlb_one_mask(current->domain->cpumask, va);
|
||||
else if ( flush != 0 )
|
||||
flush_tlb_mask(current->domain->cpumask);
|
||||
(void)__gnttab_map_grant_ref(&uop[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
__gnttab_unmap_grant_ref(
|
||||
gnttab_unmap_grant_ref_t *uop,
|
||||
unsigned long *va)
|
||||
gnttab_unmap_grant_ref_t *uop)
|
||||
{
|
||||
domid_t dom;
|
||||
grant_ref_t ref;
|
||||
@@ -500,7 +422,7 @@ __gnttab_unmap_grant_ref(
|
||||
grant_entry_t *sha;
|
||||
grant_mapping_t *map;
|
||||
u16 flags;
|
||||
s16 rc = 1;
|
||||
s16 rc = 0;
|
||||
u64 addr, dev_bus_addr;
|
||||
unsigned long frame;
|
||||
|
||||
@@ -541,11 +463,6 @@ __gnttab_unmap_grant_ref(
|
||||
return GNTST_bad_domain;
|
||||
}
|
||||
|
||||
#if GRANT_DEBUG_VERBOSE
|
||||
DPRINTK("Unmapping grant ref (%hu) for domain (%hu) with handle (%hu)\n",
|
||||
ref, dom, handle);
|
||||
#endif
|
||||
|
||||
act = &rd->grant_table->active[ref];
|
||||
sha = &rd->grant_table->shared[ref];
|
||||
|
||||
@@ -566,8 +483,6 @@ __gnttab_unmap_grant_ref(
|
||||
|
||||
map->ref_and_flags &= ~GNTMAP_device_map;
|
||||
(void)__put_user(0, &uop->dev_bus_addr);
|
||||
|
||||
/* Frame is now unmapped for device access. */
|
||||
}
|
||||
|
||||
if ( (addr != 0) &&
|
||||
@@ -589,10 +504,6 @@ __gnttab_unmap_grant_ref(
|
||||
|
||||
act->pin -= (flags & GNTMAP_readonly) ? GNTPIN_hstr_inc
|
||||
: GNTPIN_hstw_inc;
|
||||
|
||||
rc = 0;
|
||||
if ( !( flags & GNTMAP_contains_pte) )
|
||||
*va = addr;
|
||||
}
|
||||
|
||||
if ( (map->ref_and_flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0)
|
||||
@@ -632,17 +543,12 @@ static long
|
||||
gnttab_unmap_grant_ref(
|
||||
gnttab_unmap_grant_ref_t *uop, unsigned int count)
|
||||
{
|
||||
int i, flush = 0;
|
||||
unsigned long va = 0;
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < count; i++ )
|
||||
if ( __gnttab_unmap_grant_ref(&uop[i], &va) == 0 )
|
||||
flush++;
|
||||
(void)__gnttab_unmap_grant_ref(&uop[i]);
|
||||
|
||||
if ( flush == 1 )
|
||||
flush_tlb_one_mask(current->domain->cpumask, va);
|
||||
else if ( flush != 0 )
|
||||
flush_tlb_mask(current->domain->cpumask);
|
||||
flush_tlb_mask(current->domain->cpumask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -703,9 +609,9 @@ gnttab_setup_table(
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if GRANT_DEBUG
|
||||
static int
|
||||
gnttab_dump_table(gnttab_dump_table_t *uop)
|
||||
gnttab_dump_table(
|
||||
gnttab_dump_table_t *uop)
|
||||
{
|
||||
grant_table_t *gt;
|
||||
gnttab_dump_table_t op;
|
||||
@@ -716,6 +622,8 @@ gnttab_dump_table(gnttab_dump_table_t *uop)
|
||||
grant_mapping_t *maptrack;
|
||||
int i;
|
||||
|
||||
if ( !IS_PRIV(current->domain) )
|
||||
return -EPERM;
|
||||
|
||||
if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) )
|
||||
{
|
||||
@@ -724,9 +632,7 @@ gnttab_dump_table(gnttab_dump_table_t *uop)
|
||||
}
|
||||
|
||||
if ( op.dom == DOMID_SELF )
|
||||
{
|
||||
op.dom = current->domain->domain_id;
|
||||
}
|
||||
|
||||
if ( unlikely((d = find_domain_by_id(op.dom)) == NULL) )
|
||||
{
|
||||
@@ -750,14 +656,11 @@ gnttab_dump_table(gnttab_dump_table_t *uop)
|
||||
|
||||
for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
|
||||
{
|
||||
sha_copy = gt->shared[i];
|
||||
|
||||
sha_copy = gt->shared[i];
|
||||
if ( sha_copy.flags )
|
||||
{
|
||||
DPRINTK("Grant: dom (%hu) SHARED (%d) flags:(%hx) "
|
||||
"dom:(%hu) frame:(%x)\n",
|
||||
op.dom, i, sha_copy.flags, sha_copy.domid, sha_copy.frame);
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock(>->lock);
|
||||
@@ -765,28 +668,22 @@ gnttab_dump_table(gnttab_dump_table_t *uop)
|
||||
for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
|
||||
{
|
||||
act = >->active[i];
|
||||
|
||||
if ( act->pin )
|
||||
{
|
||||
DPRINTK("Grant: dom (%hu) ACTIVE (%d) pin:(%x) "
|
||||
"dom:(%hu) frame:(%lx)\n",
|
||||
op.dom, i, act->pin, act->domid, act->frame);
|
||||
}
|
||||
}
|
||||
|
||||
for ( i = 0; i < gt->maptrack_limit; i++ )
|
||||
{
|
||||
maptrack = >->maptrack[i];
|
||||
|
||||
if ( maptrack->ref_and_flags & MAPTRACK_GNTMAP_MASK )
|
||||
{
|
||||
DPRINTK("Grant: dom (%hu) MAP (%d) ref:(%hu) flags:(%x) "
|
||||
"dom:(%hu)\n",
|
||||
op.dom, i,
|
||||
maptrack->ref_and_flags >> MAPTRACK_REF_SHIFT,
|
||||
maptrack->ref_and_flags & MAPTRACK_GNTMAP_MASK,
|
||||
maptrack->domid);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(>->lock);
|
||||
@@ -794,10 +691,10 @@ gnttab_dump_table(gnttab_dump_table_t *uop)
|
||||
put_domain(d);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static long
|
||||
gnttab_transfer(gnttab_transfer_t *uop, unsigned int count)
|
||||
gnttab_transfer(
|
||||
gnttab_transfer_t *uop, unsigned int count)
|
||||
{
|
||||
struct domain *d = current->domain;
|
||||
struct domain *e;
|
||||
@@ -810,10 +707,7 @@ gnttab_transfer(gnttab_transfer_t *uop, unsigned int count)
|
||||
for ( i = 0; i < count; i++ )
|
||||
{
|
||||
gnttab_transfer_t *gop = &uop[i];
|
||||
#if GRANT_DEBUG
|
||||
printk("gnttab_transfer: i=%d mfn=%lx domid=%d gref=%08x\n",
|
||||
i, gop->mfn, gop->domid, gop->handle);
|
||||
#endif
|
||||
|
||||
page = &frame_table[gop->mfn];
|
||||
|
||||
if ( unlikely(IS_XEN_HEAP_FRAME(page)))
|
||||
@@ -956,11 +850,9 @@ do_grant_table_op(
|
||||
case GNTTABOP_setup_table:
|
||||
rc = gnttab_setup_table((gnttab_setup_table_t *)uop, count);
|
||||
break;
|
||||
#if GRANT_DEBUG
|
||||
case GNTTABOP_dump_table:
|
||||
rc = gnttab_dump_table((gnttab_dump_table_t *)uop);
|
||||
break;
|
||||
#endif
|
||||
case GNTTABOP_transfer:
|
||||
if (unlikely(!array_access_ok(
|
||||
uop, count, sizeof(gnttab_transfer_t))))
|
||||
@@ -1002,12 +894,6 @@ gnttab_check_unmap(
|
||||
|
||||
lgt = ld->grant_table;
|
||||
|
||||
#if GRANT_DEBUG_VERBOSE
|
||||
if ( ld->domain_id != 0 )
|
||||
DPRINTK("Foreign unref rd(%d) ld(%d) frm(%lx) flgs(%x).\n",
|
||||
rd->domain_id, ld->domain_id, frame, readonly);
|
||||
#endif
|
||||
|
||||
/* Fast exit if we're not mapping anything using grant tables */
|
||||
if ( lgt->map_count == 0 )
|
||||
return 0;
|
||||
@@ -1098,11 +984,6 @@ gnttab_prepare_for_transfer(
|
||||
int retries = 0;
|
||||
unsigned long target_pfn;
|
||||
|
||||
#if GRANT_DEBUG_VERBOSE
|
||||
DPRINTK("gnttab_prepare_for_transfer rd(%hu) ld(%hu) ref(%hu).\n",
|
||||
rd->domain_id, ld->domain_id, ref);
|
||||
#endif
|
||||
|
||||
if ( unlikely((rgt = rd->grant_table) == NULL) ||
|
||||
unlikely(ref >= NR_GRANT_ENTRIES) )
|
||||
{
|
||||
|
||||
@@ -11,6 +11,11 @@
|
||||
#define E820_NVS 4
|
||||
#define E820_IO 16
|
||||
#define E820_SHARED_PAGE 17
|
||||
#define E820_XENSTORE 18
|
||||
|
||||
#define E820_MAP_PAGE 0x00090000
|
||||
#define E820_MAP_NR_OFFSET 0x000001E8
|
||||
#define E820_MAP_OFFSET 0x000002D0
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
struct e820entry {
|
||||
|
||||
@@ -380,11 +380,9 @@ extern int __sync_lazy_execstate(void);
|
||||
* hold a reference to the page.
|
||||
*/
|
||||
int update_grant_va_mapping(
|
||||
unsigned long va, l1_pgentry_t _nl1e,
|
||||
struct domain *d, struct vcpu *v);
|
||||
unsigned long va, l1_pgentry_t _nl1e, struct vcpu *v);
|
||||
int update_grant_pte_mapping(
|
||||
unsigned long pte_addr, l1_pgentry_t _nl1e,
|
||||
struct domain *d, struct vcpu *v);
|
||||
unsigned long pte_addr, l1_pgentry_t _nl1e, struct vcpu *v);
|
||||
int clear_grant_va_mapping(unsigned long addr, unsigned long frame);
|
||||
int clear_grant_pte_mapping(
|
||||
unsigned long addr, unsigned long frame, struct domain *d);
|
||||
|
||||
@@ -93,7 +93,6 @@ struct virtual_platform_def {
|
||||
|
||||
extern void handle_mmio(unsigned long, unsigned long);
|
||||
extern void vmx_wait_io(void);
|
||||
extern int vmx_setup_platform(struct vcpu *, struct cpu_user_regs *);
|
||||
extern void vmx_io_assist(struct vcpu *v);
|
||||
|
||||
// XXX - think about this -- maybe use bit 30 of the mfn to signify an MMIO frame.
|
||||
|
||||
@@ -110,8 +110,4 @@ gnttab_prepare_for_transfer(
|
||||
void
|
||||
gnttab_release_dev_mappings(grant_table_t *gt);
|
||||
|
||||
/* Extra GNTST_ values, for internal use only. */
|
||||
#define GNTST_flush_all (2) /* Success, need to flush entire TLB. */
|
||||
#define GNTST_flush_one (1) /* Success, need to flush a vaddr. */
|
||||
|
||||
#endif /* __XEN_GRANT_H__ */
|
||||